summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsjaz <sjaz@5417fbe8-f217-4b02-8779-1006273d7864>2009-01-01 12:00:20 +0000
committersjaz <sjaz@5417fbe8-f217-4b02-8779-1006273d7864>2009-01-01 12:00:20 +0000
commitc777c8d9aa7cd5c2e9a399727a7fa9985a77fb1c (patch)
tree9e996ae4a1bbb833cec036c5cd4d87a590149e85 /src
Anope Stable Branch
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/stable@1902 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src')
-rw-r--r--src/Makefile138
-rw-r--r--src/actions.c270
-rw-r--r--src/anope-icon.icobin0 -> 3774 bytes
-rw-r--r--src/base64.c410
-rwxr-xr-xsrc/bin/am499
-rw-r--r--src/bin/anoperc.in141
-rwxr-xr-xsrc/bin/cp-recursive21
-rwxr-xr-xsrc/bin/langtool239
-rwxr-xr-xsrc/bin/mydbgen222
-rwxr-xr-xsrc/bin/register101
-rw-r--r--src/botserv.c1171
-rw-r--r--src/channels.c2322
-rw-r--r--src/chanserv.c2674
-rw-r--r--src/commands.c271
-rw-r--r--src/compat.c228
-rw-r--r--src/config.c1420
-rw-r--r--src/core/Makefile45
-rw-r--r--src/core/Makefile.sub29
-rw-r--r--src/core/Makefile.win3224
-rw-r--r--src/core/bs_act.c92
-rw-r--r--src/core/bs_assign.c102
-rw-r--r--src/core/bs_badwords.c326
-rw-r--r--src/core/bs_bot.c378
-rw-r--r--src/core/bs_botlist.c108
-rw-r--r--src/core/bs_fantasy.c89
-rw-r--r--src/core/bs_fantasy_kick.c98
-rw-r--r--src/core/bs_fantasy_kickban.c99
-rw-r--r--src/core/bs_fantasy_owner.c88
-rw-r--r--src/core/bs_fantasy_seen.c139
-rw-r--r--src/core/bs_help.c67
-rw-r--r--src/core/bs_info.c282
-rw-r--r--src/core/bs_kick.c379
-rw-r--r--src/core/bs_say.c97
-rw-r--r--src/core/bs_set.c208
-rw-r--r--src/core/bs_unassign.c89
-rwxr-xr-xsrc/core/configure53
-rw-r--r--src/core/cs_access.c543
-rw-r--r--src/core/cs_akick.c668
-rw-r--r--src/core/cs_ban.c227
-rw-r--r--src/core/cs_clear.c402
-rw-r--r--src/core/cs_drop.c128
-rw-r--r--src/core/cs_forbid.c139
-rw-r--r--src/core/cs_getkey.c88
-rw-r--r--src/core/cs_getpass.c102
-rw-r--r--src/core/cs_help.c84
-rw-r--r--src/core/cs_identify.c117
-rw-r--r--src/core/cs_info.c249
-rw-r--r--src/core/cs_invite.c90
-rw-r--r--src/core/cs_kick.c152
-rw-r--r--src/core/cs_list.c199
-rw-r--r--src/core/cs_logout.c131
-rw-r--r--src/core/cs_modes.c392
-rw-r--r--src/core/cs_register.c192
-rw-r--r--src/core/cs_sendpass.c125
-rw-r--r--src/core/cs_set.c837
-rw-r--r--src/core/cs_status.c102
-rw-r--r--src/core/cs_suspend.c211
-rw-r--r--src/core/cs_topic.c119
-rw-r--r--src/core/cs_xop.c509
-rw-r--r--src/core/dummy/Makefile6
-rw-r--r--src/core/enc_md5.c427
-rw-r--r--src/core/enc_none.c78
-rw-r--r--src/core/enc_old.c451
-rw-r--r--src/core/enc_sha1.c275
-rw-r--r--src/core/he_help.c76
-rw-r--r--src/core/hs_del.c91
-rw-r--r--src/core/hs_delall.c96
-rw-r--r--src/core/hs_group.c124
-rw-r--r--src/core/hs_help.c66
-rw-r--r--src/core/hs_list.c187
-rw-r--r--src/core/hs_off.c87
-rw-r--r--src/core/hs_on.c102
-rw-r--r--src/core/hs_set.c178
-rw-r--r--src/core/hs_setall.c180
-rw-r--r--src/core/ms_cancel.c105
-rw-r--r--src/core/ms_check.c118
-rw-r--r--src/core/ms_del.c202
-rw-r--r--src/core/ms_help.c66
-rw-r--r--src/core/ms_info.c231
-rw-r--r--src/core/ms_list.c197
-rw-r--r--src/core/ms_read.c203
-rw-r--r--src/core/ms_rsend.c120
-rw-r--r--src/core/ms_send.c74
-rw-r--r--src/core/ms_sendall.c96
-rw-r--r--src/core/ms_set.c266
-rw-r--r--src/core/ms_staff.c93
-rw-r--r--src/core/ns_access.c189
-rw-r--r--src/core/ns_alist.c186
-rw-r--r--src/core/ns_drop.c156
-rw-r--r--src/core/ns_forbid.c155
-rw-r--r--src/core/ns_getemail.c102
-rw-r--r--src/core/ns_getpass.c112
-rw-r--r--src/core/ns_ghost.c118
-rw-r--r--src/core/ns_group.c337
-rw-r--r--src/core/ns_help.c79
-rw-r--r--src/core/ns_identify.c171
-rw-r--r--src/core/ns_info.c284
-rw-r--r--src/core/ns_list.c247
-rw-r--r--src/core/ns_logout.c128
-rw-r--r--src/core/ns_recover.c137
-rw-r--r--src/core/ns_register.c490
-rw-r--r--src/core/ns_release.c127
-rw-r--r--src/core/ns_saset.c533
-rw-r--r--src/core/ns_sendpass.c122
-rw-r--r--src/core/ns_set.c475
-rw-r--r--src/core/ns_status.c94
-rw-r--r--src/core/ns_suspend.c193
-rw-r--r--src/core/ns_update.c90
-rw-r--r--src/core/os_admin.c249
-rw-r--r--src/core/os_akill.c386
-rw-r--r--src/core/os_chankill.c134
-rw-r--r--src/core/os_chanlist.c116
-rw-r--r--src/core/os_clearmodes.c328
-rw-r--r--src/core/os_defcon.c169
-rw-r--r--src/core/os_global.c82
-rw-r--r--src/core/os_help.c66
-rw-r--r--src/core/os_ignore.c146
-rw-r--r--src/core/os_jupe.c88
-rw-r--r--src/core/os_kick.c100
-rw-r--r--src/core/os_logonnews.c98
-rw-r--r--src/core/os_mode.c102
-rw-r--r--src/core/os_modinfo.c139
-rw-r--r--src/core/os_modlist.c195
-rw-r--r--src/core/os_modload.c83
-rw-r--r--src/core/os_modunload.c85
-rw-r--r--src/core/os_noop.c106
-rw-r--r--src/core/os_oline.c108
-rw-r--r--src/core/os_oper.c252
-rw-r--r--src/core/os_opernews.c97
-rw-r--r--src/core/os_quit.c82
-rw-r--r--src/core/os_randomnews.c66
-rw-r--r--src/core/os_raw.c78
-rw-r--r--src/core/os_reload.c84
-rw-r--r--src/core/os_restart.c91
-rw-r--r--src/core/os_session.c68
-rw-r--r--src/core/os_set.c264
-rw-r--r--src/core/os_sgline.c362
-rw-r--r--src/core/os_shutdown.c83
-rw-r--r--src/core/os_sqline.c355
-rw-r--r--src/core/os_staff.c156
-rw-r--r--src/core/os_stats.c453
-rw-r--r--src/core/os_svsnick.c125
-rw-r--r--src/core/os_szline.c350
-rw-r--r--src/core/os_umode.c116
-rw-r--r--src/core/os_update.c74
-rw-r--r--src/core/os_userlist.c121
-rw-r--r--src/datafiles.c788
-rw-r--r--src/encrypt.c122
-rw-r--r--src/events.c787
-rw-r--r--src/helpserv.c69
-rw-r--r--src/hostserv.c655
-rw-r--r--src/init.c789
-rw-r--r--src/ircd.c1215
-rw-r--r--src/language.c309
-rw-r--r--src/list.c196
-rw-r--r--src/log.c336
-rw-r--r--src/mail.c285
-rw-r--r--src/main.c752
-rw-r--r--src/makefile.win32109
-rw-r--r--src/memory.c138
-rw-r--r--src/memoserv.c445
-rw-r--r--src/messages.c415
-rw-r--r--src/misc.c1663
-rw-r--r--src/mod_version.c36
-rw-r--r--src/modules.c2874
-rw-r--r--src/modules/Makefile48
-rw-r--r--src/modules/Makefile.sub28
-rw-r--r--src/modules/README1
-rw-r--r--src/modules/bs_fantasy_unban.c82
-rwxr-xr-xsrc/modules/configure58
-rw-r--r--src/modules/cs_appendtopic.c247
-rw-r--r--src/modules/cs_enforce.c479
-rw-r--r--src/modules/cs_tban.c253
-rw-r--r--src/modules/demos/catserv/Makefile9
-rw-r--r--src/modules/demos/catserv/README4
-rw-r--r--src/modules/demos/catserv/catserv_extern.h11
-rw-r--r--src/modules/demos/catserv/catserv_messages.c14
-rw-r--r--src/modules/demos/catserv/catserv_messages.h10
-rw-r--r--src/modules/demos/catserv/ircd_catserv.c112
-rw-r--r--src/modules/demos/catserv/makefile.win324
-rw-r--r--src/modules/demos/catserv/meow.c9
-rw-r--r--src/modules/demos/catserv/meow.h9
-rw-r--r--src/modules/demos/catserv/purr.c8
-rw-r--r--src/modules/demos/catserv/purr.h9
-rw-r--r--src/modules/demos/events.c82
-rw-r--r--src/modules/demos/hs_conf.c74
-rw-r--r--src/modules/demos/hs_moo.c119
-rw-r--r--src/modules/dummy/Makefile6
-rw-r--r--src/modules/hs_request.c986
-rw-r--r--src/modules/makefile.inc.win322
-rw-r--r--src/modules/makefile.sub.win3219
-rw-r--r--src/modules/makefile.win3241
-rw-r--r--src/modules/ns_maxemail.c228
-rw-r--r--src/modules/ns_noop_convert.c173
-rw-r--r--src/modules/os_ignore_db.c545
-rw-r--r--src/modules/os_info.c780
-rw-r--r--src/mypasql.c122
-rw-r--r--src/mypasql.def10
-rw-r--r--src/mysql.c2058
-rw-r--r--src/news.c554
-rw-r--r--src/nickserv.c1995
-rw-r--r--src/operserv.c1774
-rw-r--r--src/process.c417
-rw-r--r--src/protocol/Makefile45
-rw-r--r--src/protocol/Makefile.sub29
-rw-r--r--src/protocol/Makefile.win3226
-rw-r--r--src/protocol/bahamut.c1680
-rw-r--r--src/protocol/bahamut.h131
-rw-r--r--src/protocol/charybdis.c2008
-rw-r--r--src/protocol/charybdis.h120
-rwxr-xr-xsrc/protocol/configure53
-rw-r--r--src/protocol/dreamforge.c1384
-rw-r--r--src/protocol/dreamforge.h111
-rw-r--r--src/protocol/dummy/Makefile6
-rw-r--r--src/protocol/hybrid.c1573
-rw-r--r--src/protocol/hybrid.h115
-rw-r--r--src/protocol/inspircd10.c1713
-rw-r--r--src/protocol/inspircd10.h133
-rw-r--r--src/protocol/inspircd11.c1928
-rwxr-xr-xsrc/protocol/inspircd11.h134
-rw-r--r--src/protocol/plexus2.c1880
-rw-r--r--src/protocol/plexus2.h126
-rw-r--r--src/protocol/plexus3.c1857
-rw-r--r--src/protocol/plexus3.h113
-rw-r--r--src/protocol/ptlink.c1800
-rw-r--r--src/protocol/ptlink.h152
-rw-r--r--src/protocol/rageircd.c1679
-rw-r--r--src/protocol/rageircd.h113
-rw-r--r--src/protocol/ratbox.c1882
-rw-r--r--src/protocol/ratbox.h119
-rw-r--r--src/protocol/shadowircd.c1833
-rw-r--r--src/protocol/shadowircd.h142
-rw-r--r--src/protocol/solidircd.c1710
-rw-r--r--src/protocol/solidircd.h137
-rw-r--r--src/protocol/ultimate2.c1734
-rw-r--r--src/protocol/ultimate2.h120
-rw-r--r--src/protocol/ultimate3.c1818
-rw-r--r--src/protocol/ultimate3.h125
-rw-r--r--src/protocol/unreal31.c1592
-rw-r--r--src/protocol/unreal31.h124
-rw-r--r--src/protocol/unreal32.c2232
-rw-r--r--src/protocol/unreal32.h153
-rw-r--r--src/protocol/viagra.c1716
-rw-r--r--src/protocol/viagra.h132
-rw-r--r--src/rdb.c499
-rw-r--r--src/send.c341
-rw-r--r--src/servers.c618
-rw-r--r--src/sessions.c873
-rw-r--r--src/slist.c395
-rw-r--r--src/sockutil.c737
-rw-r--r--src/timeout.c132
-rw-r--r--src/tools/Anope_Install_Script.nsi540
-rw-r--r--src/tools/Anope_MySQL_Install_Script.nsi542
-rw-r--r--src/tools/Makefile39
-rw-r--r--src/tools/Makefile.win3229
-rw-r--r--src/tools/README58
-rw-r--r--src/tools/anopesmtp.c604
-rw-r--r--src/tools/db-merger.c2031
-rw-r--r--src/tools/epona2anope.c856
-rw-r--r--src/tools/smtp.h130
-rw-r--r--src/users.c1125
-rw-r--r--src/win32.rc.template90
262 files changed, 100982 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 000000000..739c91814
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,138 @@
+MYSQL_OBJ = $(MYSQL:.c=.o)
+RDB_OBJ = $(RDB:.c=.o)
+OBJS = actions.o base64.o botserv.o channels.o chanserv.o commands.o compat.o \
+ config.o datafiles.o encrypt.o events.o helpserv.o hostserv.o init.o ircd.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 send.o servers.o sessions.o slist.o sockutil.o timeout.o users.o \
+ $(RDB_OBJ) $(MYSQL_OBJ)
+SRCS = actions.c base64.c botserv.c channels.c chanserv.c commands.c compat.c \
+ config.c datafiles.c encrypt.c events.c helpserv.c hostserv.c init.c ircd.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 send.c servers.c sessions.c slist.c sockutil.c timeout.c users.c \
+ $(RDB) $(MYSQL)
+
+INCLUDES = ../include/commands.h ../include/defs.h ../include/language.h \
+ ../include/pseudo.h ../include/sysconf.h ../include/config.h \
+ ../include/encrypt.h ../include/messages.h ../include/services.h \
+ ../include/timeout.h ../include/datafiles.h ../include/extern.h \
+ ../include/modules.h ../include/slist.h
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' 'MYSQL=${MYSQL}'\
+ 'RDB=${RDB}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+.c.o:
+ $(CC) $(CFLAGS) -I../include/ -c $<
+
+all: services
+
+distclean: spotless
+distclean_modules: clean_modules spotless
+
+services: $(OBJS) mod_version
+ $(CC) $(CFLAGS) $(OBJS) $(ANOPELIBS) $(MLIBS) -o $@ $(LDFLAGS)
+
+$(OBJS): Makefile
+actions.o: actions.c $(INCLUDES)
+base64.o: base64.c $(INCLUDES)
+botserv.o: botserv.c $(INCLUDES)
+channels.o: channels.c $(INCLUDES)
+chanserv.o: chanserv.c $(INCLUDES)
+commands.o: commands.c $(INCLUDES)
+compat.o: compat.c $(INCLUDES)
+config.o: config.c $(INCLUDES)
+datafiles.o: datafiles.c $(INCLUDES)
+encrypt.o: encrypt.c $(INCLUDES)
+events.o: events.c $(INCLUDES)
+init.o: init.c $(INCLUDES)
+ircd.o: ircd.c $(INCLUDES)
+helpserv.o: helpserv.c $(INCLUDES)
+hostserv.o: hostserv.c $(INCLUDES)
+language.o: language.c $(INCLUDES)
+list.o: list.c $(INCLUDES)
+log.o: log.c $(INCLUDES)
+mail.o: mail.c $(INCLUDES)
+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)
+misc.o: misc.c $(INCLUDES)
+news.o: news.c $(INCLUDES)
+nickserv.o: nickserv.c $(INCLUDES)
+operserv.o: operserv.c $(INCLUDES)
+process.o: process.c $(INCLUDES)
+send.o: send.c $(INCLUDES)
+servers.o: servers.c $(INCLUDES)
+sessions.o: sessions.c $(INCLUDES)
+slist.o: slist.c $(INCLUDES)
+sockutil.o: sockutil.c $(INCLUDES)
+timeout.o: timeout.c $(INCLUDES)
+users.o: users.c $(INCLUDES)
+vsnprintf.o: vsnprintf.c $(INCLUDES)
+mysql.o: mysql.c $(INCLUDES)
+rdb.o: rdb.c $(INCLUDES)
+
+mod_version: mod_version.c $(INCLUDES)
+ $(CC) $(CDEFS) $(CFLAGS) $(MODULEFLAGS) -I../include/ -c mod_version.c
+
+
+modules: DUMMY
+ (cd modules ; ./configure ; ${MAKE} ${MAKEARGS} all)
+
+protocols: DUMMY
+ (cd protocol ; ./configure ; ${MAKE} ${MAKEARGS} all)
+core: DUMMY
+ (cd core ; ./configure ; ${MAKE} ${MAKEARGS} all)
+
+clean: clean_modules clean_protocols clean_core
+ rm -f *.o services a.out
+clean_modules:
+ @touch modules/Makefile.inc # Horribly ugly...
+ (cd modules ; ${MAKE} clean)
+
+clean_protocols:
+ @touch protocol/Makefile.inc
+ (cd protocol ; ${MAKE} clean)
+
+clean_core:
+ @touch core/Makefile.inc
+ (cd core ; ${MAKE} clean)
+
+spotless:
+ (cd modules ; ${MAKE} distclean)
+ (cd protocol ; ${MAKE} distclean)
+ (cd core ; ${MAKE} distclean)
+
+install: services
+ test -d ${BINDEST} || mkdir ${BINDEST}
+ $(INSTALL) services $(BINDEST)/services
+ $(INSTALL) bin/anoperc $(BINDEST)/anoperc
+ rm -f $(BINDEST)/listnicks $(BINDEST)/listchans
+ ln $(BINDEST)/services $(BINDEST)/listnicks
+ ln $(BINDEST)/services $(BINDEST)/listchans
+ (cd ../lang ; $(MAKE) install)
+ $(CP) ../data/* $(DATDEST)
+ $(INSTALL) bin/mydbgen $(DATDEST)/mydbgen
+ test -d $(DATDEST)/backups || mkdir $(DATDEST)/backups
+ test -d $(DATDEST)/logs || mkdir $(DATDEST)/logs
+ @if [ "$(MODULE_PATH)" ] ; then \
+ test -d ${MODULE_PATH} || mkdir ${MODULE_PATH} ; \
+ test -d ${MODULE_PATH}/runtime || mkdir ${MODULE_PATH}/runtime ; \
+ (cd modules ; $(MAKE) install) ; \
+ (cd protocol ; ${MAKE} install) ; \
+ (cd core ; ${MAKE} install) ; \
+ fi
+ @if [ "$(RUNGROUP)" ] ; then \
+ echo chgrp -R $(RUNGROUP) $(DATDEST) ; \
+ chgrp -R $(RUNGROUP) $(DATDEST) ; \
+ echo chmod -R g+rw $(DATDEST) ; \
+ chmod -R g+rw $(DATDEST) ; \
+ echo find $(DATDEST) -type d -exec chmod g+xs \'\{\}\' \\\; ; \
+ find $(DATDEST) -type d -exec chmod g+xs '{}' \; ; \
+ fi
+
+DUMMY:
diff --git a/src/actions.c b/src/actions.c
new file mode 100644
index 000000000..46617643b
--- /dev/null
+++ b/src/actions.c
@@ -0,0 +1,270 @@
+/* Various routines to perform simple actions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+/**
+ * Note a bad password attempt for the given user. If they've used up
+ * their limit, toss them off.
+ * @param u the User to check
+ * @return void
+ */
+void bad_password(User * u)
+{
+ time_t now = time(NULL);
+
+ if (!u || !BadPassLimit) {
+ return;
+ }
+
+ if (BadPassTimeout > 0 && u->invalid_pw_time > 0
+ && u->invalid_pw_time < now - BadPassTimeout)
+ u->invalid_pw_count = 0;
+ u->invalid_pw_count++;
+ u->invalid_pw_time = now;
+ if (u->invalid_pw_count >= BadPassLimit) {
+ kill_user(NULL, u->nick, "Too many invalid passwords");
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Remove a user from the IRC network.
+ * @param source is the nick which should generate the kill, or NULL for a server-generated kill.
+ * @param user to remove
+ * @param reason for the kill
+ * @return void
+ */
+void kill_user(char *source, char *user, char *reason)
+{
+ char buf[BUFSIZE];
+
+ if (!user || !*user) {
+ return;
+ }
+ if (!source || !*source) {
+ source = ServerName;
+ }
+ if (!reason) {
+ reason = "";
+ }
+
+ snprintf(buf, sizeof(buf), "%s (%s)", source, reason);
+
+ anope_cmd_svskill(source, user, buf);
+
+ if (!ircd->quitonkill && finduser(user)) {
+ do_kill(user, buf);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Check and enforce SQlines
+ * @param mask of the sqline
+ * @param reason for the sqline
+ * @return void
+ */
+void sqline(char *mask, char *reason)
+{
+ int i;
+ Channel *c, *next;
+ char *av[3];
+ struct c_userlist *cu, *cunext;
+
+ if (ircd->chansqline) {
+ if (*mask == '#') {
+ anope_cmd_sqline(mask, reason);
+
+ for (i = 0; i < 1024; i++) {
+ for (c = chanlist[i]; c; c = next) {
+ next = c->next;
+
+ if (!match_wild_nocase(mask, c->name)) {
+ continue;
+ }
+ for (cu = c->users; cu; cu = cunext) {
+ cunext = cu->next;
+ if (is_oper(cu->user)) {
+ continue;
+ }
+ av[0] = c->name;
+ av[1] = cu->user->nick;
+ av[2] = reason;
+ anope_cmd_kick(s_OperServ, av[0], av[1],
+ "Q-Lined: %s", av[2]);
+ do_kick(s_ChanServ, 3, av);
+ }
+ }
+ }
+ } else {
+ anope_cmd_sqline(mask, reason);
+ }
+ } else {
+ anope_cmd_sqline(mask, reason);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Unban the nick from a channel
+ * @param ci channel info for the channel
+ * @param nick to remove the ban for
+ * @return void
+ */
+void common_unban(ChannelInfo * ci, char *nick)
+{
+ char *av[4];
+ char *host = NULL;
+ char buf[BUFSIZE];
+ int ac;
+ uint32 ip = 0;
+ User *u;
+ Entry *ban, *next;
+
+ if (!ci || !ci->c || !nick) {
+ return;
+ }
+
+ if (!(u = finduser(nick))) {
+ return;
+ }
+
+ if (!ci->c->bans || (ci->c->bans->count == 0))
+ return;
+
+ if (u->hostip == NULL) {
+ host = host_resolve(u->host);
+ /* we store the just resolved hostname so we don't
+ * need to do this again */
+ if (host) {
+ u->hostip = sstrdup(host);
+ }
+ } else {
+ host = sstrdup(u->hostip);
+ }
+ /* Convert the host to an IP.. */
+ if (host)
+ ip = str_is_ip(host);
+
+ if (ircd->svsmode_unban) {
+ anope_cmd_unban(ci->name, nick);
+ } else {
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = ci->name;
+ av[1] = buf;
+ av[2] = sstrdup("-b");
+ ac = 4;
+ } else {
+ av[0] = ci->name;
+ av[1] = sstrdup("-b");
+ ac = 3;
+ }
+
+ for (ban = ci->c->bans->entries; ban; ban = next) {
+ next = ban->next;
+ if (entry_match(ban, u->nick, u->username, u->host, ip) ||
+ entry_match(ban, u->nick, u->username, u->vhost, ip)) {
+ anope_cmd_mode(whosends(ci), ci->name, "-b %s", ban->mask);
+ if (ircdcap->tsmode)
+ av[3] = ban->mask;
+ else
+ av[2] = ban->mask;
+
+ do_cmode(whosends(ci), ac, av);
+ }
+ }
+
+ if (ircdcap->tsmode)
+ free(av[2]);
+ else
+ free(av[1]);
+ }
+ /* host_resolve() sstrdup us this info so we gotta free it */
+ if (host) {
+ free(host);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Prepare to set SVSMODE and update internal user modes
+ * @param u user to apply modes to
+ * @param modes the modes to set on the user
+ * @param arg the arguments for the user modes
+ * @return void
+ */
+void common_svsmode(User * u, char *modes, char *arg)
+{
+ int ac = 1;
+ char *av[2];
+
+ av[0] = modes;
+ if (arg) {
+ av[1] = arg;
+ ac++;
+ }
+
+ anope_cmd_svsmode(u, ac, av);
+ anope_set_umode(u, ac, av);
+}
+
+/*************************************************************************/
+
+/**
+ * Get the vhost for the user, if set else return the host, on ircds without
+ * vhost this returns the host
+ * @param u user to get the vhost for
+ * @return vhost
+ */
+char *common_get_vhost(User * u)
+{
+ if (!u)
+ return NULL;
+
+ if (ircd->vhostmode && (u->mode & ircd->vhostmode))
+ return u->vhost;
+ else if (ircd->vhost && u->vhost)
+ return u->vhost;
+ else
+ return u->host;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the vident for the user, if set else return the ident, on ircds without
+ * vident this returns the ident
+ * @param u user to get info the vident for
+ * @return vident
+ */
+char *common_get_vident(User * u)
+{
+ if (!u)
+ return NULL;
+
+ if (ircd->vhostmode && (u->mode & ircd->vhostmode))
+ return u->vident;
+ else if (ircd->vident && u->vident)
+ return u->vident;
+ else
+ return u->username;
+}
diff --git a/src/anope-icon.ico b/src/anope-icon.ico
new file mode 100644
index 000000000..be735614a
--- /dev/null
+++ b/src/anope-icon.ico
Binary files differ
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 000000000..10b2f0254
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,410 @@
+/* base64 routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ *
+ */
+
+/*
+ This is borrowed from Unreal
+*/
+
+#include "services.h"
+
+static char *int_to_base64(long);
+static long base64_to_int(char *);
+
+char *base64enc(long i)
+{
+ if (i < 0)
+ return ("0");
+ return int_to_base64(i);
+}
+
+long base64dec(char *b64)
+{
+ if (b64)
+ return base64_to_int(b64);
+ else
+ return 0;
+}
+
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int b64_encode(char *src, size_t srclength, char *target, size_t targsize)
+{
+ size_t datalength = 0;
+ unsigned char input[3];
+ unsigned char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int b64_decode(char *src, char *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t) tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t) tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex + 1] = ((pos - Base64) & 0x0f)
+ << 4;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t) tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex + 1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t) tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void) NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void) NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
+
+char *encode_ip(unsigned char *ip)
+{
+ static char buf[25];
+ unsigned char *cp;
+ struct in_addr ia; /* For IPv4 */
+ char *s_ip; /* Signed ip string */
+
+ if (!ip)
+ return "*";
+
+ if (strchr((char *) ip, ':')) {
+ return NULL;
+ } else {
+ s_ip = str_signed(ip);
+ ia.s_addr = inet_addr(s_ip);
+ cp = (unsigned char *) ia.s_addr;
+ b64_encode((char *) &cp, sizeof(struct in_addr), buf, 25);
+ }
+ return buf;
+}
+
+int decode_ip(char *buf)
+{
+ int len = strlen(buf);
+ char targ[25];
+ struct in_addr ia;
+
+ b64_decode(buf, targ, 25);
+ ia = *(struct in_addr *) targ;
+ if (len == 24) { /* IPv6 */
+ return 0;
+ } else if (len == 8) /* IPv4 */
+ return ia.s_addr;
+ else /* Error?? */
+ return 0;
+}
+
+/* ':' and '#' and '&' and '+' and '@' must never be in this table. */
+/* these tables must NEVER CHANGE! >) */
+char int6_to_base64_map[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+ 'E', 'F',
+ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V',
+ 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '{', '}'
+};
+
+char base64_to_int6_map[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, 63, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char *int_to_base64(long val)
+{
+ /* 32/6 == max 6 bytes for representation,
+ * +1 for the null, +1 for byte boundaries
+ */
+ static char base64buf[8];
+ long i = 7;
+
+ base64buf[i] = '\0';
+
+ /* Temporary debugging code.. remove before 2038 ;p.
+ * This might happen in case of 64bit longs (opteron/ia64),
+ * if the value is then too large it can easily lead to
+ * a buffer underflow and thus to a crash. -- Syzop
+ */
+ if (val > 2147483647L) {
+ abort();
+ }
+
+ do {
+ base64buf[--i] = int6_to_base64_map[val & 63];
+ }
+ while (val >>= 6);
+
+ return base64buf + i;
+}
+
+static long base64_to_int(char *b64)
+{
+ int v = base64_to_int6_map[(unsigned char) *b64++];
+
+ if (!b64)
+ return 0;
+
+ while (*b64) {
+ v <<= 6;
+ v += base64_to_int6_map[(unsigned char) *b64++];
+ }
+
+ return v;
+}
+
+long base64dects(char *ts)
+{
+ char *token;
+ long value;
+
+ if (!ts) {
+ return 0;
+ }
+ token = myStrGetToken(ts, '!', 1);
+
+ if (!token) {
+ return strtoul(ts, NULL, 10);
+ }
+ value = base64dec(token);
+ Anope_Free(token);
+ return value;
+}
diff --git a/src/bin/am b/src/bin/am
new file mode 100755
index 000000000..df9a71a14
--- /dev/null
+++ b/src/bin/am
@@ -0,0 +1,499 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# anomgr: Anope Manager. Used to manage anope revision on SubVersion.
+#
+# For usage, see the usage subroutine or run the script with no
+# command line arguments.
+#
+# $Id$
+#
+# ====================================================================
+require 5.6.0;
+use strict;
+use Getopt::Std;
+use Net::FTP;
+use Cwd;
+
+######################################################################
+# Configuration section.
+my $myver="1.0";
+my $svnrev="http://www.zero.org/anosvn.php";
+my $fhint="version.log";
+
+# Default values, change or use environment variables instead.
+my $copy="anope";
+my $svnuser="evil_closet_monkey";
+my $svnpath="/usr/bin";
+my $svnroot="svn://svn.anope.org/$copy";
+my $editor="/usr/bin/mcedit";
+
+# Environment variables SVNBINDIR and SVNROOT override the above
+# hardcoded values.
+$svnuser="$ENV{SVNUSER}" if ($ENV{SVNUSER});
+$svnpath="$ENV{SVNBINDIR}" if ($ENV{SVNBINDIR});
+$svnroot="$ENV{SVNROOT}" if ($ENV{SVNROOT});
+$editor="$ENV{EDITOR}" if ($ENV{EDITOR});
+
+# Svnlook path.
+my $svnlook = "$svnpath/svnlook";
+
+# Svn path.
+my $svn = "$svnpath/svn";
+
+# wget path. Need to change to a perl module instead...
+my $wget = "$svnpath/wget";
+
+my (
+ $rev,
+ $branch,
+ $proto,
+ $tag,
+ $ftp,
+ $dst,
+ $ver_major,
+ $ver_minor,
+ $ver_patch,
+ $ver_build,
+ $ver_revision,
+ $ver_comment,
+ $svn_comment,
+ $cver,
+ $nver,
+ $ctrlfile,
+ $tmpfile,
+ @source,
+ %opt
+);
+
+{
+ my $ok = 1;
+ foreach my $program ($svnlook, $svn, $editor)
+ {
+ if (-e $program)
+ {
+ unless (-x $program)
+ {
+ warn "$0: required program `$program' is not executable, ",
+ "edit $0.\n";
+ $ok = 0;
+ }
+ }
+ else
+ {
+ warn "$0: required program `$program' does not exist, edit $0.\n";
+ $ok = 0;
+ }
+ }
+ exit 1 unless $ok;
+}
+
+sub usage()
+{
+ # More features to add:
+ # --diff N:M to produce a diff between revisions
+ # --bugs CLI method to add bug number to the commit message
+ # --mesg CLI methos to add the commit message
+ # --create-branch to create a branch
+ # --create-tag to create a tag
+ # --switch to switch between branches/tags
+ print "Usage: $0 <-g | -p | -f | -l> [-r revision | -b branch | -t tag | -P proto] <destination>\n";
+ print " Operations:\n";
+ print " -g Get Operation\n";
+ print " -p Put Operation\n";
+ print " -f[tar|diff] FTP Operation, retrieve latest tar or diff\n";
+ print " -l List Operation, for valid selector options\n";
+ print " Selector:\n";
+ print " -r revision Retrieve by revision number\n";
+ print " -b branch Retrieve by branch name\n";
+ print " -t tag Retrieve by tag name\n";
+ print " -P proto Retrieve by prototype name\n";
+ print " Destination:\n";
+ print " The working copy to perform the operation in or to. The script will \n";
+ print " try to guess where that is, unless you provide a specific path.\n";
+ exit;
+}
+
+sub banner() {
+
+ print "Anope Source Managemnt Utility - Version $myver\n\n";
+
+}
+
+sub getans {
+ my $ans;
+ while (! (($ans =~ /y/) || ($ans =~ /n/))) {
+ print "*** Ready to continue? (y/n): ";
+ $ans = <STDIN>;
+ chomp($ans);
+ $ans = lc($ans);
+ # $ans = &getans();
+ }
+
+ # return $ans;
+ return ($ans eq "y") ? 1 : 0
+}
+
+sub find_conflict() {
+
+ my $filename=shift;
+ my $retval=0;
+ open (IN2, "$filename") || die "Can't open $filename\n";
+ while (<IN2>) {
+ if (/^<<<<<<</) {
+ $retval=1;
+ }
+ }
+ close(IN2);
+
+ return $retval;
+}
+
+sub do_lst() {
+ my $out;
+ print "*** BRANCHES:\n";
+ print "trunk (DEFAULT)\n";
+ open (IN, "$svn list $svnroot/branches|");
+ while (<IN>) {
+ if (! /proto/) {
+ $out="$_";
+ $out =~ s/\/$//;
+ print "$out";
+ }
+ }
+ close(IN);
+
+ print "\n*** PROTOTYPES:\n";
+ open (IN, "$svn list $svnroot/branches/proto|");
+ while (<IN>) {
+ $out="$_";
+ $out =~ s/\/$//;
+ chomp($out);
+ if (/bahamut18/) {
+ $out .= "\t(OBSOLETE)";
+ } elsif (/capab/) {
+ $out .= "\t(OBSOLETE)";
+ }
+ print "$out\n";
+ }
+ close(IN);
+
+ print "\n*** TAGS:\n";
+ open (IN, "$svn list $svnroot/tags|");
+ while (<IN>) {
+ $out="$_";
+ $out =~ s/\/$//;
+ print "$out";
+ }
+ close(IN);
+ print "\n";
+
+}
+
+sub do_ftp() {
+
+ my $ftpc;
+ $ftpc = Net::FTP->new("ftp.zero.org");
+ $ftpc->login("ftp","-anonymou@");
+ $ftpc->cwd("/incoming");
+
+ if ( lc($ftp) eq "tar" ) {
+ print "Retrieving latest tar ball...\n";
+ $ftpc->get("anope.tgz");
+ } elsif ( lc($ftp) eq "diff" ) {
+ print "Retrieving latest patch file...\n";
+ $ftpc->get("anope.diff");
+ } else {
+ print "Unknown type $ftp, aborting...\n";
+ }
+ $ftpc->quit();
+}
+
+sub do_get() {
+
+ my $options = "" ; # Options to be passed to the svn command
+ my $selector = "" ; # Selector to be passed to the svn command
+
+ if ($rev) {
+ $options .= "-r $rev";
+ $selector = "trunk";
+ $copy = $copy . "-$rev";
+ } elsif ($tag) {
+ $selector = "tags/$tag";
+ $copy = "$tag";
+ } elsif ($branch) {
+ $selector = "branches/$branch";
+ $copy = $copy . "-$branch";
+ } elsif ($proto) {
+ $selector = "branches/proto/$proto";
+ $copy = "$proto";
+ } else {
+ $selector = "trunk";
+ }
+
+ if ($dst eq undef) {
+ my $cwd = &Cwd::cwd();
+ if (-f "$cwd/$fhint") {
+ system("$svn update $options $cwd");
+ } elsif (-f "$cwd/$copy/$fhint") {
+ system("$svn update $options $cwd/$copy");
+ } else {
+ system("$svn checkout $svnroot/$selector $options $cwd/$copy");
+ }
+ } else {
+ $dst = &Cwd::cwd() if ($dst eq "\.") ;
+ if (-f "$dst/$fhint") {
+ system("$svn update $options $dst");
+ } else {
+ system("$svn checkout $svnroot/$selector $options $dst");
+ }
+ }
+}
+
+sub do_put() {
+
+ if ($dst eq undef) {
+ my $cwd = &Cwd::cwd();
+ if (-f "$cwd/$fhint") {
+ $dst = "$cwd";
+ } elsif (-f "$cwd/$copy/$fhint") {
+ $dst .= "$cwd/$copy";
+ } else {
+ print "Error: Unable to determine your working copy location.\n";
+ exit;
+ }
+ } else {
+ $dst = &Cwd::cwd() if ($dst eq "\.") ;
+ if (! -f "$dst/$fhint") {
+ print "Error: Unable to determine your working copy location.\n";
+ exit;
+ }
+ }
+
+ # Check to see if we need to update our working copy first.
+ my $nupdate;
+ open (IN, "$svn status --show-updates --verbose $dst|");
+ while (<IN>) {
+ if (/\*/) {
+ $nupdate .= "$_";
+ }
+ }
+ close(IN);
+
+ if ($nupdate ne undef) {
+ print "*** Warning: There are files modified in the repository that need\n";
+ print "*** to be merged back to your working copy before the commit can\n";
+ print "*** take place. These files are:\n";
+ print $nupdate;
+ print "Please use: $0 -g $dst\n";
+ exit;
+ }
+
+ # Get a prelim diff of the changes...
+ my $dcount=0;
+ my $conflict;
+ # open (IN, "$svn diff $dst|");
+ open (IN, "$svn status $dst|");
+ while (<IN>) {
+ if (!/^\?/) {
+ $dcount++;
+ }
+
+ if (/^C/) {
+ $_ =~ s/^C\s+//;
+ chomp($_);
+ # I don't want to use grep. But my find_conflict sub
+ # does not seem to work :( Too bad
+ if (`grep "^<<<<<<<" $_`) {
+ $conflict .= "$_\n" ;
+ } else {
+ system("$svn resolved $_");
+ }
+ }
+ }
+ close(IN);
+
+ if ($dcount == 0) {
+ print "*** Warning: There are no modified files to be commited. Are you\n";
+ print "*** sure you are in the right working copy? Verify changes with:\n";
+ print "*** $svn diff $dst\n";
+ exit;
+ }
+
+ if ($conflict ne undef) {
+ print "*** Warning: There are merge conflicts to be resolved! Please take\n";
+ print "*** a look at the following files and resolve them manually:\n\n";
+ print "$conflict\n";
+ exit;
+ }
+
+ $ctrlfile = "$dst/$fhint";
+ # Grab the current revision number. Clunky way, I know!
+# $ver_revision=`$wget -qO - $svnrev`;
+ $ver_revision=`svnversion . | sed "s/.*:\\\(.*\\\)/\\1/" | cut -d 'M' -f 1 | cut -d 'S' -f 1`;
+ chomp($ver_revision);
+
+ unless ($ver_revision =~ /^\d+/ and $ver_revision > 0)
+ {
+ print "*** Error: Got bogus result $ver_revision from $svnrev.\n";
+ exit;
+ }
+
+ $ver_revision++;
+ open (REV, "$ctrlfile") || die "Can't open $ctrlfile\n";
+ while (<REV>) {
+ push (@source, $_);
+ $ver_major = $_ if (/VERSION_MAJOR/);
+ $ver_minor = $_ if (/VERSION_MINOR/);
+ $ver_patch = $_ if (/VERSION_PATCH/);
+ $ver_build = $_ if (/VERSION_BUILD/);
+ }
+ close(REV);
+
+ my $junk;
+ ($junk, $ver_major) = split('"', $ver_major);
+ ($junk, $ver_minor) = split('"', $ver_minor);
+ ($junk, $ver_patch) = split('"', $ver_patch);
+ ($junk, $ver_build) = split('"', $ver_build);
+
+ $cver = "$ver_major.$ver_minor.$ver_patch ($ver_build)";
+ $nver = "$ver_major.$ver_minor.$ver_patch ($ver_revision)";
+
+ # Greet the developer
+ banner();
+
+
+ # Check to see if we need to update our working copy first.
+ my $svnrepo;
+ open (IN, "$svn info|");
+ while (<IN>) {
+ if (/URL/) {
+ $svnrepo = "$_";
+ $svnrepo =~ s/URL: //;
+ }
+ }
+ close(IN);
+
+ print "*** Repository : $svnroot \n";
+ print "*** Working copy : $dst \n" ;
+ print "*** Current ver. : $cver \n";
+ print "*** Updated ver. : $nver \n";
+ print "*** Files Changed: $dcount (before indent and version change)\n";
+ die ("Aborting...\n") unless &getans();
+
+ # Need to add a clause for -c "comment" and -b "buglist"
+
+ # Get developers input for commit
+ $tmpfile=".commit";
+ open (OUT, ">$tmpfile") or die ("*** Error! Unable to open $tmpfile file\n");
+ print OUT "# Anope commit utility. Please use this template for your commits.
+# Add Bugzilla bugs separated by spaces. The note part is free form.
+BUILD : $nver
+BUGS :
+NOTES : ";
+ close(OUT);
+
+ system("$editor $tmpfile");
+
+ my $tmp_comment="";
+ $ver_comment="#\n";
+ $svn_comment="";
+ open (IN, "$tmpfile") or die ("*** Error! Unable to open $tmpfile file\n");
+ while (<IN>) {
+ if ( !/^#/) {
+ $tmp_comment.="$_";
+ chomp($_);
+ $_ =~ s/\t/ /g;
+ $ver_comment.="# $_\n";
+ $svn_comment.="$_ ";
+ }
+ }
+ close(IN);
+
+ $svn_comment =~ s/\s\s+/ /g;
+ # Confirm the commit one last time...
+ print "*** Ready to commit, please verify:\n";
+ print "\n$tmp_comment\n";
+
+ die ("Aborting...\n") unless &getans();
+
+ print "*** Running Indent...\n";
+ my $prefix=".";
+ if (-d "src") {
+ $prefix="src";
+ }
+ system("indent -kr -nut $prefix/*.c");
+ system("rm -f $prefix/*~");
+# if (-d "src/core") {
+# system("indent -kr -nut src/core/*.c");
+# system("rm -f src/core/*~");
+# }
+# if (-d "src/protocol") {
+# system("indent -kr -nut src/protocol/*.c");
+# system("rm -f src/protocol/*~");
+# }
+
+ print "*** Bumping the revision number...\n";
+ # Re-write the control file
+ open(OUT, ">$ctrlfile") or die ("*** Error! Unable to open $ctrlfile ... aborting");
+ foreach (@source) {
+ if (/^VERSION_BUILD/) {
+ $_ =~ s/\"\d+\"/\"$ver_revision\"/;
+ } elsif (/# \$Log\$/) {
+ $_ .= "$ver_comment";
+ }
+ print OUT $_;
+ }
+ close(OUT);
+
+ print "*** Starting the upload...\n\n";
+ my $rval=system("$svn commit $dst --username='$svnuser' --message '$svn_comment'");
+ if ( $rval ) {
+ print "*** Error: Unable to complete commit. Rolling back....\n\n";
+ system("$svn revert $ctrlfile");
+ }
+
+}
+
+{
+ usage() if (! @ARGV);
+
+ my $opt = 'hgplf:r:b:t:P:';
+ getopts ("$opt", \%opt) or usage();
+ usage() if $opt{h};
+
+ usage() if ($opt{g} && $opt{p});
+ usage() if ($opt{g} && $opt{f});
+ usage() if ($opt{g} && $opt{l});
+ usage() if ($opt{p} && $opt{f});
+ usage() if ($opt{p} && $opt{l});
+ usage() if ($opt{f} && $opt{l});
+ usage() if ($opt{r} && $opt{b});
+ usage() if ($opt{r} && $opt{t});
+ usage() if ($opt{b} && $opt{t});
+ usage() if ($opt{b} && $opt{P});
+
+ $rev = $opt{r} ;
+ $branch = $opt{b} ;
+ $tag = $opt{t} ;
+ $ftp = $opt{f} ;
+ $proto = $opt{P} ;
+ $dst = shift;
+
+ if ($rev ne undef) {
+ unless ($rev =~ /^\d+/ and $rev > 0)
+ {
+ print "*** Error: Revision number '$rev' must be an integer > 0.\n";
+ exit;
+ }
+ }
+
+ do_lst() if $opt{l};
+ do_ftp() if $opt{f};
+ do_get() if $opt{g};
+ do_put() if $opt{p};
+ print "*** Done!\n";
+
+}
+
+
diff --git a/src/bin/anoperc.in b/src/bin/anoperc.in
new file mode 100644
index 000000000..4f4961c9c
--- /dev/null
+++ b/src/bin/anoperc.in
@@ -0,0 +1,141 @@
+#!/bin/sh
+#
+# Configuration script for Services
+#
+# (C) 2003-2008 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.
+#
+# $Id$
+#
+
+
+
+ANOPEPID="@DATDEST@/services.pid"
+ANOPROG="@BINDEST@/services"
+LOG="@DATDEST@/logs/"
+ARCVERSION="1.2"
+
+isAnopeRunning () {
+if [ ! -f $ANOPEPID ] ; then
+ echo "Warning: Anope is not currently running"
+ exit 1
+fi
+
+PID=`cat $ANOPEPID`
+
+if [ ! `ps auxw | grep $ANOPROG | grep $PID | grep -v -c grep` ] ; then
+ echo "Warning: Anope is not currently running"
+ exit 1
+fi
+}
+
+if [ ! -f $ANOPROG ] ; then
+ echo "Error: $ANOPROG cannot be accessed"
+ exit 1
+fi
+
+
+if [ "$UID" = "0" ] ; then
+ echo "######################################";
+ echo "# Warning: Do NOT run Anope as root! #";
+ echo "######################################";
+ exit 1
+fi
+
+if [ "$1" = "start" ] ; then
+
+if [ -f $ANOPEPID ] ; then
+ PID=`cat $ANOPEPID`
+ if [ `ps auxw | grep $ANOPROG | grep $PID | grep -v -c grep` = 1 ] ; then
+ echo "Warning! Anope is already running"
+ exit 1
+ fi
+fi
+ echo "Starting Anope"
+ shift
+ $ANOPROG $*
+ sleep 1
+ if [ ! -f $ANOPEPID ] ; then
+ echo "Unfortunately it seems Anope did not start successfully"
+ echo "This error has been logged in your Anope Log file"
+ echo "Located in "$LOG""
+ echo "This may help you diagnose the problem"
+ echo "Further help may be available from http://www.anope.org/"
+ exit 1
+ fi
+ PID=`cat $ANOPEPID`
+ if [ ! `ps auxw | grep $ANOPROG | grep $PID | grep -v -c grep` ] ; then
+ echo "Unfortunately it seems Anope did not start successfully"
+ echo "This error has been logged in your Anope Log file"
+ echo "Located in "$LOG""
+ echo "This may help you diagnose the problem"
+ echo "Further help may be available from http://www.anope.org/"
+ exit 1
+ fi
+
+elif [ "$1" = "stop" ] ; then
+ isAnopeRunning
+ echo "Terminating Anope"
+ kill -15 `cat $ANOPEPID`
+
+elif [ "$1" = "status" ] ; then
+ if [ -f $ANOPEPID ] ; then
+ PID=`cat $ANOPEPID`
+ if [ `ps auxw | grep $PID | grep -v -c grep` = 1 ] ; then
+ echo "Anope is currently running"
+ exit 1
+ fi
+ fi
+
+ echo "Anope is not currently running"
+
+## :/ SIGUSR2 is ignored after the first restart so we stop / start Anope for now ##
+elif [ "$1" = "restart" ] ; then
+ isAnopeRunning
+ echo "Restarting Anope"
+ kill -15 `cat $ANOPEPID`
+ sleep 1
+ shift
+ $ANOPROG $*
+
+elif [ "$1" = "rehash" ] ; then
+ isAnopeRunning
+ echo "Saving Databases and Rehashing Configuration"
+ kill -12 `cat $ANOPEPID`
+
+elif [ "$1" = "version" ] ; then
+ $ANOPROG -version
+
+elif [ "$1" = "help" ] ; then
+ if [ "$2" = "paramlist" ] ; then
+ $ANOPROG -help
+ else
+ echo "AnopeRC is a remote control script for easy"
+ echo "controlling of Anope from the command console"
+ echo "$0 start Start Anope"
+ echo " Additional parameters may be passed"
+ echo " (e.g. $0 start -nofork)"
+ echo " For a list type $0 $1 paramlist"
+ echo "$0 stop Shutdown Anope"
+ echo "$0 status Show Anope's Status"
+ echo "$0 restart Restart Anope (Databases will be saved)"
+ echo " Additional parameters may be passed"
+ echo " (e.g. $0 restart -logchan)"
+ echo " For a list type $0 $1 paramlist"
+ echo "$0 rehash Rehash Configuration and Save Databases"
+ echo "$0 version Return Anope Version and Build Information"
+ echo "$0 help Show this help menu"
+ echo "If you need further help please check the /docs/"
+ echo "folder or make use of our extensive online support at"
+ echo "http://www.anope.org/"
+ fi
+
+else
+ echo "Anope Remote Control ($ARCVERSION)"
+ echo "Usage: $0 [start|stop|status|restart|rehash|version|help]"
+fi
diff --git a/src/bin/cp-recursive b/src/bin/cp-recursive
new file mode 100755
index 000000000..e51230db7
--- /dev/null
+++ b/src/bin/cp-recursive
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+if [ $1 = "-t" ] ; then
+ shift
+fi
+if [ ! "$2" ] ; then
+ echo >&2 Usage: $0 '<sourcedir> <targetdir>'
+ exit 1
+fi
+if [ -d "$1" ] ; then
+ dir="$1"
+else
+ dir="`echo $1 | sed 's#\(.*\)/.*#\1#'`"
+fi
+while [ "$2" ] ; do
+ shift
+done
+if [ ! -d $1 ] ; then
+ mkdir -p $1 || exit 1
+fi
+/bin/tar -Ccf $dir - . | /bin/tar -Cxf $1 -
diff --git a/src/bin/langtool b/src/bin/langtool
new file mode 100755
index 000000000..c1072760c
--- /dev/null
+++ b/src/bin/langtool
@@ -0,0 +1,239 @@
+#!/usr/bin/perl
+#
+# Ribosome's all in one language tool
+# 1) Compares to check for missing lines
+# 2) Compares to check for equal lines
+# 3) Fixes (on request) missing lines
+# 4) Checks for errors in lines
+# 5) Checks for long lines (>60 characters)
+#
+
+# Check to see if we have received arguments
+if (!$ARGV[0]) {
+print "Usage: $0 [language file]\n";
+exit;
+}
+
+# If yes, set $sourcefile to the language filename
+$testagainst = $ARGV[0];
+
+# Set $sourcefile to en_us language file
+$sourcefile = "en_us.l";
+
+# Number of Keys in File, Number of Equal Lines, Number of Missing Lines
+# Fixed Lines (optional) and Number of Format Error Lines, Number of Long Lines
+my $numberlines = 0;
+my $equallines = 0;
+my $missinglines = 0;
+my $fixedlines = 0;
+my $errorline = 0;
+my $longlines = 0;
+
+# Array to hold the lines from the source file and explosion array for long line check
+
+my @sourcearray;
+my @explosion;
+
+# Create associative arrays which will contain keys and definitions
+# One for the control source and one for what is being tested against
+
+my %sourcehash= ();
+my %testhash= ();
+
+# Check if Files Exist
+
+if (! -f $sourcefile) {
+print "Critical Error: The source file does not exist or is unreadable.\nNote: This tool must be run from the language directory.\n";
+exit;
+}
+
+if (! -f $testagainst) {
+print "Critical Error: The language file does not exist or is unreadable\n";
+exit;
+}
+###########################################
+# Function to load sourcefile into memory #
+###########################################
+
+sub load_sourcefile {
+
+ my $_key; # This variable will hold the key
+ my $_def; # This variable will hold the definition
+ my $line; # This variable will hold the current line
+
+ open (SOURCEFILE, "< $sourcefile"); # Open the source file
+ while (<SOURCEFILE>) { # For each line the source file
+ $line = $_; # $line is set to the line in the source file
+
+ # Skip comments
+ if (/^#/) { # This checks for # which indicates comment
+ next; # If detected, the next line is skipped to
+ }
+
+ # Start of a key
+ if (/^[A-Z]/) { # Checks to see if the line is a key
+ chomp($line); # Removes things that shouldn't be at the end
+ push (@sourcearray, $line); # Puts the line into the source array
+ # If a key is defined, load definition into the hash
+ if ($_key ne undef) { # If the key is defined
+ $sourcehash{$_key} = $_def; # Add the definition to the associative array
+ }
+ $_key=$line; # Set the key to the line
+ $_def=""; # Reset the definition
+ next; # Move onto the next line
+ }
+
+ if ($_key ne undef) { # If the key is set already
+ $_def.=$line; # The definition is the current line
+ }
+
+ $sourcehash{$_key} = $_def; # Load the definition into the associative array
+ } # End of while which reads lines
+
+ close (SOURCEFILE); # Close the source file
+
+} # End of load_sourcefile function
+
+#################################################
+# Function to load testagainst file into memory #
+#################################################
+
+sub load_testagainst {
+
+ my $_key; # This variable will hold the key
+ my $_def; # This variable will hold the definition
+ my $line; # This variable will hold the current line
+
+ open (TESTAGAINSTFILE, "< $testagainst"); # Open the file containing the control lines
+ while (<TESTAGAINSTFILE>) { # For each line in the file
+ $line = $_; # $line is set to the lines value
+
+
+ # Skip comments
+ if (/^#/) { # This checks for # which indicates comment
+ next; # If detected, the next line is skipped to
+ }
+
+ # Start of a key
+ if (/^[A-Z]/) { # Checks to see if the line is a key
+ chomp($line); # Removes things that shouldn't be at the end
+
+
+ if ($_key ne undef) { # If the key is defined
+ $testhash{$_key} = $_def; # Add the definition to the associative array
+ }
+ $_key=$line; # Set the key to the line
+ $_def=""; # Reset the definition
+ next; # Move onto the next line
+ }
+
+ if ($_key ne undef) { # If the key is set already
+ $_def.=$line; # The definition is the current line
+ }
+
+ $testhash{$_key} = $_def; # Load the definition into the associative array
+ } # End of while which reads lines
+ close (TESTAGAINSTFILE); # Close the source file
+
+}
+
+
+sub get_format { # Function to get the formatting from a string
+ my $fmt="";
+ my $str=shift; # Get the input
+
+ while ($str =~ m/%\w/g) {
+ $fmt .= $&;
+ }
+
+ return $fmt; # Return the formatting
+}
+
+
+load_sourcefile; # Call function to load the source file
+load_testagainst; # Call function to load the test file
+
+if (!grep(/^LANG_NAME/,%testhash)) {
+print "Critical Error: $ARGV[0] is not a valid language file!\n";
+exit;
+}
+
+open (LOG,"> langcheck.log"); # Open logfile for writing
+
+foreach $sourcearray (@sourcearray) { # For each key stored in the source array
+ my $_key=$_; # Store key from source array in $_key
+
+ if ((get_format($sourcehash{$sourcearray})) ne (get_format($testhash{$sourcearray}))) {
+ if ($sourcearray !~ STRFTIME ) {
+ $errorline++;
+ print LOG "FORMAT: $sourcearray - (expecting '".get_format($sourcehash{$sourcearray})."' and got '".get_format($testhash{$sourcearray})."')\n";
+ } }
+
+ if ($testhash{$sourcearray} eq $sourcehash{$sourcearray} ) {
+ # If the definitions between the source and the test are equal
+ $equallines++; # Number of equal lines increases
+ print LOG "EQUAL: $sourcearray\n"; # Line is written to logfile
+ }
+
+ if (!grep(/^$sourcearray/,%testhash)) { # If the key is found in the testhash associative array
+ $missinglines++; # Increase missing lines
+ print LOG "MISSING: $sourcearray\n"; # Line is written to logfile
+ }
+
+ @explosion = split(/\n/, $testhash{$sourcearray});
+ foreach $explosion (@explosion) {
+ $explosion =~ s/\002//g;
+ $explosion =~ s/\037//g;
+ if (length($explosion) > 61) {
+ print LOG "LONGLINE: $sourcearray (".substr($explosion,1,30)."...)\n";
+ $longlines++;
+ }
+ }
+
+$numberlines++; # Increase the number of lines tested by 1
+}
+close (LOG); # Close the logfile
+
+
+#########################
+# Show the test results #
+#########################
+
+print "Calculation Results:\n";
+print "----------------------------------\n";
+print "[$numberlines] line(s) were compared\n";
+print "[$equallines] line(s) were found to equal their $sourcefile counterpart(s)\n";
+print "[$missinglines] line(s) were found to be missing\n";
+print "[$longlines] line(s) were found to be long (>60 chars)\n";
+print "[$errorline] line(s) were found to have formatting errors\n";
+print "The specific details of the test have been saved in langcheck.log\n";
+
+if ($missinglines) { # If missing lines exist
+print "----------------------------------\n";
+print "Missing line(s) have been detected in this test, would you like to fix the file?\n";
+print "This automatically inserts values from the control file ($sourcefile) for the missing values\n";
+print "y/N? (Default: No) ";
+
+my $input = <STDIN>; # Ask if the file should be fixed
+if ((substr($input,0,1) eq "y") || (substr($input,0,1) eq "Y")) { # If Yes...
+
+open (FIX, ">> $testagainst"); # Open the file and append changes
+
+foreach $sourcearray (@sourcearray) { # For each key stored in the source array
+ my $_key=$_; # Store key from source array in $_key
+
+ if (!grep(/^$sourcearray/,%testhash)) { # If the key is not found in the testhash associative array
+ print FIX "$sourcearray\n$sourcehash{$sourcearray}"; # Add the line(s) to the language file
+ $fixedlines++; # Increase the fixed line count
+ }
+}
+
+close (FIX); # Close file after fixing
+
+print "Fixing Compete. [$fixedlines] line(s) fixed.\n";
+exit; # And Exit!
+}
+ # Otherwise, quit without fixing
+print "Exiting. The language file has NOT been fixed.\n";
+
+}
diff --git a/src/bin/mydbgen b/src/bin/mydbgen
new file mode 100755
index 000000000..e513a4917
--- /dev/null
+++ b/src/bin/mydbgen
@@ -0,0 +1,222 @@
+#!/bin/sh
+#
+# $Id$
+
+# Location of the .sql file with the schema
+DBSQL="tables.sql"
+
+# Schema Version
+SVER="1"
+
+# Local Version, defaults to 0
+LVER="0"
+
+TFILE="/tmp/.anopedb.$$"
+
+if [ "`eval echo -n 'a'`" = "-n a" ] ; then
+ c="\c"
+else
+ n="-n"
+fi
+
+# Fix for bug 10
+for try in HOME/services anope/data ../data data .. .
+do
+ if [ -f "$try/$DBSQL" ]; then
+ DBFILE="$try/$DBSQL"
+ fi
+done
+
+if [ ! -f "./$DBFILE" ] ; then
+ echo "Error: Required file $DBSQL was not found!";
+ exit
+fi
+
+echo ""
+echo "This script will guide you through the process of configuring your Anope"
+echo "installation to make use of MySQL support. This script must be used for both"
+echo "new installs as well as for upgrading for users who have a previous version"
+echo "of Anope installed"
+
+while [ -z "$SQLHOST" ] ; do
+ echo ""
+ echo "What is the hostname of your MySQL server?"
+ echo $n "-> $c"
+ read cc
+ if [ ! -z "$cc" ] ; then
+ SQLHOST=$cc
+ fi
+done
+
+while [ -z "$SQLUSER" ] ; do
+ echo ""
+ echo "What is your MySQL username?"
+ echo $n "-> $c"
+ read cc
+ if [ ! -z "$cc" ] ; then
+ SQLUSER=$cc
+ fi
+done
+
+OLD_TTY=`stty -g`
+
+echo ""
+echo "What is your MySQL password?"
+echo $n "-> $c"
+stty -echo echonl
+read cc
+SQLPASS_PREFIX=""
+if [ ! -z "$cc" ] ; then
+ SQLPASS_PREFIX="-p"
+ SQLPASS=$cc
+fi
+stty $OLD_TTY
+
+mysqlshow -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS >/dev/null 2>&1
+if test "$?" = "1" ; then
+ echo "Error: Unable to login, verify your login/password and hostname"
+ exit
+fi
+
+while [ -z "$SQLDB" ] ; do
+ echo ""
+ echo "What is the name of the Anope SQL database?"
+ echo $n "-> $c"
+ read cc
+ if [ ! -z "$cc" ] ; then
+ SQLDB=$cc
+ fi
+done
+
+MYSQLDUMP="mysqldump -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
+MYSQLSHOW="mysqlshow -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
+MYSQL="mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
+
+echo ""
+
+$MYSQLSHOW | grep -q $SQLDB
+if test "$?" = "1" ; then
+ echo -n "Unable to find databse, creating... "
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS -Bs -e "create database $SQLDB" >/dev/null 2>&1
+ if test "$?" = "0" ; then
+ echo "done!"
+ else
+ echo "failed!"
+ FAILED="$FAILED 'database creation'"
+ fi
+fi
+
+$MYSQL -Bs -e "show tables like 'anope_os_core'" | grep -q anope_os_core
+if test "$?" = "1" ; then
+ echo -n "Unable to find Anope schema, creating... "
+ $MYSQL < $DBFILE
+ if test "$?" = "0" ; then
+ echo "done!"
+ else
+ echo "failed!"
+ FAILED="$FAILED 'schema creation'"
+ fi
+else
+ # Introduced on Anope 1.6.0 -> Table anope_info
+ $MYSQL -Bs -e "show tables like 'anope_info'" | grep -q anope_info
+ if test "$?" = "1" ; then
+ echo -n "Unable to find Anope info table, creating... "
+ echo "CREATE TABLE anope_info (version int, date datetime) TYPE=MyISAM" > $TFILE
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
+ if test "$?" = "0" ; then
+ echo "done!"
+
+ else
+ echo "failed!"
+ FAILED="$FAILED 'anope_info table'"
+ fi
+ else
+ LVER="$($MYSQL -sB -e "select version from anope_info")"
+ if test "x$LVER" = "x" ; then
+ LVER=0
+ fi
+ fi
+
+ # Introduced on Anope 1.5.14.5 -> anope_cs_info.memomax
+ $MYSQL -Bs -e "describe anope_cs_info memomax" 2> /dev/null | grep -q memomax
+ if test "$?" = "1" ; then
+ echo -n "Unable to find anope_cs_info.memomax, altering... "
+ echo "ALTER TABLE anope_cs_info ADD memomax smallint unsigned NOT NULL default 0" > $TFILE
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
+ if test "$?" = "0" ; then
+ echo "done!"
+
+ else
+ echo "failed!"
+ FAILED="$FAILED 'anope_cs_info.memomax alter'"
+ fi
+ fi
+
+ # Introduced on Anope 1.5.14.5 -> anope_cs_info.ttb
+ $MYSQL -Bs -e "describe anope_cs_info ttb" 2> /dev/null | grep -q ttb
+ if test "$?" = "1" ; then
+ echo -n "Unable to find anope_cs_info.ttb, altering... "
+ echo "ALTER TABLE anope_cs_info ADD ttb smallint NOT NULL default 0" > $TFILE
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
+ if test "$?" = "0" ; then
+ echo "done!"
+
+ else
+ echo "failed!"
+ FAILED="$FAILED 'anope_cs_info.ttb alter'"
+ fi
+ fi
+
+ # Introduced on Anope 1.7.7 -> status smallint to inst unsigned.
+ echo "Blindly altering status for bigger capacity... "
+ echo "ALTER TABLE anope_ns_alias CHANGE status status int(11) unsigned NOT NULL default 0" > $TFILE
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
+
+ # Introduced on Anope 1.7.8 (620) proxy scanner removed.
+ echo "Removing proxy scanner cache... "
+ echo "DROP TABLE IF EXISTS anope_os_cache" > $TFILE
+ mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB < $TFILE >/dev/null 2>&1
+
+ echo "done!"
+
+fi
+
+echo ""
+
+# Insert initial version number. This will have to be redesigned for 1.7
+if [ $LVER -ne $SVER ]; then
+echo -n "Inserting initial version number... "
+$MYSQL -Bs -e "delete from anope_info"
+echo "INSERT INTO anope_info (version, date) VALUES ($SVER, now())" > $TFILE
+$MYSQL < $TFILE >/dev/null 2>&1
+if test "$?" = "0" ; then
+ echo "done!"
+else
+ echo "failed!"
+ FAILED="$FAILED 'version insert'"
+fi
+fi
+
+rm -f $TFILE
+if test "x$FAILED" = "x" ; then
+ # Try to find out more about this installation
+ SQLSOCK="$(mysql_config --socket 2> /dev/null)"
+ SQLPORT="$(mysql_config --port 2> /dev/null)"
+ echo ""
+ echo "Your MySQL setup is complete and your Anope schema is up to date. Make"
+ echo "sure you configure MySQL on your services.conf file prior to launching"
+ echo "Anope with MySQL support. Your configuration values are:"
+ echo ""
+ echo "MysqlHost \"$SQLHOST\""
+ echo "MysqlUser \"$SQLUSER\""
+ echo "MysqlPass \"$SQLPASS\""
+ echo "MysqlName \"$SQLDB\""
+ echo "MysqlSock \"$SQLSOCK\""
+ echo "MysqlPort \"$SQLPORT\""
+ echo ""
+else
+ echo "The following operations failed:"
+ echo "$FAILED"
+fi
+
+exit
diff --git a/src/bin/register b/src/bin/register
new file mode 100755
index 000000000..1c236fbe4
--- /dev/null
+++ b/src/bin/register
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+###############################################
+# Set Variables
+###############################################
+
+# CONFIGURATION CACHE (e.g. ../config.cache)
+CACHEFILE="../../config.cache"
+
+# REGISTRATION INFORMATION CACHE FILE (no need to alter this)
+REGCACHE="register.cache"
+
+# SENDMAIL PATH
+SENDMAIL="/usr/sbin/sendmail"
+
+# SCRIPT VERSION NUMBER (DO NOT ALTER)
+REGISTERVERSION="1.3"
+
+# DO NOT CHANGE IF YOU WANT TO REGISTER WITH ANOPE
+REGISTRYADDRESS="register@anope.org"
+
+################################################
+# END OF CONFIGURATION
+# YOU ARE NOT REQUIRED TO CHANGE ANYTHING BELOW
+################################################
+
+if [ $0 != "./register" ] ; then
+ echo "Warning: Run this file while in the /src/bin/ directory (e.g. ./register)"
+ exit 1
+fi
+
+if [ ! -f $CACHEFILE ] ; then
+ echo "Warning: Configuration cache file missing. Run ./Config first"
+ exit 1
+fi
+
+if [ ! -f $SENDMAIL ] ; then
+ echo "Warning: Sendmail cannot be found. Please open this file and set variable correctly"
+ exit 1;
+fi
+
+clear
+
+if [ -f $REGCACHE ] ; then
+ echo "Previous registration cache file found. Removing..."
+ rm $REGCACHE
+fi
+
+ echo "##################################################"
+ echo "Anope registration script (v$REGISTERVERSION)"
+ echo "##################################################"
+ echo "This script allows you to register your network"
+ echo "with the Anope central registry. This gives us"
+ echo "an idea of how many networks use Anope and what options"
+ echo "they compile with so we can spend more time developing"
+ echo "options that are more widely used. Note: The options"
+ echo "you selected in ./Config will be sent."
+ echo "You will be asked a series of questions, if you wish"
+ echo "to be listed in the public network database all the"
+ echo "information will be required."
+ echo "NOTE: NO PRIVATE OR SENSITIVE INFORMATION WILL BE SENT"
+ echo "##################################################"
+ echo "Would you like to register? [Type YES to continue]"
+ read answer
+
+if [ $answer = "YES" ] || [ $answer = "yes" ] || [ $answer = "Yes" ] ; then
+
+ echo "Beginning registration..."
+ echo "1. What is your network name? (e.g. Anope IRC Network)"
+ read NETWORKNAME
+ echo CONNECTADDRESS=\"$NETWORKNAME\" >> $REGCACHE
+ echo "2. What is your network's connection address (e.g. irc.anope.org)"
+ read CONNECTADDRESS
+ echo CONNECTADDRESS=\"$CONNECTADDRESS\" >> $REGCACHE
+ echo "3. Primary contact email address? (e.g. irc-admin@anope.org)"
+ read CONTACTEMAIL
+ echo CONTACTEMAIL=\"$CONTACTEMAIL\" >> $REGCACHE
+ echo "4. What is your network's website address (e.g. http://www.anope.org)"
+ read WEBSITEADDRESS
+ echo WEBSITEADDRESS=\"$WEBSITEADDRESS\" >> $REGCACHE
+ echo "5. Would you like your network to be listed in a public database?"
+ echo "[Please type YES if you would like to be listed]"
+ read LISTED
+ echo LISTED=\"$LISTED\" >> $REGCACHE
+ echo "6. (Bonus Devel-Only Question) Why did the chicken cross the road?!"
+ read BONUS
+ echo BONUS=\"$BONUS\" >> $REGCACHE
+ echo >> $REGCACHE
+ echo "Processing registration..."
+ cat $CACHEFILE >> $REGCACHE
+ $SENDMAIL $REGISTRYADDRESS < $REGCACHE
+ if [ -f $REGCACHE ] ; then
+ echo "Cleaning up..."
+ rm $REGCACHE
+ fi
+ echo "Registration Completed. Thank you for registering Anope."
+ exit 0;
+
+fi
+
+echo "Registration Cancelled"
diff --git a/src/botserv.c b/src/botserv.c
new file mode 100644
index 000000000..ed5af558d
--- /dev/null
+++ b/src/botserv.c
@@ -0,0 +1,1171 @@
+/* BotServ functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+/*************************************************************************/
+
+#include "services.h"
+#include "pseudo.h"
+
+
+/*************************************************************************/
+
+BotInfo *botlists[256]; /* Hash list of bots */
+int nbots = 0;
+
+/*************************************************************************/
+
+static UserData *get_user_data(Channel * c, User * u);
+
+static void check_ban(ChannelInfo * ci, User * u, int ttbtype);
+static void bot_kick(ChannelInfo * ci, User * u, int message, ...);
+
+E void moduleAddBotServCmds(void);
+
+/*************************************************************************/
+/* *INDENT-OFF* */
+void moduleAddBotServCmds(void) {
+ modules_core_init(BotServCoreNumber, BotServCoreModules);
+}
+/* *INDENT-ON* */
+/*************************************************************************/
+/*************************************************************************/
+
+/* Return information on memory use. Assumes pointers are valid. */
+
+void get_botserv_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i;
+ BotInfo *bi;
+
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ count++;
+ mem += sizeof(*bi);
+ mem += strlen(bi->nick) + 1;
+ mem += strlen(bi->user) + 1;
+ mem += strlen(bi->host) + 1;
+ mem += strlen(bi->real) + 1;
+ }
+ }
+
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* BotServ initialization. */
+
+void bs_init(void)
+{
+ if (s_BotServ) {
+ moduleAddBotServCmds();
+ }
+}
+
+/*************************************************************************/
+
+/* Main BotServ routine. */
+
+void botserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_BotServ, u->nick, "PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_BotServ, u, SERVICE_OFFLINE, s_BotServ);
+ } else {
+ mod_run_cmd(s_BotServ, u, BOTSERV, cmd);
+ }
+
+}
+
+/*************************************************************************/
+
+/* Handles all messages sent to bots. (Currently only answers to pings ;) */
+
+void botmsgs(User * u, BotInfo * bi, char *buf)
+{
+ char *cmd = strtok(buf, " ");
+ char *s;
+
+ if (!cmd || !u)
+ return;
+
+ if (!stricmp(cmd, "\1PING")) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(bi->nick, u->nick, "PING %s", s);
+ }
+}
+
+/*************************************************************************/
+
+/* Handles all messages that are sent to registered channels where a
+ * bot is on.
+ *
+ */
+
+void botchanmsgs(User * u, ChannelInfo * ci, char *buf)
+{
+ int c;
+ int16 cstatus = 0;
+ char *cmd;
+ UserData *ud;
+
+ if (!u || !buf || !ci) {
+ return;
+ }
+
+ /* Answer to ping if needed, without breaking the buffer. */
+ if (!strnicmp(buf, "\1PING", 5)) {
+ anope_cmd_ctcp(ci->bi->nick, u->nick, "PING %s", buf);
+ }
+
+ /* If it's a /me, cut the CTCP part at the beginning (not
+ * at the end, because one character just doesn't matter,
+ * but the ACTION may create strange behaviours with the
+ * caps or badwords kickers */
+ if (!strnicmp(buf, "\1ACTION ", 8))
+ buf += 8;
+
+ /* Now we can make kicker stuff. We try to order the checks
+ * from the fastest one to the slowest one, since there's
+ * no need to process other kickers if an user is kicked before
+ * the last kicker check.
+ *
+ * But FIRST we check whether the user is protected in any
+ * way.
+ */
+
+ /* We first retrieve the user status on the channel if needed */
+ if (ci->botflags & (BS_DONTKICKOPS | BS_DONTKICKVOICES))
+ cstatus = chan_get_user_status(ci->c, u);
+
+ if (buf && !check_access(u, ci, CA_NOKICK) &&
+ (!(ci->botflags & BS_DONTKICKOPS)
+ || !(cstatus & (CUS_HALFOP | CUS_OP | CUS_OWNER | CUS_PROTECT)))
+
+ && (!(ci->botflags & BS_DONTKICKVOICES) || !(cstatus & CUS_VOICE))) {
+ /* Bolds kicker */
+ if ((ci->botflags & BS_KICK_BOLDS) && strchr(buf, 2)) {
+ check_ban(ci, u, TTB_BOLDS);
+ bot_kick(ci, u, BOT_REASON_BOLD);
+ return;
+ }
+
+ /* Color kicker */
+ if ((ci->botflags & BS_KICK_COLORS) && strchr(buf, 3)) {
+ check_ban(ci, u, TTB_COLORS);
+ bot_kick(ci, u, BOT_REASON_COLOR);
+ return;
+ }
+
+ /* Reverses kicker */
+ if ((ci->botflags & BS_KICK_REVERSES) && strchr(buf, 22)) {
+ check_ban(ci, u, TTB_REVERSES);
+ bot_kick(ci, u, BOT_REASON_REVERSE);
+ return;
+ }
+
+ /* Underlines kicker */
+ if ((ci->botflags & BS_KICK_UNDERLINES) && strchr(buf, 31)) {
+ check_ban(ci, u, TTB_UNDERLINES);
+ bot_kick(ci, u, BOT_REASON_UNDERLINE);
+ return;
+ }
+
+ /* Caps kicker */
+ if ((ci->botflags & BS_KICK_CAPS)
+ && ((c = strlen(buf)) >= ci->capsmin)) {
+ int i = 0;
+ int l = 0;
+ char *s = buf;
+
+ do {
+ if (isupper(*s))
+ i++;
+ else if (islower(*s))
+ l++;
+ } while (*s++);
+
+ /* i counts uppercase chars, l counts lowercase chars. Only
+ * alphabetic chars (so islower || isupper) qualify for the
+ * percentage of caps to kick for; the rest is ignored. -GD
+ */
+
+ if (i >= ci->capsmin && i * 100 / (i + l) >= ci->capspercent) {
+ check_ban(ci, u, TTB_CAPS);
+ bot_kick(ci, u, BOT_REASON_CAPS);
+ return;
+ }
+ }
+
+ /* Bad words kicker */
+ if (ci->botflags & BS_KICK_BADWORDS) {
+ int i;
+ int mustkick = 0;
+ char *nbuf;
+ BadWord *bw;
+
+ /* Normalize the buffer */
+ nbuf = normalizeBuffer(buf);
+
+ for (i = 0, bw = ci->badwords; i < ci->bwcount; i++, bw++) {
+ if (!bw->in_use)
+ continue;
+
+ if (bw->type == BW_ANY
+ && ((BSCaseSensitive && strstr(nbuf, bw->word))
+ || (!BSCaseSensitive && stristr(nbuf, bw->word)))) {
+ mustkick = 1;
+ } else if (bw->type == BW_SINGLE) {
+ int len = strlen(bw->word);
+
+ if ((BSCaseSensitive && !strcmp(nbuf, bw->word))
+ || (!BSCaseSensitive
+ && (!stricmp(nbuf, bw->word)))) {
+ mustkick = 1;
+ /* two next if are quite odd isn't it? =) */
+ } else if ((strchr(nbuf, ' ') == nbuf + len)
+ &&
+ ((BSCaseSensitive
+ && !strcmp(nbuf, bw->word))
+ || (!BSCaseSensitive
+ && (stristr(nbuf, bw->word) ==
+ nbuf)))) {
+ mustkick = 1;
+ } else {
+ if ((strrchr(nbuf, ' ') ==
+ nbuf + strlen(nbuf) - len - 1)
+ &&
+ ((BSCaseSensitive
+ && (strstr(nbuf, bw->word) ==
+ nbuf + strlen(nbuf) - len))
+ || (!BSCaseSensitive
+ && (stristr(nbuf, bw->word) ==
+ nbuf + strlen(nbuf) - len)))) {
+ mustkick = 1;
+ } else {
+ char *wordbuf = scalloc(len + 3, 1);
+
+ wordbuf[0] = ' ';
+ wordbuf[len + 1] = ' ';
+ wordbuf[len + 2] = '\0';
+ memcpy(wordbuf + 1, bw->word, len);
+
+ if ((BSCaseSensitive
+ && (strstr(nbuf, wordbuf)))
+ || (!BSCaseSensitive
+ && (stristr(nbuf, wordbuf)))) {
+ mustkick = 1;
+ }
+
+ /* free previous (sc)allocated memory (#850) */
+ free(wordbuf);
+ }
+ }
+ } else if (bw->type == BW_START) {
+ int len = strlen(bw->word);
+
+ if ((BSCaseSensitive
+ && (!strncmp(nbuf, bw->word, len)))
+ || (!BSCaseSensitive
+ && (!strnicmp(nbuf, bw->word, len)))) {
+ mustkick = 1;
+ } else {
+ char *wordbuf = scalloc(len + 2, 1);
+
+ memcpy(wordbuf + 1, bw->word, len);
+ wordbuf[0] = ' ';
+ wordbuf[len + 1] = '\0';
+
+ if ((BSCaseSensitive && (strstr(nbuf, wordbuf)))
+ || (!BSCaseSensitive
+ && (stristr(nbuf, wordbuf))))
+ mustkick = 1;
+
+ free(wordbuf);
+ }
+ } else if (bw->type == BW_END) {
+ int len = strlen(bw->word);
+
+ if ((BSCaseSensitive
+ &&
+ (!strncmp
+ (nbuf + strlen(nbuf) - len, bw->word, len)))
+ || (!BSCaseSensitive
+ &&
+ (!strnicmp
+ (nbuf + strlen(nbuf) - len, bw->word,
+ len)))) {
+ mustkick = 1;
+ } else {
+ char *wordbuf = scalloc(len + 2, 1);
+
+ memcpy(wordbuf, bw->word, len);
+ wordbuf[len] = ' ';
+ wordbuf[len + 1] = '\0';
+
+ if ((BSCaseSensitive && (strstr(nbuf, wordbuf)))
+ || (!BSCaseSensitive
+ && (stristr(nbuf, wordbuf))))
+ mustkick = 1;
+
+ free(wordbuf);
+ }
+ }
+
+ if (mustkick) {
+ check_ban(ci, u, TTB_BADWORDS);
+ if (BSGentleBWReason)
+ bot_kick(ci, u, BOT_REASON_BADWORD_GENTLE);
+ else
+ bot_kick(ci, u, BOT_REASON_BADWORD, bw->word);
+
+ /* free the normalized buffer before return (#850) */
+ Anope_Free(nbuf);
+
+ return;
+ }
+ }
+
+ /* Free the normalized buffer */
+ Anope_Free(nbuf);
+ }
+
+ /* Flood kicker */
+ if (ci->botflags & BS_KICK_FLOOD) {
+ time_t now = time(NULL);
+
+ ud = get_user_data(ci->c, u);
+ if (!ud) {
+ return;
+ }
+
+ if (now - ud->last_start > ci->floodsecs) {
+ ud->last_start = time(NULL);
+ ud->lines = 0;
+ }
+
+ ud->lines++;
+ if (ud->lines >= ci->floodlines) {
+ check_ban(ci, u, TTB_FLOOD);
+ bot_kick(ci, u, BOT_REASON_FLOOD);
+ return;
+ }
+ }
+
+ /* Repeat kicker */
+ if (ci->botflags & BS_KICK_REPEAT) {
+ ud = get_user_data(ci->c, u);
+ if (!ud) {
+ return;
+ }
+ if (ud->lastline && stricmp(ud->lastline, buf)) {
+ free(ud->lastline);
+ ud->lastline = sstrdup(buf);
+ ud->times = 0;
+ } else {
+ if (!ud->lastline)
+ ud->lastline = sstrdup(buf);
+ ud->times++;
+ }
+
+ if (ud->times >= ci->repeattimes) {
+ check_ban(ci, u, TTB_REPEAT);
+ bot_kick(ci, u, BOT_REASON_REPEAT);
+ return;
+ }
+ }
+ }
+
+
+ /* return if the user is on the ignore list */
+ if (get_ignore(u->nick) != NULL) {
+ return;
+ }
+
+ /* Fantaisist commands */
+
+ if (buf && (ci->botflags & BS_FANTASY) && *buf == *BSFantasyCharacter) {
+ cmd = strtok(buf, " ");
+
+ if (cmd && (cmd[0] == *BSFantasyCharacter)) {
+ char *params = strtok(NULL, "");
+ char *event_name = EVENT_BOT_FANTASY_NO_ACCESS;
+
+ /* Strip off the fantasy character */
+ cmd++;
+
+ if (check_access(u, ci, CA_FANTASIA))
+ event_name = EVENT_BOT_FANTASY;
+
+ if (params)
+ send_event(event_name, 4, cmd, u->nick, ci->name, params);
+ else
+ send_event(event_name, 3, cmd, u->nick, ci->name);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Load/save data files. */
+
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", BotDBName); \
+ failed = 1; \
+ break; \
+ } \
+} while (0)
+
+void load_bs_dbase(void)
+{
+ dbFILE *f;
+ int c, ver;
+ uint16 tmp16;
+ uint32 tmp32;
+ BotInfo *bi;
+ int failed = 0;
+
+ if (!(f = open_db(s_BotServ, BotDBName, "r", BOT_VERSION)))
+ return;
+
+ ver = get_file_version(f);
+
+ while (!failed && (c = getc_db(f)) != 0) {
+ char *s;
+
+ if (c != 1)
+ fatal("Invalid format in %s %d", BotDBName, c);
+
+ SAFE(read_string(&s, f));
+ bi = makebot(s);
+ free(s);
+ SAFE(read_string(&bi->user, f));
+ SAFE(read_string(&bi->host, f));
+ SAFE(read_string(&bi->real, f));
+ if (ver >= 10) {
+ SAFE(read_int16(&tmp16, f));
+ bi->flags = tmp16;
+ }
+ SAFE(read_int32(&tmp32, f));
+ bi->created = tmp32;
+ SAFE(read_int16(&tmp16, f));
+ bi->chancount = tmp16;
+ }
+
+ close_db(f);
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", BotDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", BotDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_bs_dbase(void)
+{
+ dbFILE *f;
+ BotInfo *bi;
+ static time_t lastwarn = 0;
+ int i;
+
+ if (!(f = open_db(s_BotServ, BotDBName, "w", BOT_VERSION)))
+ return;
+
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(bi->nick, f));
+ SAFE(write_string(bi->user, f));
+ SAFE(write_string(bi->host, f));
+ SAFE(write_string(bi->real, f));
+ SAFE(write_int16(bi->flags, f));
+ SAFE(write_int32(bi->created, f));
+ SAFE(write_int16(bi->chancount, f));
+ }
+ }
+ SAFE(write_int8(0, f));
+
+ close_db(f);
+
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+void save_bs_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ int i;
+ BotInfo *bi;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_bs_core") == 0) {
+ alog("Unable to tag table 'anope_bs_core' - BotServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ if (rdb_save_bs_core(bi) == 0) {
+ alog("Unable to save BotInfo for %s - BotServ RDB save failed.", bi->nick);
+ rdb_close();
+ return;
+ }
+ }
+ }
+
+ if (rdb_clean_table("anope_bs_core") == 0)
+ alog("Unable to clean table 'anope_bs_core' - BotServ RDB save failed.");
+
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+
+/* Inserts a bot in the bot list. I can't be much explicit mh? */
+
+void insert_bot(BotInfo * bi)
+{
+ BotInfo *ptr, *prev;
+
+ for (prev = NULL, ptr = botlists[tolower(*bi->nick)];
+ ptr != NULL && stricmp(ptr->nick, bi->nick) < 0;
+ prev = ptr, ptr = ptr->next);
+ bi->prev = prev;
+ bi->next = ptr;
+ if (!prev)
+ botlists[tolower(*bi->nick)] = bi;
+ else
+ prev->next = bi;
+ if (ptr)
+ ptr->prev = bi;
+}
+
+/*************************************************************************/
+
+BotInfo *makebot(char *nick)
+{
+ BotInfo *bi;
+
+ if (!nick) {
+ if (debug) {
+ alog("debug: makebot called with NULL values");
+ }
+ return NULL;
+ }
+
+ bi = scalloc(sizeof(BotInfo), 1);
+ bi->nick = sstrdup(nick);
+ bi->lastmsg = time(NULL);
+ insert_bot(bi);
+ nbots++;
+ return bi;
+}
+
+/*************************************************************************/
+
+
+/*************************************************************************/
+
+
+/*************************************************************************/
+
+BotInfo *findbot(char *nick)
+{
+ BotInfo *bi;
+ Uid *ud;
+
+ /* to keep make strict happy */
+ ud = NULL;
+
+ if (!nick || !*nick)
+ return NULL;
+
+ for (bi = botlists[tolower(*nick)]; bi; bi = bi->next) {
+ if (UseTS6 && ircd->ts6) {
+ ud = find_nickuid(nick);
+ }
+ if (!stricmp(nick, bi->nick)) {
+ return bi;
+ }
+ if (ud && UseTS6 && ircd->ts6) {
+ if (!stricmp(ud->nick, bi->nick)) {
+ return bi;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Unassign a bot from a channel. Assumes u, ci and ci->bi are not NULL */
+
+void unassign(User * u, ChannelInfo * ci)
+{
+ send_event(EVENT_BOT_UNASSIGN, 2, ci->name, ci->bi->nick);
+
+ if (ci->c && ci->c->usercount >= BSMinUsers) {
+ anope_cmd_part(ci->bi->nick, ci->name, "UNASSIGN from %s",
+ u->nick);
+ }
+ ci->bi->chancount--;
+ ci->bi = NULL;
+}
+
+/*************************************************************************/
+
+/* Returns ban data associated with an user if it exists, allocates it
+ otherwise. */
+
+static BanData *get_ban_data(Channel * c, User * u)
+{
+ char mask[BUFSIZE];
+ BanData *bd, *next;
+ time_t now = time(NULL);
+
+ if (!c || !u)
+ return NULL;
+
+ snprintf(mask, sizeof(mask), "%s@%s", u->username,
+ common_get_vhost(u));
+
+ for (bd = c->bd; bd; bd = next) {
+ if (now - bd->last_use > BSKeepData) {
+ if (bd->next)
+ bd->next->prev = bd->prev;
+ if (bd->prev)
+ bd->prev->next = bd->next;
+ else
+ c->bd = bd->next;
+ if (bd->mask)
+ free(bd->mask);
+ next = bd->next;
+ free(bd);
+ continue;
+ }
+ if (!stricmp(bd->mask, mask)) {
+ bd->last_use = now;
+ return bd;
+ }
+ next = bd->next;
+ }
+
+ /* If we fall here it is that we haven't found the record */
+ bd = scalloc(sizeof(BanData), 1);
+ bd->mask = sstrdup(mask);
+ bd->last_use = now;
+
+ bd->prev = NULL;
+ bd->next = c->bd;
+ if (bd->next)
+ bd->next->prev = bd;
+ c->bd = bd;
+
+ return bd;
+}
+
+/*************************************************************************/
+
+/* Returns BotServ data associated with an user on a given channel.
+ * Allocates it if necessary.
+ */
+
+static UserData *get_user_data(Channel * c, User * u)
+{
+ struct c_userlist *user;
+
+ if (!c || !u)
+ return NULL;
+
+ for (user = c->users; user; user = user->next) {
+ if (user->user == u) {
+ if (user->ud) {
+ time_t now = time(NULL);
+
+ /* Checks whether data is obsolete */
+ if (now - user->ud->last_use > BSKeepData) {
+ if (user->ud->lastline)
+ free(user->ud->lastline);
+ /* We should not free and realloc, but reset to 0
+ instead. */
+ memset(user->ud, 0, sizeof(UserData));
+ user->ud->last_use = now;
+ }
+
+ return user->ud;
+ } else {
+ user->ud = scalloc(sizeof(UserData), 1);
+ user->ud->last_use = time(NULL);
+ return user->ud;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Makes the bot join a channel and op himself. */
+
+void bot_join(ChannelInfo * ci)
+{
+ if (!ci || !ci->c || !ci->bi)
+ return;
+
+ if (BSSmartJoin) {
+ /* We check for bans */
+ if (ci->c->bans && ci->c->bans->count) {
+ char buf[BUFSIZE];
+ char *av[4];
+ Entry *ban, *next;
+ int ac;
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = ci->c->name;
+ av[1] = buf;
+ av[2] = sstrdup("-b");
+ ac = 4;
+ } else {
+ av[0] = ci->c->name;
+ av[1] = sstrdup("-b");
+ ac = 3;
+ }
+
+ for (ban = ci->c->bans->entries; ban; ban = next) {
+ next = ban->next;
+ if (entry_match
+ (ban, ci->bi->nick, ci->bi->user, ci->bi->host, 0)) {
+ anope_cmd_mode(whosends(ci), ci->name, "-b %s",
+ ban->mask);
+ if (ircdcap->tsmode)
+ av[3] = ban->mask;
+ else
+ av[2] = ban->mask;
+
+ do_cmode(whosends(ci), ac, av);
+ }
+ }
+
+ if (ircdcap->tsmode)
+ free(av[2]);
+ else
+ free(av[1]);
+ }
+
+ /* Should we be invited? */
+ if ((ci->c->mode & anope_get_invite_mode())
+ || (ci->c->limit && ci->c->usercount >= ci->c->limit))
+ anope_cmd_notice_ops(NULL, ci->c->name,
+ "%s invited %s into the channel.",
+ ci->bi->nick, ci->bi->nick);
+ }
+ 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, 2, ci->name, ci->bi->nick);
+}
+
+/*************************************************************************/
+
+/* This makes the bot rejoin all channel he is on when he gets killed
+ * or changed.
+ */
+
+void bot_rejoin_all(BotInfo * bi)
+{
+ int i;
+ ChannelInfo *ci;
+
+ for (i = 0; i < 256; i++)
+ for (ci = chanlists[i]; ci; ci = ci->next)
+ if (ci->bi == bi && ci->c && (ci->c->usercount >= BSMinUsers))
+ bot_join(ci);
+}
+
+/*************************************************************************/
+
+/* This makes a ban if the user has to have one. In every cases it increments
+ the kick count for the user. */
+
+static void check_ban(ChannelInfo * ci, User * u, int ttbtype)
+{
+ BanData *bd = get_ban_data(ci->c, u);
+
+ if (!bd)
+ return;
+
+ bd->ttb[ttbtype]++;
+ if (bd->ttb[ttbtype] == ci->ttb[ttbtype]) {
+ char *av[4];
+ int ac;
+ char mask[BUFSIZE];
+ char buf[BUFSIZE];
+
+ bd->ttb[ttbtype] = 0;
+
+ get_idealban(ci, u, mask, sizeof(mask));
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = ci->name;
+ av[1] = buf;
+ av[2] = sstrdup("+b");
+ av[3] = mask;
+ ac = 4;
+ } else {
+ av[0] = ci->name;
+ av[1] = sstrdup("+b");
+ av[2] = mask;
+ ac = 3;
+ }
+
+ anope_cmd_mode(ci->bi->nick, ci->name, "+b %s", mask);
+ do_cmode(ci->bi->nick, ac, av);
+ send_event(EVENT_BOT_BAN, 3, u->nick, ci->name, mask);
+ if (ircdcap->tsmode)
+ free(av[2]);
+ else
+ free(av[1]);
+ }
+}
+
+/*************************************************************************/
+
+/* This makes a bot kick an user. Works somewhat like notice_lang in fact ;) */
+
+static void bot_kick(ChannelInfo * ci, User * u, int message, ...)
+{
+ va_list args;
+ char buf[1024];
+ const char *fmt;
+ char *av[3];
+
+ if (!ci || !ci->bi || !ci->c || !u)
+ return;
+
+ va_start(args, message);
+ fmt = getstring(u->na, message);
+ if (!fmt)
+ return;
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ av[0] = ci->name;
+ av[1] = u->nick;
+ av[2] = buf;
+ anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
+ do_kick(ci->bi->nick, 3, av);
+ send_event(EVENT_BOT_KICK, 3, u->nick, ci->name, buf);
+}
+
+/*************************************************************************/
+
+/* Makes a simple ban and kicks the target */
+
+void bot_raw_ban(User * requester, ChannelInfo * ci, char *nick,
+ char *reason)
+{
+ int ac;
+ char *av[4];
+ char mask[BUFSIZE];
+ char buf[BUFSIZE];
+ User *u = finduser(nick);
+
+ if (!u)
+ return;
+
+ if (ircd->protectedumode) {
+ if (is_protected(u) && (requester != u)) {
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
+ getstring2(NULL, PERMISSION_DENIED));
+ return;
+ }
+ }
+
+ if ((ci->flags & CI_PEACE) && stricmp(requester->nick, nick)
+ && (get_access(u, ci) >= get_access(requester, ci)))
+ return;
+
+ if (ircd->except) {
+ if (is_excepted(ci, u) == 1) {
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
+ getstring2(NULL, BOT_EXCEPT));
+ return;
+ }
+ }
+
+ get_idealban(ci, u, mask, sizeof(mask));
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = ci->name;
+ av[1] = buf;
+ av[2] = sstrdup("+b");
+ av[3] = mask;
+ ac = 4;
+ } else {
+ av[0] = ci->name;
+ av[1] = sstrdup("+b");
+ av[2] = mask;
+ ac = 3;
+ }
+
+ anope_cmd_mode(ci->bi->nick, ci->name, "+b %s", mask);
+ do_cmode(ci->bi->nick, ac, av);
+
+ /* We need to free our sstrdup'd "+b" -GD */
+ if (ircdcap->tsmode)
+ free(av[2]);
+ else
+ free(av[1]);
+
+ av[0] = ci->name;
+ av[1] = nick;
+
+ if (!reason) {
+ av[2] = ci->bi->nick;
+ } else {
+ if (strlen(reason) > 200)
+ reason[200] = '\0';
+ av[2] = reason;
+ }
+
+ /* Check if we need to do a signkick or not -GD */
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(requester, ci, CA_SIGNKICK)))
+ anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s (%s)", av[2],
+ requester->nick);
+ else
+ anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
+
+ do_kick(ci->bi->nick, 3, av);
+ send_event(EVENT_BOT_KICK, 3, av[1], av[0], av[2]);
+}
+
+/*************************************************************************/
+
+/* Makes a kick with a "dynamic" reason ;) */
+
+void bot_raw_kick(User * requester, ChannelInfo * ci, char *nick,
+ char *reason)
+{
+ char *av[3];
+ User *u = finduser(nick);
+
+ if (!u || !is_on_chan(ci->c, u))
+ return;
+
+ if (ircd->protectedumode) {
+ if (is_protected(u) && (requester != u)) {
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
+ getstring2(NULL, PERMISSION_DENIED));
+ return;
+ }
+ }
+
+ if ((ci->flags & CI_PEACE) && stricmp(requester->nick, nick)
+ && (get_access(u, ci) >= get_access(requester, ci)))
+ return;
+
+ av[0] = ci->name;
+ av[1] = nick;
+
+ if (!reason) {
+ av[2] = ci->bi->nick;
+ } else {
+ if (strlen(reason) > 200)
+ reason[200] = '\0';
+ av[2] = reason;
+ }
+
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(requester, ci, CA_SIGNKICK)))
+ anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s (%s)", av[2],
+ requester->nick);
+ else
+ anope_cmd_kick(ci->bi->nick, av[0], av[1], "%s", av[2]);
+ do_kick(ci->bi->nick, 3, av);
+ send_event(EVENT_BOT_KICK, 3, av[1], av[0], av[2]);
+}
+
+/*************************************************************************/
+
+/* Makes a mode operation on a channel for a nick */
+
+void bot_raw_mode(User * requester, ChannelInfo * ci, char *mode,
+ char *nick)
+{
+ char *av[4];
+ int ac;
+ char buf[BUFSIZE];
+ User *u;
+
+ *buf = '\0';
+ u = finduser(nick);
+
+ if (!u || !is_on_chan(ci->c, u))
+ return;
+
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+
+ if (ircd->protectedumode) {
+ if (is_protected(u) && *mode == '-' && (requester != u)) {
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s",
+ getstring2(NULL, PERMISSION_DENIED));
+ return;
+ }
+ }
+
+ if (*mode == '-' && (ci->flags & CI_PEACE)
+ && stricmp(requester->nick, nick)
+ && (get_access(u, ci) >= get_access(requester, ci)))
+ return;
+
+ if (ircdcap->tsmode) {
+ av[0] = ci->name;
+ av[1] = buf;
+ av[2] = mode;
+ av[3] = nick;
+ ac = 4;
+ anope_cmd_mode(ci->bi->nick, av[0], "%s %s", av[2], av[3]);
+ } else {
+ av[0] = ci->name;
+ av[1] = mode;
+ av[2] = nick;
+ ac = 3;
+ anope_cmd_mode(ci->bi->nick, av[0], "%s %s", av[1], av[2]);
+ }
+
+ do_cmode(ci->bi->nick, ac, av);
+}
+
+/*************************************************************************/
+/**
+ * Normalize buffer stripping control characters and colors
+ * @param A string to be parsed for control and color codes
+ * @return A string stripped of control and color codes
+ */
+char *normalizeBuffer(char *buf)
+{
+ char *newbuf;
+ int i, len, j = 0;
+
+ len = strlen(buf);
+ newbuf = (char *) smalloc(sizeof(char) * len + 1);
+
+ for (i = 0; i < len; i++) {
+ switch (buf[i]) {
+ /* ctrl char */
+ case 1:
+ break;
+ /* Bold ctrl char */
+ case 2:
+ break;
+ /* Color ctrl char */
+ case 3:
+ /* If the next character is a digit, its also removed */
+ if (isdigit(buf[i + 1])) {
+ i++;
+
+ /* not the best way to remove colors
+ * which are two digit but no worse then
+ * how the Unreal does with +S - TSL
+ */
+ if (isdigit(buf[i + 1])) {
+ i++;
+ }
+
+ /* Check for background color code
+ * and remove it as well
+ */
+ if (buf[i + 1] == ',') {
+ i++;
+
+ if (isdigit(buf[i + 1])) {
+ i++;
+ }
+ /* not the best way to remove colors
+ * which are two digit but no worse then
+ * how the Unreal does with +S - TSL
+ */
+ if (isdigit(buf[i + 1])) {
+ i++;
+ }
+ }
+ }
+
+ break;
+ /* line feed char */
+ case 10:
+ break;
+ /* carriage returns char */
+ case 13:
+ break;
+ /* Reverse ctrl char */
+ case 22:
+ break;
+ /* Underline ctrl char */
+ case 31:
+ break;
+ /* A valid char gets copied into the new buffer */
+ default:
+ newbuf[j] = buf[i];
+ j++;
+ }
+ }
+
+ /* Terminate the string */
+ newbuf[j] = 0;
+
+ return (newbuf);
+}
diff --git a/src/channels.c b/src/channels.c
new file mode 100644
index 000000000..8ce8a0c51
--- /dev/null
+++ b/src/channels.c
@@ -0,0 +1,2322 @@
+/* Channel-handling routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+
+Channel *chanlist[1024];
+
+#define HASH(chan) ((chan)[1] ? ((chan)[1]&31)<<5 | ((chan)[2]&31) : 0)
+
+/**************************** External Calls *****************************/
+/*************************************************************************/
+
+void chan_deluser(User * user, Channel * c)
+{
+ struct c_userlist *u;
+
+ if (c->ci)
+ update_cs_lastseen(user, c->ci);
+
+ for (u = c->users; u && u->user != user; u = u->next);
+ if (!u)
+ return;
+
+ if (u->ud) {
+ if (u->ud->lastline)
+ free(u->ud->lastline);
+ free(u->ud);
+ }
+
+ if (u->next)
+ u->next->prev = u->prev;
+ if (u->prev)
+ u->prev->next = u->next;
+ else
+ c->users = u->next;
+ free(u);
+ c->usercount--;
+
+ if (s_BotServ && c->ci && c->ci->bi && c->usercount == BSMinUsers - 1) {
+ anope_cmd_part(c->ci->bi->nick, c->name, NULL);
+ }
+
+ if (!c->users)
+ chan_delete(c);
+}
+
+/*************************************************************************/
+
+/* Returns a fully featured binary modes string. If complete is 0, the
+ * eventual parameters won't be added to the string.
+ */
+
+char *chan_get_modes(Channel * chan, int complete, int plus)
+{
+ static char res[BUFSIZE];
+ char *end = res;
+
+ if (chan->mode) {
+ int n = 0;
+ CBModeInfo *cbmi = cbmodeinfos;
+
+ do {
+ if (chan->mode & cbmi->flag)
+ *end++ = cbmi->mode;
+ } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
+
+ if (complete) {
+ cbmi = cbmodeinfos;
+
+ do {
+ if (cbmi->getvalue && (chan->mode & cbmi->flag) &&
+ (plus || !(cbmi->flags & CBM_MINUS_NO_ARG))) {
+ char *value = cbmi->getvalue(chan);
+
+ if (value) {
+ *end++ = ' ';
+ while (*value)
+ *end++ = *value++;
+ }
+ }
+ } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
+ }
+ }
+
+ *end = 0;
+
+ return res;
+}
+
+/*************************************************************************/
+
+/* Retrieves the status of an user on a channel */
+
+int chan_get_user_status(Channel * chan, User * user)
+{
+ struct u_chanlist *uc;
+
+ for (uc = user->chans; uc; uc = uc->next)
+ if (uc->chan == chan)
+ return uc->status;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Has the given user the given status on the given channel? :p */
+
+int chan_has_user_status(Channel * chan, User * user, int16 status)
+{
+ struct u_chanlist *uc;
+
+ for (uc = user->chans; uc; uc = uc->next) {
+ if (uc->chan == chan) {
+ if (debug) {
+ alog("debug: chan_has_user_status wanted %d the user is %d", status, uc->status);
+ }
+ return (uc->status & status);
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Remove the status of an user on a channel */
+
+void chan_remove_user_status(Channel * chan, User * user, int16 status)
+{
+ struct u_chanlist *uc;
+
+ if (debug >= 2)
+ alog("debug: removing user status (%d) from %s for %s", status,
+ user->nick, chan->name);
+
+ for (uc = user->chans; uc; uc = uc->next) {
+ if (uc->chan == chan) {
+ uc->status &= ~status;
+ break;
+ }
+ }
+}
+
+/*************************************************************************/
+
+void chan_set_modes(const char *source, Channel * chan, int ac, char **av,
+ int check)
+{
+ int add = 1;
+ char *modes = av[0], mode;
+ CBMode *cbm;
+ CMMode *cmm;
+ CUMode *cum;
+ unsigned char botmode = 0;
+ BotInfo *bi;
+ User *u, *user;
+ int i, real_ac = ac;
+ char **real_av = av;
+
+ if (debug)
+ alog("debug: Changing modes for %s to %s", chan->name,
+ merge_args(ac, av));
+
+ u = finduser(source);
+ if (u && (chan_get_user_status(chan, u) & CUS_DEOPPED)) {
+ char *s;
+
+ if (debug)
+ alog("debug: Removing instead of setting due to DEOPPED flag");
+
+ /* Swap adding and removing of the modes */
+ for (s = av[0]; *s; s++) {
+ if (*s == '+')
+ *s = '-';
+ else if (*s == '-')
+ *s = '+';
+ }
+
+ /* Set the resulting mode buffer */
+ anope_cmd_mode(whosends(chan->ci), chan->name, merge_args(ac, av));
+
+ return;
+ }
+
+ ac--;
+
+ while ((mode = *modes++)) {
+
+ switch (mode) {
+ case '+':
+ add = 1;
+ continue;
+ case '-':
+ add = 0;
+ continue;
+ }
+
+ if (((int) mode) < 0) {
+ if (debug)
+ alog("Debug: Malformed mode detected on %s.", chan->name);
+ continue;
+ }
+
+ if ((cum = &cumodes[(int) mode])->status != 0) {
+ if (ac == 0) {
+ alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name);
+ continue;
+ }
+ ac--;
+ av++;
+
+ if ((cum->flags & CUF_PROTECT_BOTSERV) && !add) {
+ if ((bi = findbot(*av))) {
+ if (!botmode || botmode != mode) {
+ anope_cmd_mode(bi->nick, chan->name, "+%c %s",
+ mode, bi->nick);
+ botmode = mode;
+ continue;
+ } else {
+ botmode = mode;
+ continue;
+ }
+ }
+ } else {
+ if ((bi = findbot(*av))) {
+ continue;
+ }
+ }
+
+ if (!(user = finduser(*av))
+ && !(UseTS6 && ircd->ts6 && (user = find_byuid(*av)))) {
+ if (debug) {
+ alog("debug: MODE %s %c%c for nonexistent user %s",
+ chan->name, (add ? '+' : '-'), mode, *av);
+ }
+ continue;
+ }
+
+ if (debug)
+ alog("debug: Setting %c%c on %s for %s", (add ? '+' : '-'),
+ mode, chan->name, user->nick);
+
+ if (add) {
+ chan_set_user_status(chan, user, cum->status);
+ /* If this does +o, remove any DEOPPED flag */
+ if (cum->status & CUS_OP)
+ chan_remove_user_status(chan, user, CUS_DEOPPED);
+ } else {
+ chan_remove_user_status(chan, user, cum->status);
+ }
+
+ } else if ((cbm = &cbmodes[(int) mode])->flag != 0) {
+ if (check >= 0) {
+ if (add)
+ chan->mode |= cbm->flag;
+ else
+ chan->mode &= ~cbm->flag;
+ }
+
+ if (cbm->setvalue) {
+ if (add || !(cbm->flags & CBM_MINUS_NO_ARG)) {
+ if (ac == 0) {
+ alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name);
+ continue;
+ }
+ ac--;
+ av++;
+ }
+ cbm->setvalue(chan, add ? *av : NULL);
+ }
+
+ if (check < 0) {
+ if (add)
+ chan->mode |= cbm->flag;
+ else
+ chan->mode &= ~cbm->flag;
+ }
+ } else if ((cmm = &cmmodes[(int) mode])->addmask) {
+ if (ac == 0) {
+ alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name);
+ continue;
+ }
+
+ ac--;
+ av++;
+ if (add)
+ cmm->addmask(chan, *av);
+ else
+ cmm->delmask(chan, *av);
+ }
+ }
+
+ if (check > 0) {
+ check_modes(chan);
+
+ if (check < 2) {
+ /* Walk through all users we've set modes for and see if they are
+ * valid. Invalid modes (like +o with SECUREOPS on) will be removed
+ */
+ real_ac--;
+ real_av++;
+ for (i = 0; i < real_ac; i++) {
+ if ((user = finduser(*real_av)) && is_on_chan(chan, user))
+ chan_set_correct_modes(user, chan, 0);
+ real_av++;
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Set the status of an user on a channel */
+
+void chan_set_user_status(Channel * chan, User * user, int16 status)
+{
+ struct u_chanlist *uc;
+
+ if (debug >= 2)
+ alog("debug: setting user status (%d) on %s for %s", status,
+ user->nick, chan->name);
+
+ if (HelpChannel && ircd->supporthelper && (status & CUS_OP)
+ && (stricmp(chan->name, HelpChannel) == 0)
+ && (!chan->ci || check_access(user, chan->ci, CA_AUTOOP))) {
+ if (debug) {
+ alog("debug: %s being given +h for having %d status in %s",
+ user->nick, status, chan->name);
+ }
+ common_svsmode(user, "+h", NULL);
+ }
+
+ for (uc = user->chans; uc; uc = uc->next) {
+ if (uc->chan == chan) {
+ uc->status |= status;
+ break;
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Return the Channel structure corresponding to the named channel, or NULL
+ * if the channel was not found. chan is assumed to be non-NULL and valid
+ * (i.e. pointing to a channel name of 2 or more characters). */
+
+Channel *findchan(const char *chan)
+{
+ Channel *c;
+
+ if (!chan || !*chan) {
+ if (debug) {
+ alog("debug: findchan() called with NULL values");
+ }
+ return NULL;
+ }
+
+ if (debug >= 3)
+ alog("debug: findchan(%p)", chan);
+ c = chanlist[HASH(chan)];
+ while (c) {
+ if (stricmp(c->name, chan) == 0) {
+ if (debug >= 3)
+ alog("debug: findchan(%s) -> %p", chan, (void *) c);
+ return c;
+ }
+ c = c->next;
+ }
+ if (debug >= 3)
+ alog("debug: findchan(%s) -> %p", chan, (void *) c);
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Iterate over all channels in the channel list. Return NULL at end of
+ * list.
+ */
+
+static Channel *current;
+static int next_index;
+
+Channel *firstchan(void)
+{
+ next_index = 0;
+ while (next_index < 1024 && current == NULL)
+ current = chanlist[next_index++];
+ if (debug >= 3)
+ alog("debug: firstchan() returning %s",
+ current ? current->name : "NULL (end of list)");
+ return current;
+}
+
+Channel *nextchan(void)
+{
+ if (current)
+ current = current->next;
+ if (!current && next_index < 1024) {
+ while (next_index < 1024 && current == NULL)
+ current = chanlist[next_index++];
+ }
+ if (debug >= 3)
+ alog("debug: nextchan() returning %s",
+ current ? current->name : "NULL (end of list)");
+ return current;
+}
+
+/*************************************************************************/
+
+/* Return statistics. Pointers are assumed to be valid. */
+
+void get_channel_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ Channel *chan;
+ struct c_userlist *cu;
+ BanData *bd;
+ int i;
+
+ for (i = 0; i < 1024; i++) {
+ for (chan = chanlist[i]; chan; chan = chan->next) {
+ count++;
+ mem += sizeof(*chan);
+ if (chan->topic)
+ mem += strlen(chan->topic) + 1;
+ if (chan->key)
+ mem += strlen(chan->key) + 1;
+ if (ircd->fmode) {
+ if (chan->flood)
+ mem += strlen(chan->flood) + 1;
+ }
+ if (ircd->Lmode) {
+ if (chan->redirect)
+ mem += strlen(chan->redirect) + 1;
+ }
+ mem += get_memuse(chan->bans);
+ if (ircd->except) {
+ mem += get_memuse(chan->excepts);
+ }
+ if (ircd->invitemode) {
+ mem += get_memuse(chan->invites);
+ }
+ for (cu = chan->users; cu; cu = cu->next) {
+ mem += sizeof(*cu);
+ if (cu->ud) {
+ mem += sizeof(*cu->ud);
+ if (cu->ud->lastline)
+ mem += strlen(cu->ud->lastline) + 1;
+ }
+ }
+ for (bd = chan->bd; bd; bd = bd->next) {
+ if (bd->mask)
+ mem += strlen(bd->mask) + 1;
+ mem += sizeof(*bd);
+ }
+ }
+ }
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+
+/* Is the given nick on the given channel? */
+
+int is_on_chan(Channel * c, User * u)
+{
+ struct u_chanlist *uc;
+
+ for (uc = u->chans; uc; uc = uc->next)
+ if (uc->chan == c)
+ return 1;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Is the given nick on the given channel?
+ This function supports links. */
+
+User *nc_on_chan(Channel * c, NickCore * nc)
+{
+ struct c_userlist *u;
+
+ if (!c || !nc)
+ return NULL;
+
+ for (u = c->users; u; u = u->next) {
+ if (u->user->na && u->user->na->nc == nc
+ && nick_recognized(u->user))
+ return u->user;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+/*************************** Message Handling ****************************/
+/*************************************************************************/
+
+/* Handle a JOIN command.
+ * av[0] = channels to join
+ */
+
+void do_join(const char *source, int ac, char **av)
+{
+ User *user;
+ Channel *chan;
+ char *s, *t;
+ struct u_chanlist *c, *nextc;
+ char *channame;
+ time_t ts = time(NULL);
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(source);
+ if (!user)
+ user = finduser(source);
+ } else {
+ user = finduser(source);
+ }
+ if (!user) {
+ if (debug) {
+ alog("debug: JOIN from nonexistent user %s: %s", source,
+ merge_args(ac, av));
+ }
+ return;
+ }
+
+ t = av[0];
+ while (*(s = t)) {
+ t = s + strcspn(s, ",");
+ if (*t)
+ *t++ = 0;
+
+ if (*s == '0') {
+ c = user->chans;
+ while (c) {
+ nextc = c->next;
+ channame = sstrdup(c->chan->name);
+ send_event(EVENT_PART_CHANNEL, 3, EVENT_START, user->nick,
+ channame);
+ chan_deluser(user, c->chan);
+ send_event(EVENT_PART_CHANNEL, 3, EVENT_STOP, user->nick,
+ channame);
+ free(channame);
+ free(c);
+ c = nextc;
+ }
+ user->chans = NULL;
+ continue;
+ }
+
+ /* how about not triggering the JOIN event on an actual /part :) -certus */
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_START, source, s);
+
+ /* Make sure check_kick comes before chan_adduser, so banned users
+ * don't get to see things like channel keys. */
+ /* If channel already exists, check_kick() will use correct TS.
+ * Otherwise, we lose. */
+ if (check_kick(user, s, ts))
+ continue;
+
+ if (ac == 2) {
+ ts = strtoul(av[1], NULL, 10);
+ if (debug) {
+ alog("debug: recieved a new TS for JOIN: %ld",
+ (long int) ts);
+ }
+ }
+
+ chan = findchan(s);
+ chan = join_user_update(user, chan, s, ts);
+ chan_set_correct_modes(user, chan, 1);
+
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_STOP, source, s);
+ }
+}
+
+/*************************************************************************/
+
+/* Handle a KICK command.
+ * av[0] = channel
+ * av[1] = nick(s) being kicked
+ * av[2] = reason
+ */
+
+void do_kick(const char *source, int ac, char **av)
+{
+ BotInfo *bi;
+ ChannelInfo *ci;
+ User *user;
+ char *s, *t;
+ struct u_chanlist *c;
+
+ t = av[1];
+ while (*(s = t)) {
+ t = s + strcspn(s, ",");
+ if (*t)
+ *t++ = 0;
+
+ /* If it is the bot that is being kicked, we make it rejoin the
+ * channel and stop immediately.
+ * --lara
+ */
+ if (s_BotServ && (bi = findbot(s)) && (ci = cs_findchan(av[0]))) {
+ bot_join(ci);
+ continue;
+ }
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(s);
+ if (!user) {
+ user = finduser(s);
+ }
+ } else {
+ user = finduser(s);
+ }
+ if (!user) {
+ if (debug) {
+ alog("debug: KICK for nonexistent user %s on %s: %s", s,
+ av[0], merge_args(ac - 2, av + 2));
+ }
+ continue;
+ }
+ if (debug) {
+ alog("debug: kicking %s from %s", user->nick, av[0]);
+ }
+ for (c = user->chans; c && stricmp(av[0], c->chan->name) != 0;
+ c = c->next);
+ if (c) {
+ send_event(EVENT_CHAN_KICK, 2, user->nick, av[0]);
+ chan_deluser(user, c->chan);
+ if (c->next)
+ c->next->prev = c->prev;
+ if (c->prev)
+ c->prev->next = c->next;
+ else
+ user->chans = c->next;
+ free(c);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Handle a PART command.
+ * av[0] = channels to leave
+ * av[1] = reason (optional)
+ */
+
+void do_part(const char *source, int ac, char **av)
+{
+ User *user;
+ char *s, *t;
+ struct u_chanlist *c;
+ char *channame;
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(source);
+ if (!user)
+ user = finduser(source);
+ } else {
+ user = finduser(source);
+ }
+ if (!user) {
+ if (debug) {
+ alog("debug: PART from nonexistent user %s: %s", source,
+ merge_args(ac, av));
+ }
+ return;
+ }
+ t = av[0];
+ while (*(s = t)) {
+ t = s + strcspn(s, ",");
+ if (*t)
+ *t++ = 0;
+ if (debug)
+ alog("debug: %s leaves %s", source, s);
+ for (c = user->chans; c && stricmp(s, c->chan->name) != 0;
+ c = c->next);
+ if (c) {
+ if (!c->chan) {
+ alog("user: BUG parting %s: channel entry found but c->chan NULL", s);
+ return;
+ }
+ channame = sstrdup(c->chan->name);
+ send_event(EVENT_PART_CHANNEL, (ac >= 2 ? 4 : 3), EVENT_START,
+ user->nick, channame, (ac >= 2 ? av[1] : ""));
+
+ chan_deluser(user, c->chan);
+ if (c->next)
+ c->next->prev = c->prev;
+ if (c->prev)
+ c->prev->next = c->next;
+ else
+ user->chans = c->next;
+ free(c);
+
+ send_event(EVENT_PART_CHANNEL, (ac >= 2 ? 4 : 3), EVENT_STOP,
+ user->nick, channame, (ac >= 2 ? av[1] : ""));
+ free(channame);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Handle a SJOIN command.
+
+ On channel creation, syntax is:
+
+ av[0] = timestamp
+ av[1] = channel name
+ av[2|3|4] = modes \ depends of whether the modes k and l
+ av[3|4|5] = users / are set or not.
+
+ When a single user joins an (existing) channel, it is:
+
+ av[0] = timestamp
+ av[1] = user
+
+ ============================================================
+
+ Unreal SJOIN
+
+ On Services connect there is
+ SJOIN !11LkOb #ircops +nt :@Trystan &*!*@*.aol.com "*@*.home.com
+
+ av[0] = time stamp (base64)
+ av[1] = channel
+ av[2] = modes
+ av[3] = users + bans + exceptions
+
+ On Channel Creation or a User joins an existing
+ Luna.NomadIrc.Net SJOIN !11LkW9 #akill :@Trystan
+ Luna.NomadIrc.Net SJOIN !11LkW9 #akill :Trystan`
+
+ av[0] = time stamp (base64)
+ av[1] = channel
+ av[2] = users
+
+*/
+
+void do_sjoin(const char *source, int ac, char **av)
+{
+ Channel *c;
+ User *user;
+ Server *serv;
+ struct c_userlist *cu;
+ char *s = NULL;
+ char *end, cubuf[7], *end2, *cumodes[6];
+ int is_sqlined = 0;
+ int ts = 0;
+ int is_created = 0;
+ int keep_their_modes = 1;
+
+ serv = findserver(servlist, source);
+
+ if (ircd->sjb64) {
+ ts = base64dects(av[0]);
+ } else {
+ ts = strtoul(av[0], NULL, 10);
+ }
+ c = findchan(av[1]);
+ if (c != NULL) {
+ if (c->creation_time == 0 || ts == 0)
+ c->creation_time = 0;
+ else if (c->creation_time > ts) {
+ c->creation_time = ts;
+ for (cu = c->users; cu; cu = cu->next) {
+ /* XXX */
+ cumodes[0] = "-ov";
+ cumodes[1] = cu->user->nick;
+ cumodes[2] = cu->user->nick;
+ chan_set_modes(source, c, 3, cumodes, 2);
+ }
+ if (c->ci && c->ci->bi) {
+ /* This is ugly, but it always works */
+ anope_cmd_part(c->ci->bi->nick, c->name, "TS reop");
+ bot_join(c->ci);
+ }
+ /* XXX simple modes and bans */
+ } else if (c->creation_time < ts)
+ keep_their_modes = 0;
+ } else
+ is_created = 1;
+
+ /* Double check to avoid unknown modes that need parameters */
+ if (ac >= 4) {
+ if (ircd->chansqline) {
+ if (!c)
+ is_sqlined = check_chan_sqline(av[1]);
+ }
+
+ cubuf[0] = '+';
+ cumodes[0] = cubuf;
+
+ /* We make all the users join */
+ s = av[ac - 1]; /* Users are always the last element */
+
+ while (*s) {
+ end = strchr(s, ' ');
+ if (end)
+ *end = 0;
+
+ end2 = cubuf + 1;
+
+
+ if (ircd->sjoinbanchar) {
+ if (*s == ircd->sjoinbanchar && keep_their_modes) {
+ add_ban(c, myStrGetToken(s, ircd->sjoinbanchar, 1));
+ if (!end)
+ break;
+ s = end + 1;
+ continue;
+ }
+ }
+ if (ircd->sjoinexchar) {
+ if (*s == ircd->sjoinexchar && keep_their_modes) {
+ add_exception(c,
+ myStrGetToken(s, ircd->sjoinexchar, 1));
+ if (!end)
+ break;
+ s = end + 1;
+ continue;
+ }
+ }
+
+ if (ircd->sjoininvchar) {
+ if (*s == ircd->sjoininvchar && keep_their_modes) {
+ add_invite(c, myStrGetToken(s, ircd->sjoininvchar, 1));
+ if (!end)
+ break;
+ s = end + 1;
+ continue;
+ }
+ }
+
+ while (csmodes[(int) *s] != 0)
+ *end2++ = csmodes[(int) *s++];
+ *end2 = 0;
+
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(s);
+ if (!user)
+ user = finduser(s);
+ } else {
+ user = finduser(s);
+ }
+
+ if (!user) {
+ if (debug) {
+ alog("debug: SJOIN for nonexistent user %s on %s", s,
+ av[1]);
+ }
+ return;
+ }
+
+ if (is_sqlined && !is_oper(user)) {
+ anope_cmd_kick(s_OperServ, av[1], s, "Q-Lined");
+ } else {
+ if (!check_kick(user, av[1], ts)) {
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_START,
+ user->nick, av[1]);
+
+ /* Make the user join; if the channel does not exist it
+ * will be created there. This ensures that the channel
+ * is not created to be immediately destroyed, and
+ * that the locked key or topic is not shown to anyone
+ * who joins the channel when empty.
+ */
+ c = join_user_update(user, c, av[1], ts);
+
+ /* We update user mode on the channel */
+ if (end2 - cubuf > 1 && keep_their_modes) {
+ int i;
+
+ for (i = 1; i < end2 - cubuf; i++)
+ cumodes[i] = user->nick;
+ chan_set_modes(source, c, 1 + (end2 - cubuf - 1),
+ cumodes, 2);
+ }
+
+ if (c->ci && (!serv || is_sync(serv))
+ && !c->topic_sync)
+ restore_topic(c->name);
+ chan_set_correct_modes(user, c, 1);
+
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_STOP,
+ user->nick, av[1]);
+ }
+ }
+
+ if (!end)
+ break;
+ s = end + 1;
+ }
+
+ if (c && keep_their_modes) {
+ /* We now update the channel mode. */
+ chan_set_modes(source, c, ac - 3, &av[2], 2);
+ }
+
+ /* Unreal just had to be different */
+ } else if (ac == 3 && !ircd->ts6) {
+ if (ircd->chansqline) {
+ if (!c)
+ is_sqlined = check_chan_sqline(av[1]);
+ }
+
+ cubuf[0] = '+';
+ cumodes[0] = cubuf;
+
+ /* We make all the users join */
+ s = av[2]; /* Users are always the last element */
+
+ while (*s) {
+ end = strchr(s, ' ');
+ if (end)
+ *end = 0;
+
+ end2 = cubuf + 1;
+
+ while (csmodes[(int) *s] != 0)
+ *end2++ = csmodes[(int) *s++];
+ *end2 = 0;
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(s);
+ if (!user)
+ user = finduser(s);
+ } else {
+ user = finduser(s);
+ }
+
+ if (!user) {
+ if (debug) {
+ alog("debug: SJOIN for nonexistent user %s on %s", s,
+ av[1]);
+ }
+ return;
+ }
+
+ if (is_sqlined && !is_oper(user)) {
+ anope_cmd_kick(s_OperServ, av[1], s, "Q-Lined");
+ } else {
+ if (!check_kick(user, av[1], ts)) {
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_START,
+ user->nick, av[1]);
+
+ /* Make the user join; if the channel does not exist it
+ * will be created there. This ensures that the channel
+ * is not created to be immediately destroyed, and
+ * that the locked key or topic is not shown to anyone
+ * who joins the channel when empty.
+ */
+ c = join_user_update(user, c, av[1], ts);
+
+ /* We update user mode on the channel */
+ if (end2 - cubuf > 1 && keep_their_modes) {
+ int i;
+
+ for (i = 1; i < end2 - cubuf; i++)
+ cumodes[i] = user->nick;
+ chan_set_modes(source, c, 1 + (end2 - cubuf - 1),
+ cumodes, 2);
+ }
+
+ chan_set_correct_modes(user, c, 1);
+
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_STOP,
+ user->nick, av[1]);
+ }
+ }
+
+ if (!end)
+ break;
+ s = end + 1;
+ }
+ } else if (ac == 3 && ircd->ts6) {
+ if (ircd->chansqline) {
+ if (!c)
+ is_sqlined = check_chan_sqline(av[1]);
+ }
+
+ cubuf[0] = '+';
+ cumodes[0] = cubuf;
+
+ /* We make all the users join */
+ s = sstrdup(source); /* Users are always the last element */
+
+ while (*s) {
+ end = strchr(s, ' ');
+ if (end)
+ *end = 0;
+
+ end2 = cubuf + 1;
+
+ while (csmodes[(int) *s] != 0)
+ *end2++ = csmodes[(int) *s++];
+ *end2 = 0;
+
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(s);
+ if (!user)
+ user = finduser(s);
+ } else {
+ user = finduser(s);
+ }
+ if (!user) {
+ if (debug) {
+ alog("debug: SJOIN for nonexistent user %s on %s", s,
+ av[1]);
+ }
+ free(s);
+ return;
+ }
+
+ if (is_sqlined && !is_oper(user)) {
+ anope_cmd_kick(s_OperServ, av[1], s, "Q-Lined");
+ } else {
+ if (!check_kick(user, av[1], ts)) {
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_START,
+ user->nick, av[1]);
+
+ /* Make the user join; if the channel does not exist it
+ * will be created there. This ensures that the channel
+ * is not created to be immediately destroyed, and
+ * that the locked key or topic is not shown to anyone
+ * who joins the channel when empty.
+ */
+ c = join_user_update(user, c, av[1], ts);
+
+ /* We update user mode on the channel */
+ if (end2 - cubuf > 1 && keep_their_modes) {
+ int i;
+
+ for (i = 1; i < end2 - cubuf; i++)
+ cumodes[i] = user->nick;
+ chan_set_modes(source, c, 1 + (end2 - cubuf - 1),
+ cumodes, 2);
+ }
+
+ chan_set_correct_modes(user, c, 1);
+
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_STOP,
+ user->nick, av[1]);
+ }
+ }
+
+ if (!end)
+ break;
+ s = end + 1;
+ }
+ free(s);
+ } else if (ac == 2) {
+ if (UseTS6 && ircd->ts6) {
+ user = find_byuid(source);
+ if (!user)
+ user = finduser(source);
+ } else {
+ user = finduser(source);
+ }
+ if (!user) {
+ if (debug) {
+ alog("debug: SJOIN for nonexistent user %s on %s", source,
+ av[1]);
+ }
+ return;
+ }
+
+ if (check_kick(user, av[1], ts))
+ return;
+
+ if (ircd->chansqline) {
+ if (!c)
+ is_sqlined = check_chan_sqline(av[1]);
+ }
+
+ if (is_sqlined && !is_oper(user)) {
+ anope_cmd_kick(s_OperServ, av[1], user->nick, "Q-Lined");
+ } else {
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_START, user->nick,
+ av[1]);
+
+ c = join_user_update(user, c, av[1], ts);
+ if (is_created && c->ci)
+ restore_topic(c->name);
+ chan_set_correct_modes(user, c, 1);
+
+ send_event(EVENT_JOIN_CHANNEL, 3, EVENT_STOP, user->nick,
+ av[1]);
+ }
+ }
+}
+
+
+/*************************************************************************/
+
+/* Handle a channel MODE command. */
+
+void do_cmode(const char *source, int ac, char **av)
+{
+ Channel *chan;
+ ChannelInfo *ci = NULL;
+ int i;
+ char *t;
+
+ if (ircdcap->tsmode) {
+ /* TSMODE for bahamut - leave this code out to break MODEs. -GD */
+ /* if they don't send it in CAPAB check if we just want to enable it */
+ if (uplink_capab & ircdcap->tsmode || UseTSMODE) {
+ for (i = 0; i < strlen(av[1]); i++) {
+ if (!isdigit(av[1][i]))
+ break;
+ }
+ if (av[1][i] == '\0') {
+ /* We have a valid TS field in av[1] now, so we can strip it off */
+ /* After we swap av[0] and av[1] ofcourse to not break stuff! :) */
+ t = av[0];
+ av[0] = av[1];
+ av[1] = t;
+ ac--;
+ av++;
+ } else {
+ alog("TSMODE enabled but MODE has no valid TS");
+ }
+ }
+ }
+
+ /* :42XAAAAAO TMODE 1106409026 #ircops +b *!*@*.aol.com */
+ if (UseTS6 && ircd->ts6) {
+ if (isdigit(av[0][0])) {
+ ac--;
+ av++;
+ }
+ }
+
+ chan = findchan(av[0]);
+ if (!chan) {
+ if (debug) {
+ ci = cs_findchan(av[0]);
+ if (!(ci && (ci->flags & CI_VERBOTEN)))
+ alog("debug: MODE %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return;
+ }
+
+ /* This shouldn't trigger on +o, etc. */
+ if (strchr(source, '.') && !av[1][strcspn(av[1], "bovahq")]) {
+ if (time(NULL) != chan->server_modetime) {
+ chan->server_modecount = 0;
+ chan->server_modetime = time(NULL);
+ }
+ chan->server_modecount++;
+ }
+
+ ac--;
+ av++;
+ chan_set_modes(source, chan, ac, av, 1);
+}
+
+/*************************************************************************/
+
+/* Handle a TOPIC command. */
+
+void do_topic(const char *source, int ac, char **av)
+{
+ Channel *c = findchan(av[0]);
+ ChannelInfo *ci;
+ int ts;
+ time_t topic_time;
+ char *topicsetter;
+
+ if (ircd->sjb64) {
+ ts = base64dects(av[2]);
+ if (debug) {
+ alog("debug: encoded TOPIC TS %s converted to %d", av[2], ts);
+ }
+ } else {
+ ts = strtoul(av[2], NULL, 10);
+ }
+
+ topic_time = ts;
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return;
+ }
+
+ /* We can be sure that the topic will be in sync here -GD */
+ c->topic_sync = 1;
+
+ ci = c->ci;
+
+ /* For Unreal, cut off the ! and any futher part of the topic setter.
+ * This way, nick!ident@host setters will only show the nick. -GD
+ */
+ topicsetter = myStrGetToken(av[1], '!', 0);
+
+ /* If the current topic we have matches the last known topic for this
+ * channel exactly, there's no need to update anything and we can as
+ * well just return silently without updating anything. -GD
+ */
+ if ((ac > 3) && *av[3] && ci && ci->last_topic
+ && (strcmp(av[3], ci->last_topic) == 0)
+ && (strcmp(topicsetter, ci->last_topic_setter) == 0)) {
+ free(topicsetter);
+ return;
+ }
+
+ if (check_topiclock(c, topic_time)) {
+ free(topicsetter);
+ return;
+ }
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 3 && *av[3]) {
+ c->topic = sstrdup(av[3]);
+ }
+
+ strscpy(c->topic_setter, topicsetter, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+ free(topicsetter);
+
+ record_topic(av[0]);
+
+ if (ci && ci->last_topic) {
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], ci->last_topic);
+ } else {
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+ }
+}
+
+/*************************************************************************/
+/**************************** Internal Calls *****************************/
+/*************************************************************************/
+
+void add_ban(Channel * chan, char *mask)
+{
+ Entry *ban;
+ /* check for NULL values otherwise we will segfault */
+ if (!chan || !mask) {
+ if (debug) {
+ alog("debug: add_ban called with NULL values");
+ }
+ return;
+ }
+
+ /* Check if the list already exists, if not create it.
+ * Create a new ban and add it to the list.. ~ Viper */
+ if (!chan->bans)
+ chan->bans = list_create();
+ ban = entry_add(chan->bans, mask);
+
+ if (!ban)
+ fatal("Creating new ban entry failed");
+
+ /* Check whether it matches a botserv bot after adding internally
+ * and parsing it through cidr support. ~ Viper */
+ if (s_BotServ && BSSmartJoin && chan->ci && chan->ci->bi
+ && chan->usercount >= BSMinUsers) {
+ BotInfo *bi = chan->ci->bi;
+
+ if (entry_match(ban, bi->nick, bi->user, bi->host, 0)) {
+ anope_cmd_mode(bi->nick, chan->name, "-b %s", mask);
+ entry_delete(chan->bans, ban);
+ return;
+ }
+ }
+
+ if (debug)
+ alog("debug: Added ban %s to channel %s", mask, chan->name);
+}
+
+/*************************************************************************/
+
+void add_exception(Channel * chan, char *mask)
+{
+ Entry *exception;
+
+ if (!chan || !mask) {
+ if (debug)
+ alog("debug: add_exception called with NULL values");
+ return;
+ }
+
+ /* Check if the list already exists, if not create it.
+ * Create a new exception and add it to the list.. ~ Viper */
+ if (!chan->excepts)
+ chan->excepts = list_create();
+ exception = entry_add(chan->excepts, mask);
+
+ if (!exception)
+ fatal("Creating new exception entry failed");
+
+ if (debug)
+ alog("debug: Added except %s to channel %s", mask, chan->name);
+}
+
+/*************************************************************************/
+
+void add_invite(Channel * chan, char *mask)
+{
+ Entry *invite;
+
+ if (!chan || !mask) {
+ if (debug)
+ alog("debug: add_invite called with NULL values");
+ return;
+ }
+
+ /* Check if the list already exists, if not create it.
+ * Create a new invite and add it to the list.. ~ Viper */
+ if (!chan->invites)
+ chan->invites = list_create();
+ invite = entry_add(chan->invites, mask);
+
+ if (!invite)
+ fatal("Creating new exception entry failed");
+
+ if (debug)
+ alog("debug: Added invite %s to channel %s", mask, chan->name);
+}
+
+/*************************************************************************/
+
+/**
+ * Set the correct modes, or remove the ones granted without permission,
+ * for the specified user on ths specified channel. This doesn't give
+ * modes to ignored users, but does remove them if needed.
+ * @param user The user to give/remove modes to/from
+ * @param c The channel to give/remove modes on
+ * @param give_modes Set to 1 to give modes, 0 to not give modes
+ * @return void
+ **/
+void chan_set_correct_modes(User * user, Channel * c, int give_modes)
+{
+ char *tmp;
+ char modebuf[BUFSIZE];
+ char userbuf[BUFSIZE];
+ int status;
+ int add_modes = 0;
+ int rem_modes = 0;
+ ChannelInfo *ci;
+
+ if (!c || !(ci = c->ci))
+ return;
+
+ if ((ci->flags & CI_VERBOTEN) || (*(c->name) == '+'))
+ return;
+
+ status = chan_get_user_status(c, user);
+
+ if (debug)
+ alog("debug: Setting correct user modes for %s on %s (current status: %d, %sgiving modes)", user->nick, c->name, status, (give_modes ? "" : "not "));
+
+ /* Changed the second line of this if a bit, to make sure unregistered
+ * users can always get modes (IE: they always have autoop enabled). Before
+ * this change, you were required to have a registered nick to be able
+ * to receive modes. I wonder who added that... *looks at Rob* ;) -GD
+ */
+ if (give_modes && (get_ignore(user->nick) == NULL)
+ && (!user->na || !(user->na->nc->flags & NI_AUTOOP))) {
+ if (ircd->owner && is_founder(user, ci))
+ add_modes |= CUS_OWNER;
+ else if ((ircd->protect || ircd->admin)
+ && check_access(user, ci, CA_AUTOPROTECT))
+ add_modes |= CUS_PROTECT;
+ if (check_access(user, ci, CA_AUTOOP))
+ add_modes |= CUS_OP;
+ else if (ircd->halfop && check_access(user, ci, CA_AUTOHALFOP))
+ add_modes |= CUS_HALFOP;
+ else if (check_access(user, ci, CA_AUTOVOICE))
+ add_modes |= CUS_VOICE;
+ }
+
+ /* We check if every mode they have is legally acquired here, and remove
+ * the modes that they're not allowed to have. But only if SECUREOPS is
+ * on, because else every mode is legal. -GD
+ * Unless the channel has just been created. -heinz
+ * Or the user matches CA_AUTODEOP... -GD
+ */
+ if (((ci->flags & CI_SECUREOPS) || (c->usercount == 1)
+ || check_access(user, ci, CA_AUTODEOP))
+ && !is_ulined(user->server->name)) {
+ if (ircd->owner && (status & CUS_OWNER) && !is_founder(user, ci))
+ rem_modes |= CUS_OWNER;
+ if ((ircd->protect || ircd->admin) && (status & CUS_PROTECT)
+ && !check_access(user, ci, CA_AUTOPROTECT)
+ && !check_access(user, ci, CA_PROTECTME))
+ rem_modes |= CUS_PROTECT;
+ if ((status & CUS_OP) && !check_access(user, ci, CA_AUTOOP)
+ && !check_access(user, ci, CA_OPDEOPME))
+ rem_modes |= CUS_OP;
+ if (ircd->halfop && (status & CUS_HALFOP)
+ && !check_access(user, ci, CA_AUTOHALFOP)
+ && !check_access(user, ci, CA_HALFOPME))
+ rem_modes |= CUS_HALFOP;
+ }
+
+ /* No modes to add or remove, exit function -GD */
+ if (!add_modes && !rem_modes)
+ return;
+
+ /* No need for strn* functions for modebuf, as every possible string
+ * will always fit in. -GD
+ */
+ strcpy(modebuf, "");
+ strcpy(userbuf, "");
+ if (add_modes > 0) {
+ strcat(modebuf, "+");
+ if ((add_modes & CUS_OWNER) && !(status & CUS_OWNER)) {
+ tmp = stripModePrefix(ircd->ownerset);
+ strcat(modebuf, tmp);
+ free(tmp);
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ } else {
+ add_modes &= ~CUS_OWNER;
+ }
+ if ((add_modes & CUS_PROTECT) && !(status & CUS_PROTECT)) {
+ tmp = stripModePrefix(ircd->adminset);
+ strcat(modebuf, tmp);
+ free(tmp);
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ } else {
+ add_modes &= ~CUS_PROTECT;
+ }
+ if ((add_modes & CUS_OP) && !(status & CUS_OP)) {
+ strcat(modebuf, "o");
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ rem_modes |= CUS_DEOPPED;
+ } else {
+ add_modes &= ~CUS_OP;
+ }
+ if ((add_modes & CUS_HALFOP) && !(status & CUS_HALFOP)) {
+ strcat(modebuf, "h");
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ } else {
+ add_modes &= ~CUS_HALFOP;
+ }
+ if ((add_modes & CUS_VOICE) && !(status & CUS_VOICE)) {
+ strcat(modebuf, "v");
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ } else {
+ add_modes &= ~CUS_VOICE;
+ }
+ }
+ if (rem_modes > 0) {
+ strcat(modebuf, "-");
+ if (rem_modes & CUS_OWNER) {
+ tmp = stripModePrefix(ircd->ownerset);
+ strcat(modebuf, tmp);
+ free(tmp);
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ }
+ if (rem_modes & CUS_PROTECT) {
+ tmp = stripModePrefix(ircd->adminset);
+ strcat(modebuf, tmp);
+ free(tmp);
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ }
+ if (rem_modes & CUS_OP) {
+ strcat(modebuf, "o");
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ add_modes |= CUS_DEOPPED;
+ }
+ if (rem_modes & CUS_HALFOP) {
+ strcat(modebuf, "h");
+ strcat(userbuf, " ");
+ strcat(userbuf, user->nick);
+ }
+ }
+
+ /* Here, both can be empty again due to the "isn't it set already?"
+ * checks above. -GD
+ */
+ if (!add_modes && !rem_modes)
+ return;
+
+ anope_cmd_mode(whosends(ci), c->name, "%s%s", modebuf, userbuf);
+ if (add_modes > 0)
+ chan_set_user_status(c, user, add_modes);
+ if (rem_modes > 0)
+ chan_remove_user_status(c, user, rem_modes);
+}
+
+/*************************************************************************/
+
+/* Add/remove a user to/from a channel, creating or deleting the channel as
+ * necessary. If creating the channel, restore mode lock and topic as
+ * necessary. Also check for auto-opping and auto-voicing.
+ */
+
+void chan_adduser2(User * user, Channel * c)
+{
+ struct c_userlist *u;
+
+ u = scalloc(sizeof(struct c_userlist), 1);
+ u->next = c->users;
+ if (c->users)
+ c->users->prev = u;
+ c->users = u;
+ u->user = user;
+ c->usercount++;
+
+ if (get_ignore(user->nick) == NULL) {
+ if (c->ci && (check_access(user, c->ci, CA_MEMO))
+ && (c->ci->memos.memocount > 0)) {
+ if (c->ci->memos.memocount == 1) {
+ notice_lang(s_MemoServ, user, MEMO_X_ONE_NOTICE,
+ c->ci->memos.memocount, c->ci->name);
+ } else {
+ notice_lang(s_MemoServ, user, MEMO_X_MANY_NOTICE,
+ c->ci->memos.memocount, c->ci->name);
+ }
+ }
+ /* Added channelname to entrymsg - 30.03.2004, Certus */
+ /* Also, don't send the entrymsg when bursting -GD */
+ if (c->ci && c->ci->entry_message && is_sync(user->server))
+ notice_user(whosends(c->ci), user, "[%s] %s", c->name,
+ c->ci->entry_message);
+ }
+
+ /**
+ * We let the bot join even if it was an ignored user, as if we don't,
+ * and the ignored user dosnt just leave, the bot will never
+ * make it into the channel, leaving the channel botless even for
+ * legit users - Rob
+ **/
+ if (s_BotServ && c->ci && c->ci->bi) {
+ if (c->usercount == BSMinUsers)
+ bot_join(c->ci);
+ if (c->usercount >= BSMinUsers && (c->ci->botflags & BS_GREET)
+ && user->na && user->na->nc->greet
+ && check_access(user, c->ci, CA_GREET)) {
+ /* Only display the greet if the main uplink we're connected
+ * to has synced, or we'll get greet-floods when the net
+ * recovers from a netsplit. -GD
+ */
+ if (is_sync(user->server)) {
+ anope_cmd_privmsg(c->ci->bi->nick, c->name, "[%s] %s",
+ user->na->nick, user->na->nc->greet);
+ c->ci->bi->lastmsg = time(NULL);
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* This creates the channel structure (was originally in
+ chan_adduser, but splitted to make it more efficient to use for
+ SJOINs). */
+
+Channel *chan_create(char *chan, time_t ts)
+{
+ Channel *c;
+ Channel **list;
+
+ if (debug)
+ alog("debug: Creating channel %s", chan);
+ /* Allocate pre-cleared memory */
+ c = scalloc(sizeof(Channel), 1);
+ strscpy(c->name, chan, sizeof(c->name));
+ list = &chanlist[HASH(c->name)];
+ c->next = *list;
+ if (*list)
+ (*list)->prev = c;
+ *list = c;
+ c->creation_time = ts;
+ /* Store ChannelInfo pointer in channel record */
+ c->ci = cs_findchan(chan);
+ if (c->ci)
+ c->ci->c = c;
+ /* Restore locked modes and saved topic */
+ if (c->ci) {
+ check_modes(c);
+ stick_all(c->ci);
+ }
+
+ if (serv_uplink && is_sync(serv_uplink) && (!(c->topic_sync))) {
+ restore_topic(chan);
+ }
+
+ return c;
+}
+
+/*************************************************************************/
+
+/* This destroys the channel structure, freeing everything in it. */
+
+void chan_delete(Channel * c)
+{
+ BanData *bd, *next;
+
+ if (debug)
+ alog("debug: Deleting channel %s", c->name);
+
+ for (bd = c->bd; bd; bd = next) {
+ if (bd->mask)
+ free(bd->mask);
+ next = bd->next;
+ free(bd);
+ }
+
+ if (c->ci)
+ c->ci->c = NULL;
+
+ if (c->topic)
+ free(c->topic);
+
+ if (c->key)
+ free(c->key);
+ if (ircd->fmode) {
+ if (c->flood)
+ free(c->flood);
+ }
+ if (ircd->Lmode) {
+ if (c->redirect)
+ free(c->redirect);
+ }
+
+ if (c->bans && c->bans->count) {
+ while (c->bans->entries) {
+ entry_delete(c->bans, c->bans->entries);
+ }
+ }
+
+ if (ircd->except) {
+ if (c->excepts && c->excepts->count) {
+ while (c->excepts->entries) {
+ entry_delete(c->excepts, c->excepts->entries);
+ }
+ }
+ }
+
+ if (ircd->invitemode) {
+ if (c->invites && c->invites->count) {
+ while (c->invites->entries) {
+ entry_delete(c->invites, c->invites->entries);
+ }
+ }
+ }
+
+ if (c->next)
+ c->next->prev = c->prev;
+ if (c->prev)
+ c->prev->next = c->next;
+ else
+ chanlist[HASH(c->name)] = c->next;
+
+ free(c);
+}
+
+/*************************************************************************/
+
+void del_ban(Channel * chan, char *mask)
+{
+ AutoKick *akick;
+ Entry *ban;
+
+ /* Sanity check as it seems some IRCD will just send -b without a mask */
+ if (!mask || !chan->bans || (chan->bans->count == 0))
+ return;
+
+ ban = elist_find_mask(chan->bans, mask);
+
+ if (ban) {
+ entry_delete(chan->bans, ban);
+
+ if (debug)
+ alog("debug: Deleted ban %s from channel %s", mask,
+ chan->name);
+ }
+
+ if (chan->ci && (akick = is_stuck(chan->ci, mask)))
+ stick_mask(chan->ci, akick);
+}
+
+/*************************************************************************/
+
+void del_exception(Channel * chan, char *mask)
+{
+ Entry *exception;
+
+ /* Sanity check as it seems some IRCD will just send -e without a mask */
+ if (!mask || !chan->excepts || (chan->excepts->count == 0))
+ return;
+
+ exception = elist_find_mask(chan->excepts, mask);
+
+ if (exception) {
+ entry_delete(chan->excepts, exception);
+
+ if (debug)
+ alog("debug: Deleted except %s to channel %s", mask,
+ chan->name);
+ }
+}
+
+/*************************************************************************/
+
+void del_invite(Channel * chan, char *mask)
+{
+ Entry *invite;
+
+ /* Sanity check as it seems some IRCD will just send -I without a mask */
+ if (!mask || !chan->invites || (chan->invites->count == 0)) {
+ return;
+ }
+
+ invite = elist_find_mask(chan->invites, mask);
+
+ if (invite) {
+ entry_delete(chan->invites, invite);
+
+ if (debug)
+ alog("debug: Deleted invite %s to channel %s", mask,
+ chan->name);
+ }
+}
+
+
+/*************************************************************************/
+
+char *get_flood(Channel * chan)
+{
+ return chan->flood;
+}
+
+/*************************************************************************/
+
+char *get_key(Channel * chan)
+{
+ return chan->key;
+}
+
+/*************************************************************************/
+
+char *get_limit(Channel * chan)
+{
+ static char limit[16];
+
+ if (chan->limit == 0)
+ return NULL;
+
+ snprintf(limit, sizeof(limit), "%lu", (unsigned long int) chan->limit);
+ return limit;
+}
+
+/*************************************************************************/
+
+char *get_redirect(Channel * chan)
+{
+ return chan->redirect;
+}
+
+/*************************************************************************/
+
+Channel *join_user_update(User * user, Channel * chan, char *name,
+ time_t chants)
+{
+ struct u_chanlist *c;
+
+ /* If it's a new channel, so we need to create it first. */
+ if (!chan)
+ chan = chan_create(name, chants);
+
+ if (debug)
+ alog("debug: %s joins %s", user->nick, chan->name);
+
+ c = scalloc(sizeof(*c), 1);
+ c->next = user->chans;
+ if (user->chans)
+ user->chans->prev = c;
+ user->chans = c;
+ c->chan = chan;
+
+ chan_adduser2(user, chan);
+
+ return chan;
+}
+
+/*************************************************************************/
+
+void set_flood(Channel * chan, char *value)
+{
+ if (chan->flood)
+ free(chan->flood);
+ chan->flood = value ? sstrdup(value) : NULL;
+
+ if (debug)
+ alog("debug: Flood mode for channel %s set to %s", chan->name,
+ chan->flood ? chan->flood : "no flood settings");
+}
+
+/*************************************************************************/
+
+void chan_set_key(Channel * chan, char *value)
+{
+ if (chan->key)
+ free(chan->key);
+ chan->key = value ? sstrdup(value) : NULL;
+
+ if (debug)
+ alog("debug: Key of channel %s set to %s", chan->name,
+ chan->key ? chan->key : "no key");
+}
+
+/*************************************************************************/
+
+void set_limit(Channel * chan, char *value)
+{
+ chan->limit = value ? strtoul(value, NULL, 10) : 0;
+
+ if (debug)
+ alog("debug: Limit of channel %s set to %u", chan->name,
+ chan->limit);
+}
+
+/*************************************************************************/
+
+void set_redirect(Channel * chan, char *value)
+{
+ if (chan->redirect)
+ free(chan->redirect);
+ chan->redirect = value ? sstrdup(value) : NULL;
+
+ if (debug)
+ alog("debug: Redirect of channel %s set to %s", chan->name,
+ chan->redirect ? chan->redirect : "no redirect");
+}
+
+void do_mass_mode(char *modes)
+{
+ int ac;
+ char **av;
+ Channel *c;
+ char *myModes;
+
+ if (!modes) {
+ return;
+ }
+
+ /* Prevent modes being altered by split_buf */
+ myModes = sstrdup(modes);
+ ac = split_buf(myModes, &av, 1);
+
+ for (c = firstchan(); c; c = nextchan()) {
+ if (c->bouncy_modes) {
+ free(av);
+ free(myModes);
+ return;
+ } else {
+ anope_cmd_mode(s_OperServ, c->name, "%s", modes);
+ chan_set_modes(s_OperServ, c, ac, av, 1);
+ }
+ }
+ free(av);
+ free(myModes);
+}
+
+/*************************************************************************/
+
+void restore_unsynced_topics(void)
+{
+ Channel *c;
+
+ for (c = firstchan(); c; c = nextchan()) {
+ if (!(c->topic_sync))
+ restore_topic(c->name);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * This handles creating a new Entry.
+ * This function destroys and free's the given mask as a side effect.
+ * @param mask Host/IP/CIDR mask to convert to an entry
+ * @return Entry struct for the given mask, NULL if creation failed
+ */
+Entry *entry_create(char *mask)
+{
+ Entry *entry;
+ char *nick = NULL, *user, *host, *cidrhost;
+ uint32 ip, cidr;
+
+ entry = scalloc(1, sizeof(Entry));
+ entry->type = ENTRYTYPE_NONE;
+ entry->prev = NULL;
+ entry->next = NULL;
+ entry->nick = NULL;
+ entry->user = NULL;
+ entry->host = NULL;
+ entry->mask = sstrdup(mask);
+
+ host = strchr(mask, '@');
+ if (host) {
+ *host++ = '\0';
+ /* If the user is purely a wildcard, ignore it */
+ if (str_is_pure_wildcard(mask))
+ user = NULL;
+ else {
+
+ /* There might be a nick too */
+ user = strchr(mask, '!');
+ if (user) {
+ *user++ = '\0';
+ /* If the nick is purely a wildcard, ignore it */
+ if (str_is_pure_wildcard(mask))
+ nick = NULL;
+ else
+ nick = mask;
+ } else {
+ nick = NULL;
+ user = mask;
+ }
+ }
+ } else {
+ /* It is possibly an extended ban/invite mask, but we do
+ * not support these at this point.. ~ Viper */
+ /* If there's no user in the mask, assume a pure wildcard */
+ user = NULL;
+ host = mask;
+ }
+
+ if (nick) {
+ entry->nick = sstrdup(nick);
+ /* Check if we have a wildcard user */
+ if (str_is_wildcard(nick))
+ entry->type |= ENTRYTYPE_NICK_WILD;
+ else
+ entry->type |= ENTRYTYPE_NICK;
+ }
+
+ if (user) {
+ entry->user = sstrdup(user);
+ /* Check if we have a wildcard user */
+ if (str_is_wildcard(user))
+ entry->type |= ENTRYTYPE_USER_WILD;
+ else
+ entry->type |= ENTRYTYPE_USER;
+ }
+
+ /* Only check the host if it's not a pure wildcard */
+ if (*host && !str_is_pure_wildcard(host)) {
+ if (ircd->cidrchanbei && str_is_cidr(host, &ip, &cidr, &cidrhost)) {
+ entry->cidr_ip = ip;
+ entry->cidr_mask = cidr;
+ entry->type |= ENTRYTYPE_CIDR4;
+ host = cidrhost;
+ } else if (ircd->cidrchanbei && strchr(host, '/')) {
+ /* Most IRCd's don't enforce sane bans therefore it is not
+ * so unlikely we will encounter this.
+ * Currently we only support strict CIDR without taking into
+ * account quirks of every single ircd (nef) that ignore everything
+ * after the first /cidr. To add this, sanitaze before sending to
+ * str_is_cidr() as this expects a standard cidr.
+ * Add it to the internal list (so it is included in for example clear)
+ * but do not use if during matching.. ~ Viper */
+ entry->type = ENTRYTYPE_NONE;
+ } else {
+ entry->host = sstrdup(host);
+ if (str_is_wildcard(host))
+ entry->type |= ENTRYTYPE_HOST_WILD;
+ else
+ entry->type |= ENTRYTYPE_HOST;
+ }
+ }
+ free(mask);
+
+ return entry;
+}
+
+
+/**
+ * Create an entry and add it at the beginning of given list.
+ * @param list The List the mask should be added to
+ * @param mask The mask to parse and add to the list
+ * @return Pointer to newly added entry. NULL if it fails.
+ */
+Entry *entry_add(EList * list, char *mask)
+{
+ Entry *e;
+ char *hostmask;
+
+ hostmask = sstrdup(mask);
+ e = entry_create(hostmask);
+
+ if (!e)
+ return NULL;
+
+ e->next = list->entries;
+ e->prev = NULL;
+
+ if (list->entries)
+ list->entries->prev = e;
+ list->entries = e;
+ list->count++;
+
+ return e;
+}
+
+
+/**
+ * Delete the given entry from a given list.
+ * @param list Linked list from which entry needs to be removed.
+ * @param e The entry to be deleted, must be member of list.
+ */
+void entry_delete(EList * list, Entry * e)
+{
+ if (!list || !e)
+ return;
+
+ if (e->next)
+ e->next->prev = e->prev;
+ if (e->prev)
+ e->prev->next = e->next;
+
+ if (list->entries == e)
+ list->entries = e->next;
+
+ if (e->nick)
+ free(e->nick);
+ if (e->user)
+ free(e->user);
+ if (e->host)
+ free(e->host);
+ free(e->mask);
+ free(e);
+
+ list->count--;
+}
+
+
+/**
+ * Create and initialize a new entrylist
+ * @return Pointer to the created EList object
+ **/
+EList *list_create()
+{
+ EList *list;
+
+ list = scalloc(1, sizeof(EList));
+ list->entries = NULL;
+ list->count = 0;
+
+ return list;
+}
+
+
+/**
+ * Match the given Entry to the given user/host and optional IP addy
+ * @param e Entry struct to match against
+ * @param nick Nick to match against
+ * @param user User to match against
+ * @param host Host to match against
+ * @param ip IP to match against, set to 0 to not match this
+ * @return 1 for a match, 0 for no match
+ */
+int entry_match(Entry * e, char *nick, char *user, char *host, uint32 ip)
+{
+ /* If we don't get an entry, or it s an invalid one, no match ~ Viper */
+ if (!e || e->type == ENTRYTYPE_NONE)
+ return 0;
+
+ if (ircd->cidrchanbei && (e->type & ENTRYTYPE_CIDR4) &&
+ (!ip || (ip && ((ip & e->cidr_mask) != e->cidr_ip))))
+ return 0;
+ if ((e->type & ENTRYTYPE_NICK)
+ && (!nick || stricmp(e->nick, nick) != 0))
+ return 0;
+ if ((e->type & ENTRYTYPE_USER)
+ && (!user || stricmp(e->user, user) != 0))
+ return 0;
+ if ((e->type & ENTRYTYPE_HOST)
+ && (!user || stricmp(e->host, host) != 0))
+ return 0;
+ if ((e->type & ENTRYTYPE_NICK_WILD)
+ && !match_wild_nocase(e->nick, nick))
+ return 0;
+ if ((e->type & ENTRYTYPE_USER_WILD)
+ && !match_wild_nocase(e->user, user))
+ return 0;
+ if ((e->type & ENTRYTYPE_HOST_WILD)
+ && !match_wild_nocase(e->host, host))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Match the given Entry to the given hostmask and optional IP addy.
+ * @param e Entry struct to match against
+ * @param mask Hostmask to match against
+ * @param ip IP to match against, set to 0 to not match this
+ * @return 1 for a match, 0 for no match
+ */
+int entry_match_mask(Entry * e, char *mask, uint32 ip)
+{
+ char *hostmask, *nick, *user, *host;
+ int res;
+
+ hostmask = sstrdup(mask);
+
+ host = strchr(hostmask, '@');
+ if (host) {
+ *host++ = '\0';
+ user = strchr(hostmask, '!');
+ if (user) {
+ *user++ = '\0';
+ nick = hostmask;
+ } else {
+ nick = NULL;
+ user = hostmask;
+ }
+ } else {
+ nick = NULL;
+ user = NULL;
+ host = hostmask;
+ }
+
+ res = entry_match(e, nick, user, host, ip);
+
+ /* Free the destroyed mask. */
+ free(hostmask);
+
+ return res;
+}
+
+/**
+ * Match a nick, user, host, and ip to a list entry
+ * @param e List that should be matched against
+ * @param nick The nick to match
+ * @param user The user to match
+ * @param host The host to match
+ * @param ip The ip to match
+ * @return Returns the first matching entry, if none, NULL is returned.
+ */
+Entry *elist_match(EList * list, char *nick, char *user, char *host,
+ uint32 ip)
+{
+ Entry *e;
+
+ if (!list || !list->entries)
+ return NULL;
+
+ for (e = list->entries; e; e = e->next) {
+ if (entry_match(e, nick, user, host, ip))
+ return e;
+ }
+
+ /* We matched none */
+ return NULL;
+}
+
+/**
+ * Match a mask and ip to a list.
+ * @param list EntryList that should be matched against
+ * @param mask The nick!user@host mask to match
+ * @param ip The ip to match
+ * @return Returns the first matching entry, if none, NULL is returned.
+ */
+Entry *elist_match_mask(EList * list, char *mask, uint32 ip)
+{
+ char *hostmask, *nick, *user, *host;
+ Entry *res;
+
+ if (!list || !list->entries || !mask)
+ return NULL;
+
+ hostmask = sstrdup(mask);
+
+ host = strchr(hostmask, '@');
+ if (host) {
+ *host++ = '\0';
+ user = strchr(hostmask, '!');
+ if (user) {
+ *user++ = '\0';
+ nick = hostmask;
+ } else {
+ nick = NULL;
+ user = hostmask;
+ }
+ } else {
+ nick = NULL;
+ user = NULL;
+ host = hostmask;
+ }
+
+ res = elist_match(list, nick, user, host, ip);
+
+ /* Free the destroyed mask. */
+ free(hostmask);
+
+ return res;
+}
+
+/**
+ * Check if a user matches an entry on a list.
+ * @param list EntryList that should be matched against
+ * @param user The user to match against the entries
+ * @return Returns the first matching entry, if none, NULL is returned.
+ */
+Entry *elist_match_user(EList * list, User * u)
+{
+ Entry *res;
+ char *host;
+ uint32 ip = 0;
+
+ if (!list || !list->entries || !u)
+ return NULL;
+
+ if (u->hostip == NULL) {
+ host = host_resolve(u->host);
+ /* we store the just resolved hostname so we don't
+ * need to do this again */
+ if (host) {
+ u->hostip = sstrdup(host);
+ }
+ } else {
+ host = sstrdup(u->hostip);
+ }
+
+ /* Convert the host to an IP.. */
+ if (host)
+ ip = str_is_ip(host);
+
+ /* Match what we ve got against the lists.. */
+ res = elist_match(list, u->nick, u->username, u->host, ip);
+ if (!res)
+ elist_match(list, u->nick, u->username, u->vhost, ip);
+
+ if (host)
+ free(host);
+
+ return res;
+}
+
+/**
+ * Find a entry identical to the given mask..
+ * @param list EntryList that should be matched against
+ * @param mask The *!*@* mask to match
+ * @return Returns the first matching entry, if none, NULL is returned.
+ */
+Entry *elist_find_mask(EList * list, char *mask)
+{
+ Entry *e;
+
+ if (!list || !list->entries || !mask)
+ return NULL;
+
+ for (e = list->entries; e; e = e->next) {
+ if (!stricmp(e->mask, mask))
+ return e;
+ }
+
+ return NULL;
+}
+
+/**
+ * Gets the total memory use of an entrylit.
+ * @param list The list we should estimate the mem use of.
+ * @return Returns the memory useage of the given list.
+ */
+long get_memuse(EList * list)
+{
+ Entry *e;
+ long mem = 0;
+
+ if (!list)
+ return 0;
+
+ mem += sizeof(EList *);
+ mem += sizeof(Entry *) * list->count;
+ if (list->entries) {
+ for (e = list->entries; e; e = e->next) {
+ if (e->nick)
+ mem += strlen(e->nick) + 1;
+ if (e->user)
+ mem += strlen(e->user) + 1;
+ if (e->host)
+ mem += strlen(e->host) + 1;
+ if (e->mask)
+ mem += strlen(e->mask) + 1;
+ }
+ }
+
+ return mem;
+}
+
+/*************************************************************************/
diff --git a/src/chanserv.c b/src/chanserv.c
new file mode 100644
index 000000000..98f3b9391
--- /dev/null
+++ b/src/chanserv.c
@@ -0,0 +1,2674 @@
+/* ChanServ functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+/*************************************************************************/
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+/* *INDENT-OFF* */
+
+ChannelInfo *chanlists[256];
+
+static int def_levels[][2] = {
+ { CA_AUTOOP, 5 },
+ { CA_AUTOVOICE, 3 },
+ { CA_AUTODEOP, -1 },
+ { CA_NOJOIN, -2 },
+ { CA_INVITE, 5 },
+ { CA_AKICK, 10 },
+ { CA_SET, ACCESS_INVALID },
+ { CA_CLEAR, ACCESS_INVALID },
+ { CA_UNBAN, 5 },
+ { CA_OPDEOP, 5 },
+ { CA_ACCESS_LIST, 1 },
+ { CA_ACCESS_CHANGE, 10 },
+ { CA_MEMO, 10 },
+ { CA_ASSIGN, ACCESS_INVALID },
+ { CA_BADWORDS, 10 },
+ { CA_NOKICK, 1 },
+ { CA_FANTASIA, 3 },
+ { CA_SAY, 5 },
+ { CA_GREET, 5 },
+ { CA_VOICEME, 3 },
+ { CA_VOICE, 5 },
+ { CA_GETKEY, 5 },
+ { CA_AUTOHALFOP, 4 },
+ { CA_AUTOPROTECT, 10 },
+ { CA_OPDEOPME, 5 },
+ { CA_HALFOPME, 4 },
+ { CA_HALFOP, 5 },
+ { CA_PROTECTME, 10 },
+ { CA_PROTECT, ACCESS_INVALID },
+ { CA_KICKME, 5 },
+ { CA_KICK, 5 },
+ { CA_SIGNKICK, ACCESS_INVALID },
+ { CA_BANME, 5 },
+ { CA_BAN, 5 },
+ { CA_TOPIC, ACCESS_INVALID },
+ { CA_INFO, ACCESS_INVALID },
+ { -1 }
+};
+
+
+LevelInfo levelinfo[] = {
+ { CA_AUTODEOP, "AUTODEOP", CHAN_LEVEL_AUTODEOP },
+ { CA_AUTOHALFOP, "AUTOHALFOP", CHAN_LEVEL_AUTOHALFOP },
+ { CA_AUTOOP, "AUTOOP", CHAN_LEVEL_AUTOOP },
+ { CA_AUTOPROTECT, "", CHAN_LEVEL_AUTOPROTECT },
+ { CA_AUTOVOICE, "AUTOVOICE", CHAN_LEVEL_AUTOVOICE },
+ { CA_NOJOIN, "NOJOIN", CHAN_LEVEL_NOJOIN },
+ { CA_SIGNKICK, "SIGNKICK", CHAN_LEVEL_SIGNKICK },
+ { CA_ACCESS_LIST, "ACC-LIST", CHAN_LEVEL_ACCESS_LIST },
+ { CA_ACCESS_CHANGE, "ACC-CHANGE", CHAN_LEVEL_ACCESS_CHANGE },
+ { CA_AKICK, "AKICK", CHAN_LEVEL_AKICK },
+ { CA_SET, "SET", CHAN_LEVEL_SET },
+ { CA_BAN, "BAN", CHAN_LEVEL_BAN },
+ { CA_BANME, "BANME", CHAN_LEVEL_BANME },
+ { CA_CLEAR, "CLEAR", CHAN_LEVEL_CLEAR },
+ { CA_GETKEY, "GETKEY", CHAN_LEVEL_GETKEY },
+ { CA_HALFOP, "HALFOP", CHAN_LEVEL_HALFOP },
+ { CA_HALFOPME, "HALFOPME", CHAN_LEVEL_HALFOPME },
+ { CA_INFO, "INFO", CHAN_LEVEL_INFO },
+ { CA_KICK, "KICK", CHAN_LEVEL_KICK },
+ { CA_KICKME, "KICKME", CHAN_LEVEL_KICKME },
+ { CA_INVITE, "INVITE", CHAN_LEVEL_INVITE },
+ { CA_OPDEOP, "OPDEOP", CHAN_LEVEL_OPDEOP },
+ { CA_OPDEOPME, "OPDEOPME", CHAN_LEVEL_OPDEOPME },
+ { CA_PROTECT, "", CHAN_LEVEL_PROTECT },
+ { CA_PROTECTME, "", CHAN_LEVEL_PROTECTME },
+ { CA_TOPIC, "TOPIC", CHAN_LEVEL_TOPIC },
+ { CA_UNBAN, "UNBAN", CHAN_LEVEL_UNBAN },
+ { CA_VOICE, "VOICE", CHAN_LEVEL_VOICE },
+ { CA_VOICEME, "VOICEME", CHAN_LEVEL_VOICEME },
+ { CA_MEMO, "MEMO", CHAN_LEVEL_MEMO },
+ { CA_ASSIGN, "ASSIGN", CHAN_LEVEL_ASSIGN },
+ { CA_BADWORDS, "BADWORDS", CHAN_LEVEL_BADWORDS },
+ { CA_FANTASIA, "FANTASIA", CHAN_LEVEL_FANTASIA },
+ { CA_GREET, "GREET", CHAN_LEVEL_GREET },
+ { CA_NOKICK, "NOKICK", CHAN_LEVEL_NOKICK },
+ { CA_SAY, "SAY", CHAN_LEVEL_SAY },
+ { -1 }
+};
+int levelinfo_maxwidth = 0;
+
+CSModeUtil csmodeutils[] = {
+ { "DEOP", "deop", "-o", CI_OPNOTICE, CA_OPDEOP, CA_OPDEOPME },
+ { "OP", "op", "+o", CI_OPNOTICE, CA_OPDEOP, CA_OPDEOPME },
+ { "DEVOICE", "devoice", "-v", 0, CA_VOICE, CA_VOICEME },
+ { "VOICE", "voice", "+v", 0, CA_VOICE, CA_VOICEME },
+ { "DEHALFOP", "dehalfop", "-h", 0, CA_HALFOP, CA_HALFOPME },
+ { "HALFOP", "halfop", "+h", 0, CA_HALFOP, CA_HALFOPME },
+ { "DEPROTECT", "", "", 0, CA_PROTECT, CA_PROTECTME },
+ { "PROTECT", "", "", 0, CA_PROTECT, CA_PROTECTME },
+ { NULL }
+};
+
+/*************************************************************************/
+
+void moduleAddChanServCmds(void) {
+ modules_core_init(ChanServCoreNumber, ChanServCoreModules);
+}
+
+/* *INDENT-ON* */
+/*************************************************************************/
+/*************************************************************************/
+
+/* Returns modes for mlock in a nice way. */
+
+char *get_mlock_modes(ChannelInfo * ci, int complete)
+{
+ static char res[BUFSIZE];
+
+ char *end = res;
+
+ if (ci->mlock_on || ci->mlock_off) {
+ int n = 0;
+ CBModeInfo *cbmi = cbmodeinfos;
+
+ if (ci->mlock_on) {
+ *end++ = '+';
+ n++;
+
+ do {
+ if (ci->mlock_on & cbmi->flag)
+ *end++ = cbmi->mode;
+ } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
+
+ cbmi = cbmodeinfos;
+ }
+
+ if (ci->mlock_off) {
+ *end++ = '-';
+ n++;
+
+ do {
+ if (ci->mlock_off & cbmi->flag)
+ *end++ = cbmi->mode;
+ } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
+
+ cbmi = cbmodeinfos;
+ }
+
+ if (ci->mlock_on && complete) {
+ do {
+ if (cbmi->csgetvalue && (ci->mlock_on & cbmi->flag)) {
+ char *value = cbmi->csgetvalue(ci);
+
+ if (value) {
+ *end++ = ' ';
+ while (*value)
+ *end++ = *value++;
+ }
+ }
+ } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
+ }
+ }
+
+ *end = 0;
+
+ return res;
+}
+
+/* Display total number of registered channels and info about each; or, if
+ * a specific channel is given, display information about that channel
+ * (like /msg ChanServ INFO <channel>). If count_only != 0, then only
+ * display the number of registered channels (the channel parameter is
+ * ignored).
+ */
+
+void listchans(int count_only, const char *chan)
+{
+ int count = 0;
+ ChannelInfo *ci;
+ int i;
+
+ if (count_only) {
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next)
+ count++;
+ }
+ printf("%d channels registered.\n", count);
+
+ } else if (chan) {
+
+ struct tm *tm;
+ char buf[BUFSIZE];
+
+ if (!(ci = cs_findchan(chan))) {
+ printf("Channel %s not registered.\n", chan);
+ return;
+ }
+ if (ci->flags & CI_VERBOTEN) {
+ printf("Channel %s is FORBIDden.\n", ci->name);
+ } else {
+ printf("Information about channel %s:\n", ci->name);
+ printf(" Founder: %s\n", ci->founder->display);
+ printf(" Description: %s\n", ci->desc);
+ tm = localtime(&ci->time_registered);
+ strftime(buf, sizeof(buf),
+ getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
+ printf(" Registered: %s\n", buf);
+ tm = localtime(&ci->last_used);
+ strftime(buf, sizeof(buf),
+ getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
+ printf(" Last used: %s\n", buf);
+ if (ci->last_topic) {
+ printf(" Last topic: %s\n", ci->last_topic);
+ printf(" Topic set by: %s\n", ci->last_topic_setter);
+ }
+ if (ci->url)
+ printf(" URL: %s\n", ci->url);
+ if (ci->email)
+ printf(" E-mail address: %s\n", ci->email);
+ printf(" Options: ");
+ if (!ci->flags) {
+ printf("None\n");
+ } else {
+ int need_comma = 0;
+ static const char commastr[] = ", ";
+ if (ci->flags & CI_PRIVATE) {
+ printf("Private");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_KEEPTOPIC) {
+ printf("%sTopic Retention",
+ need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_TOPICLOCK) {
+ printf("%sTopic Lock", need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_SECUREOPS) {
+ printf("%sSecure Ops", need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_RESTRICTED) {
+ printf("%sRestricted Access",
+ need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_SECURE) {
+ printf("%sSecure", need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (ci->flags & CI_NO_EXPIRE) {
+ printf("%sNo Expire", need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ printf("\n");
+ }
+ if (ci->mlock_on || ci->mlock_off) {
+ printf(" Mode lock: %s\n", get_mlock_modes(ci, 1));
+ }
+ if (ci->flags & CI_SUSPENDED) {
+ printf
+ ("This nickname is currently suspended by %s, reason: %s\n",
+ ci->forbidby,
+ (ci->forbidreason ? ci->forbidreason : "No reason"));
+ }
+ }
+
+ } else {
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ printf(" %s %-20s %s\n",
+ ci->flags & CI_NO_EXPIRE ? "!" : " ", ci->name,
+ ci->flags & CI_VERBOTEN ?
+ "Disallowed (FORBID)" : (ci->flags & CI_SUSPENDED ?
+ "Disallowed (SUSPENDED)" :
+ ci->desc));
+ count++;
+ }
+ }
+ printf("%d channels registered.\n", count);
+
+ }
+}
+
+/*************************************************************************/
+
+/* Return information on memory use. Assumes pointers are valid. */
+
+void get_chanserv_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i, j;
+ ChannelInfo *ci;
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ count++;
+ mem += sizeof(*ci);
+ if (ci->desc)
+ mem += strlen(ci->desc) + 1;
+ if (ci->url)
+ mem += strlen(ci->url) + 1;
+ if (ci->email)
+ mem += strlen(ci->email) + 1;
+ mem += ci->accesscount * sizeof(ChanAccess);
+ mem += ci->akickcount * sizeof(AutoKick);
+ for (j = 0; j < ci->akickcount; j++) {
+ if (!(ci->akick[j].flags & AK_ISNICK)
+ && ci->akick[j].u.mask)
+ mem += strlen(ci->akick[j].u.mask) + 1;
+ if (ci->akick[j].reason)
+ mem += strlen(ci->akick[j].reason) + 1;
+ if (ci->akick[j].creator)
+ mem += strlen(ci->akick[j].creator) + 1;
+ }
+ if (ci->mlock_key)
+ mem += strlen(ci->mlock_key) + 1;
+ if (ircd->fmode) {
+ if (ci->mlock_flood)
+ mem += strlen(ci->mlock_flood) + 1;
+ }
+ if (ircd->Lmode) {
+ if (ci->mlock_redirect)
+ mem += strlen(ci->mlock_redirect) + 1;
+ }
+ if (ci->last_topic)
+ mem += strlen(ci->last_topic) + 1;
+ if (ci->entry_message)
+ mem += strlen(ci->entry_message) + 1;
+ if (ci->forbidby)
+ mem += strlen(ci->forbidby) + 1;
+ if (ci->forbidreason)
+ mem += strlen(ci->forbidreason) + 1;
+ if (ci->levels)
+ mem += sizeof(*ci->levels) * CA_SIZE;
+ mem += ci->memos.memocount * sizeof(Memo);
+ for (j = 0; j < ci->memos.memocount; j++) {
+ if (ci->memos.memos[j].text)
+ mem += strlen(ci->memos.memos[j].text) + 1;
+ }
+ if (ci->ttb)
+ mem += sizeof(*ci->ttb) * TTB_SIZE;
+ mem += ci->bwcount * sizeof(BadWord);
+ for (j = 0; j < ci->bwcount; j++)
+ if (ci->badwords[j].word)
+ mem += strlen(ci->badwords[j].word) + 1;
+ }
+ }
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* ChanServ initialization. */
+
+void cs_init(void)
+{
+ moduleAddChanServCmds();
+}
+
+/*************************************************************************/
+
+/* Main ChanServ routine. */
+
+void chanserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_ChanServ, u->nick, "PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_ChanServ, u, SERVICE_OFFLINE, s_ChanServ);
+ } else {
+ mod_run_cmd(s_ChanServ, u, CHANSERV, cmd);
+ }
+}
+
+/*************************************************************************/
+
+/* Load/save data files. */
+
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", ChanDBName); \
+ failed = 1; \
+ break; \
+ } \
+} while (0)
+
+void load_cs_dbase(void)
+{
+ dbFILE *f;
+ int ver, i, j, c;
+ ChannelInfo *ci, **last, *prev;
+ int failed = 0;
+
+ if (!(f = open_db(s_ChanServ, ChanDBName, "r", CHAN_VERSION)))
+ return;
+
+ ver = get_file_version(f);
+
+ for (i = 0; i < 256 && !failed; i++) {
+ uint16 tmp16;
+ uint32 tmp32;
+ int n_levels;
+ char *s;
+ NickAlias *na;
+
+ last = &chanlists[i];
+ prev = NULL;
+ while ((c = getc_db(f)) != 0) {
+ if (c != 1)
+ fatal("Invalid format in %s", ChanDBName);
+ ci = scalloc(sizeof(ChannelInfo), 1);
+ *last = ci;
+ last = &ci->next;
+ ci->prev = prev;
+ prev = ci;
+ SAFE(read_buffer(ci->name, f));
+ SAFE(read_string(&s, f));
+ if (s) {
+ if (ver >= 13)
+ ci->founder = findcore(s);
+ else {
+ na = findnick(s);
+ if (na)
+ ci->founder = na->nc;
+ else
+ ci->founder = NULL;
+ }
+ free(s);
+ } else
+ ci->founder = NULL;
+ if (ver >= 7) {
+ SAFE(read_string(&s, f));
+ if (s) {
+ if (ver >= 13)
+ ci->successor = findcore(s);
+ else {
+ na = findnick(s);
+ if (na)
+ ci->successor = na->nc;
+ else
+ ci->successor = NULL;
+ }
+ free(s);
+ } else
+ ci->successor = NULL;
+ } else {
+ ci->successor = NULL;
+ }
+ SAFE(read_buffer(ci->founderpass, f));
+ SAFE(read_string(&ci->desc, f));
+ if (!ci->desc)
+ ci->desc = sstrdup("");
+ SAFE(read_string(&ci->url, f));
+ SAFE(read_string(&ci->email, f));
+ SAFE(read_int32(&tmp32, f));
+ ci->time_registered = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ ci->last_used = tmp32;
+ SAFE(read_string(&ci->last_topic, f));
+ SAFE(read_buffer(ci->last_topic_setter, f));
+ SAFE(read_int32(&tmp32, f));
+ ci->last_topic_time = tmp32;
+ SAFE(read_int32(&ci->flags, f));
+
+ /* Leaveops cleanup */
+ if (ver <= 13 && (ci->flags & 0x00000020))
+ ci->flags &= ~0x00000020;
+ /* Temporary flags cleanup */
+ ci->flags &= ~CI_INHABIT;
+
+ if (ver >= 9) {
+ SAFE(read_string(&ci->forbidby, f));
+ SAFE(read_string(&ci->forbidreason, f));
+ } else {
+ ci->forbidreason = NULL;
+ ci->forbidby = NULL;
+ }
+ if (ver >= 9)
+ SAFE(read_int16(&tmp16, f));
+ else
+ tmp16 = CSDefBantype;
+ ci->bantype = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ n_levels = tmp16;
+ ci->levels = scalloc(2 * CA_SIZE, 1);
+ reset_levels(ci);
+ for (j = 0; j < n_levels; j++) {
+ SAFE(read_int16(&tmp16, f));
+ if (j < CA_SIZE)
+ ci->levels[j] = (int16) tmp16;
+ }
+ /* To avoid levels list silly hacks */
+ if (ver < 10)
+ ci->levels[CA_OPDEOPME] = ci->levels[CA_OPDEOP];
+ if (ver < 11) {
+ ci->levels[CA_KICKME] = ci->levels[CA_OPDEOP];
+ ci->levels[CA_KICK] = ci->levels[CA_OPDEOP];
+ }
+ if (ver < 15) {
+
+ /* Old Ultimate levels import */
+ /* We now conveniently use PROTECT internals for Ultimate's ADMIN support - ShadowMaster */
+ /* Doh, must of course be done before we change the values were trying to import - ShadowMaster */
+ ci->levels[CA_AUTOPROTECT] = ci->levels[32];
+ ci->levels[CA_PROTECTME] = ci->levels[33];
+ ci->levels[CA_PROTECT] = ci->levels[34];
+
+ ci->levels[CA_BANME] = ci->levels[CA_OPDEOP];
+ ci->levels[CA_BAN] = ci->levels[CA_OPDEOP];
+ ci->levels[CA_TOPIC] = ACCESS_INVALID;
+
+
+ }
+
+ SAFE(read_int16(&ci->accesscount, f));
+ if (ci->accesscount) {
+ ci->access = scalloc(ci->accesscount, sizeof(ChanAccess));
+ for (j = 0; j < ci->accesscount; j++) {
+ SAFE(read_int16(&ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ SAFE(read_int16(&tmp16, f));
+ ci->access[j].level = (int16) tmp16;
+ SAFE(read_string(&s, f));
+ if (s) {
+ if (ver >= 13)
+ ci->access[j].nc = findcore(s);
+ else {
+ na = findnick(s);
+ if (na)
+ ci->access[j].nc = na->nc;
+ else
+ ci->access[j].nc = NULL;
+ }
+ free(s);
+ }
+ if (ci->access[j].nc == NULL)
+ ci->access[j].in_use = 0;
+ if (ver >= 11) {
+ SAFE(read_int32(&tmp32, f));
+ ci->access[j].last_seen = tmp32;
+ } else {
+ ci->access[j].last_seen = 0; /* Means we have never seen the user */
+ }
+ }
+ }
+ } else {
+ ci->access = NULL;
+ }
+
+ SAFE(read_int16(&ci->akickcount, f));
+ if (ci->akickcount) {
+ ci->akick = scalloc(ci->akickcount, sizeof(AutoKick));
+ for (j = 0; j < ci->akickcount; j++) {
+ if (ver >= 15) {
+ SAFE(read_int16(&ci->akick[j].flags, f));
+ } else {
+ SAFE(read_int16(&tmp16, f));
+ if (tmp16)
+ ci->akick[j].flags |= AK_USED;
+ }
+ if (ci->akick[j].flags & AK_USED) {
+ if (ver < 15) {
+ SAFE(read_int16(&tmp16, f));
+ if (tmp16)
+ ci->akick[j].flags |= AK_ISNICK;
+ }
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & AK_ISNICK) {
+ if (ver >= 13) {
+ ci->akick[j].u.nc = findcore(s);
+ } else {
+ na = findnick(s);
+ if (na)
+ ci->akick[j].u.nc = na->nc;
+ else
+ ci->akick[j].u.nc = NULL;
+ }
+ if (!ci->akick[j].u.nc)
+ ci->akick[j].flags &= ~AK_USED;
+ free(s);
+ } else {
+ ci->akick[j].u.mask = s;
+ }
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & AK_USED)
+ ci->akick[j].reason = s;
+ else if (s)
+ free(s);
+ if (ver >= 9) {
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & AK_USED) {
+ ci->akick[j].creator = s;
+ } else if (s) {
+ free(s);
+ }
+ SAFE(read_int32(&tmp32, f));
+ if (ci->akick[j].flags & AK_USED)
+ ci->akick[j].addtime = tmp32;
+ } else {
+ ci->akick[j].creator = NULL;
+ ci->akick[j].addtime = 0;
+ }
+ }
+
+ /* Bugfix */
+ if ((ver == 15) && ci->akick[j].flags > 8) {
+ ci->akick[j].flags = 0;
+ ci->akick[j].u.nc = NULL;
+ ci->akick[j].u.nc = NULL;
+ ci->akick[j].addtime = 0;
+ ci->akick[j].creator = NULL;
+ ci->akick[j].reason = NULL;
+ }
+ }
+ } else {
+ ci->akick = NULL;
+ }
+
+ if (ver >= 10) {
+ SAFE(read_int32(&ci->mlock_on, f));
+ SAFE(read_int32(&ci->mlock_off, f));
+ } else {
+ SAFE(read_int16(&tmp16, f));
+ ci->mlock_on = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->mlock_off = tmp16;
+ }
+ SAFE(read_int32(&ci->mlock_limit, f));
+ SAFE(read_string(&ci->mlock_key, f));
+ if (ver >= 10) {
+ if (ircd->fmode) {
+ SAFE(read_string(&ci->mlock_flood, f));
+ } else {
+ SAFE(read_string(&s, f));
+ if (s)
+ free(s);
+ }
+ if (ircd->Lmode) {
+ SAFE(read_string(&ci->mlock_redirect, f));
+ } else {
+ SAFE(read_string(&s, f));
+ if (s)
+ free(s);
+ }
+ }
+
+ SAFE(read_int16(&tmp16, f));
+ ci->memos.memocount = (int16) tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->memos.memomax = (int16) tmp16;
+ if (ci->memos.memocount) {
+ Memo *memos;
+ memos = scalloc(sizeof(Memo) * ci->memos.memocount, 1);
+ ci->memos.memos = memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ SAFE(read_int32(&memos->number, f));
+ SAFE(read_int16(&memos->flags, f));
+ SAFE(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ SAFE(read_buffer(memos->sender, f));
+ SAFE(read_string(&memos->text, f));
+ memos->moduleData = NULL;
+ }
+ }
+
+ SAFE(read_string(&ci->entry_message, f));
+
+ ci->c = NULL;
+
+ /* Some cleanup */
+ if (ver <= 11) {
+ /* Cleanup: Founder must be != than successor */
+ if (!(ci->flags & CI_VERBOTEN)
+ && ci->successor == ci->founder) {
+ alog("Warning: founder and successor of %s are equal. Cleaning up.", ci->name);
+ ci->successor = NULL;
+ }
+ }
+
+ /* BotServ options */
+
+ if (ver >= 8) {
+ int n_ttb;
+
+ SAFE(read_string(&s, f));
+ if (s) {
+ ci->bi = findbot(s);
+ free(s);
+ } else
+ ci->bi = NULL;
+
+ SAFE(read_int32(&tmp32, f));
+ ci->botflags = tmp32;
+ SAFE(read_int16(&tmp16, f));
+ n_ttb = tmp16;
+ ci->ttb = scalloc(2 * TTB_SIZE, 1);
+ for (j = 0; j < n_ttb; j++) {
+ SAFE(read_int16(&tmp16, f));
+ if (j < TTB_SIZE)
+ ci->ttb[j] = (int16) tmp16;
+ }
+ for (j = n_ttb; j < TTB_SIZE; j++)
+ ci->ttb[j] = 0;
+ SAFE(read_int16(&tmp16, f));
+ ci->capsmin = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->capspercent = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->floodlines = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->floodsecs = tmp16;
+ SAFE(read_int16(&tmp16, f));
+ ci->repeattimes = tmp16;
+
+ SAFE(read_int16(&ci->bwcount, f));
+ if (ci->bwcount) {
+ ci->badwords = scalloc(ci->bwcount, sizeof(BadWord));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(read_int16(&ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(read_string(&ci->badwords[j].word, f));
+ SAFE(read_int16(&ci->badwords[j].type, f));
+ }
+ }
+ } else {
+ ci->badwords = NULL;
+ }
+ } else {
+ ci->bi = NULL;
+ ci->botflags = 0;
+ ci->ttb = scalloc(2 * TTB_SIZE, 1);
+ for (j = 0; j < TTB_SIZE; j++)
+ ci->ttb[j] = 0;
+ ci->bwcount = 0;
+ ci->badwords = NULL;
+ }
+
+ } /* while (getc_db(f) != 0) */
+
+ *last = NULL;
+
+ } /* for (i) */
+
+ close_db(f);
+
+ /* Check for non-forbidden channels with no founder.
+ Makes also other essential tasks. */
+ for (i = 0; i < 256; i++) {
+ ChannelInfo *next;
+ for (ci = chanlists[i]; ci; ci = next) {
+ next = ci->next;
+ if (!(ci->flags & CI_VERBOTEN) && !ci->founder) {
+ alog("%s: database load: Deleting founderless channel %s",
+ s_ChanServ, ci->name);
+ delchan(ci);
+ continue;
+ }
+ if (ver < 13) {
+ ChanAccess *access, *access2;
+ AutoKick *akick, *akick2;
+ int k;
+
+ if (ci->flags & CI_VERBOTEN)
+ continue;
+ /* Need to regenerate the channel count for the founder */
+ ci->founder->channelcount++;
+ /* Check for eventual double entries in access/akick lists. */
+ for (j = 0, access = ci->access; j < ci->accesscount;
+ j++, access++) {
+ if (!access->in_use)
+ continue;
+ for (k = 0, access2 = ci->access; k < j;
+ k++, access2++) {
+ if (access2->in_use && access2->nc == access->nc) {
+ alog("%s: deleting %s channel access entry of %s because it is already in the list (this is OK).", s_ChanServ, access->nc->display, ci->name);
+ memset(access, 0, sizeof(ChanAccess));
+ break;
+ }
+ }
+ }
+ for (j = 0, akick = ci->akick; j < ci->akickcount;
+ j++, akick++) {
+ if (!(akick->flags & AK_USED)
+ || !(akick->flags & AK_ISNICK))
+ continue;
+ for (k = 0, akick2 = ci->akick; k < j; k++, akick2++) {
+ if ((akick2->flags & AK_USED)
+ && (akick2->flags & AK_ISNICK)
+ && akick2->u.nc == akick->u.nc) {
+ alog("%s: deleting %s channel akick entry of %s because it is already in the list (this is OK).", s_ChanServ, akick->u.nc->display, ci->name);
+ if (akick->reason)
+ free(akick->reason);
+ if (akick->creator)
+ free(akick->creator);
+ memset(akick, 0, sizeof(AutoKick));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", ChanDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", ChanDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_cs_dbase(void)
+{
+ dbFILE *f;
+ int i, j;
+ ChannelInfo *ci;
+ Memo *memos;
+ static time_t lastwarn = 0;
+
+ if (!(f = open_db(s_ChanServ, ChanDBName, "w", CHAN_VERSION)))
+ return;
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_buffer(ci->name, f));
+ if (ci->founder)
+ SAFE(write_string(ci->founder->display, f));
+ else
+ SAFE(write_string(NULL, f));
+ if (ci->successor)
+ SAFE(write_string(ci->successor->display, f));
+ else
+ SAFE(write_string(NULL, f));
+ SAFE(write_buffer(ci->founderpass, f));
+ SAFE(write_string(ci->desc, f));
+ SAFE(write_string(ci->url, f));
+ SAFE(write_string(ci->email, f));
+ SAFE(write_int32(ci->time_registered, f));
+ SAFE(write_int32(ci->last_used, f));
+ SAFE(write_string(ci->last_topic, f));
+ SAFE(write_buffer(ci->last_topic_setter, f));
+ SAFE(write_int32(ci->last_topic_time, f));
+ SAFE(write_int32(ci->flags, f));
+ SAFE(write_string(ci->forbidby, f));
+ SAFE(write_string(ci->forbidreason, f));
+ SAFE(write_int16(ci->bantype, f));
+
+ tmp16 = CA_SIZE;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < CA_SIZE; j++)
+ SAFE(write_int16(ci->levels[j], f));
+
+ SAFE(write_int16(ci->accesscount, f));
+ for (j = 0; j < ci->accesscount; j++) {
+ SAFE(write_int16(ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ SAFE(write_int16(ci->access[j].level, f));
+ SAFE(write_string(ci->access[j].nc->display, f));
+ SAFE(write_int32(ci->access[j].last_seen, f));
+ }
+ }
+
+ SAFE(write_int16(ci->akickcount, f));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(write_int16(ci->akick[j].flags, f));
+ if (ci->akick[j].flags & AK_USED) {
+ if (ci->akick[j].flags & AK_ISNICK)
+ SAFE(write_string(ci->akick[j].u.nc->display, f));
+ else
+ SAFE(write_string(ci->akick[j].u.mask, f));
+ SAFE(write_string(ci->akick[j].reason, f));
+ SAFE(write_string(ci->akick[j].creator, f));
+ SAFE(write_int32(ci->akick[j].addtime, f));
+ }
+ }
+
+ SAFE(write_int32(ci->mlock_on, f));
+ SAFE(write_int32(ci->mlock_off, f));
+ SAFE(write_int32(ci->mlock_limit, f));
+ SAFE(write_string(ci->mlock_key, f));
+ if (ircd->fmode) {
+ SAFE(write_string(ci->mlock_flood, f));
+ } else {
+ SAFE(write_string(NULL, f));
+ }
+ if (ircd->Lmode) {
+ SAFE(write_string(ci->mlock_redirect, f));
+ } else {
+ SAFE(write_string(NULL, f));
+ }
+ SAFE(write_int16(ci->memos.memocount, f));
+ SAFE(write_int16(ci->memos.memomax, f));
+ memos = ci->memos.memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ SAFE(write_int32(memos->number, f));
+ SAFE(write_int16(memos->flags, f));
+ SAFE(write_int32(memos->time, f));
+ SAFE(write_buffer(memos->sender, f));
+ SAFE(write_string(memos->text, f));
+ }
+
+ SAFE(write_string(ci->entry_message, f));
+
+ if (ci->bi)
+ SAFE(write_string(ci->bi->nick, f));
+ else
+ SAFE(write_string(NULL, f));
+
+ SAFE(write_int32(ci->botflags, f));
+
+ tmp16 = TTB_SIZE;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < TTB_SIZE; j++)
+ SAFE(write_int16(ci->ttb[j], f));
+
+ SAFE(write_int16(ci->capsmin, f));
+ SAFE(write_int16(ci->capspercent, f));
+ SAFE(write_int16(ci->floodlines, f));
+ SAFE(write_int16(ci->floodsecs, f));
+ SAFE(write_int16(ci->repeattimes, f));
+
+ SAFE(write_int16(ci->bwcount, f));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(write_int16(ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(write_string(ci->badwords[j].word, f));
+ SAFE(write_int16(ci->badwords[j].type, f));
+ }
+ }
+ } /* for (chanlists[i]) */
+
+ SAFE(write_int8(0, f));
+
+ } /* for (i) */
+
+ close_db(f);
+
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+void save_cs_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ int i;
+ ChannelInfo *ci;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_cs_info") == 0) {
+ alog("Unable to tag table 'anope_cs_info' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_cs_access") == 0) {
+ alog("Unable to tag table 'anope_cs_access' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_cs_levels") == 0) {
+ alog("Unable to tag table 'anope_cs_levels' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_cs_akicks") == 0) {
+ alog("Unable to tag table 'anope_cs_akicks' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_cs_badwords") == 0) {
+ alog("Unable to tag table 'anope_cs_badwords' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_cs_ttb") == 0) {
+ alog("Unable to tag table 'anope_cs_ttb' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table_where("anope_ms_info", "serv='CHAN'") == 0) {
+ alog("Unable to tag table 'anope_ms_info' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ if (rdb_save_cs_info(ci) == 0) {
+ alog("Unable to save ChanInfo for %s - ChanServ RDB save failed.", ci->name);
+ rdb_close();
+ return;
+ }
+ } /* for (chanlists[i]) */
+ } /* for (i) */
+
+ if (rdb_clean_table("anope_cs_info") == 0) {
+ alog("Unable to clean table 'anope_cs_info' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_cs_access") == 0) {
+ alog("Unable to clean table 'anope_cs_access' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_cs_levels") == 0) {
+ alog("Unable to clean table 'anope_cs_levels' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_cs_akicks") == 0) {
+ alog("Unable to clean table 'anope_cs_akicks' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_cs_badwords") == 0) {
+ alog("Unable to clean table 'anope_cs_badwords' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_cs_ttb") == 0) {
+ alog("Unable to clean table 'anope_cs_ttb' - ChanServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table_where("anope_ms_info", "serv='CHAN'") == 0)
+ alog("Unable to clean table 'anope_ms_info' - ChanServ RDB save failed.");
+
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+
+/* Check the current modes on a channel; if they conflict with a mode lock,
+ * fix them.
+ *
+ * Also check to make sure that every mode set or unset is allowed by the
+ * defcon mlock settings. This is more important than any normal channel
+ * mlock'd mode. --gdex (21-04-07)
+ */
+
+void check_modes(Channel * c)
+{
+ char modebuf[64], argbuf[BUFSIZE], *end = modebuf, *end2 = argbuf;
+ uint32 modes;
+ ChannelInfo *ci;
+ CBModeInfo *cbmi;
+ CBMode *cbm;
+
+ if (!c) {
+ if (debug) {
+ alog("debug: check_modes called with NULL values");
+ }
+ return;
+ }
+
+ if (c->bouncy_modes)
+ return;
+
+ /* Check for mode bouncing */
+ if (c->server_modecount >= 3 && c->chanserv_modecount >= 3) {
+ anope_cmd_global(NULL,
+ "Warning: unable to set modes on channel %s. "
+ "Are your servers' U:lines configured correctly?",
+ c->name);
+ alog("%s: Bouncy modes on channel %s", s_ChanServ, c->name);
+ c->bouncy_modes = 1;
+ return;
+ }
+
+ if (c->chanserv_modetime != time(NULL)) {
+ c->chanserv_modecount = 0;
+ c->chanserv_modetime = time(NULL);
+ }
+ c->chanserv_modecount++;
+
+ /* Check if the channel is registered; if not remove mode -r */
+ if (!(ci = c->ci)) {
+ if (ircd->regmode) {
+ if (c->mode & ircd->regmode) {
+ c->mode &= ~ircd->regmode;
+ anope_cmd_mode(whosends(ci), c->name, "-r");
+ }
+ }
+ return;
+ }
+
+ /* Initialize te modes-var to set all modes not set yet but which should
+ * be set as by mlock and defcon.
+ */
+ modes = ~c->mode & ci->mlock_on;
+ if (DefConModesSet)
+ modes |= (~c->mode & DefConModesOn);
+
+ /* Initialize the buffers */
+ *end++ = '+';
+ cbmi = cbmodeinfos;
+
+ do {
+ if (modes & cbmi->flag) {
+ *end++ = cbmi->mode;
+ c->mode |= cbmi->flag;
+
+ /* Add the eventual parameter and modify the Channel structure */
+ if (cbmi->getvalue && cbmi->csgetvalue) {
+ char *value;
+ /* Check if it's a defcon or mlock mode */
+ if (DefConModesOn & cbmi->flag)
+ value = cbmi->csgetvalue(&DefConModesCI);
+ else
+ value = cbmi->csgetvalue(ci);
+
+ cbm = &cbmodes[(int) cbmi->mode];
+ cbm->setvalue(c, value);
+
+ if (value) {
+ *end2++ = ' ';
+ while (*value)
+ *end2++ = *value++;
+ }
+ }
+ } else if (cbmi->getvalue && cbmi->csgetvalue
+ && ((ci->mlock_on & cbmi->flag)
+ || (DefConModesOn & cbmi->flag))
+ && (c->mode & cbmi->flag)) {
+ char *value = cbmi->getvalue(c);
+ char *csvalue;
+
+ /* Check if it's a defcon or mlock mode */
+ if (DefConModesOn & cbmi->flag)
+ csvalue = cbmi->csgetvalue(&DefConModesCI);
+ else
+ csvalue = cbmi->csgetvalue(ci);
+
+ /* Lock and actual values don't match, so fix the mode */
+ if (value && csvalue && strcmp(value, csvalue)) {
+ *end++ = cbmi->mode;
+
+ cbm = &cbmodes[(int) cbmi->mode];
+ cbm->setvalue(c, csvalue);
+
+ *end2++ = ' ';
+ while (*csvalue)
+ *end2++ = *csvalue++;
+ }
+ }
+ } while ((++cbmi)->flag != 0);
+
+ if (*(end - 1) == '+')
+ end--;
+
+ modes = c->mode & ci->mlock_off;
+ if (DefConModesSet)
+ modes |= (~c->mode & DefConModesOff);
+
+ if (modes) {
+ *end++ = '-';
+ cbmi = cbmodeinfos;
+
+ do {
+ if (modes & cbmi->flag) {
+ *end++ = cbmi->mode;
+ c->mode &= ~cbmi->flag;
+
+ /* Add the eventual parameter and clean up the Channel structure */
+ if (cbmi->getvalue) {
+ cbm = &cbmodes[(int) cbmi->mode];
+
+ if (!(cbm->flags & CBM_MINUS_NO_ARG)) {
+ char *value = cbmi->getvalue(c);
+
+ if (value) {
+ *end2++ = ' ';
+ while (*value)
+ *end2++ = *value++;
+ }
+ }
+
+ cbm->setvalue(c, NULL);
+ }
+ }
+ } while ((++cbmi)->flag != 0);
+ }
+
+ if (end == modebuf)
+ return;
+
+ *end = 0;
+ *end2 = 0;
+
+ anope_cmd_mode(whosends(ci), c->name, "%s%s", modebuf,
+ (end2 == argbuf ? "" : argbuf));
+}
+
+/*************************************************************************/
+
+int check_valid_admin(User * user, Channel * chan, int servermode)
+{
+ if (!chan || !chan->ci)
+ return 1;
+
+ if (!ircd->admin) {
+ return 0;
+ }
+
+ /* They will be kicked; no need to deop, no need to update our internal struct too */
+ if (chan->ci->flags & CI_VERBOTEN)
+ return 0;
+
+ if (servermode && !check_access(user, chan->ci, CA_AUTOPROTECT)) {
+ notice_lang(s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
+ anope_cmd_mode(whosends(chan->ci), chan->name, "%s %s",
+ ircd->adminunset, user->nick);
+ return 0;
+ }
+
+ if (check_access(user, chan->ci, CA_AUTODEOP)) {
+ anope_cmd_mode(whosends(chan->ci), chan->name, "%s %s",
+ ircd->adminunset, user->nick);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Check whether a user is allowed to be opped on a channel; if they
+ * aren't, deop them. If serverop is 1, the +o was done by a server.
+ * Return 1 if the user is allowed to be opped, 0 otherwise. */
+
+int check_valid_op(User * user, Channel * chan, int servermode)
+{
+ char *tmp;
+ if (!chan || !chan->ci)
+ return 1;
+
+ /* They will be kicked; no need to deop, no need to update our internal struct too */
+ if (chan->ci->flags & CI_VERBOTEN)
+ return 0;
+
+ if (servermode && !check_access(user, chan->ci, CA_AUTOOP)) {
+ notice_lang(s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
+ if (ircd->halfop) {
+ if (ircd->owner && ircd->protect) {
+ if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
+ tmp = stripModePrefix(ircd->ownerunset);
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "%so%s %s %s %s", ircd->adminunset,
+ tmp, user->nick,
+ user->nick, user->nick);
+ free(tmp);
+ } else {
+ tmp = stripModePrefix(ircd->ownerunset);
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "%sho%s %s %s %s %s",
+ ircd->adminunset, tmp,
+ user->nick, user->nick, user->nick,
+ user->nick);
+ free(tmp);
+ }
+ } else if (!ircd->owner && ircd->protect) {
+ if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "%so %s %s", ircd->adminunset,
+ user->nick, user->nick);
+ } else {
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "%soh %s %s %s", ircd->adminunset,
+ user->nick, user->nick, user->nick);
+ }
+ } else {
+ if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
+ anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
+ user->nick);
+ } else {
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "-ho %s %s", user->nick, user->nick);
+ }
+ }
+ } else {
+ anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
+ user->nick);
+ }
+ return 0;
+ }
+
+ if (check_access(user, chan->ci, CA_AUTODEOP)) {
+ if (ircd->halfop) {
+ if (ircd->owner && ircd->protect) {
+ tmp = stripModePrefix(ircd->ownerunset);
+ anope_cmd_mode(whosends(chan->ci), chan->name,
+ "%sho%s %s %s %s %s", ircd->adminunset,
+ tmp, user->nick, user->nick,
+ user->nick, user->nick);
+ free(tmp);
+ } else {
+ anope_cmd_mode(whosends(chan->ci), chan->name, "-ho %s %s",
+ user->nick, user->nick);
+ }
+ } else {
+ anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
+ user->nick);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Check whether a user should be opped on a channel, and if so, do it.
+ * Return 1 if the user was opped, 0 otherwise. (Updates the channel's
+ * last used time if the user was opped.) */
+
+int check_should_op(User * user, char *chan)
+{
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
+ return 0;
+
+ if ((ci->flags & CI_SECURE) && !nick_identified(user))
+ return 0;
+
+ if (check_access(user, ci, CA_AUTOOP)) {
+ anope_cmd_mode(whosends(ci), chan, "+o %s", user->nick);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Check whether a user should be voiced on a channel, and if so, do it.
+ * Return 1 if the user was voiced, 0 otherwise. */
+
+int check_should_voice(User * user, char *chan)
+{
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
+ return 0;
+
+ if ((ci->flags & CI_SECURE) && !nick_identified(user))
+ return 0;
+
+ if (check_access(user, ci, CA_AUTOVOICE)) {
+ anope_cmd_mode(whosends(ci), chan, "+v %s", user->nick);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int check_should_halfop(User * user, char *chan)
+{
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
+ return 0;
+
+ if (check_access(user, ci, CA_AUTOHALFOP)) {
+ anope_cmd_mode(whosends(ci), chan, "+h %s", user->nick);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int check_should_owner(User * user, char *chan)
+{
+ char *tmp;
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
+ return 0;
+
+ if (((ci->flags & CI_SECUREFOUNDER) && is_real_founder(user, ci))
+ || (!(ci->flags & CI_SECUREFOUNDER) && is_founder(user, ci))) {
+ tmp = stripModePrefix(ircd->ownerset);
+ anope_cmd_mode(whosends(ci), chan, "+o%s %s %s", tmp, user->nick,
+ user->nick);
+ free(tmp);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int check_should_protect(User * user, char *chan)
+{
+ char *tmp;
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
+ return 0;
+
+ if (check_access(user, ci, CA_AUTOPROTECT)) {
+ tmp = stripModePrefix(ircd->adminset);
+ anope_cmd_mode(whosends(ci), chan, "+o%s %s %s", tmp, user->nick,
+ user->nick);
+ free(tmp);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Tiny helper routine to get ChanServ out of a channel after it went in. */
+
+static void timeout_leave(Timeout * to)
+{
+ char *chan = to->data;
+ ChannelInfo *ci = cs_findchan(chan);
+
+ if (ci) /* Check cos the channel may be dropped in the meantime */
+ ci->flags &= ~CI_INHABIT;
+
+ anope_cmd_part(s_ChanServ, chan, NULL);
+ free(to->data);
+}
+
+
+/* Check whether a user is permitted to be on a channel. If so, return 0;
+ * else, kickban the user with an appropriate message (could be either
+ * AKICK or restricted access) and return 1. Note that this is called
+ * _before_ the user is added to internal channel lists (so do_kick() is
+ * not called). The channel TS must be given for a new channel.
+ */
+
+int check_kick(User * user, char *chan, time_t chants)
+{
+ ChannelInfo *ci = cs_findchan(chan);
+ Channel *c;
+ AutoKick *akick;
+ int i, set_modes = 0;
+ NickCore *nc;
+ char *av[4];
+ int ac;
+ char buf[BUFSIZE];
+ char mask[BUFSIZE];
+ const char *reason;
+ Timeout *t;
+
+ if (!ci)
+ return 0;
+
+ if (user->isSuperAdmin == 1)
+ return 0;
+
+ if (ci->flags & CI_VERBOTEN) {
+ get_idealban(ci, user, mask, sizeof(mask));
+ reason =
+ ci->forbidreason ? ci->forbidreason : getstring(user->na,
+ CHAN_MAY_NOT_BE_USED);
+ set_modes = 1;
+ goto kick;
+ }
+
+ if (ci->flags & CI_SUSPENDED) {
+ get_idealban(ci, user, mask, sizeof(mask));
+ reason =
+ ci->forbidreason ? ci->forbidreason : getstring(user->na,
+ CHAN_MAY_NOT_BE_USED);
+ set_modes = 1;
+ goto kick;
+ }
+
+ if (nick_recognized(user))
+ nc = user->na->nc;
+ else
+ nc = NULL;
+
+ /*
+ * Before we go through akick lists, see if they're excepted FIRST
+ * We cannot kick excempted users that are akicked or not on the channel access list
+ * as that will start services <-> server wars which ends up as a DoS against services.
+ *
+ * UltimateIRCd 3.x at least informs channel staff when a joining user is matching an exempt.
+ */
+ if (ircd->except && is_excepted(ci, user) == 1) {
+ return 0;
+ }
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ if ((akick->flags & AK_ISNICK && akick->u.nc == nc)
+ || (!(akick->flags & AK_ISNICK)
+ && match_usermask(akick->u.mask, user))) {
+ if (debug >= 2)
+ alog("debug: %s matched akick %s", user->nick,
+ (akick->flags & AK_ISNICK) ? akick->u.nc->
+ display : akick->u.mask);
+ if (akick->flags & AK_ISNICK)
+ get_idealban(ci, user, mask, sizeof(mask));
+ else
+ strcpy(mask, akick->u.mask);
+ reason = akick->reason ? akick->reason : CSAutokickReason;
+ goto kick;
+ }
+ }
+
+ if (is_ulined(user->server->name)) {
+ return 0;
+ }
+
+ if (check_access(user, ci, CA_NOJOIN)) {
+ get_idealban(ci, user, mask, sizeof(mask));
+ reason = getstring(user->na, CHAN_NOT_ALLOWED_TO_JOIN);
+ goto kick;
+ }
+
+ return 0;
+
+ kick:
+ if (debug)
+ alog("debug: channel: AutoKicking %s!%s@%s from %s", user->nick,
+ user->username, user->host, chan);
+
+ /* Remember that the user has not been added to our channel user list
+ * yet, so we check whether the channel does not exist OR has no user
+ * on it (before SJOIN would have created the channel structure, while
+ * JOIN would not). */
+ /* Don't check for CI_INHABIT before for the Channel record cos else
+ * c may be NULL even if it exists */
+ if ((!(c = findchan(chan)) || c->usercount == 0)
+ && !(ci->flags & CI_INHABIT)) {
+ anope_cmd_join(s_ChanServ, chan, (c ? c->creation_time : chants));
+ /* Lets hide the channel from /list just incase someone does /list
+ * while we are here. - katsklaw
+ * We don't want to block users from joining a legit chan though.. - Viper
+ */
+ if (set_modes)
+ anope_cmd_mode(s_ChanServ, chan, "+ntsi");
+ t = add_timeout(CSInhabit, timeout_leave, 0);
+ t->data = sstrdup(chan);
+ ci->flags |= CI_INHABIT;
+ }
+
+ if (c) {
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = chan;
+ av[1] = buf;
+ av[2] = sstrdup("+b");
+ av[3] = mask;
+ ac = 4;
+ } else {
+ av[0] = chan;
+ av[1] = sstrdup("+b");
+ av[2] = mask;
+ ac = 3;
+ }
+
+ do_cmode(whosends(ci), ac, av);
+
+ if (ircdcap->tsmode)
+ free(av[2]);
+ else
+ free(av[1]);
+ }
+
+ anope_cmd_mode(whosends(ci), chan, "+b %s", mask);
+ anope_cmd_kick(whosends(ci), chan, user->nick, "%s", reason);
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Record the current channel topic in the ChannelInfo structure. */
+
+void record_topic(const char *chan)
+{
+ Channel *c;
+ ChannelInfo *ci;
+
+ if (readonly)
+ return;
+
+ c = findchan(chan);
+ if (!c || !(ci = c->ci))
+ return;
+
+ if (ci->last_topic)
+ free(ci->last_topic);
+
+ if (c->topic)
+ ci->last_topic = sstrdup(c->topic);
+ else
+ ci->last_topic = NULL;
+
+ strscpy(ci->last_topic_setter, c->topic_setter, NICKMAX);
+ ci->last_topic_time = c->topic_time;
+}
+
+/*************************************************************************/
+
+/* Restore the topic in a channel when it's created, if we should. */
+
+void restore_topic(char *chan)
+{
+ Channel *c = findchan(chan);
+ ChannelInfo *ci;
+
+ if (!c || !(ci = c->ci))
+ return;
+ /* We can be sure that the topic will be in sync when we return -GD */
+ c->topic_sync = 1;
+ if (!(ci->flags & CI_KEEPTOPIC)) {
+ /* We need to reset the topic here, since it's currently empty and
+ * should be updated with a TOPIC from the IRCd soon. -GD
+ */
+ ci->last_topic = NULL;
+ strscpy(ci->last_topic_setter, whosends(ci), NICKMAX);
+ ci->last_topic_time = time(NULL);
+ return;
+ }
+ if (c->topic)
+ free(c->topic);
+ if (ci->last_topic) {
+ c->topic = sstrdup(ci->last_topic);
+ strscpy(c->topic_setter, ci->last_topic_setter, NICKMAX);
+ c->topic_time = ci->last_topic_time;
+ } else {
+ c->topic = NULL;
+ strscpy(c->topic_setter, whosends(ci), NICKMAX);
+ }
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_join(s_ChanServ, chan, c->creation_time);
+ anope_cmd_mode(NULL, chan, "+o %s", s_ChanServ);
+ }
+ }
+ anope_cmd_topic(whosends(ci), c->name, c->topic_setter,
+ c->topic ? c->topic : "", c->topic_time);
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_part(s_ChanServ, c->name, NULL);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* See if the topic is locked on the given channel, and return 1 (and fix
+ * the topic) if so. */
+
+int check_topiclock(Channel * c, time_t topic_time)
+{
+ ChannelInfo *ci;
+
+ if (!c) {
+ if (debug) {
+ alog("debug: check_topiclock called with NULL values");
+ }
+ return 0;
+ }
+
+ if (!(ci = c->ci) || !(ci->flags & CI_TOPICLOCK))
+ return 0;
+
+ if (c->topic)
+ free(c->topic);
+ if (ci->last_topic) {
+ c->topic = sstrdup(ci->last_topic);
+ strscpy(c->topic_setter, ci->last_topic_setter, NICKMAX);
+ } else {
+ c->topic = NULL;
+ /* Bot assigned & Symbiosis ON?, the bot will set the topic - doc */
+ /* Altough whosends() also checks for BSMinUsers -GD */
+ strscpy(c->topic_setter, whosends(ci), NICKMAX);
+ }
+
+ if (ircd->topictsforward) {
+ /* Because older timestamps are rejected */
+ /* Some how the topic_time from do_topic is 0 set it to current + 1 */
+ if (!topic_time) {
+ c->topic_time = time(NULL) + 1;
+ } else {
+ c->topic_time = topic_time + 1;
+ }
+ } else {
+ /* If no last topic, we can't use last topic time! - doc */
+ if (ci->last_topic)
+ c->topic_time = ci->last_topic_time;
+ else
+ c->topic_time = time(NULL) + 1;
+ }
+
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_join(s_ChanServ, c->name, c->creation_time);
+ anope_cmd_mode(NULL, c->name, "+o %s", s_ChanServ);
+ }
+ }
+
+ anope_cmd_topic(whosends(ci), c->name, c->topic_setter,
+ c->topic ? c->topic : "", c->topic_time);
+
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_part(s_ChanServ, c->ci->name, NULL);
+ }
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Remove all channels which have expired. */
+
+void expire_chans()
+{
+ ChannelInfo *ci, *next;
+ int i;
+ time_t now = time(NULL);
+
+ if (!CSExpire)
+ return;
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = next) {
+ next = ci->next;
+ if (!ci->c && now - ci->last_used >= CSExpire
+ && !(ci->
+ flags & (CI_VERBOTEN | CI_NO_EXPIRE | CI_SUSPENDED)))
+ {
+ send_event(EVENT_CHAN_EXPIRE, 1, ci->name);
+ alog("Expiring channel %s (founder: %s)", ci->name,
+ (ci->founder ? ci->founder->display : "(none)"));
+ delchan(ci);
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Remove a (deleted or expired) nickname from all channel lists. */
+
+void cs_remove_nick(const NickCore * nc)
+{
+ int i, j, k;
+ ChannelInfo *ci, *next;
+ ChanAccess *ca;
+ AutoKick *akick;
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = next) {
+ next = ci->next;
+ if (ci->founder == nc) {
+ if (ci->successor) {
+ NickCore *nc2 = ci->successor;
+ if (!nick_is_services_admin(nc2) && nc2->channelmax > 0
+ && nc2->channelcount >= nc2->channelmax) {
+ alog("%s: Successor (%s) of %s owns too many channels, " "deleting channel", s_ChanServ, nc2->display, ci->name);
+ delchan(ci);
+ continue;
+ } else {
+ alog("%s: Transferring foundership of %s from deleted " "nick %s to successor %s", s_ChanServ, ci->name, nc->display, nc2->display);
+ ci->founder = nc2;
+ ci->successor = NULL;
+ nc2->channelcount++;
+ }
+ } else {
+ alog("%s: Deleting channel %s owned by deleted nick %s", s_ChanServ, ci->name, nc->display);
+ if (ircd->regmode) {
+ /* Maybe move this to delchan() ? */
+ if ((ci->c) && (ci->c->mode & ircd->regmode)) {
+ ci->c->mode &= ~ircd->regmode;
+ anope_cmd_mode(whosends(ci), ci->name, "-r");
+ }
+ }
+
+ delchan(ci);
+ continue;
+ }
+ }
+
+ if (ci->successor == nc)
+ ci->successor = NULL;
+
+ for (ca = ci->access, j = ci->accesscount; j > 0; ca++, j--) {
+ if (ca->in_use && ca->nc == nc) {
+ ca->in_use = 0;
+ ca->nc = NULL;
+ }
+ }
+
+ for (akick = ci->akick, j = 0; j < ci->akickcount; akick++, j++) {
+ if ((akick->flags & AK_USED) && (akick->flags & AK_ISNICK)
+ && akick->u.nc == nc) {
+ if (akick->creator) {
+ free(akick->creator);
+ akick->creator = NULL;
+ }
+ if (akick->reason) {
+ free(akick->reason);
+ akick->reason = NULL;
+ }
+ akick->flags = 0;
+ akick->addtime = 0;
+ akick->u.nc = NULL;
+
+ /* Only one occurance can exist in every akick list.. ~ Viper */
+ break;
+ }
+ }
+
+ /* Are there any akicks behind us?
+ * If so, move all following akicks.. ~ Viper */
+ if (j < ci->akickcount - 1) {
+ for (k = j + 1; k < ci->akickcount; j++, k++) {
+ if (ci->akick[k].flags & AK_USED) {
+ /* Move the akick one place ahead and clear the original */
+ if (ci->akick[k].flags & AK_ISNICK) {
+ ci->akick[j].u.nc = ci->akick[k].u.nc;
+ ci->akick[k].u.nc = NULL;
+ } else {
+ ci->akick[j].u.mask = sstrdup(ci->akick[k].u.mask);
+ free(ci->akick[k].u.mask);
+ ci->akick[k].u.mask = NULL;
+ }
+
+ if (ci->akick[k].reason) {
+ ci->akick[j].reason = sstrdup(ci->akick[k].reason);
+ free(ci->akick[k].reason);
+ ci->akick[k].reason = NULL;
+ } else
+ ci->akick[j].reason = NULL;
+
+ ci->akick[j].creator = sstrdup(ci->akick[k].creator);
+ free(ci->akick[k].creator);
+ ci->akick[k].creator = NULL;
+
+ ci->akick[j].flags = ci->akick[k].flags;
+ ci->akick[k].flags = 0;
+
+ ci->akick[j].addtime = ci->akick[k].addtime;
+ ci->akick[k].addtime = 0;
+ }
+ }
+ }
+
+ /* After moving only the last entry should still be empty.
+ * Free the place no longer in use... ~ Viper */
+ ci->akickcount = j;
+ ci->akick = srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Removes any reference to a bot */
+
+void cs_remove_bot(const BotInfo * bi)
+{
+ int i;
+ ChannelInfo *ci;
+
+ for (i = 0; i < 256; i++)
+ for (ci = chanlists[i]; ci; ci = ci->next)
+ if (ci->bi == bi)
+ ci->bi = NULL;
+}
+
+/*************************************************************************/
+
+/* Return the ChannelInfo structure for the given channel, or NULL if the
+ * channel isn't registered. */
+
+ChannelInfo *cs_findchan(const char *chan)
+{
+ ChannelInfo *ci;
+
+ if (!chan || !*chan) {
+ if (debug) {
+ alog("debug: cs_findchan() called with NULL values");
+ }
+ return NULL;
+ }
+
+ for (ci = chanlists[(unsigned char) tolower(chan[1])]; ci;
+ ci = ci->next) {
+ if (stricmp(ci->name, chan) == 0)
+ return ci;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Return 1 if the user's access level on the given channel falls into the
+ * given category, 0 otherwise. Note that this may seem slightly confusing
+ * in some cases: for example, check_access(..., CA_NOJOIN) returns true if
+ * the user does _not_ have access to the channel (i.e. matches the NOJOIN
+ * criterion). */
+
+int check_access(User * user, ChannelInfo * ci, int what)
+{
+ int level;
+ int limit;
+
+ if (!user || !ci) {
+ return 0;
+ }
+
+ level = get_access(user, ci);
+ limit = ci->levels[what];
+
+ /* Resetting the last used time */
+ if (level > 0)
+ ci->last_used = time(NULL);
+
+ if (level >= ACCESS_FOUNDER)
+ return (what == CA_AUTODEOP || what == CA_NOJOIN) ? 0 : 1;
+ /* Hacks to make flags work */
+ if (what == CA_AUTODEOP && (ci->flags & CI_SECUREOPS) && level == 0)
+ return 1;
+ if (limit == ACCESS_INVALID)
+ return 0;
+ if (what == CA_AUTODEOP || what == CA_NOJOIN)
+ return level <= ci->levels[what];
+ else
+ return level >= ci->levels[what];
+}
+
+/*************************************************************************/
+/*********************** ChanServ private routines ***********************/
+/*************************************************************************/
+
+/* Insert a channel alphabetically into the database. */
+
+void alpha_insert_chan(ChannelInfo * ci)
+{
+ ChannelInfo *ptr, *prev;
+ char *chan;
+
+ if (!ci) {
+ if (debug) {
+ alog("debug: alpha_insert_chan called with NULL values");
+ }
+ return;
+ }
+
+ chan = ci->name;
+
+ for (prev = NULL, ptr = chanlists[(unsigned char) tolower(chan[1])];
+ ptr != NULL && stricmp(ptr->name, chan) < 0;
+ prev = ptr, ptr = ptr->next);
+ ci->prev = prev;
+ ci->next = ptr;
+ if (!prev)
+ chanlists[(unsigned char) tolower(chan[1])] = ci;
+ else
+ prev->next = ci;
+ if (ptr)
+ ptr->prev = ci;
+}
+
+/*************************************************************************/
+
+/* Add a channel to the database. Returns a pointer to the new ChannelInfo
+ * structure if the channel was successfully registered, NULL otherwise.
+ * Assumes channel does not already exist. */
+
+ChannelInfo *makechan(const char *chan)
+{
+ int i;
+ ChannelInfo *ci;
+
+ ci = scalloc(sizeof(ChannelInfo), 1);
+ strscpy(ci->name, chan, CHANMAX);
+ ci->time_registered = time(NULL);
+ reset_levels(ci);
+ ci->ttb = scalloc(2 * TTB_SIZE, 1);
+ for (i = 0; i < TTB_SIZE; i++)
+ ci->ttb[i] = 0;
+ alpha_insert_chan(ci);
+ return ci;
+}
+
+/*************************************************************************/
+
+/* Remove a channel from the ChanServ database. Return 1 on success, 0
+ * otherwise. */
+
+int delchan(ChannelInfo * ci)
+{
+ int i;
+ NickCore *nc;
+ User *u;
+ struct u_chaninfolist *cilist, *cilist_next;
+
+ if (!ci) {
+ if (debug) {
+ alog("debug: delchan called with NULL values");
+ }
+ return 0;
+ }
+
+ nc = ci->founder;
+
+ if (debug >= 2) {
+ alog("debug: delchan removing %s", ci->name);
+ }
+
+ if (ci->bi) {
+ ci->bi->chancount--;
+ }
+
+ if (debug >= 2) {
+ alog("debug: delchan top of removing the bot");
+ }
+ if (ci->c) {
+ if (ci->bi && ci->c->usercount >= BSMinUsers) {
+ anope_cmd_part(ci->bi->nick, ci->c->name, NULL);
+ }
+ ci->c->ci = NULL;
+ }
+ if (debug >= 2) {
+ alog("debug: delchan() Bot has been removed moving on");
+ }
+
+ if (debug >= 2) {
+ alog("debug: delchan() founder cleanup");
+ }
+ for (i = 0; i < 1024; i++) {
+ for (u = userlist[i]; u; u = u->next) {
+ cilist = u->founder_chans;
+ while (cilist) {
+ cilist_next = cilist->next;
+ if (cilist->chan == ci) {
+ if (debug)
+ alog("debug: Dropping founder login of %s for %s",
+ u->nick, ci->name);
+ if (cilist->next)
+ cilist->next->prev = cilist->prev;
+ if (cilist->prev)
+ cilist->prev->next = cilist->next;
+ else
+ u->founder_chans = cilist->next;
+ free(cilist);
+ }
+ cilist = cilist_next;
+ }
+ }
+ }
+ if (debug >= 2) {
+ alog("debug: delchan() founder cleanup done");
+ }
+
+ if (ci->next)
+ ci->next->prev = ci->prev;
+ if (ci->prev)
+ ci->prev->next = ci->next;
+ else
+ chanlists[(unsigned char) tolower(ci->name[1])] = ci->next;
+ if (ci->desc)
+ free(ci->desc);
+ if (ci->url)
+ free(ci->url);
+ if (ci->email)
+ free(ci->email);
+ if (ci->entry_message)
+ free(ci->entry_message);
+
+ if (ci->mlock_key)
+ free(ci->mlock_key);
+ if (ircd->fmode) {
+ if (ci->mlock_flood)
+ free(ci->mlock_flood);
+ }
+ if (ircd->Lmode) {
+ if (ci->mlock_redirect)
+ free(ci->mlock_redirect);
+ }
+ if (ci->last_topic)
+ free(ci->last_topic);
+ if (ci->forbidby)
+ free(ci->forbidby);
+ if (ci->forbidreason)
+ free(ci->forbidreason);
+ if (ci->access)
+ free(ci->access);
+ if (debug >= 2) {
+ alog("debug: delchan() top of the akick list");
+ }
+ for (i = 0; i < ci->akickcount; i++) {
+ if (!(ci->akick[i].flags & AK_ISNICK) && ci->akick[i].u.mask)
+ free(ci->akick[i].u.mask);
+ if (ci->akick[i].reason)
+ free(ci->akick[i].reason);
+ if (ci->akick[i].creator)
+ free(ci->akick[i].creator);
+ }
+ if (debug >= 2) {
+ alog("debug: delchan() done with the akick list");
+ }
+ if (ci->akick)
+ free(ci->akick);
+ if (ci->levels)
+ free(ci->levels);
+ if (debug >= 2) {
+ alog("debug: delchan() top of the memo list");
+ }
+ if (ci->memos.memos) {
+ for (i = 0; i < ci->memos.memocount; i++) {
+ if (ci->memos.memos[i].text)
+ free(ci->memos.memos[i].text);
+ moduleCleanStruct(&ci->memos.memos[i].moduleData);
+ }
+ free(ci->memos.memos);
+ }
+ if (debug >= 2) {
+ alog("debug: delchan() done with the memo list");
+ }
+ if (ci->ttb)
+ free(ci->ttb);
+
+ if (debug >= 2) {
+ alog("debug: delchan() top of the badword list");
+ }
+ for (i = 0; i < ci->bwcount; i++) {
+ if (ci->badwords[i].word)
+ free(ci->badwords[i].word);
+ }
+ if (ci->badwords)
+ free(ci->badwords);
+ if (debug >= 2) {
+ alog("debug: delchan() done with the badword list");
+ }
+
+
+ if (debug >= 2) {
+ alog("debug: delchan() calling on moduleCleanStruct()");
+ }
+ moduleCleanStruct(&ci->moduleData);
+
+ free(ci);
+ if (nc)
+ nc->channelcount--;
+
+ if (debug >= 2) {
+ alog("debug: delchan() all done");
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Reset channel access level values to their default state. */
+
+void reset_levels(ChannelInfo * ci)
+{
+ int i;
+
+ if (!ci) {
+ if (debug) {
+ alog("debug: reset_levels called with NULL values");
+ }
+ return;
+ }
+
+ if (ci->levels)
+ free(ci->levels);
+ ci->levels = scalloc(CA_SIZE * sizeof(*ci->levels), 1);
+ for (i = 0; def_levels[i][0] >= 0; i++)
+ ci->levels[def_levels[i][0]] = def_levels[i][1];
+}
+
+/*************************************************************************/
+
+/* Does the given user have founder access to the channel? */
+
+int is_founder(User * user, ChannelInfo * ci)
+{
+ if (!user || !ci) {
+ return 0;
+ }
+
+ if (user->isSuperAdmin) {
+ return 1;
+ }
+
+ if (user->na && user->na->nc == ci->founder) {
+ if ((nick_identified(user)
+ || (nick_recognized(user) && !(ci->flags & CI_SECURE))))
+ return 1;
+ }
+ if (is_identified(user, ci))
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+int is_real_founder(User * user, ChannelInfo * ci)
+{
+ if (user->isSuperAdmin) {
+ return 1;
+ }
+
+ if (user->na && user->na->nc == ci->founder) {
+ if ((nick_identified(user)
+ || (nick_recognized(user) && !(ci->flags & CI_SECURE))))
+ return 1;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Has the given user password-identified as founder for the channel? */
+
+int is_identified(User * user, ChannelInfo * ci)
+{
+ struct u_chaninfolist *c;
+
+ for (c = user->founder_chans; c; c = c->next) {
+ if (c->chan == ci)
+ return 1;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Returns the ChanAccess entry for an user */
+
+ChanAccess *get_access_entry(NickCore * nc, ChannelInfo * ci)
+{
+ ChanAccess *access;
+ int i;
+
+ if (!ci || !nc) {
+ return NULL;
+ }
+
+ for (access = ci->access, i = 0; i < ci->accesscount; access++, i++)
+ if (access->in_use && access->nc == nc)
+ return access;
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Return the access level the given user has on the channel. If the
+ * channel doesn't exist, the user isn't on the access list, or the channel
+ * is CS_SECURE and the user hasn't IDENTIFY'd with NickServ, return 0. */
+
+int get_access(User * user, ChannelInfo * ci)
+{
+ ChanAccess *access;
+
+ if (!ci || !user)
+ return 0;
+
+ /* SuperAdmin always has highest level */
+ if (user->isSuperAdmin)
+ return ACCESS_SUPERADMIN;
+
+ if (is_founder(user, ci))
+ return ACCESS_FOUNDER;
+
+ if (!user->na)
+ return 0;
+
+ if (nick_identified(user)
+ || (nick_recognized(user) && !(ci->flags & CI_SECURE)))
+ if ((access = get_access_entry(user->na->nc, ci)))
+ return access->level;
+
+ if (nick_identified(user))
+ return 0;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+void update_cs_lastseen(User * user, ChannelInfo * ci)
+{
+ ChanAccess *access;
+
+ if (!ci || !user || !user->na)
+ return;
+
+ if (is_founder(user, ci) || nick_identified(user)
+ || (nick_recognized(user) && !(ci->flags & CI_SECURE)))
+ if ((access = get_access_entry(user->na->nc, ci)))
+ access->last_seen = time(NULL);
+}
+
+/*************************************************************************/
+
+/* Returns the best ban possible for an user depending of the bantype
+ value. */
+
+int get_idealban(ChannelInfo * ci, User * u, char *ret, int retlen)
+{
+ char *mask;
+
+ if (!ci || !u || !ret || retlen == 0)
+ return 0;
+
+ switch (ci->bantype) {
+ case 0:
+ snprintf(ret, retlen, "*!%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+ return 1;
+ case 1:
+ snprintf(ret, retlen, "*!%s%s@%s",
+ (strlen(common_get_vident(u)) <
+ (*(common_get_vident(u)) ==
+ '~' ? USERMAX + 1 : USERMAX) ? "*" : ""),
+ (*(common_get_vident(u)) ==
+ '~' ? common_get_vident(u) + 1 : common_get_vident(u)),
+ common_get_vhost(u));
+ return 1;
+ case 2:
+ snprintf(ret, retlen, "*!*@%s", common_get_vhost(u));
+ return 1;
+ case 3:
+ mask = create_mask(u);
+ snprintf(ret, retlen, "*!%s", mask);
+ free(mask);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*************************************************************************/
+
+char *cs_get_flood(ChannelInfo * ci)
+{
+ if (!ci) {
+ return NULL;
+ } else {
+ return ci->mlock_flood;
+ }
+}
+
+/*************************************************************************/
+
+char *cs_get_key(ChannelInfo * ci)
+{
+ if (!ci) {
+ return NULL;
+ } else {
+ return ci->mlock_key;
+ }
+}
+
+/*************************************************************************/
+
+char *cs_get_limit(ChannelInfo * ci)
+{
+ static char limit[16];
+
+ if (!ci) {
+ return NULL;
+ }
+
+ if (ci->mlock_limit == 0)
+ return NULL;
+
+ snprintf(limit, sizeof(limit), "%lu",
+ (unsigned long int) ci->mlock_limit);
+ return limit;
+}
+
+/*************************************************************************/
+
+char *cs_get_redirect(ChannelInfo * ci)
+{
+ if (!ci) {
+ return NULL;
+ } else {
+ return ci->mlock_redirect;
+ }
+}
+
+/*************************************************************************/
+
+void cs_set_flood(ChannelInfo * ci, char *value)
+{
+ if (!ci) {
+ return;
+ }
+
+ if (ci->mlock_flood)
+ free(ci->mlock_flood);
+
+ /* This looks ugly, but it works ;) */
+ if (anope_flood_mode_check(value)) {
+ ci->mlock_flood = sstrdup(value);
+ } else {
+ ci->mlock_on &= ~ircd->chan_fmode;
+ ci->mlock_flood = NULL;
+ }
+}
+
+/*************************************************************************/
+
+void cs_set_key(ChannelInfo * ci, char *value)
+{
+ if (!ci) {
+ return;
+ }
+
+ if (ci->mlock_key)
+ free(ci->mlock_key);
+
+ /* Don't allow keys with a coma */
+ if (value && *value != ':' && !strchr(value, ',')) {
+ ci->mlock_key = sstrdup(value);
+ } else {
+ ci->mlock_on &= ~anope_get_key_mode();
+ ci->mlock_key = NULL;
+ }
+}
+
+/*************************************************************************/
+
+void cs_set_limit(ChannelInfo * ci, char *value)
+{
+ if (!ci) {
+ return;
+ }
+
+ ci->mlock_limit = value ? strtoul(value, NULL, 10) : 0;
+
+ if (ci->mlock_limit <= 0)
+ ci->mlock_on &= ~anope_get_limit_mode();
+}
+
+/*************************************************************************/
+
+void cs_set_redirect(ChannelInfo * ci, char *value)
+{
+ if (!ci) {
+ return;
+ }
+
+ if (ci->mlock_redirect)
+ free(ci->mlock_redirect);
+
+ /* Don't allow keys with a coma */
+ if (value && *value == '#') {
+ ci->mlock_redirect = sstrdup(value);
+ } else {
+ ci->mlock_on &= ~ircd->chan_lmode;
+ ci->mlock_redirect = NULL;
+ }
+}
+
+int get_access_level(ChannelInfo * ci, NickAlias * na)
+{
+ ChanAccess *access;
+ int num;
+
+ if (!ci || !na) {
+ return 0;
+ }
+
+ if (na->nc == ci->founder) {
+ return ACCESS_FOUNDER;
+ }
+
+ for (num = 0; num < ci->accesscount; num++) {
+
+ access = &ci->access[num];
+
+ if (access->nc && access->nc == na->nc && access->in_use) {
+ return access->level;
+ }
+
+ }
+
+ return 0;
+
+}
+
+const char *get_xop_level(int level)
+{
+ if (level < ACCESS_VOP) {
+ return "Err";
+ } else if (ircd->halfop && level < ACCESS_HOP) {
+ return "VOP";
+ } else if (!ircd->halfop && level < ACCESS_AOP) {
+ return "VOP";
+ } else if (ircd->halfop && level < ACCESS_AOP) {
+ return "HOP";
+ } else if (level < ACCESS_SOP) {
+ return "AOP";
+ } else if (level < ACCESS_FOUNDER) {
+ return "SOP";
+ } else {
+ return "Founder";
+ }
+
+}
+
+/*************************************************************************/
+/*********************** ChanServ command routines ***********************/
+/*************************************************************************/
+
+/*************************************************************************/
+
+
+/*************************************************************************/
+
+/* `last' is set to the last index this routine was called with
+ * `perm' is incremented whenever a permission-denied error occurs
+ */
+
+
+/*************************************************************************/
+
+/* Is the mask stuck? */
+
+AutoKick *is_stuck(ChannelInfo * ci, char *mask)
+{
+ int i;
+ AutoKick *akick;
+
+ if (!ci) {
+ return NULL;
+ }
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)
+ || !(akick->flags & AK_STUCK))
+ continue;
+ /* Example: mask = *!*@*.org and akick->u.mask = *!*@*.anope.org */
+ if (match_wild_nocase(mask, akick->u.mask))
+ return akick;
+ if (ircd->reversekickcheck) {
+ /* Example: mask = *!*@irc.anope.org and akick->u.mask = *!*@*.anope.org */
+ if (match_wild_nocase(akick->u.mask, mask))
+ return akick;
+ }
+ }
+
+ return NULL;
+}
+
+/* Ban the stuck mask in a safe manner. */
+
+void stick_mask(ChannelInfo * ci, AutoKick * akick)
+{
+ char *av[2];
+ Entry *ban;
+
+ if (!ci) {
+ return;
+ }
+
+ if (ci->c->bans && ci->c->bans->entries != 0) {
+ for (ban = ci->c->bans->entries; ban; ban = ban->next) {
+ /* If akick is already covered by a wider ban.
+ Example: c->bans[i] = *!*@*.org and akick->u.mask = *!*@*.epona.org */
+ if (entry_match_mask(ban, sstrdup(akick->u.mask), 0))
+ return;
+
+ if (ircd->reversekickcheck) {
+ /* If akick is wider than a ban already in place.
+ Example: c->bans[i] = *!*@irc.epona.org and akick->u.mask = *!*@*.epona.org */
+ if (match_wild_nocase(akick->u.mask, ban->mask))
+ return;
+ }
+ }
+ }
+
+ /* Falling there means set the ban */
+ av[0] = sstrdup("+b");
+ av[1] = akick->u.mask;
+ anope_cmd_mode(whosends(ci), ci->c->name, "+b %s", akick->u.mask);
+ chan_set_modes(s_ChanServ, ci->c, 2, av, 1);
+ free(av[0]);
+}
+
+/* Ban the stuck mask in a safe manner. */
+
+void stick_all(ChannelInfo * ci)
+{
+ int i;
+ char *av[2];
+ AutoKick *akick;
+
+ if (!ci) {
+ return;
+ }
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)
+ || !(akick->flags & AK_STUCK))
+ continue;
+
+ av[0] = sstrdup("+b");
+ av[1] = akick->u.mask;
+ anope_cmd_mode(whosends(ci), ci->c->name, "+b %s", akick->u.mask);
+ chan_set_modes(s_ChanServ, ci->c, 2, av, 1);
+ free(av[0]);
+ }
+}
diff --git a/src/commands.c b/src/commands.c
new file mode 100644
index 000000000..4c827458d
--- /dev/null
+++ b/src/commands.c
@@ -0,0 +1,271 @@
+/* Routines for looking up commands in a *Serv command list.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "commands.h"
+#include "language.h"
+
+/*************************************************************************/
+
+/**
+ * Return the Command corresponding to the given name, or NULL if no such
+ * command exists.
+ * @param list Command struct
+ * @param cmd Command to look up
+ * @return Command Struct for the given cmd
+ */
+Command *lookup_cmd(Command * list, char *cmd)
+{
+ Command *c;
+
+ for (c = list; c->name; c++) {
+ if (stricmp(c->name, cmd) == 0) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * Run the routine for the given command, if it exists and the user has
+ * privilege to do so; if not, print an appropriate error message.
+ * @param services Services Client
+ * @param u User Struct
+ * @param list Command struct
+ * @param cmd Command
+ * @return void
+ */
+void run_cmd(char *service, User * u, Command * list, char *cmd)
+{
+ Command *c = lookup_cmd(list, cmd);
+ do_run_cmd(service, u, c, cmd);
+}
+
+/*************************************************************************/
+
+/**
+ * Run the routine for the given command, if it exists and the user has
+ * privilege to do so; if not, print an appropriate error message.
+ * @param services Services Client
+ * @param u User Struct
+ * @param Command Hash Table
+ * @param cmd Command
+ * @return void
+ */
+void mod_run_cmd(char *service, User * u, CommandHash * cmdTable[],
+ const char *cmd)
+{
+ Command *c = findCommand(cmdTable, cmd);
+ do_run_cmd(service, u, c, cmd);
+}
+
+
+/*************************************************************************/
+
+/**
+ * Run the given command
+ * @param services Services Client
+ * @param u User Struct
+ * @param c Command Struct
+ * @param cmd Command
+ * @return void
+ */
+void do_run_cmd(char *service, User * u, Command * c, const char *cmd)
+{
+ int retVal = 0;
+ Command *current;
+
+ if (c && c->routine) {
+ if ((checkDefCon(DEFCON_OPER_ONLY)
+ || checkDefCon(DEFCON_SILENT_OPER_ONLY)) && !is_oper(u)) {
+ if (!checkDefCon(DEFCON_SILENT_OPER_ONLY)) {
+ notice_lang(service, u, OPER_DEFCON_DENIED);
+ }
+ } else {
+ mod_current_module_name = c->mod_name;
+ mod_current_module = NULL;
+ if ((c->has_priv == NULL) || c->has_priv(u)) {
+ retVal = c->routine(u);
+ mod_current_module_name = NULL;
+ if (retVal == MOD_CONT) {
+ current = c->next;
+ while (current && retVal == MOD_CONT) {
+ mod_current_module_name = current->mod_name;
+ mod_current_module = NULL;
+ retVal = current->routine(u);
+ mod_current_module_name = NULL;
+ current = current->next;
+ }
+ }
+ } else {
+ notice_lang(service, u, ACCESS_DENIED);
+ alog("Access denied for %s with service %s and command %s",
+ u->nick, service, cmd);
+ }
+ mod_current_module_name = NULL;
+ }
+ } else {
+ if ((!checkDefCon(DEFCON_SILENT_OPER_ONLY)) || is_oper(u)) {
+ notice_lang(service, u, UNKNOWN_COMMAND_HELP, cmd, service);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Output the 'Limited to' line for the given command
+ * @param service Services Client
+ * @param u User Struct
+ * @param c Command Struct
+ * @return void
+ */
+void do_help_limited(char *service, User * u, Command * c)
+{
+ if (c->has_priv == is_services_oper)
+ notice_lang(service, u, HELP_LIMIT_SERV_OPER);
+ else if (c->has_priv == is_services_admin)
+ notice_lang(service, u, HELP_LIMIT_SERV_ADMIN);
+ else if (c->has_priv == is_services_root)
+ notice_lang(service, u, HELP_LIMIT_SERV_ROOT);
+ else if (c->has_priv == is_oper)
+ notice_lang(service, u, HELP_LIMIT_IRC_OPER);
+ else if (c->has_priv == is_host_setter)
+ notice_lang(service, u, HELP_LIMIT_HOST_SETTER);
+ else if (c->has_priv == is_host_remover)
+ notice_lang(service, u, HELP_LIMIT_HOST_REMOVER);
+}
+
+/*************************************************************************/
+
+/**
+ * Print a help message for the given command.
+ * @param services Services Client
+ * @param u User Struct
+ * @param c Command Struct
+ * @param cmd Command
+ * @return void
+ */
+void do_help_cmd(char *service, User * u, Command * c, const char *cmd)
+{
+ Command *current;
+ int has_had_help = 0;
+ int cont = MOD_CONT;
+ const char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
+ Module *calling_module = mod_current_module;
+ char *calling_module_name = mod_current_module_name;
+
+ for (current = c; (current) && (cont == MOD_CONT);
+ current = current->next) {
+ mod_current_module_name = current->mod_name;
+ if (mod_current_module_name)
+ mod_current_module = findModule(mod_current_module_name);
+ else
+ mod_current_module = NULL;
+
+ p1 = current->help_param1;
+ p2 = current->help_param2;
+ p3 = current->help_param3;
+ p4 = current->help_param4;
+ if (current->helpmsg_all >= 0) {
+ notice_help(service, u, current->helpmsg_all, p1, p2, p3, p4);
+ has_had_help = 1;
+ } else if (current->all_help) {
+ cont = current->all_help(u);
+ has_had_help = 1;
+ }
+ if (is_services_root(u)) {
+ if (current->helpmsg_root >= 0) {
+ notice_help(service, u, current->helpmsg_root, p1, p2, p3,
+ p4);
+ has_had_help = 1;
+ } else if (current->root_help) {
+ cont = current->root_help(u);
+ has_had_help = 1;
+ }
+ } else if (is_services_admin(u)) {
+ if (current->helpmsg_admin >= 0) {
+ notice_help(service, u, current->helpmsg_admin, p1, p2, p3,
+ p4);
+ has_had_help = 1;
+ } else if (current->admin_help) {
+ cont = current->admin_help(u);
+ has_had_help = 1;
+ }
+ } else if (is_services_oper(u)) {
+ if (current->helpmsg_oper >= 0) {
+ notice_help(service, u, current->helpmsg_oper, p1, p2, p3,
+ p4);
+ has_had_help = 1;
+ } else if (current->oper_help) {
+ cont = current->oper_help(u);
+ has_had_help = 1;
+ }
+ } else {
+ if (current->helpmsg_reg >= 0) {
+ notice_help(service, u, current->helpmsg_reg, p1, p2, p3,
+ p4);
+ has_had_help = 1;
+ } else if (current->regular_help) {
+ cont = current->regular_help(u);
+ has_had_help = 1;
+ }
+ }
+ }
+ if (has_had_help == 0) {
+ notice_lang(service, u, NO_HELP_AVAILABLE, cmd);
+ } else {
+ do_help_limited(service, u, c);
+ }
+
+ mod_current_module = calling_module;
+ mod_current_module_name = calling_module_name;
+}
+
+/*************************************************************************/
+
+/**
+ * Find the Help Command
+ * @param services Services Client
+ * @param u User Struct
+ * @param c Command Struct
+ * @param cmd Command
+ * @return void
+ */
+void help_cmd(char *service, User * u, Command * list, char *cmd)
+{
+ Command *c = lookup_cmd(list, cmd);
+ do_help_cmd(service, u, c, cmd);
+}
+
+/*************************************************************************/
+
+/**
+ * Find the Help Command
+ * @param services Services Client
+ * @param u User Struct
+ * @param Command Hash Table
+ * @param cmd Command
+ * @return void
+ */
+void mod_help_cmd(char *service, User * u, CommandHash * cmdTable[],
+ const char *cmd)
+{
+ Command *c = findCommand(cmdTable, cmd);
+ do_help_cmd(service, u, c, cmd);
+}
+
+/*************************************************************************/
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 000000000..ec0856f46
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,228 @@
+/* Compatibility routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+#if !HAVE_SNPRINTF
+
+/* [v]snprintf: Like [v]sprintf, but don't write more than len bytes
+ * (including null terminator). Return the number of bytes
+ * written.
+ */
+
+#if BAD_SNPRINTF
+int vsnprintf(char *buf, size_t len, const char *fmt, va_list args)
+{
+ if (len <= 0)
+ return 0;
+ *buf = 0;
+ vsnprintf(buf, len, fmt, args);
+ buf[len - 1] = 0;
+ return strlen(buf);
+}
+#endif /* BAD_SNPRINTF */
+
+int snprintf(char *buf, size_t len, const char *fmt, ...)
+{
+ va_list args;
+ int ret = 0;
+
+ va_start(args, fmt);
+ ret = vsnprintf(buf, len, fmt, args);
+ va_end(args);
+ return ret;
+}
+
+#endif /* !HAVE_SNPRINTF */
+
+/*************************************************************************/
+
+#if !HAVE_STRICMP && !HAVE_STRCASECMP
+
+/* stricmp, strnicmp: Case-insensitive versions of strcmp() and
+ * strncmp().
+ */
+
+int stricmp(const char *s1, const char *s2)
+{
+ register int c;
+
+ while ((c = tolower(*s1)) == tolower(*s2)) {
+ if (c == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ if (c < tolower(*s2))
+ return -1;
+ return 1;
+}
+
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+ register int c;
+
+ if (!len)
+ return 0;
+ while ((c = tolower(*s1)) == tolower(*s2) && len > 0) {
+ if (c == 0 || --len == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ if (c < tolower(*s2))
+ return -1;
+ return 1;
+}
+#endif
+
+/*************************************************************************/
+
+#if !HAVE_STRDUP
+char *strdup(const char *s)
+{
+ char *new = calloc(strlen(s) + 1, 1);
+ if (new)
+ strcpy(new, s);
+ return new;
+}
+#endif
+
+/*************************************************************************/
+
+#if !HAVE_STRSPN
+size_t strspn(const char *s, const char *accept)
+{
+ size_t i = 0;
+
+ while (*s && strchr(accept, *s))
+ ++i, ++s;
+ return i;
+}
+#endif
+
+/*************************************************************************/
+
+#if !HAVE_STRERROR
+# if HAVE_SYS_ERRLIST
+extern char *sys_errlist[];
+# endif
+
+char *strerror(int errnum)
+{
+# if HAVE_SYS_ERRLIST
+ return sys_errlist[errnum];
+# else
+ static char buf[20];
+ snprintf(buf, sizeof(buf), "Error %d", errnum);
+ return buf;
+# endif
+}
+#endif
+
+/*************************************************************************/
+
+#if !HAVE_STRSIGNAL
+/* Windows only supports 6 signals:
+ * SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM
+ * -- codemastr
+ */
+char *strsignal(int signum)
+{
+ static char buf[32];
+ switch (signum) {
+#ifndef _WIN32
+ case SIGHUP:
+ strscpy(buf, "Hangup", sizeof(buf));
+ break;
+#endif
+ case SIGINT:
+ strscpy(buf, "Interrupt", sizeof(buf));
+ break;
+#ifndef _WIN32
+ case SIGQUIT:
+ strscpy(buf, "Quit", sizeof(buf));
+ break;
+#endif
+#ifdef SIGILL
+ case SIGILL:
+ strscpy(buf, "Illegal instruction", sizeof(buf));
+ break;
+#endif
+#ifdef SIGABRT
+ case SIGABRT:
+ strscpy(buf, "Abort", sizeof(buf));
+ break;
+#endif
+#if defined(SIGIOT) && (!defined(SIGABRT) || SIGIOT != SIGABRT)
+ case SIGIOT:
+ strscpy(buf, "IOT trap", sizeof(buf));
+ break;
+#endif
+#ifdef SIGBUS
+ case SIGBUS:
+ strscpy(buf, "Bus error", sizeof(buf));
+ break;
+#endif
+ case SIGFPE:
+ strscpy(buf, "Floating point exception", sizeof(buf));
+ break;
+#ifndef _WIN32
+ case SIGKILL:
+ strscpy(buf, "Killed", sizeof(buf));
+ break;
+ case SIGUSR1:
+ strscpy(buf, "User signal 1", sizeof(buf));
+ break;
+#endif
+ case SIGSEGV:
+ strscpy(buf, "Segmentation fault", sizeof(buf));
+ break;
+#ifndef _WIN32
+ case SIGUSR2:
+ strscpy(buf, "User signal 2", sizeof(buf));
+ break;
+ case SIGPIPE:
+ strscpy(buf, "Broken pipe", sizeof(buf));
+ break;
+ case SIGALRM:
+ strscpy(buf, "Alarm clock", sizeof(buf));
+ break;
+#endif
+ case SIGTERM:
+ strscpy(buf, "Terminated", sizeof(buf));
+ break;
+#ifndef _WIN32
+ case SIGSTOP:
+ strscpy(buf, "Suspended (signal)", sizeof(buf));
+ break;
+ case SIGTSTP:
+ strscpy(buf, "Suspended", sizeof(buf));
+ break;
+ case SIGIO:
+ strscpy(buf, "I/O error", sizeof(buf));
+ break;
+#endif
+ default:
+ snprintf(buf, sizeof(buf), "Signal %d\n", signum);
+ break;
+ }
+ return buf;
+}
+#endif
+
+
+/*************************************************************************/
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 000000000..b4ff90b28
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,1420 @@
+/* Configuration file handling.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+/* Configurable variables: */
+
+char *IRCDModule;
+char *EncModule;
+char *RemoteServer;
+int RemotePort;
+char *RemotePassword;
+
+char *RemoteServer2;
+int RemotePort2;
+char *RemotePassword2;
+
+char *RemoteServer3;
+int RemotePort3;
+char *RemotePassword3;
+
+char *LocalHost;
+int LocalPort;
+
+char *ServerName;
+char *ServerDesc;
+char *ServiceUser;
+char *ServiceHost;
+static char *temp_userhost;
+
+char *HelpChannel;
+char *LogChannel;
+char *NetworkName;
+int NickLen;
+
+char *s_NickServ;
+char *s_ChanServ;
+char *s_MemoServ;
+char *s_BotServ;
+char *s_HelpServ;
+char *s_OperServ;
+char *s_GlobalNoticer;
+char *s_DevNull;
+char *desc_NickServ;
+char *desc_ChanServ;
+char *desc_MemoServ;
+char *desc_BotServ;
+char *desc_HelpServ;
+char *desc_OperServ;
+char *desc_GlobalNoticer;
+char *desc_DevNull;
+
+char *HostDBName; /* Name of HostServ DB File */
+char *s_HostServ; /* HostServ Name */
+char *desc_HostServ; /* HostServ Description */
+
+char *s_NickServAlias;
+char *s_ChanServAlias;
+char *s_MemoServAlias;
+char *s_BotServAlias;
+char *s_HelpServAlias;
+char *s_OperServAlias;
+char *s_GlobalNoticerAlias;
+char *s_DevNullAlias;
+char *s_HostServAlias;
+char *desc_NickServAlias;
+char *desc_ChanServAlias;
+char *desc_MemoServAlias;
+char *desc_BotServAlias;
+char *desc_HelpServAlias;
+char *desc_OperServAlias;
+char *desc_GlobalNoticerAlias;
+char *desc_DevNullAlias;
+char *desc_HostServAlias;
+
+char *PIDFilename;
+char *MOTDFilename;
+char *NickDBName;
+char *PreNickDBName;
+char *ChanDBName;
+char *BotDBName;
+char *OperDBName;
+char *AutokillDBName;
+char *NewsDBName;
+
+char *HostSetter;
+char **HostSetters;
+int HostNumber = 0; /* needs to be set to 0 */
+
+int NoBackupOkay;
+int StrictPasswords;
+int BadPassLimit;
+int BadPassTimeout;
+int UpdateTimeout;
+int ExpireTimeout;
+int ReadTimeout;
+int WarningTimeout;
+int TimeoutCheck;
+int KeepLogs;
+int KeepBackups;
+int ForceForbidReason;
+int UsePrivmsg;
+int UseStrictPrivMsg;
+int DumpCore;
+int LogUsers;
+int NickRegDelay;
+int UseSVSHOLD;
+int UseTokens;
+int UseSVS2MODE;
+int NewsCount;
+
+int UseMail;
+char *SendMailPath;
+char *SendFrom;
+int RestrictMail;
+int MailDelay;
+int DontQuoteAddresses;
+
+static int NSDefNone;
+char *NSGuestNickPrefix;
+int NSAllowKillImmed;
+int NSNoGroupChange;
+int NSDefKill;
+int NSDefKillQuick;
+int NSDefSecure;
+int NSDefPrivate;
+int NSDefMsg;
+int NSDefHideEmail;
+int NSDefHideUsermask;
+int NSDefHideQuit;
+int NSDefMemoSignon;
+int NSDefMemoReceive;
+int NSDefFlags;
+int NSDefLanguage;
+int NSDefAutoop;
+int NSRegDelay;
+int NSResendDelay;
+int NSExpire;
+int NSRExpire;
+int NSForceEmail;
+int NSMaxAliases;
+int NSAccessMax;
+char *NSEnforcerUser;
+char *NSEnforcerHost;
+static char *temp_nsuserhost;
+int NSReleaseTimeout;
+int NSListOpersOnly;
+int NSListMax;
+int NSSecureAdmins;
+int NSStrictPrivileges;
+int NSEmailReg;
+int NSModeOnID;
+int NSRestrictGetPass;
+int NSNickTracking;
+int NSAddAccessOnReg;
+
+int CSDefNone;
+int CSDefKeepTopic;
+int CSDefOpNotice;
+int CSDefPeace;
+int CSDefPrivate;
+int CSDefRestricted;
+int CSDefSecure;
+int CSDefSecureOps;
+int CSDefSecureFounder;
+int CSDefSignKick;
+int CSDefSignKickLevel;
+int CSDefTopicLock;
+int CSDefXOP;
+int CSDefFlags;
+int CSMaxReg;
+int CSExpire;
+int CSDefBantype;
+int CSAccessMax;
+int CSAutokickMax;
+char *CSAutokickReason;
+int CSInhabit;
+int CSListOpersOnly;
+int CSListMax;
+int CSRestrictGetPass;
+int CSOpersOnly;
+
+int MSMaxMemos;
+int MSSendDelay;
+int MSNotifyAll;
+int MSMemoReceipt;
+
+int BSDefDontKickOps;
+int BSDefDontKickVoices;
+int BSDefFantasy;
+int BSDefGreet;
+int BSDefSymbiosis;
+int BSDefFlags;
+int BSKeepData;
+int BSMinUsers;
+int BSBadWordsMax;
+int BSSmartJoin;
+int BSGentleBWReason;
+int BSCaseSensitive;
+char *BSFantasyCharacter;
+
+int HideStatsO;
+int GlobalOnCycle;
+int AnonymousGlobal;
+int RestrictOperNicks;
+char *GlobalOnCycleMessage;
+char *GlobalOnCycleUP;
+char *ServicesRoot;
+char **ServicesRoots;
+int RootNumber;
+int SuperAdmin;
+int LogBot;
+int LogMaxUsers;
+int DisableRaw;
+int AutokillExpiry;
+int ChankillExpiry;
+int SGLineExpiry;
+int SQLineExpiry;
+int SZLineExpiry;
+int AkillOnAdd;
+int KillonSGline;
+int KillonSQline;
+int WallOper;
+int WallBadOS;
+int WallOSGlobal;
+int WallOSMode;
+int WallOSClearmodes;
+int WallOSKick;
+int WallOSAkill;
+int WallOSSGLine;
+int WallOSSQLine;
+int WallOSSZLine;
+int WallOSNoOp;
+int WallOSJupe;
+int WallOSRaw;
+int WallAkillExpire;
+int WallSGLineExpire;
+int WallSQLineExpire;
+int WallSZLineExpire;
+int WallExceptionExpire;
+int WallDrop;
+int WallForbid;
+int WallGetpass;
+int WallSetpass;
+int AddAkiller;
+
+int LimitSessions;
+int DefSessionLimit;
+int ExceptionExpiry;
+int MaxSessionKill;
+int MaxSessionLimit;
+int SessionAutoKillExpiry;
+char *ExceptionDBName;
+char *SessionLimitExceeded;
+char *SessionLimitDetailsLoc;
+
+int OSOpersOnly;
+
+char *Modules;
+char *ModulesDelayed;
+char **ModulesAutoload;
+int ModulesNumber;
+int ModulesDelayedNumber;
+char **ModulesDelayedAutoload;
+
+/**
+ * Core Module Stuff
+ **/
+char *HostCoreModules;
+char **HostServCoreModules;
+int HostServCoreNumber;
+
+char *MemoCoreModules;
+char **MemoServCoreModules;
+int MemoServCoreNumber;
+
+char *HelpCoreModules;
+char **HelpServCoreModules;
+int HelpServCoreNumber;
+
+char *BotCoreModules;
+char **BotServCoreModules;
+int BotServCoreNumber;
+
+char *OperCoreModules;
+char **OperServCoreModules;
+int OperServCoreNumber;
+
+char *NickCoreModules;
+char **NickServCoreModules;
+int NickServCoreNumber;
+
+char *ChanCoreModules;
+char **ChanServCoreModules;
+int ChanServCoreNumber;
+
+
+char *MysqlHost;
+char *MysqlUser;
+char *MysqlPass;
+char *MysqlName;
+int MysqlPort;
+char *MysqlSecure;
+char *MysqlSock;
+int MysqlRetries = 0;
+int MysqlRetryGap = 0;
+int UseRDB = 0;
+
+int DefConLevel;
+int DefCon1;
+int DefCon2;
+int DefCon3;
+int DefCon4;
+int DefCon5;
+int DefCon[6];
+char *DefConTimeOut;
+int DefConSessionLimit;
+char *DefConAKILL;
+char *DefConChanModes;
+int GlobalOnDefcon;
+int GlobalOnDefconMore;
+char *DefConOffMessage;
+char *DefconMessage;
+char *DefConAkillReason;
+
+long unsigned int UserKey1;
+long unsigned int UserKey2;
+long unsigned int UserKey3;
+
+char *Numeric;
+
+int UnRestrictSAdmin;
+
+char *UlineServers;
+char **Ulines;
+int NumUlines;
+
+int UseTS6;
+
+
+/*************************************************************************/
+
+/* Deprecated directive (dep_) and value checking (chk_) functions: */
+
+/* Hey, there are no left! -GD */
+
+/*************************************************************************/
+
+Directive directives[] = {
+ {"AkillOnAdd", {{PARAM_SET, PARAM_RELOAD, &AkillOnAdd}}},
+ {"AutokillDB", {{PARAM_STRING, PARAM_RELOAD, &AutokillDBName}}},
+ {"AutokillExpiry", {{PARAM_TIME, PARAM_RELOAD, &AutokillExpiry}}},
+ {"ChankillExpiry", {{PARAM_TIME, PARAM_RELOAD, &ChankillExpiry}}},
+ {"BadPassLimit", {{PARAM_POSINT, PARAM_RELOAD, &BadPassLimit}}},
+ {"BadPassTimeout", {{PARAM_TIME, PARAM_RELOAD, &BadPassTimeout}}},
+ {"BotCoreModules", {{PARAM_STRING, PARAM_RELOAD, &BotCoreModules}}},
+ {"BotServDB", {{PARAM_STRING, PARAM_RELOAD, &BotDBName}}},
+ {"BotServName", {{PARAM_STRING, 0, &s_BotServ},
+ {PARAM_STRING, 0, &desc_BotServ}}},
+ {"BotServAlias", {{PARAM_STRING, 0, &s_BotServAlias},
+ {PARAM_STRING, 0, &desc_BotServAlias}}},
+ {"BSBadWordsMax", {{PARAM_POSINT, PARAM_RELOAD, &BSBadWordsMax}}},
+ {"BSDefDontKickOps", {{PARAM_SET, PARAM_RELOAD, &BSDefDontKickOps}}},
+ {"BSDefDontKickVoices",
+ {{PARAM_SET, PARAM_RELOAD, &BSDefDontKickVoices}}},
+ {"BSDefGreet", {{PARAM_SET, PARAM_RELOAD, &BSDefGreet}}},
+ {"BSDefFantasy", {{PARAM_SET, PARAM_RELOAD, &BSDefFantasy}}},
+ {"BSDefSymbiosis", {{PARAM_SET, PARAM_RELOAD, &BSDefSymbiosis}}},
+ {"BSCaseSensitive", {{PARAM_SET, PARAM_RELOAD, &BSCaseSensitive}}},
+ {"BSFantasyCharacter",
+ {{PARAM_STRING, PARAM_RELOAD, &BSFantasyCharacter}}},
+ {"BSGentleBWReason", {{PARAM_SET, PARAM_RELOAD, &BSGentleBWReason}}},
+ {"BSKeepData", {{PARAM_TIME, PARAM_RELOAD, &BSKeepData}}},
+ {"BSMinUsers", {{PARAM_POSINT, PARAM_RELOAD, &BSMinUsers}}},
+ {"BSSmartJoin", {{PARAM_SET, PARAM_RELOAD, &BSSmartJoin}}},
+ {"HostServDB", {{PARAM_STRING, PARAM_RELOAD, &HostDBName}}},
+ {"HostServName", {{PARAM_STRING, 0, &s_HostServ},
+ {PARAM_STRING, 0, &desc_HostServ}}},
+ {"ChanCoreModules", {{PARAM_STRING, PARAM_RELOAD, &ChanCoreModules}}},
+ {"ChanServDB", {{PARAM_STRING, PARAM_RELOAD, &ChanDBName}}},
+ {"ChanServName", {{PARAM_STRING, 0, &s_ChanServ},
+ {PARAM_STRING, 0, &desc_ChanServ}}},
+ {"ChanServAlias", {{PARAM_STRING, 0, &s_ChanServAlias},
+ {PARAM_STRING, 0, &desc_ChanServAlias}}},
+ {"CSAccessMax", {{PARAM_POSINT, PARAM_RELOAD, &CSAccessMax}}},
+ {"CSAutokickMax", {{PARAM_POSINT, PARAM_RELOAD, &CSAutokickMax}}},
+ {"CSAutokickReason",
+ {{PARAM_STRING, PARAM_RELOAD, &CSAutokickReason}}},
+ {"CSDefBantype", {{PARAM_INT, PARAM_RELOAD, &CSDefBantype}}},
+ {"CSDefNone", {{PARAM_SET, PARAM_RELOAD, &CSDefNone}}},
+ {"CSDefKeepTopic", {{PARAM_SET, PARAM_RELOAD, &CSDefKeepTopic}}},
+ {"CSDefOpNotice", {{PARAM_SET, PARAM_RELOAD, &CSDefOpNotice}}},
+ {"CSDefPeace", {{PARAM_SET, PARAM_RELOAD, &CSDefPeace}}},
+ {"CSDefPrivate", {{PARAM_SET, PARAM_RELOAD, &CSDefPrivate}}},
+ {"CSDefRestricted", {{PARAM_SET, PARAM_RELOAD, &CSDefRestricted}}},
+ {"CSDefSecure", {{PARAM_SET, PARAM_RELOAD, &CSDefSecure}}},
+ {"CSDefSecureOps", {{PARAM_SET, PARAM_RELOAD, &CSDefSecureOps}}},
+ {"CSDefSecureFounder",
+ {{PARAM_SET, PARAM_RELOAD, &CSDefSecureFounder}}},
+ {"CSDefSignKick", {{PARAM_SET, PARAM_RELOAD, &CSDefSignKick}}},
+ {"CSDefSignKickLevel",
+ {{PARAM_SET, PARAM_RELOAD, &CSDefSignKickLevel}}},
+ {"CSDefTopicLock", {{PARAM_SET, PARAM_RELOAD, &CSDefTopicLock}}},
+ {"CSDefXOP", {{PARAM_SET, PARAM_RELOAD, &CSDefXOP}}},
+ {"CSExpire", {{PARAM_TIME, PARAM_RELOAD, &CSExpire}}},
+ {"CSInhabit", {{PARAM_TIME, PARAM_RELOAD, &CSInhabit}}},
+ {"CSListMax", {{PARAM_POSINT, PARAM_RELOAD, &CSListMax}}},
+ {"CSListOpersOnly", {{PARAM_SET, PARAM_RELOAD, &CSListOpersOnly}}},
+ {"CSMaxReg", {{PARAM_POSINT, 0, &CSMaxReg}}},
+ {"CSRestrictGetPass", {{PARAM_SET, PARAM_RELOAD, &CSRestrictGetPass}}},
+ {"CSOpersOnly", {{PARAM_SET, PARAM_RELOAD, &CSOpersOnly}}},
+ {"DefSessionLimit", {{PARAM_POSINT, 0, &DefSessionLimit}}},
+ {"DevNullName", {{PARAM_STRING, 0, &s_DevNull},
+ {PARAM_STRING, 0, &desc_DevNull}}},
+ {"DevNullAlias", {{PARAM_STRING, 0, &s_DevNullAlias},
+ {PARAM_STRING, 0, &desc_DevNullAlias}}},
+ {"DisableRaw", {{PARAM_SET, PARAM_RELOAD, &DisableRaw}}},
+ {"DontQuoteAddresses",
+ {{PARAM_SET, PARAM_RELOAD, &DontQuoteAddresses}}},
+ {"DumpCore", {{PARAM_SET, 0, &DumpCore}}},
+ {"DefConLevel", {{PARAM_INT, PARAM_RELOAD, &DefConLevel}}},
+ {"DefCon1", {{PARAM_INT, PARAM_RELOAD, &DefCon1}}},
+ {"DefCon2", {{PARAM_INT, PARAM_RELOAD, &DefCon2}}},
+ {"DefCon3", {{PARAM_INT, PARAM_RELOAD, &DefCon3}}},
+ {"DefCon4", {{PARAM_INT, PARAM_RELOAD, &DefCon4}}},
+ {"DefConSessionLimit",
+ {{PARAM_INT, PARAM_RELOAD, &DefConSessionLimit}}},
+ {"DefConAkillExpire", {{PARAM_STRING, PARAM_RELOAD, &DefConAKILL}}},
+ {"DefConChanModes", {{PARAM_STRING, PARAM_RELOAD, &DefConChanModes}}},
+ {"DefConTimeOut", {{PARAM_STRING, PARAM_RELOAD, &DefConTimeOut}}},
+ {"DefConAkillReason",
+ {{PARAM_STRING, PARAM_RELOAD, &DefConAkillReason}}},
+ {"DefConOffMessage",
+ {{PARAM_STRING, PARAM_RELOAD, &DefConOffMessage}}},
+ {"EncModule", {{PARAM_STRING, 0, &EncModule}}},
+ {"ExceptionDB", {{PARAM_STRING, PARAM_RELOAD, &ExceptionDBName}}},
+ {"ExceptionExpiry", {{PARAM_TIME, PARAM_RELOAD, &ExceptionExpiry}}},
+ {"ExpireTimeout", {{PARAM_TIME, PARAM_RELOAD, &ExpireTimeout}}},
+ {"ForceForbidReason", {{PARAM_SET, PARAM_RELOAD, &ForceForbidReason}}},
+ {"GlobalName", {{PARAM_STRING, 0, &s_GlobalNoticer},
+ {PARAM_STRING, 0, &desc_GlobalNoticer}}},
+ {"GlobalAlias", {{PARAM_STRING, 0, &s_GlobalNoticerAlias},
+ {PARAM_STRING, 0, &desc_GlobalNoticerAlias}}},
+ {"HelpCoreModules", {{PARAM_STRING, PARAM_RELOAD, &HelpCoreModules}}},
+ {"HelpChannel", {{PARAM_STRING, PARAM_RELOAD, &HelpChannel}}},
+ {"HostCoreModules", {{PARAM_STRING, PARAM_RELOAD, &HostCoreModules}}},
+ {"HostServAlias", {{PARAM_STRING, 0, &s_HostServAlias},
+ {PARAM_STRING, 0, &desc_HostServAlias}}},
+ {"HostSetters", {{PARAM_STRING, PARAM_RELOAD, &HostSetter}}},
+ {"IRCDModule", {{PARAM_STRING, 0, &IRCDModule}}},
+ {"LogChannel", {{PARAM_STRING, PARAM_RELOAD, &LogChannel}}},
+ {"LogBot", {{PARAM_SET, PARAM_RELOAD, &LogBot}}},
+ {"HelpServName", {{PARAM_STRING, 0, &s_HelpServ},
+ {PARAM_STRING, 0, &desc_HelpServ}}},
+ {"HelpServAlias", {{PARAM_STRING, 0, &s_HelpServAlias},
+ {PARAM_STRING, 0, &desc_HelpServAlias}}},
+ {"KeepBackups", {{PARAM_INT, PARAM_RELOAD, &KeepBackups}}},
+ {"KeepLogs", {{PARAM_INT, PARAM_RELOAD, &KeepLogs}}},
+ {"KillonSGline", {{PARAM_SET, PARAM_RELOAD, &KillonSGline}}},
+ {"KillonSQline", {{PARAM_SET, PARAM_RELOAD, &KillonSQline}}},
+ {"AddAkiller", {{PARAM_SET, PARAM_RELOAD, &AddAkiller}}},
+ {"LimitSessions", {{PARAM_SET, PARAM_FULLONLY, &LimitSessions}}},
+ {"LocalAddress", {{PARAM_STRING, 0, &LocalHost},
+ {PARAM_PORT, PARAM_OPTIONAL, &LocalPort}}},
+ {"LogUsers", {{PARAM_SET, PARAM_RELOAD, &LogUsers}}},
+ {"SuperAdmin", {{PARAM_SET, PARAM_RELOAD, &SuperAdmin}}},
+ {"LogMaxUsers", {{PARAM_SET, PARAM_RELOAD, &LogMaxUsers}}},
+ {"MailDelay", {{PARAM_TIME, PARAM_RELOAD, &MailDelay}}},
+ {"MaxSessionKill", {{PARAM_INT, PARAM_RELOAD, &MaxSessionKill}}},
+ {"MaxSessionLimit", {{PARAM_POSINT, PARAM_RELOAD, &MaxSessionLimit}}},
+ {"MemoCoreModules", {{PARAM_STRING, PARAM_RELOAD, &MemoCoreModules}}},
+ {"MemoServName", {{PARAM_STRING, 0, &s_MemoServ},
+ {PARAM_STRING, 0, &desc_MemoServ}}},
+ {"MemoServAlias", {{PARAM_STRING, 0, &s_MemoServAlias},
+ {PARAM_STRING, 0, &desc_MemoServAlias}}},
+ {"MysqlHost", {{PARAM_STRING, PARAM_RELOAD, &MysqlHost}}},
+ {"MysqlUser", {{PARAM_STRING, PARAM_RELOAD, &MysqlUser}}},
+ {"MysqlPass", {{PARAM_STRING, PARAM_RELOAD, &MysqlPass}}},
+ {"MysqlName", {{PARAM_STRING, PARAM_RELOAD, &MysqlName}}},
+ {"MysqlPort", {{PARAM_PORT, PARAM_RELOAD, &MysqlPort}}},
+ {"MysqlSecure", {{PARAM_STRING, PARAM_RELOAD, &MysqlSecure}}},
+ {"MysqlSock", {{PARAM_STRING, PARAM_RELOAD, &MysqlSock}}},
+ {"MysqlRetries", {{PARAM_POSINT, PARAM_RELOAD, &MysqlRetries}}},
+ {"MysqlRetryGap", {{PARAM_POSINT, PARAM_RELOAD, &MysqlRetryGap}}},
+ {"UseRDB", {{PARAM_SET, PARAM_RELOAD, &UseRDB}}},
+ {"ModuleAutoload", {{PARAM_STRING, PARAM_RELOAD, &Modules}}},
+ {"ModuleDelayedAutoload",
+ {{PARAM_STRING, PARAM_RELOAD, &ModulesDelayed}}},
+ {"MOTDFile", {{PARAM_STRING, PARAM_RELOAD, &MOTDFilename}}},
+ {"MSMaxMemos", {{PARAM_POSINT, PARAM_RELOAD, &MSMaxMemos}}},
+ {"MSNotifyAll", {{PARAM_SET, PARAM_RELOAD, &MSNotifyAll}}},
+ {"MSSendDelay", {{PARAM_TIME, PARAM_RELOAD, &MSSendDelay}}},
+ {"MSMemoReceipt", {{PARAM_POSINT, PARAM_RELOAD, &MSMemoReceipt}}},
+ {"NetworkName", {{PARAM_STRING, PARAM_RELOAD, &NetworkName}}},
+ {"NewsCount", {{PARAM_POSINT, PARAM_RELOAD, &NewsCount}}},
+ {"NewsDB", {{PARAM_STRING, PARAM_RELOAD, &NewsDBName}}},
+ {"NickLen", {{PARAM_POSINT, 0, &NickLen}}},
+ {"NickservDB", {{PARAM_STRING, PARAM_RELOAD, &NickDBName}}},
+ {"Numeric", {{PARAM_STRING, PARAM_RELOAD, &Numeric}}},
+ {"PreNickServDB", {{PARAM_STRING, PARAM_RELOAD, &PreNickDBName}}},
+ {"NSEmailReg", {{PARAM_SET, PARAM_RELOAD, &NSEmailReg}}},
+ {"NickCoreModules", {{PARAM_STRING, PARAM_RELOAD, &NickCoreModules}}},
+ {"NickRegDelay", {{PARAM_POSINT, PARAM_RELOAD, &NickRegDelay}}},
+ {"NickServName", {{PARAM_STRING, 0, &s_NickServ},
+ {PARAM_STRING, 0, &desc_NickServ}}},
+ {"NickServAlias", {{PARAM_STRING, 0, &s_NickServAlias},
+ {PARAM_STRING, 0, &desc_NickServAlias}}},
+ {"NoBackupOkay", {{PARAM_SET, PARAM_RELOAD, &NoBackupOkay}}},
+ {"NSAccessMax", {{PARAM_POSINT, PARAM_RELOAD, &NSAccessMax}}},
+ {"NSAllowKillImmed", {{PARAM_SET, 0, &NSAllowKillImmed}}},
+ {"NSDefHideEmail", {{PARAM_SET, PARAM_RELOAD, &NSDefHideEmail}}},
+ {"NSDefHideQuit", {{PARAM_SET, PARAM_RELOAD, &NSDefHideQuit}}},
+ {"NSDefHideUsermask", {{PARAM_SET, PARAM_RELOAD, &NSDefHideUsermask}}},
+ {"NSDefKill", {{PARAM_SET, PARAM_RELOAD, &NSDefKill}}},
+ {"NSDefKillQuick", {{PARAM_SET, PARAM_RELOAD, &NSDefKillQuick}}},
+ {"NSDefLanguage", {{PARAM_POSINT, PARAM_RELOAD, &NSDefLanguage}}},
+ {"NSDefMemoReceive", {{PARAM_SET, PARAM_RELOAD, &NSDefMemoReceive}}},
+ {"NSDefMemoSignon", {{PARAM_SET, PARAM_RELOAD, &NSDefMemoSignon}}},
+ {"NSDefMsg", {{PARAM_SET, PARAM_RELOAD, &NSDefMsg}}},
+ {"NSDefNone", {{PARAM_SET, PARAM_RELOAD, &NSDefNone}}},
+ {"NSDefPrivate", {{PARAM_SET, PARAM_RELOAD, &NSDefPrivate}}},
+ {"NSDefSecure", {{PARAM_SET, PARAM_RELOAD, &NSDefSecure}}},
+ {"NSDefAutoop", {{PARAM_SET, PARAM_RELOAD, &NSDefAutoop}}},
+ {"NSEnforcerUser", {{PARAM_STRING, PARAM_RELOAD, &temp_nsuserhost}}},
+ {"NSExpire", {{PARAM_TIME, PARAM_RELOAD, &NSExpire}}},
+ {"NSRExpire", {{PARAM_TIME, PARAM_RELOAD, &NSRExpire}}},
+ {"NSModeOnID", {{PARAM_SET, PARAM_RELOAD, &NSModeOnID}}},
+ {"NSForceEmail", {{PARAM_SET, PARAM_RELOAD, &NSForceEmail}}},
+ {"NSGuestNickPrefix",
+ {{PARAM_STRING, PARAM_RELOAD, &NSGuestNickPrefix}}},
+ {"NSListMax", {{PARAM_POSINT, PARAM_RELOAD, &NSListMax}}},
+ {"NSListOpersOnly", {{PARAM_SET, PARAM_RELOAD, &NSListOpersOnly}}},
+ {"NSMaxAliases", {{PARAM_INT, PARAM_RELOAD, &NSMaxAliases}}},
+ {"NSNoGroupChange", {{PARAM_SET, PARAM_RELOAD, &NSNoGroupChange}}},
+ {"NSRegDelay", {{PARAM_TIME, PARAM_RELOAD, &NSRegDelay}}},
+ {"NSResendDelay", {{PARAM_TIME, PARAM_RELOAD, &NSResendDelay}}},
+ {"NSReleaseTimeout", {{PARAM_TIME, PARAM_RELOAD, &NSReleaseTimeout}}},
+ {"NSSecureAdmins", {{PARAM_SET, PARAM_RELOAD, &NSSecureAdmins}}},
+ {"NSStrictPrivileges",
+ {{PARAM_SET, PARAM_RELOAD, &NSStrictPrivileges}}},
+ {"NSRestrictGetPass", {{PARAM_SET, PARAM_RELOAD, &NSRestrictGetPass}}},
+ {"NSNickTracking", {{PARAM_SET, PARAM_RELOAD, &NSNickTracking}}},
+ {"NSAddAccessOnReg", {{PARAM_SET, PARAM_RELOAD, &NSAddAccessOnReg}}},
+ {"OperCoreModules", {{PARAM_STRING, PARAM_RELOAD, &OperCoreModules}}},
+ {"OperServDB", {{PARAM_STRING, PARAM_RELOAD, &OperDBName}}},
+ {"OperServName", {{PARAM_STRING, 0, &s_OperServ},
+ {PARAM_STRING, 0, &desc_OperServ}}},
+ {"OperServAlias", {{PARAM_STRING, 0, &s_OperServAlias},
+ {PARAM_STRING, 0, &desc_OperServAlias}}},
+ {"PIDFile", {{PARAM_STRING, 0, &PIDFilename}}},
+ {"ReadTimeout", {{PARAM_TIME, PARAM_RELOAD, &ReadTimeout}}},
+ {"RemoteServer", {{PARAM_STRING, 0, &RemoteServer},
+ {PARAM_PORT, 0, &RemotePort},
+ {PARAM_STRING, 0, &RemotePassword}}},
+ {"RemoteServer2", {{PARAM_STRING, 0, &RemoteServer2},
+ {PARAM_PORT, 0, &RemotePort2},
+ {PARAM_STRING, 0, &RemotePassword2}}},
+ {"RemoteServer3", {{PARAM_STRING, 0, &RemoteServer3},
+ {PARAM_PORT, 0, &RemotePort3},
+ {PARAM_STRING, 0, &RemotePassword3}}},
+ {"RestrictMail", {{PARAM_SET, PARAM_RELOAD, &RestrictMail}}},
+ {"RestrictOperNicks", {{PARAM_SET, PARAM_RELOAD, &RestrictOperNicks}}},
+ {"SendMailPath", {{PARAM_STRING, PARAM_RELOAD, &SendMailPath}}},
+ {"SendFrom", {{PARAM_STRING, PARAM_RELOAD, &SendFrom}}},
+ {"ServerDesc", {{PARAM_STRING, 0, &ServerDesc}}},
+ {"ServerName", {{PARAM_STRING, 0, &ServerName}}},
+ {"ServicesRoot", {{PARAM_STRING, PARAM_RELOAD, &ServicesRoot}}},
+ {"ServiceUser", {{PARAM_STRING, 0, &temp_userhost}}},
+ {"SessionLimitDetailsLoc",
+ {{PARAM_STRING, PARAM_RELOAD, &SessionLimitDetailsLoc}}},
+ {"OSOpersOnly", {{PARAM_SET, PARAM_RELOAD, &OSOpersOnly}}},
+ {"SessionLimitExceeded",
+ {{PARAM_STRING, PARAM_RELOAD, &SessionLimitExceeded}}},
+ {"SessionAutoKillExpiry",
+ {{PARAM_TIME, PARAM_RELOAD, &SessionAutoKillExpiry}}},
+ {"SGLineExpiry", {{PARAM_TIME, PARAM_RELOAD, &SGLineExpiry}}},
+ {"SQLineExpiry", {{PARAM_TIME, PARAM_RELOAD, &SQLineExpiry}}},
+ {"SZLineExpiry", {{PARAM_TIME, PARAM_RELOAD, &SZLineExpiry}}},
+ {"HideStatsO", {{PARAM_SET, PARAM_RELOAD, &HideStatsO}}},
+ {"GlobalOnCycle", {{PARAM_SET, PARAM_RELOAD, &GlobalOnCycle}}},
+ {"AnonymousGlobal", {{PARAM_SET, PARAM_RELOAD, &AnonymousGlobal}}},
+ {"GlobalOnCycleMessage",
+ {{PARAM_STRING, PARAM_RELOAD, &GlobalOnCycleMessage}}},
+ {"GlobalOnCycleUP", {{PARAM_STRING, PARAM_RELOAD, &GlobalOnCycleUP}}},
+ {"StrictPasswords", {{PARAM_SET, PARAM_RELOAD, &StrictPasswords}}},
+ {"TimeoutCheck", {{PARAM_TIME, PARAM_RELOAD, &TimeoutCheck}}},
+ {"UpdateTimeout", {{PARAM_TIME, PARAM_RELOAD, &UpdateTimeout}}},
+ {"UseMail", {{PARAM_SET, PARAM_RELOAD, &UseMail}}},
+ {"UsePrivmsg", {{PARAM_SET, PARAM_RELOAD, &UsePrivmsg}}},
+ {"UseStrictPrivMsg", {{PARAM_SET, PARAM_RELOAD, &UseStrictPrivMsg}}},
+ {"UserKey1", {{PARAM_POSINT, PARAM_RELOAD, &UserKey1}}},
+ {"UserKey2", {{PARAM_POSINT, PARAM_RELOAD, &UserKey2}}},
+ {"UserKey3", {{PARAM_POSINT, PARAM_RELOAD, &UserKey3}}},
+ {"UseSVSHOLD", {{PARAM_SET, PARAM_RELOAD, &UseSVSHOLD}}},
+ {"UseSVS2MODE", {{PARAM_SET, PARAM_RELOAD, &UseSVS2MODE}}},
+ {"UseTokens", {{PARAM_SET, 0, &UseTokens}}},
+ {"UseTS6", {{PARAM_SET, 0, &UseTS6}}},
+ {"UnRestrictSAdmin", {{PARAM_SET, PARAM_RELOAD, &UnRestrictSAdmin}}},
+ {"WallAkillExpire", {{PARAM_SET, PARAM_RELOAD, &WallAkillExpire}}},
+ {"WallBadOS", {{PARAM_SET, PARAM_RELOAD, &WallBadOS}}},
+ {"WallDrop", {{PARAM_SET, PARAM_RELOAD, &WallDrop}}},
+ {"WallExceptionExpire",
+ {{PARAM_SET, PARAM_RELOAD, &WallExceptionExpire}}},
+ {"WallForbid", {{PARAM_SET, PARAM_RELOAD, &WallForbid}}},
+ {"WallGetpass", {{PARAM_SET, PARAM_RELOAD, &WallGetpass}}},
+ {"WallOper", {{PARAM_SET, PARAM_RELOAD, &WallOper}}},
+ {"WallOSAkill", {{PARAM_SET, PARAM_RELOAD, &WallOSAkill}}},
+ {"WallOSClearmodes", {{PARAM_SET, PARAM_RELOAD, &WallOSClearmodes}}},
+ {"WallOSGlobal", {{PARAM_SET, PARAM_RELOAD, &WallOSGlobal}}},
+ {"WallOSKick", {{PARAM_SET, PARAM_RELOAD, &WallOSKick}}},
+ {"WallOSJupe", {{PARAM_SET, PARAM_RELOAD, &WallOSJupe}}},
+ {"WallOSMode", {{PARAM_SET, PARAM_RELOAD, &WallOSMode}}},
+ {"WallOSNoOp", {{PARAM_SET, PARAM_RELOAD, &WallOSNoOp}}},
+ {"WallOSRaw", {{PARAM_SET, PARAM_RELOAD, &WallOSRaw}}},
+ {"WallOSSGLine", {{PARAM_SET, PARAM_RELOAD, &WallOSSGLine}}},
+ {"WallOSSQLine", {{PARAM_SET, PARAM_RELOAD, &WallOSSQLine}}},
+ {"WallOSSZLine", {{PARAM_SET, PARAM_RELOAD, &WallOSSZLine}}},
+ {"WallSetpass", {{PARAM_SET, PARAM_RELOAD, &WallSetpass}}},
+ {"WallSGLineExpire", {{PARAM_SET, PARAM_RELOAD, &WallSGLineExpire}}},
+ {"WallSQLineExpire", {{PARAM_SET, PARAM_RELOAD, &WallSQLineExpire}}},
+ {"WallSZLineExpire", {{PARAM_SET, PARAM_RELOAD, &WallSZLineExpire}}},
+ {"WarningTimeout", {{PARAM_TIME, PARAM_RELOAD, &WarningTimeout}}},
+ {"GlobalOnDefcon", {{PARAM_SET, PARAM_RELOAD, &GlobalOnDefcon}}},
+ {"GlobalOnDefconMore",
+ {{PARAM_SET, PARAM_RELOAD, &GlobalOnDefconMore}}},
+ {"DefconMessage", {{PARAM_STRING, PARAM_RELOAD, &DefconMessage}}},
+ {"UlineServers", {{PARAM_STRING, PARAM_RELOAD, &UlineServers}}},
+};
+
+/*************************************************************************/
+
+/* Print an error message to the log (and the console, if open). */
+
+void error(int linenum, const char *message, ...)
+{
+ char buf[4096];
+ va_list args;
+
+ va_start(args, message);
+ vsnprintf(buf, sizeof(buf), message, args);
+ va_end(args);
+
+#ifndef NOT_MAIN
+ if (linenum)
+ alog("%s:%d: %s", SERVICES_CONF, linenum, buf);
+ else
+ alog("%s: %s", SERVICES_CONF, buf);
+ if (!nofork && isatty(2)) {
+#endif
+ if (linenum)
+ fprintf(stderr, "%s:%d: %s\n", SERVICES_CONF, linenum, buf);
+ else
+ fprintf(stderr, "%s: %s\n", SERVICES_CONF, buf);
+#ifndef NOT_MAIN
+ }
+#endif
+}
+
+/*************************************************************************/
+
+/* Parse a configuration line. Return 1 on success; otherwise, print an
+ * appropriate error message and return 0. Destroys the buffer by side
+ * effect.
+ */
+
+int parse_directive(Directive * d, char *dir, int ac, char *av[MAXPARAMS],
+ int linenum, int reload, char *s)
+{
+ int retval = 1;
+ int i;
+ long val;
+ int optind;
+
+ if (stricmp(dir, d->name) != 0)
+ return 1;
+ optind = 0;
+ for (i = 0; i < MAXPARAMS && d->params[i].type != PARAM_NONE; i++) {
+ if (reload && !(d->params[i].flags & PARAM_RELOAD))
+ continue;
+
+ if (d->params[i].type == PARAM_SET) {
+ *(int *) d->params[i].ptr = 1;
+ continue;
+ }
+#ifdef STREAMLINED
+ if (d->params[i].flags & PARAM_FULLONLY) {
+ error(linenum,
+ "Directive `%s' not available in STREAMLINED mode",
+ d->name);
+ break;
+ }
+#endif
+
+ /* Should we remove PARAM_DEPRECATED because it's
+ * useless right now? -GD */
+ if (d->params[i].type == PARAM_DEPRECATED) {
+ void (*func) (void);
+ error(linenum, "Deprecated directive `%s' used", d->name);
+ func = (void (*)(void)) (d->params[i].ptr);
+ func(); /* For clarity */
+ continue;
+ }
+ if (optind >= ac) {
+ if (!(d->params[i].flags & PARAM_OPTIONAL)) {
+ error(linenum, "Not enough parameters for `%s'", d->name);
+ retval = 0;
+ }
+ break;
+ }
+ switch (d->params[i].type) {
+ case PARAM_INT:
+ val = strtol(av[optind++], &s, 0);
+ if (*s) {
+ error(linenum,
+ "%s: Expected an integer for parameter %d",
+ d->name, optind);
+ retval = 0;
+ break;
+ }
+ *(int *) d->params[i].ptr = val;
+ break;
+ case PARAM_POSINT:
+ val = strtol(av[optind++], &s, 0);
+ if (*s || val <= 0) {
+ error(linenum,
+ "%s: Expected a positive integer for parameter %d",
+ d->name, optind);
+ retval = 0;
+ break;
+ }
+ if (errno == ERANGE && val == LONG_MAX) {
+ /* well the true top off is 2,147,483,647 but lets not give them the real top */
+ error(linenum,
+ "%s: paramter %d is to large, reduce this value (0 to 2,147,483,646)",
+ d->name, optind);
+ }
+ *(int *) d->params[i].ptr = val;
+ break;
+ case PARAM_PORT:
+ val = strtol(av[optind++], &s, 0);
+ if (*s) {
+ error(linenum,
+ "%s: Expected a port number for parameter %d",
+ d->name, optind);
+ retval = 0;
+ break;
+ }
+ if (val < 1 || val > 65535) {
+ error(linenum,
+ "Port numbers must be in the range 1..65535");
+ retval = 0;
+ break;
+ }
+ *(int *) d->params[i].ptr = val;
+ break;
+ case PARAM_STRING:
+/* if (reload && *(char **)d->params[i].ptr)
+ free(*(char **)d->params[i].ptr); */
+ *(char **) d->params[i].ptr = sstrdup(av[optind++]);
+ if (!d->params[i].ptr) {
+ error(linenum, "%s: Out of memory", d->name);
+ return 0;
+ }
+ break;
+ case PARAM_TIME:
+ val = dotime(av[optind++]);
+ if (val < 0) {
+ error(linenum,
+ "%s: Expected a time value for parameter %d",
+ d->name, optind);
+ retval = 0;
+ break;
+ }
+ *(int *) d->params[i].ptr = val;
+ break;
+ default:
+ error(linenum, "%s: Unknown type %d for param %d",
+ d->name, d->params[i].type, i + 1);
+ retval = 0; /* don't bother continuing--something's bizarre */
+ break;
+ }
+ }
+ return retval;;
+}
+
+
+int parse(char *buf, int linenum, int reload)
+{
+ char *s, *t, *dir;
+ int n;
+ int retval = 1;
+ int ac = 0;
+ char *av[MAXPARAMS];
+
+ dir = strtok(buf, " \t\r\n");
+ s = strtok(NULL, "");
+ if (s) {
+ while (isspace(*s))
+ s++;
+ while (*s) {
+ if (ac >= MAXPARAMS) {
+ error(linenum, "Warning: too many parameters (%d max)",
+ MAXPARAMS);
+ break;
+ }
+ t = s;
+ if (*s == '"') {
+ t++;
+ s++;
+ while (*s && *s != '"') {
+ if (*s == '\\' && s[1] != 0)
+ s++;
+ s++;
+ }
+ if (!*s)
+ error(linenum,
+ "Warning: unterminated double-quoted string");
+ else
+ *s++ = 0;
+ } else {
+ s += strcspn(s, " \t\r\n");
+ if (*s)
+ *s++ = 0;
+ }
+ av[ac++] = t;
+ while (isspace(*s))
+ s++;
+ }
+ }
+
+ if (!dir)
+ return 1;
+
+ for (n = 0; n < lenof(directives); n++) {
+ Directive *d = &directives[n];
+ retval = parse_directive(d, dir, ac, av, linenum, reload, s);
+ if (!retval) {
+ break;
+ }
+ }
+
+ return retval;
+}
+
+
+/*************************************************************************/
+
+#define CHECK(v) do { \
+ if (!v) { \
+ error(0, #v " missing"); \
+ retval = 0; \
+ } \
+} while (0)
+
+#define CHEK2(v,n) do { \
+ if (!v) { \
+ error(0, #n " missing"); \
+ retval = 0; \
+ } \
+} while (0)
+
+/* Read the entire configuration file. If an error occurs while reading
+ * the file or a required directive is not found, print and log an
+ * appropriate error message and return 0; otherwise, return 1.
+ *
+ * If reload is 1, will reload the configuration file.
+ * --lara
+ *
+ */
+
+int read_config(int reload)
+{
+ FILE *config;
+ int linenum = 0, retval = 1;
+ char buf[1024], *s;
+ int defconCount = 0;
+
+ if (reload) {
+ int i, n;
+
+ /* Reset all the reloadable settings */
+
+ for (n = 0; n < lenof(directives); n++) {
+ Directive *d = &directives[n];
+
+ for (i = 0; i < MAXPARAMS && d->params[i].type != PARAM_NONE;
+ i++) {
+ if (!(d->params[i].flags & PARAM_RELOAD))
+ continue;
+
+ if (d->params[i].type == PARAM_SET
+ || d->params[i].type == PARAM_INT
+ || d->params[i].type == PARAM_POSINT
+ || d->params[i].type == PARAM_TIME) {
+ *(int *) d->params[i].ptr = 0;
+ } else if (d->params[i].type == PARAM_STRING) {
+ if (*(char **) d->params[i].ptr)
+ free(*(char **) d->params[i].ptr);
+ (*(char **) d->params[i].ptr) = NULL;
+ }
+ }
+ }
+ }
+
+ config = fopen(SERVICES_CONF, "r");
+ if (!config) {
+#ifndef NOT_MAIN
+ log_perror("Can't open " SERVICES_CONF);
+ if (!nofork && isatty(2)) {
+#endif
+ if (!reload)
+ perror("Can't open " SERVICES_CONF);
+ else
+ alog("Can't open %s", SERVICES_CONF);
+ }
+ return 0;
+ }
+ while (fgets(buf, sizeof(buf), config)) {
+ linenum++;
+ if (*buf == '#' || *buf == '\r' || *buf == '\n')
+ continue;
+ if (!parse(buf, linenum, reload))
+ retval = 0;
+ }
+ fclose(config);
+
+ if (!reload) {
+ CHECK(RemoteServer);
+ CHECK(ServerName);
+ CHECK(ServerDesc);
+
+ if (RemoteServer3)
+ CHECK(RemoteServer2);
+
+ if (LocalHost && RemoteServer) {
+ if ((!stricmp(LocalHost, RemoteServer))
+ && LocalPort == RemotePort) {
+ printf
+ ("\n*** LocalAddress and RemoteServer are set to use the same IP address\n"
+ "*** (%s) and port (%d). This would have resulted in errors.\n"
+ "*** Change the LocalAddress to bind to another port.\n",
+ RemoteServer, LocalPort);
+ retval = 0;
+ }
+ }
+
+ if (NickLen == 0) {
+ alog("You have not defined the NickLen configuration directive. It is strongly");
+ alog("advised that you do configure this correctly in your services.conf");
+ NickLen = NICKMAX - 1;
+ } else if ((NickLen < 1) || (NickLen >= NICKMAX)) {
+ alog("NickLen has an invalid value; setting to %d",
+ (NICKMAX - 1));
+ NickLen = NICKMAX - 1;
+ }
+ }
+
+ CHECK(IRCDModule);
+ CHECK(EncModule);
+
+ CHECK(NetworkName);
+ if (!reload) {
+ CHEK2(temp_userhost, ServiceUser);
+ CHEK2(s_NickServ, NickServName);
+ CHEK2(s_ChanServ, ChanServName);
+ CHEK2(s_MemoServ, MemoServName);
+ CHEK2(s_HelpServ, HelpServName);
+ CHEK2(s_OperServ, OperServName);
+ CHEK2(s_GlobalNoticer, GlobalName);
+ CHEK2(PIDFilename, PIDFile);
+ }
+
+ if (s_ChanServAlias) {
+ if (!stricmp(s_ChanServ, s_ChanServAlias)) {
+ printf
+ ("\n*** ChanServ and ChanServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+ if (s_NickServAlias) {
+ if (!stricmp(s_NickServ, s_NickServAlias)) {
+ printf
+ ("\n*** NickServ and NickServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+ if (s_OperServAlias) {
+ if (!stricmp(s_OperServ, s_OperServAlias)) {
+ printf
+ ("\n*** OperServ and OperServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+ if (s_MemoServAlias) {
+ if (!stricmp(s_MemoServ, s_MemoServAlias)) {
+ printf
+ ("\n*** MemoServ and MemoServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+ if (s_HelpServAlias) {
+ if (!stricmp(s_HelpServ, s_HelpServAlias)) {
+ printf
+ ("\n*** HelpServ and HelpServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+ if (s_GlobalNoticerAlias) {
+ if (!stricmp(s_GlobalNoticer, s_GlobalNoticerAlias)) {
+ printf
+ ("\n*** GlobalNoticer and GlobalNoticer Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+
+
+ CHEK2(MOTDFilename, MOTDFile);
+ if (!reload) {
+ CHEK2(NickDBName, NickServDB);
+ CHEK2(ChanDBName, ChanServDB);
+ CHEK2(OperDBName, OperServDB);
+ CHEK2(NewsDBName, NewsDB);
+ CHEK2(ExceptionDBName, ExceptionDB);
+ }
+ CHECK(UpdateTimeout);
+ CHECK(ExpireTimeout);
+ CHECK(ReadTimeout);
+ CHECK(WarningTimeout);
+ CHECK(TimeoutCheck);
+ CHECK(NSAccessMax);
+ CHEK2(temp_nsuserhost, NSEnforcerUser);
+ CHECK(NSReleaseTimeout);
+ CHECK(NSListMax);
+ CHECK(CSAccessMax);
+ CHECK(CSAutokickMax);
+ CHECK(CSAutokickReason);
+ CHECK(CSInhabit);
+ CHECK(CSListMax);
+ CHECK(ServicesRoot);
+ CHECK(AutokillExpiry);
+ CHECK(ChankillExpiry);
+ CHECK(SGLineExpiry);
+ CHECK(SQLineExpiry);
+ CHECK(SZLineExpiry);
+
+ if (!reload) {
+
+ if (temp_userhost) {
+ if (!(s = strchr(temp_userhost, '@'))) {
+ error(0, "Missing `@' for ServiceUser");
+ } else {
+ *s++ = 0;
+ ServiceUser = temp_userhost;
+ ServiceHost = s;
+ }
+ }
+
+ }
+
+ if (temp_nsuserhost) {
+ if (!(s = strchr(temp_nsuserhost, '@'))) {
+ NSEnforcerUser = temp_nsuserhost;
+ NSEnforcerHost = ServiceHost;
+ } else {
+ *s++ = 0;
+ NSEnforcerUser = temp_nsuserhost;
+ NSEnforcerHost = s;
+ }
+ }
+
+ if (!NSDefNone &&
+ !NSDefKill &&
+ !NSDefKillQuick &&
+ !NSDefSecure &&
+ !NSDefPrivate &&
+ !NSDefHideEmail &&
+ !NSDefHideUsermask &&
+ !NSDefHideQuit && !NSDefMemoSignon && !NSDefMemoReceive) {
+ NSDefSecure = 1;
+ NSDefMemoSignon = 1;
+ NSDefMemoReceive = 1;
+ }
+
+ NSDefFlags = 0;
+ if (!NSDefNone) {
+ if (NSDefKill)
+ NSDefFlags |= NI_KILLPROTECT;
+ if (NSDefKillQuick)
+ NSDefFlags |= NI_KILL_QUICK;
+ if (NSDefSecure)
+ NSDefFlags |= NI_SECURE;
+ if (NSDefPrivate)
+ NSDefFlags |= NI_PRIVATE;
+ if (NSDefMsg) {
+ if (!UsePrivmsg)
+ alog("NSDefMsg can only be used when UsePrivmsg is set - unsetting NSDefMsg");
+ else
+ NSDefFlags |= NI_MSG;
+ }
+ if (NSDefHideEmail)
+ NSDefFlags |= NI_HIDE_EMAIL;
+ if (NSDefHideUsermask)
+ NSDefFlags |= NI_HIDE_MASK;
+ if (NSDefHideQuit)
+ NSDefFlags |= NI_HIDE_QUIT;
+ if (NSDefMemoSignon)
+ NSDefFlags |= NI_MEMO_SIGNON;
+ if (NSDefMemoReceive)
+ NSDefFlags |= NI_MEMO_RECEIVE;
+ if (!NSDefAutoop)
+ NSDefFlags |= NI_AUTOOP;
+ }
+
+ if (!ServicesRoot) {
+ error(0,
+ "You must define the 'ServicesRoot' configuration directive");
+ error(0,
+ "in your services.conf file. This is a required setting that");
+ error(0,
+ "defines the main Administrative nick(s) Anope will obey.");
+ retval = 0;
+ }
+
+ CHECK(NSGuestNickPrefix); /* Add safety check */
+ if (NSGuestNickPrefix && (strlen(NSGuestNickPrefix) > 21)) {
+ error(0, "Value of NSGuestNickPrefix must be between 1 and 21");
+ retval = 0;
+ }
+
+ CHECK(NSDefLanguage);
+ if (NSDefLanguage) {
+ NSDefLanguage--;
+ if (NSDefLanguage < 0 || NSDefLanguage >= NUM_LANGS) {
+ error(0, "Value of NSDefLanguage must be between 1 and %d",
+ USED_LANGS);
+ retval = 0;
+ }
+ }
+
+ if (!NewsCount) {
+ NewsCount = 3;
+ }
+
+ if (reload) {
+ if ((NSDefLanguage = langlist[NSDefLanguage]) < 0)
+ NSDefLanguage = DEF_LANGUAGE;
+ }
+
+ if (CSDefBantype < 0 || CSDefBantype > 3) {
+ error(0, "Value of CSDefBantype must be between 0 and 3 included");
+ retval = 0;
+ }
+
+ if (!MysqlRetries || !MysqlRetryGap) {
+ MysqlRetries = 5;
+ MysqlRetryGap = 1;
+ } else if (((MysqlRetries * MysqlRetryGap) > 60)
+ || ((MysqlRetries * MysqlRetryGap) < 1)) {
+ error(0,
+ "MysqlRetries * MysqlRetryGap must be between 1 and 60, using standard values.");
+ MysqlRetries = 5;
+ MysqlRetryGap = 1;
+ }
+
+ if (!CSDefNone &&
+ !CSDefKeepTopic &&
+ !CSDefTopicLock &&
+ !CSDefPrivate &&
+ !CSDefRestricted &&
+ !CSDefSecure &&
+ !CSDefSecureOps &&
+ !CSDefSecureFounder &&
+ !CSDefSignKick && !CSDefSignKickLevel && !CSDefOpNotice) {
+ CSDefKeepTopic = 1;
+ CSDefSecure = 1;
+ CSDefSecureFounder = 1;
+ CSDefSignKick = 1;
+ }
+
+ CSDefFlags = 0;
+ if (!CSDefNone) {
+ if (CSDefKeepTopic)
+ CSDefFlags |= CI_KEEPTOPIC;
+ if (CSDefTopicLock)
+ CSDefFlags |= CI_TOPICLOCK;
+ if (CSDefPrivate)
+ CSDefFlags |= CI_PRIVATE;
+ if (CSDefRestricted)
+ CSDefFlags |= CI_RESTRICTED;
+ if (CSDefSecure)
+ CSDefFlags |= CI_SECURE;
+ if (CSDefSecureOps)
+ CSDefFlags |= CI_SECUREOPS;
+ if (CSDefSecureFounder)
+ CSDefFlags |= CI_SECUREFOUNDER;
+ if (CSDefSignKick)
+ CSDefFlags |= CI_SIGNKICK;
+ if (CSDefSignKickLevel)
+ CSDefFlags |= CI_SIGNKICK_LEVEL;
+ if (CSDefOpNotice)
+ CSDefFlags |= CI_OPNOTICE;
+ if (CSDefXOP)
+ CSDefFlags |= CI_XOP;
+ if (CSDefPeace)
+ CSDefFlags |= CI_PEACE;
+ }
+
+ BSDefFlags = 0;
+ if (BSDefDontKickOps)
+ BSDefFlags |= BS_DONTKICKOPS;
+ if (BSDefDontKickVoices)
+ BSDefFlags |= BS_DONTKICKVOICES;
+ if (BSDefGreet)
+ BSDefFlags |= BS_GREET;
+ if (BSDefFantasy)
+ BSDefFlags |= BS_FANTASY;
+ if (BSDefSymbiosis)
+ BSDefFlags |= BS_SYMBIOSIS;
+
+ /* Services Root building */
+
+ if (ServicesRoot && !reload) { /* Check to prevent segmentation fault if it's missing */
+ RootNumber = 0;
+
+ s = strtok(ServicesRoot, " ");
+ do {
+ if (s) {
+ RootNumber++;
+ ServicesRoots =
+ realloc(ServicesRoots, sizeof(char *) * RootNumber);
+ ServicesRoots[RootNumber - 1] = sstrdup(s);
+ }
+ } while ((s = strtok(NULL, " ")));
+ }
+
+ if (!RootNumber) {
+ error(0, "No ServicesRoot defined");
+ retval = 0;
+ }
+
+ /* Ulines */
+
+ if (UlineServers) {
+ NumUlines = 0;
+
+ s = strtok(UlineServers, " ");
+ do {
+ if (s) {
+ NumUlines++;
+ Ulines = realloc(Ulines, sizeof(char *) * NumUlines);
+ Ulines[NumUlines - 1] = sstrdup(s);
+ }
+ } while ((s = strtok(NULL, " ")));
+ }
+
+ /* Host Setters building... :P */
+ HostSetters = buildStringList(HostSetter, &HostNumber);
+
+ /* Modules Autoload building... :P */
+ ModulesAutoload = buildStringList(Modules, &ModulesNumber);
+ ModulesDelayedAutoload =
+ buildStringList(ModulesDelayed, &ModulesDelayedNumber);
+ HostServCoreModules =
+ buildStringList(HostCoreModules, &HostServCoreNumber);
+ MemoServCoreModules =
+ buildStringList(MemoCoreModules, &MemoServCoreNumber);
+ HelpServCoreModules =
+ buildStringList(HelpCoreModules, &HelpServCoreNumber);
+
+ BotServCoreModules =
+ buildStringList(BotCoreModules, &BotServCoreNumber);
+
+ OperServCoreModules =
+ buildStringList(OperCoreModules, &OperServCoreNumber);
+
+ ChanServCoreModules =
+ buildStringList(ChanCoreModules, &ChanServCoreNumber);
+
+ NickServCoreModules =
+ buildStringList(NickCoreModules, &NickServCoreNumber);
+
+
+ if (LimitSessions) {
+ CHECK(DefSessionLimit);
+ CHECK(MaxSessionLimit);
+ CHECK(ExceptionExpiry);
+
+ if (MaxSessionKill && !SessionAutoKillExpiry)
+ SessionAutoKillExpiry = 30 * 60; /* 30 minutes */
+ }
+
+ if (s_BotServ) {
+ CHEK2(BotDBName, BotServDB);
+ CHECK(BSBadWordsMax);
+ CHECK(BSMinUsers);
+ CHECK(BSKeepData);
+ if (s_BotServAlias) {
+ if (!stricmp(s_BotServ, s_BotServAlias)) {
+ printf
+ ("\n*** BotServ and BotServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+ if (!BSFantasyCharacter)
+ BSFantasyCharacter = sstrdup("!");
+ if (BSFantasyCharacter && (strlen(BSFantasyCharacter) > 1)) {
+ printf
+ ("*** BSFantasyCharacter is more than 1 character long. Only the first\n"
+ "*** character ('%c') will be used. The others will be ignored.\n",
+ *BSFantasyCharacter);
+ }
+ }
+
+ if (s_HostServ) {
+ CHEK2(s_HostServ, HostServName);
+ CHEK2(HostDBName, HostServDB);
+
+ if (s_HostServAlias) {
+ if (!stricmp(s_HostServ, s_HostServAlias)) {
+ printf
+ ("\n*** HostServ and HostServ Alias are the same, this will cause errors\n");
+ retval = 0;
+ }
+ }
+ }
+
+ if (UseMail) {
+ CHECK(SendMailPath);
+ CHECK(SendFrom);
+ }
+
+ if (GlobalOnCycle) {
+ if (!GlobalOnCycleMessage && !GlobalOnCycleUP) {
+ alog("GlobalOnCycleMessage and GlobalOnCycleUP are not defined; disabling GlobalOnCycle");
+ GlobalOnCycle = 0;
+ }
+ }
+
+ /* Check the user keys */
+ if ((UserKey1 == UserKey2) || (UserKey1 == UserKey3)
+ || (UserKey3 == UserKey2))
+ alog("Every UserKey must be different. It's for YOUR safety! Remember that!");
+
+ /**
+ * Check all DEFCON dependiencies...
+ **/
+ if (DefConLevel) {
+ CHECK(DefCon1);
+ CHECK(DefCon2);
+ CHECK(DefCon3);
+ CHECK(DefCon4);
+ DefCon5 = 0; /* ALWAYS have defcon 5 as normal operation */
+ /* Build DefCon's */
+ DefCon[0] = 0;
+ DefCon[1] = DefCon1;
+ DefCon[2] = DefCon2;
+ DefCon[3] = DefCon3;
+ DefCon[4] = DefCon4;
+ DefCon[5] = DefCon5;
+ for (defconCount = 1; defconCount <= 5; defconCount++) { /* Check any defcon needed settings */
+ if (DefCon[defconCount] & DEFCON_REDUCE_SESSION) {
+ CHECK(DefConSessionLimit);
+ }
+ if (DefCon[defconCount] & DEFCON_AKILL_NEW_CLIENTS) {
+ CHECK(DefConAKILL);
+ CHECK(DefConAkillReason);
+ }
+ if (DefCon[defconCount] & DEFCON_FORCE_CHAN_MODES) {
+ CHECK(DefConChanModes);
+ }
+ }
+ if (GlobalOnDefconMore)
+ CHECK(DefconMessage);
+ }
+
+ /**
+ * If they try to enable any email registration option,
+ * make sure they have everything else they need too...
+ *
+ * rob
+ **/
+ if (NSEmailReg) {
+ CHEK2(PreNickDBName, PreNickServDB);
+ CHECK(NSEmailReg);
+ CHECK(NSRExpire);
+ CHECK(UseMail);
+ CHECK(NSForceEmail);
+ } else {
+ PreNickDBName = NULL;
+ NSRExpire = 0;
+ }
+
+ if (!retval) {
+ printf
+ ("\n*** Support resources: Read through the services.conf self-contained \n*** documentation. Read the documentation files found in the 'docs' \n*** folder. Visit our portal located at http://www.anope.org/. Join \n*** our support channel on /server irc.anope.org channel #anope.\n\n");
+ }
+
+ return retval;
+}
+
+
+/*************************************************************************/
diff --git a/src/core/Makefile b/src/core/Makefile
new file mode 100644
index 000000000..4ec275430
--- /dev/null
+++ b/src/core/Makefile
@@ -0,0 +1,45 @@
+include ./Makefile.inc
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: modules subs
+
+modules: $(OBJECTS) $(SO_FILES)
+
+install:
+ $(CP) ./*.so $(MODULE_PATH)
+
+distclean: spotless
+
+.c.o:
+ $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../${INCLUDEDIR} -c $<
+
+.o.s:
+ $(CC) ${SHARED} ../mod_version.o $< -o $*.so ${PROFILE}
+ @$(TOUCH) $*.s
+
+subs:
+ @for i in $(SUBS); do \
+ echo "make all in $$i..."; \
+ (cd $$i; $(MAKE) $(MAKEARGS) all); done
+
+subs_clean:
+ @for i in $(SUBS); do \
+ echo "cleaning in $$i..."; \
+ (cd $$i; $(MAKE) clean); done
+
+clean: subs_clean
+ rm -f *.o *.s *.so *.c~ core
+
+spotless: subs_clean
+ rm -f *.o *.s *.so *.c~ core Makefile.inc
+
diff --git a/src/core/Makefile.sub b/src/core/Makefile.sub
new file mode 100644
index 000000000..9fbadf3b0
--- /dev/null
+++ b/src/core/Makefile.sub
@@ -0,0 +1,29 @@
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: module
+
+module: $(OBJECTS) so
+
+distclean: spotless
+
+.c.o:
+ $(CC) $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../ -I../../${INCLUDEDIR} -c $<
+
+so:
+ $(CC) ${SHARED} $(OBJECTS) -o ../$(TARGET).so ${PROFILE}
+
+clean:
+ rm -f *.o *.so *.c~ core
+
+spotless: clean
+ rm -f *~ *.o *.so *.c~ core
+
diff --git a/src/core/Makefile.win32 b/src/core/Makefile.win32
new file mode 100644
index 000000000..1c05bb42b
--- /dev/null
+++ b/src/core/Makefile.win32
@@ -0,0 +1,24 @@
+include ../../Makefile.inc.win32
+
+SRCS=bs_act.c bs_assign.c bs_badwords.c bs_bot.c bs_botlist.c bs_fantasy.c bs_fantasy_kick.c bs_fantasy_kickban.c bs_fantasy_owner.c bs_fantasy_seen.c bs_help.c bs_info.c bs_kick.c bs_say.c bs_set.c bs_unassign.c cs_access.c cs_akick.c cs_ban.c cs_clear.c cs_drop.c cs_forbid.c cs_getkey.c cs_getpass.c cs_help.c cs_identify.c cs_info.c cs_invite.c cs_kick.c cs_list.c cs_logout.c cs_modes.c cs_register.c cs_sendpass.c cs_set.c cs_status.c cs_suspend.c cs_topic.c cs_xop.c enc_none.c enc_md5.c enc_old.c enc_sha1.c he_help.c hs_del.c hs_delall.c hs_group.c hs_help.c hs_list.c hs_off.c hs_on.c hs_set.c hs_setall.c ms_cancel.c ms_check.c ms_del.c ms_help.c ms_info.c ms_list.c ms_read.c ms_rsend.c ms_send.c ms_sendall.c ms_set.c ms_staff.c ns_access.c ns_alist.c ns_drop.c ns_forbid.c ns_getemail.c ns_getpass.c ns_ghost.c ns_group.c ns_help.c ns_identify.c ns_info.c ns_list.c ns_logout.c ns_recover.c ns_register.c ns_release.c ns_sendpass.c ns_set.c ns_saset.c ns_status.c ns_suspend.c ns_update.c os_admin.c os_akill.c os_chankill.c os_chanlist.c os_clearmodes.c os_defcon.c os_global.c os_help.c os_ignore.c os_jupe.c os_kick.c os_logonnews.c os_mode.c os_modinfo.c os_modlist.c os_modload.c os_modunload.c os_noop.c os_oline.c os_oper.c os_opernews.c os_quit.c os_randomnews.c os_raw.c os_reload.c os_restart.c os_session.c os_set.c os_sgline.c os_shutdown.c os_sqline.c os_staff.c os_stats.c os_svsnick.c os_szline.c os_umode.c os_update.c os_userlist.c
+OBJECTS= $(SRCS:.c=.dll)
+CFLAGS=/LD /MD /D MODULE_COMPILE $(CFLAGS) /I"../../include"
+LFLAGS=/link ../anope.lib wsock32.lib $(LIBS) $(LFLAGS) $(MYSQL_LIB_PATH) /export:AnopeInit /export:AnopeFini /VERSION:$(VERSION)
+
+all: $(OBJECTS)
+
+distclean: clean spotless
+
+.c.dll:
+ $(CC) $(CFLAGS) $< ..\mod_version.c $(LFLAGS)
+
+clean:
+ -@del *.obj
+
+spotless: clean
+ -@del *.dll *.lib *.exp *.manifest
+
+install:
+ -@mkdir ..\..\$(DATDEST)\modules
+ -@mkdir ..\..\$(DATDEST)\modules\runtime
+ -@copy *.dll ..\..\$(DATDEST)\modules
diff --git a/src/core/bs_act.c b/src/core/bs_act.c
new file mode 100644
index 000000000..1f92b7e42
--- /dev/null
+++ b/src/core/bs_act.c
@@ -0,0 +1,92 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_act(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("ACT", do_act, NULL, BOT_HELP_ACT, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_ACT);
+}
+
+/**
+ * The /bs act command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_act(User * u)
+{
+ ChannelInfo *ci;
+
+ char *chan = strtok(NULL, " ");
+ char *text = strtok(NULL, "");
+
+ if (!chan || !text)
+ syntax_error(s_BotServ, u, "ACT", BOT_ACT_SYNTAX);
+ else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if (!ci->bi)
+ notice_help(s_BotServ, u, BOT_NOT_ASSIGNED);
+ else if (!ci->c || ci->c->usercount < BSMinUsers)
+ notice_lang(s_BotServ, u, BOT_NOT_ON_CHANNEL, ci->name);
+ else if (!check_access(u, ci, CA_SAY))
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ else {
+ strnrepl(text, BUFSIZE, "\001", "");
+ anope_cmd_action(ci->bi->nick, ci->name, "%s", text);
+ ci->bi->lastmsg = time(NULL);
+ if (LogBot && LogChannel && logchan && !debug && findchan(LogChannel))
+ anope_cmd_privmsg(ci->bi->nick, LogChannel, "ACT %s %s %s",
+ u->nick, ci->name, text);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_assign.c b/src/core/bs_assign.c
new file mode 100644
index 000000000..e34ca7d81
--- /dev/null
+++ b/src/core/bs_assign.c
@@ -0,0 +1,102 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_assign(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("ASSIGN", do_assign, NULL, BOT_HELP_ASSIGN, -1, -1,
+ -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_ASSIGN);
+}
+
+/**
+ * The /bs assign command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_assign(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ BotInfo *bi;
+ ChannelInfo *ci;
+
+ if (readonly)
+ notice_lang(s_BotServ, u, BOT_ASSIGN_READONLY);
+ else if (!chan || !nick)
+ syntax_error(s_BotServ, u, "ASSIGN", BOT_ASSIGN_SYNTAX);
+ else if (!(bi = findbot(nick)))
+ notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
+ else if (bi->flags & BI_PRIVATE && !is_oper(u))
+ notice_lang(s_BotServ, u, PERMISSION_DENIED);
+ else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if ((ci->bi) && (stricmp(ci->bi->nick, nick) == 0))
+ notice_lang(s_BotServ, u, BOT_ASSIGN_ALREADY, ci->bi->nick, chan);
+ else if ((ci->botflags & BS_NOBOT)
+ || (!check_access(u, ci, CA_ASSIGN) && !is_services_admin(u)))
+ notice_lang(s_BotServ, u, PERMISSION_DENIED);
+ else {
+ if (ci->bi)
+ unassign(u, ci);
+ ci->bi = bi;
+ bi->chancount++;
+ if (ci->c && ci->c->usercount >= BSMinUsers) {
+ bot_join(ci);
+ }
+ notice_lang(s_BotServ, u, BOT_ASSIGN_ASSIGNED, bi->nick, ci->name);
+ send_event(EVENT_BOT_ASSIGN, 2, ci->name, bi->nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_badwords.c b/src/core/bs_badwords.c
new file mode 100644
index 000000000..3b5733f42
--- /dev/null
+++ b/src/core/bs_badwords.c
@@ -0,0 +1,326 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_badwords(User * u);
+void myBotServHelp(User * u);
+int badwords_del_callback(User * u, int num, va_list args);
+int badwords_list(User * u, int index, ChannelInfo * ci, int *sent_header);
+int badwords_list_callback(User * u, int num, va_list args);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("BADWORDS", do_badwords, NULL, BOT_HELP_BADWORDS, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_BADWORDS);
+}
+
+/**
+ * The /bs badwords command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_badwords(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *word = strtok(NULL, "");
+ ChannelInfo *ci;
+ BadWord *bw;
+
+ int i;
+ int need_args = (cmd
+ && (!stricmp(cmd, "LIST") || !stricmp(cmd, "CLEAR")));
+
+ if (!cmd || (need_args ? 0 : !word)) {
+ syntax_error(s_BotServ, u, "BADWORDS", BOT_BADWORDS_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!check_access(u, ci, CA_BADWORDS)
+ && (!need_args || !is_services_admin(u))) {
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ } else if (stricmp(cmd, "ADD") == 0) {
+
+ char *opt, *pos;
+ int type = BW_ANY;
+
+ if (readonly) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
+ return MOD_CONT;
+ }
+
+ pos = strrchr(word, ' ');
+ if (pos) {
+ opt = pos + 1;
+ if (*opt) {
+ if (!stricmp(opt, "SINGLE"))
+ type = BW_SINGLE;
+ else if (!stricmp(opt, "START"))
+ type = BW_START;
+ else if (!stricmp(opt, "END"))
+ type = BW_END;
+ if (type != BW_ANY)
+ *pos = 0;
+ }
+ }
+
+ for (bw = ci->badwords, i = 0; i < ci->bwcount; bw++, i++) {
+ if (bw->word && ((BSCaseSensitive && (!strcmp(bw->word, word)))
+ || (!BSCaseSensitive
+ && (!stricmp(bw->word, word))))) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_ALREADY_EXISTS,
+ bw->word, ci->name);
+ return MOD_CONT;
+ }
+ }
+
+ for (i = 0; i < ci->bwcount; i++) {
+ if (!ci->badwords[i].in_use)
+ break;
+ }
+ if (i == ci->bwcount) {
+ if (i < BSBadWordsMax) {
+ ci->bwcount++;
+ ci->badwords =
+ srealloc(ci->badwords, sizeof(BadWord) * ci->bwcount);
+ } else {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_REACHED_LIMIT,
+ BSBadWordsMax);
+ return MOD_CONT;
+ }
+ }
+ bw = &ci->badwords[i];
+ bw->in_use = 1;
+ bw->word = sstrdup(word);
+ bw->type = type;
+
+ notice_lang(s_BotServ, u, BOT_BADWORDS_ADDED, bw->word, ci->name);
+
+ } else if (stricmp(cmd, "DEL") == 0) {
+ int deleted = 0, a, b;
+
+ if (readonly) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
+ return MOD_CONT;
+ }
+
+ /* Special case: is it a number/list? Only do search if it isn't. */
+ if (isdigit(*word) && strspn(word, "1234567890,-") == strlen(word)) {
+ int count, last = -1;
+ deleted =
+ process_numlist(word, &count, badwords_del_callback, u, ci,
+ &last);
+ if (!deleted) {
+ if (count == 1) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_NO_SUCH_ENTRY,
+ last, ci->name);
+ } else {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_NO_MATCH,
+ ci->name);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED_ONE,
+ ci->name);
+ } else {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED_SEVERAL,
+ deleted, ci->name);
+ }
+ } else {
+ for (i = 0; i < ci->bwcount; i++) {
+ if (ci->badwords[i].in_use
+ && !stricmp(ci->badwords[i].word, word))
+ break;
+ }
+ if (i == ci->bwcount) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_NOT_FOUND, word,
+ chan);
+ return MOD_CONT;
+ }
+ bw = &ci->badwords[i];
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DELETED, bw->word,
+ ci->name);
+ if (bw->word)
+ free(bw->word);
+ bw->word = NULL;
+ bw->in_use = 0;
+ deleted = 1;
+ }
+
+ if (deleted) {
+ /* Reordering - DrStein */
+ for (b = 0; b < ci->bwcount; b++) {
+ if (ci->badwords[b].in_use) {
+ for (a = 0; a < ci->bwcount; a++) {
+ if (a > b)
+ break;
+ if (!(ci->badwords[a].in_use)) {
+ ci->badwords[a].in_use = ci->badwords[b].in_use;
+ ci->badwords[a].type = ci->badwords[b].type;
+ if (ci->badwords[b].word) {
+ ci->badwords[a].word = sstrdup(ci->badwords[b].word);
+ free(ci->badwords[b].word);
+ }
+ ci->badwords[b].word = NULL;
+ ci->badwords[b].in_use = 0;
+ break;
+ }
+ }
+ }
+ }
+ /* After reordering only the entries at the end could still be empty.
+ * We ll free the places no longer in use... - Viper */
+ for (i = ci->bwcount - 1; i >= 0; i--) {
+ if (ci->badwords[i].in_use)
+ break;
+ ci->bwcount--;
+ }
+ ci->badwords =
+ srealloc(ci->badwords,sizeof(BadWord) * ci->bwcount);
+ }
+
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int sent_header = 0;
+
+ if (ci->bwcount == 0) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+ if (word && strspn(word, "1234567890,-") == strlen(word)) {
+ process_numlist(word, NULL, badwords_list_callback, u, ci,
+ &sent_header);
+ } else {
+ for (i = 0; i < ci->bwcount; i++) {
+ if (!(ci->badwords[i].in_use))
+ continue;
+ if (word && ci->badwords[i].word
+ && !match_wild_nocase(word, ci->badwords[i].word))
+ continue;
+ badwords_list(u, i, ci, &sent_header);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_BotServ, u, BOT_BADWORDS_NO_MATCH, chan);
+
+ } else if (stricmp(cmd, "CLEAR") == 0) {
+
+ if (readonly) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_DISABLED);
+ return MOD_CONT;
+ }
+
+ for (i = 0; i < ci->bwcount; i++)
+ if (ci->badwords[i].word)
+ free(ci->badwords[i].word);
+
+ free(ci->badwords);
+ ci->badwords = NULL;
+ ci->bwcount = 0;
+
+ notice_lang(s_BotServ, u, BOT_BADWORDS_CLEAR);
+
+ } else {
+ syntax_error(s_BotServ, u, "BADWORDS", BOT_BADWORDS_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int badwords_del_callback(User * u, int num, va_list args)
+{
+ BadWord *bw;
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *last = va_arg(args, int *);
+
+ *last = num;
+
+ if (num < 1 || num > ci->bwcount)
+ return 0;
+
+ bw = &ci->badwords[num - 1];
+ if (bw->word)
+ free(bw->word);
+ bw->word = NULL;
+ bw->in_use = 0;
+
+ return 1;
+}
+
+int badwords_list(User * u, int index, ChannelInfo * ci, int *sent_header)
+{
+ BadWord *bw = &ci->badwords[index];
+
+ if (!bw->in_use)
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_HEADER, ci->name);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_BotServ, u, BOT_BADWORDS_LIST_FORMAT, index + 1,
+ bw->word,
+ ((bw->type ==
+ BW_SINGLE) ? "(SINGLE)" : ((bw->type ==
+ BW_START) ? "(START)"
+ : ((bw->type ==
+ BW_END) ? "(END)" : "")))
+ );
+ return 1;
+}
+
+int badwords_list_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *sent_header = va_arg(args, int *);
+ if (num < 1 || num > ci->bwcount)
+ return 0;
+ return badwords_list(u, num - 1, ci, sent_header);
+}
diff --git a/src/core/bs_bot.c b/src/core/bs_bot.c
new file mode 100644
index 000000000..f35e55152
--- /dev/null
+++ b/src/core/bs_bot.c
@@ -0,0 +1,378 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_bot(User * u);
+int delbot(BotInfo * bi);
+void myBotServHelp(User * u);
+void change_bot_nick(BotInfo * bi, char *newnick);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("BOT", do_bot, is_services_admin, -1, -1, -1,
+ BOT_SERVADMIN_HELP_BOT, BOT_SERVADMIN_HELP_BOT);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_BOT);
+ }
+}
+
+/**
+ * The /bs bot command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_bot(User * u)
+{
+ BotInfo *bi;
+ char *cmd = strtok(NULL, " ");
+ char *ch = NULL;
+
+ if (!cmd)
+ syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
+ else if (!stricmp(cmd, "ADD")) {
+ char *nick = strtok(NULL, " ");
+ char *user = strtok(NULL, " ");
+ char *host = strtok(NULL, " ");
+ char *real = strtok(NULL, "");
+
+ if (!nick || !user || !host || !real)
+ syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
+ else if (readonly)
+ notice_lang(s_BotServ, u, BOT_BOT_READONLY);
+ else if (findbot(nick))
+ notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
+ else if (strlen(nick) > NickLen)
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ else if (strlen(user) >= USERMAX)
+ notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
+ else if (strlen(user) > HOSTMAX)
+ notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
+ else {
+ NickAlias *na;
+
+ /**
+ * Check the nick is valid re RFC 2812
+ **/
+ if (isdigit(nick[0]) || nick[0] == '-') {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+ for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++) {
+ if (!isvalidnick(*ch)) {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+ }
+
+ /* check for hardcored ircd forbidden nicks */
+ if (!anope_valid_nick(nick)) {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+
+ if (!isValidHost(host, 3)) {
+ notice_lang(s_BotServ, u, BOT_BAD_HOST);
+ return MOD_CONT;
+ }
+ for (ch = user; *ch && (ch - user) < USERMAX; ch++) {
+ if (!isalnum(*ch)) {
+ notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
+ return MOD_CONT;
+ }
+ }
+
+ /**
+ * Check the host is valid re RFC 2812
+ **/
+
+ /* Check whether it's a services client's nick and return if so - Certus */
+ /* use nickIsServices reduce the total number lines of code - TSL */
+
+ if (nickIsServices(nick, 0)) {
+ notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
+ return MOD_CONT;
+ }
+
+ /* We check whether the nick is registered, and inform the user
+ * if so. You need to drop the nick manually before you can use
+ * it as a bot nick from now on -GD
+ */
+ if ((na = findnick(nick))) {
+ notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ bi = makebot(nick);
+ if (!bi) {
+ notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
+ return MOD_CONT;
+ }
+
+ bi->user = sstrdup(user);
+ bi->host = sstrdup(host);
+ bi->real = sstrdup(real);
+ bi->created = time(NULL);
+ bi->chancount = 0;
+
+ /* We check whether user with this nick is online, and kill it if so */
+ EnforceQlinedNick(nick, s_BotServ);
+
+ /* We make the bot online, ready to serve */
+ anope_cmd_bot_nick(bi->nick, bi->user, bi->host, bi->real,
+ ircd->botserv_bot_mode);
+
+ notice_lang(s_BotServ, u, BOT_BOT_ADDED, bi->nick, bi->user,
+ bi->host, bi->real);
+
+ send_event(EVENT_BOT_CREATE, 1, bi->nick);
+ }
+ } else if (!stricmp(cmd, "CHANGE")) {
+ char *oldnick = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ char *user = strtok(NULL, " ");
+ char *host = strtok(NULL, " ");
+ char *real = strtok(NULL, "");
+
+ if (!oldnick || !nick)
+ syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
+ else if (readonly)
+ notice_lang(s_BotServ, u, BOT_BOT_READONLY);
+ else if (!(bi = findbot(oldnick)))
+ notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, oldnick);
+ else if (strlen(nick) > NickLen)
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ else if (user && strlen(user) >= USERMAX)
+ notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
+ else if (host && strlen(host) > HOSTMAX)
+ notice_lang(s_BotServ, u, BOT_LONG_HOST, HOSTMAX);
+ else {
+ NickAlias *na;
+
+ /* Checks whether there *are* changes.
+ * Case sensitive because we may want to change just the case.
+ * And we must finally check that the nick is not already
+ * taken by another bot.
+ */
+ if (!strcmp(bi->nick, nick)
+ && ((user) ? !strcmp(bi->user, user) : 1)
+ && ((host) ? !strcmp(bi->host, host) : 1)
+ && ((real) ? !strcmp(bi->real, real) : 1)) {
+ notice_lang(s_BotServ, u, BOT_BOT_ANY_CHANGES);
+ return MOD_CONT;
+ }
+
+ /* Check whether it's a services client's nick and return if so - Certus */
+ /* use nickIsServices() to reduce the number of lines of code - TSL */
+ if (nickIsServices(nick, 0)) {
+ notice_lang(s_BotServ, u, BOT_BOT_CREATION_FAILED);
+ return MOD_CONT;
+ }
+
+ /**
+ * Check the nick is valid re RFC 2812
+ **/
+ if (isdigit(nick[0]) || nick[0] == '-') {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+ for (ch = nick; *ch && (ch - nick) < NICKMAX; ch++) {
+ if (!isvalidnick(*ch)) {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+ }
+
+ /* check for hardcored ircd forbidden nicks */
+ if (!anope_valid_nick(nick)) {
+ notice_lang(s_BotServ, u, BOT_BAD_NICK);
+ return MOD_CONT;
+ }
+
+ if (host && !isValidHost(host, 3)) {
+ notice_lang(s_BotServ, u, BOT_BAD_HOST);
+ return MOD_CONT;
+ }
+
+ if (user) {
+ for (ch = user; *ch && (ch - user) < USERMAX; ch++) {
+ if (!isalnum(*ch)) {
+ notice_lang(s_BotServ, u, BOT_LONG_IDENT, USERMAX - 1);
+ return MOD_CONT;
+ }
+ }
+ }
+
+ if (stricmp(bi->nick, nick) && findbot(nick)) {
+ notice_lang(s_BotServ, u, BOT_BOT_ALREADY_EXISTS, nick);
+ return MOD_CONT;
+ }
+
+ if (stricmp(bi->nick, nick)) {
+ /* We check whether the nick is registered, and inform the user
+ * if so. You need to drop the nick manually before you can use
+ * it as a bot nick from now on -GD
+ */
+ if ((na = findnick(nick))) {
+ notice_lang(s_BotServ, u, NICK_ALREADY_REGISTERED,
+ nick);
+ return MOD_CONT;
+ }
+
+ /* The new nick is really different, so we remove the Q line for
+ the old nick. */
+ if (ircd->sqline) {
+ anope_cmd_unsqline(bi->nick);
+ }
+
+ /* We check whether user with this nick is online, and kill it if so */
+ EnforceQlinedNick(nick, s_BotServ);
+ }
+
+ if (strcmp(nick, bi->nick))
+ change_bot_nick(bi, nick);
+
+ if (user && strcmp(user, bi->user)) {
+ free(bi->user);
+ bi->user = sstrdup(user);
+ }
+ if (host && strcmp(host, bi->host)) {
+ free(bi->host);
+ bi->host = sstrdup(host);
+ }
+ if (real && strcmp(real, bi->real)) {
+ free(bi->real);
+ bi->real = sstrdup(real);
+ }
+
+ /* If only the nick changes, we just make the bot change his nick,
+ else we must make it quit and rejoin. We must not forget to set
+ the Q:Line either (it's otherwise set in anope_cmd_bot_nick) */
+ if (!user) {
+ anope_cmd_chg_nick(oldnick, bi->nick);
+ anope_cmd_sqline(bi->nick, "Reserved for services");
+ } else {
+ anope_cmd_quit(oldnick, "Quit: Be right back");
+
+ anope_cmd_bot_nick(bi->nick, bi->user, bi->host, bi->real,
+ ircd->botserv_bot_mode);
+ bot_rejoin_all(bi);
+ }
+
+ notice_lang(s_BotServ, u, BOT_BOT_CHANGED, oldnick, bi->nick,
+ bi->user, bi->host, bi->real);
+
+ send_event(EVENT_BOT_CHANGE, 1, bi->nick);
+ }
+ } else if (!stricmp(cmd, "DEL")) {
+ char *nick = strtok(NULL, " ");
+
+ if (!nick)
+ syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
+ else if (readonly)
+ notice_lang(s_BotServ, u, BOT_BOT_READONLY);
+ else if (!(bi = findbot(nick)))
+ notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, nick);
+ else {
+ send_event(EVENT_BOT_DEL, 1, bi->nick);
+ anope_cmd_quit(bi->nick,
+ "Quit: Help! I'm being deleted by %s!",
+ u->nick);
+ if (ircd->sqline) {
+ anope_cmd_unsqline(bi->nick);
+ }
+ delbot(bi);
+
+ notice_lang(s_BotServ, u, BOT_BOT_DELETED, nick);
+ }
+ } else
+ syntax_error(s_BotServ, u, "BOT", BOT_BOT_SYNTAX);
+
+ return MOD_CONT;
+}
+
+int delbot(BotInfo * bi)
+{
+ cs_remove_bot(bi);
+
+ if (bi->next)
+ bi->next->prev = bi->prev;
+ if (bi->prev)
+ bi->prev->next = bi->next;
+ else
+ botlists[tolower(*bi->nick)] = bi->next;
+
+ nbots--;
+
+ free(bi->nick);
+ free(bi->user);
+ free(bi->host);
+ free(bi->real);
+
+ free(bi);
+
+ return 1;
+}
+
+void change_bot_nick(BotInfo * bi, char *newnick)
+{
+ if (bi->next)
+ bi->next->prev = bi->prev;
+ if (bi->prev)
+ bi->prev->next = bi->next;
+ else
+ botlists[tolower(*bi->nick)] = bi->next;
+
+ if (bi->nick)
+ free(bi->nick);
+ bi->nick = sstrdup(newnick);
+
+ insert_bot(bi);
+}
diff --git a/src/core/bs_botlist.c b/src/core/bs_botlist.c
new file mode 100644
index 000000000..9e0fb9d45
--- /dev/null
+++ b/src/core/bs_botlist.c
@@ -0,0 +1,108 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_botlist(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the botlist command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("BOTLIST", do_botlist, NULL, BOT_HELP_BOTLIST, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_BOTLIST);
+}
+
+/**
+ * The /bs botlist command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_botlist(User * u)
+{
+ int i, count = 0;
+ BotInfo *bi;
+
+ if (!nbots) {
+ notice_lang(s_BotServ, u, BOT_BOTLIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ if (!(bi->flags & BI_PRIVATE)) {
+ if (!count)
+ notice_lang(s_BotServ, u, BOT_BOTLIST_HEADER);
+ count++;
+ notice_user(s_BotServ, u, " %-15s (%s@%s)", bi->nick,
+ bi->user, bi->host);
+ }
+ }
+ }
+
+ if (is_oper(u) && count < nbots) {
+ notice_lang(s_BotServ, u, BOT_BOTLIST_PRIVATE_HEADER);
+
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ if (bi->flags & BI_PRIVATE) {
+ notice_user(s_BotServ, u, " %-15s (%s@%s)",
+ bi->nick, bi->user, bi->host);
+ count++;
+ }
+ }
+ }
+ }
+
+ if (!count)
+ notice_lang(s_BotServ, u, BOT_BOTLIST_EMPTY);
+ else
+ notice_lang(s_BotServ, u, BOT_BOTLIST_FOOTER, count);
+ return MOD_CONT;
+}
diff --git a/src/core/bs_fantasy.c b/src/core/bs_fantasy.c
new file mode 100644
index 000000000..c63d139b1
--- /dev/null
+++ b/src/core/bs_fantasy.c
@@ -0,0 +1,89 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle all csmodeutils fantasy commands.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u;
+ ChannelInfo *ci;
+ CSModeUtil *util = csmodeutils;
+ char *target;
+
+ if (argc < 3)
+ return MOD_CONT;
+
+ do {
+ if (stricmp(argv[0], util->bsname) == 0) {
+ /* This could have been moved to its own module
+ however it would require more coding to handle the pass holders
+ similar to how PROTECT is done
+ */
+ if (!ircd->halfop) {
+ if (!stricmp(argv[0], "halfop") || !stricmp(argv[0], "dehalfop")) {
+ return MOD_CONT;
+ }
+ }
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ target = ((argc == 4) ? argv[3] : NULL);
+
+ if (!target && check_access(u, ci, util->levelself))
+ bot_raw_mode(u, ci, util->mode, u->nick);
+ else if (target && check_access(u, ci, util->level))
+ bot_raw_mode(u, ci, util->mode, target);
+ }
+ } while ((++util)->name != NULL);
+
+ return MOD_CONT;
+}
diff --git a/src/core/bs_fantasy_kick.c b/src/core/bs_fantasy_kick.c
new file mode 100644
index 000000000..d8f272e8a
--- /dev/null
+++ b/src/core/bs_fantasy_kick.c
@@ -0,0 +1,98 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle kick/k fantasy commands.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u, *u2;
+ ChannelInfo *ci;
+ char *target = NULL;
+ char *reason = NULL;
+
+ if (argc < 3)
+ return MOD_CONT;
+
+ if ((stricmp(argv[0], "kick") == 0) || (stricmp(argv[0], "k") == 0)) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ if (argc >= 4) {
+ target = myStrGetToken(argv[3], ' ', 0);
+ reason = myStrGetTokenRemainder(argv[3], ' ', 1);
+ }
+ if (!target && check_access(u, ci, CA_KICKME)) {
+ bot_raw_kick(u, ci, u->nick, "Requested");
+ } else if (target && check_access(u, ci, CA_KICK)) {
+ if (!stricmp(target, ci->bi->nick))
+ bot_raw_kick(u, ci, u->nick, "Oops!");
+ else {
+ u2 = finduser(target);
+ if (u2 && ci->c && is_on_chan(ci->c, u2)) {
+ if (!reason && !is_protected(u2))
+ bot_raw_kick(u, ci, target, "Requested");
+ else if (!is_protected(u2))
+ bot_raw_kick(u, ci, target, reason);
+ }
+ }
+ }
+ }
+
+ if (target)
+ free(target);
+ if (reason)
+ free(reason);
+
+ return MOD_CONT;
+}
diff --git a/src/core/bs_fantasy_kickban.c b/src/core/bs_fantasy_kickban.c
new file mode 100644
index 000000000..4cb64f116
--- /dev/null
+++ b/src/core/bs_fantasy_kickban.c
@@ -0,0 +1,99 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle kickban/kb fantasy commands.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u, *u2;
+ ChannelInfo *ci;
+ char *target = NULL;
+ char *reason = NULL;
+
+ if (argc < 3)
+ return MOD_CONT;
+
+ if ((stricmp(argv[0], "kickban") == 0)
+ || (stricmp(argv[0], "kb") == 0)) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ if (argc >= 4) {
+ target = myStrGetToken(argv[3], ' ', 0);
+ reason = myStrGetTokenRemainder(argv[3], ' ', 1);
+ }
+ if (!target && check_access(u, ci, CA_BANME)) {
+ bot_raw_ban(u, ci, u->nick, "Requested");
+ } else if (target && check_access(u, ci, CA_BAN)) {
+ if (stricmp(target, ci->bi->nick) == 0) {
+ bot_raw_ban(u, ci, u->nick, "Oops!");
+ } else {
+ u2 = finduser(target);
+ if (u2 && ci->c && is_on_chan(ci->c, u2)) {
+ if (!reason && !is_protected(u2))
+ bot_raw_ban(u, ci, target, "Requested");
+ else if (!is_protected(u2))
+ bot_raw_ban(u, ci, target, reason);
+ }
+ }
+ }
+ }
+
+ if (target)
+ free(target);
+ if (reason)
+ free(reason);
+
+ return MOD_CONT;
+}
diff --git a/src/core/bs_fantasy_owner.c b/src/core/bs_fantasy_owner.c
new file mode 100644
index 000000000..934d3ccca
--- /dev/null
+++ b/src/core/bs_fantasy_owner.c
@@ -0,0 +1,88 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ /* No need to load of we don't support owner */
+ if (!ircd->owner) {
+ alog("Your ircd doesn't support the owner channelmode; bs_fantasy_owner won't be loaded");
+ return MOD_STOP;
+ }
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle owner/deowner fantasy commands.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u;
+ ChannelInfo *ci;
+
+ if (argc < 3)
+ return MOD_CONT;
+
+ if (stricmp(argv[0], "deowner") == 0) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ if (is_founder(u, ci))
+ bot_raw_mode(u, ci, ircd->ownerunset, u->nick);
+ } else if (stricmp(argv[0], "owner") == 0) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ if (is_founder(u, ci))
+ bot_raw_mode(u, ci, ircd->ownerset, u->nick);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/bs_fantasy_seen.c b/src/core/bs_fantasy_seen.c
new file mode 100644
index 000000000..75abdd26b
--- /dev/null
+++ b/src/core/bs_fantasy_seen.c
@@ -0,0 +1,139 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle seen fantasy command.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u;
+ ChannelInfo *ci;
+ User *u2;
+ NickAlias *na;
+ ChanAccess *access;
+ char buf[BUFSIZE];
+ char *target = NULL;
+
+ if (argc < 4)
+ return MOD_CONT;
+
+ if (stricmp(argv[0], "seen") == 0) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci)
+ return MOD_CONT;
+
+ target = myStrGetToken(argv[3], ' ', 0);
+
+ if (stricmp(ci->bi->nick, target) == 0) {
+ /* If we look for the bot */
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_BOT),
+ u->nick);
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ } else if (!(na = findnick(target)) || (na->status & NS_VERBOTEN)) {
+ /* If the nick is not registered or forbidden */
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_UNKNOWN),
+ target);
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ } else if ((u2 = nc_on_chan(ci->c, na->nc))) {
+ /* If the nick we're looking for is on the channel,
+ * there are three possibilities: it's yourself,
+ * it's the nick we look for, it's an alias of the
+ * nick we look for.
+ */
+ if (u == u2 || (u->na && u->na->nc == na->nc))
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_YOU),
+ u->nick);
+ else if (!stricmp(u2->nick, target))
+ snprintf(buf, sizeof(buf),
+ getstring(u->na, BOT_SEEN_ON_CHANNEL), u2->nick);
+ else
+ snprintf(buf, sizeof(buf),
+ getstring(u->na, BOT_SEEN_ON_CHANNEL_AS), target,
+ u2->nick);
+
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ } else if ((access = get_access_entry(na->nc, ci))) {
+ /* User is on the access list but not present actually.
+ Special case: if access->last_seen is 0 it's that we
+ never seen the user.
+ */
+ if (access->last_seen) {
+ char durastr[192];
+ duration(u->na, durastr, sizeof(durastr),
+ time(NULL) - access->last_seen);
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_ON),
+ target, durastr);
+ } else {
+ snprintf(buf, sizeof(buf),
+ getstring(u->na, BOT_SEEN_NEVER), target);
+ }
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ } else if (na->nc == ci->founder) {
+ /* User is the founder of the channel */
+ char durastr[192];
+ duration(u->na, durastr, sizeof(durastr),
+ time(NULL) - na->last_seen);
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_ON),
+ target, durastr);
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ } else {
+ /* All other cases */
+ snprintf(buf, sizeof(buf), getstring(u->na, BOT_SEEN_UNKNOWN),
+ target);
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", buf);
+ }
+ /* free myStrGetToken(ed) variable target (#851) */
+ Anope_Free(target);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/bs_help.c b/src/core/bs_help.c
new file mode 100644
index 000000000..7d34ef705
--- /dev/null
+++ b/src/core/bs_help.c
@@ -0,0 +1,67 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the help command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * The /bs help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_BotServ, u, BOT_HELP);
+ moduleDisplayHelp(4, u);
+ notice_help(s_BotServ, u, BOT_HELP_FOOTER, BSMinUsers);
+ } else {
+ mod_help_cmd(s_BotServ, u, BOTSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_info.c b/src/core/bs_info.c
new file mode 100644
index 000000000..281ba0055
--- /dev/null
+++ b/src/core/bs_info.c
@@ -0,0 +1,282 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_info(User * u);
+void send_bot_channels(User * u, BotInfo * bi);
+void myBotServHelp(User * u);
+
+/**
+ * Create the info command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("INFO", do_info, NULL, BOT_HELP_INFO, -1, -1, -1,
+ -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_INFO);
+}
+
+/**
+ * The /bs info command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_info(User * u)
+{
+ BotInfo *bi;
+ ChannelInfo *ci;
+ char *query = strtok(NULL, " ");
+
+ int need_comma = 0, is_servadmin = is_services_admin(u);
+ char buf[BUFSIZE], *end;
+ const char *commastr = getstring(u->na, COMMA_SPACE);
+
+ if (!query)
+ syntax_error(s_BotServ, u, "INFO", BOT_INFO_SYNTAX);
+ else if ((bi = findbot(query))) {
+ char buf[BUFSIZE];
+ struct tm *tm;
+
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_HEADER, bi->nick);
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_MASK, bi->user, bi->host);
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_REALNAME, bi->real);
+ tm = localtime(&bi->created);
+ strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_CREATED, buf);
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_OPTIONS,
+ getstring(u->na,
+ (bi->
+ flags & BI_PRIVATE) ? BOT_INFO_OPT_PRIVATE :
+ BOT_INFO_OPT_NONE));
+ notice_lang(s_BotServ, u, BOT_INFO_BOT_USAGE, bi->chancount);
+
+ if (is_services_admin(u))
+ send_bot_channels(u, bi);
+ } else if ((ci = cs_findchan(query))) {
+ if (!is_servadmin && !is_founder(u, ci)) {
+ notice_lang(s_BotServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, query);
+ return MOD_CONT;
+ }
+
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_HEADER, ci->name);
+ if (ci->bi)
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_BOT, ci->bi->nick);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_BOT_NONE);
+
+ if (ci->botflags & BS_KICK_BADWORDS) {
+ if (ci->ttb[TTB_BADWORDS])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BADWORDS_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_BADWORDS]);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BADWORDS,
+ getstring(u->na, BOT_INFO_ACTIVE));
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BADWORDS,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_BOLDS) {
+ if (ci->ttb[TTB_BOLDS])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BOLDS_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_BOLDS]);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BOLDS,
+ getstring(u->na, BOT_INFO_ACTIVE));
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_BOLDS,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_CAPS) {
+ if (ci->ttb[TTB_CAPS])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_CAPS_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_CAPS], ci->capsmin,
+ ci->capspercent);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_CAPS_ON,
+ getstring(u->na, BOT_INFO_ACTIVE), ci->capsmin,
+ ci->capspercent);
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_CAPS_OFF,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_COLORS) {
+ if (ci->ttb[TTB_COLORS])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_COLORS_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_COLORS]);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_COLORS,
+ getstring(u->na, BOT_INFO_ACTIVE));
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_COLORS,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_FLOOD) {
+ if (ci->ttb[TTB_FLOOD])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_FLOOD_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_FLOOD], ci->floodlines,
+ ci->floodsecs);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_FLOOD_ON,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->floodlines, ci->floodsecs);
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_FLOOD_OFF,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_REPEAT) {
+ if (ci->ttb[TTB_REPEAT])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REPEAT_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_REPEAT], ci->repeattimes);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REPEAT_ON,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->repeattimes);
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REPEAT_OFF,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_REVERSES) {
+ if (ci->ttb[TTB_REVERSES])
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REVERSES_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_REVERSES]);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REVERSES,
+ getstring(u->na, BOT_INFO_ACTIVE));
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_REVERSES,
+ getstring(u->na, BOT_INFO_INACTIVE));
+ if (ci->botflags & BS_KICK_UNDERLINES) {
+ if (ci->ttb[TTB_UNDERLINES])
+ notice_lang(s_BotServ, u,
+ BOT_INFO_CHAN_KICK_UNDERLINES_BAN,
+ getstring(u->na, BOT_INFO_ACTIVE),
+ ci->ttb[TTB_UNDERLINES]);
+ else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_UNDERLINES,
+ getstring(u->na, BOT_INFO_ACTIVE));
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_KICK_UNDERLINES,
+ getstring(u->na, BOT_INFO_INACTIVE));
+
+ end = buf;
+ *end = 0;
+ if (ci->botflags & BS_DONTKICKOPS) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s",
+ getstring(u->na, BOT_INFO_OPT_DONTKICKOPS));
+ need_comma = 1;
+ }
+ if (ci->botflags & BS_DONTKICKVOICES) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, BOT_INFO_OPT_DONTKICKVOICES));
+ need_comma = 1;
+ }
+ if (ci->botflags & BS_FANTASY) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, BOT_INFO_OPT_FANTASY));
+ need_comma = 1;
+ }
+ if (ci->botflags & BS_GREET) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, BOT_INFO_OPT_GREET));
+ need_comma = 1;
+ }
+ if (ci->botflags & BS_NOBOT) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, BOT_INFO_OPT_NOBOT));
+ need_comma = 1;
+ }
+ if (ci->botflags & BS_SYMBIOSIS) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, BOT_INFO_OPT_SYMBIOSIS));
+ need_comma = 1;
+ }
+ notice_lang(s_BotServ, u, BOT_INFO_CHAN_OPTIONS,
+ *buf ? buf : getstring(u->na, BOT_INFO_OPT_NONE));
+
+ } else
+ notice_lang(s_BotServ, u, BOT_INFO_NOT_FOUND, query);
+ return MOD_CONT;
+}
+
+void send_bot_channels(User * u, BotInfo * bi)
+{
+ int i;
+ ChannelInfo *ci;
+ char buf[307], *end;
+
+ *buf = 0;
+ end = buf;
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ if (ci->bi == bi) {
+ if (strlen(buf) + strlen(ci->name) > 300) {
+ notice_user(s_BotServ, u, "%s", buf);
+ *buf = 0;
+ end = buf;
+ }
+ end +=
+ snprintf(end, sizeof(buf) - (end - buf), " %s ",
+ ci->name);
+ }
+ }
+ }
+
+ if (*buf)
+ notice_user(s_BotServ, u, "%s", buf);
+ return;
+}
diff --git a/src/core/bs_kick.c b/src/core/bs_kick.c
new file mode 100644
index 000000000..22a1e72c9
--- /dev/null
+++ b/src/core/bs_kick.c
@@ -0,0 +1,379 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_kickcmd(User * u);
+
+void myBotServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("KICK", do_kickcmd, NULL, BOT_HELP_KICK, -1, -1, -1,
+ -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK BADWORDS", NULL, NULL, BOT_HELP_KICK_BADWORDS,
+ -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK BOLDS", NULL, NULL, BOT_HELP_KICK_BOLDS, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK CAPS", NULL, NULL, BOT_HELP_KICK_CAPS, -1, -1,
+ -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK COLORS", NULL, NULL, BOT_HELP_KICK_COLORS, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK FLOOD", NULL, NULL, BOT_HELP_KICK_FLOOD, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK REPEAT", NULL, NULL, BOT_HELP_KICK_REPEAT, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK REVERSES", NULL, NULL, BOT_HELP_KICK_REVERSES,
+ -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("KICK UNDERLINES", NULL, NULL,
+ BOT_HELP_KICK_UNDERLINES, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_KICK);
+}
+
+/**
+ * The /bs kick command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_kickcmd(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *option = strtok(NULL, " ");
+ char *value = strtok(NULL, " ");
+ char *ttb = strtok(NULL, " ");
+
+ ChannelInfo *ci;
+
+ if (readonly)
+ notice_lang(s_BotServ, u, BOT_KICK_DISABLED);
+ else if (!chan || !option || !value)
+ syntax_error(s_BotServ, u, "KICK", BOT_KICK_SYNTAX);
+ else if (stricmp(value, "ON") && stricmp(value, "OFF"))
+ syntax_error(s_BotServ, u, "KICK", BOT_KICK_SYNTAX);
+ else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if (!is_services_admin(u) && !check_access(u, ci, CA_SET))
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ else if (!ci->bi)
+ notice_help(s_BotServ, u, BOT_NOT_ASSIGNED);
+ else {
+ if (!stricmp(option, "BADWORDS")) {
+ if (!stricmp(value, "ON")) {
+ if (ttb) {
+ ci->ttb[TTB_BADWORDS] =
+ strtol(ttb, (char **) NULL, 10);
+ /* Only error if errno returns ERANGE or EINVAL or we are less then 0 - TSL */
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_BADWORDS] < 0) {
+ /* leaving the debug behind since we might want to know what these are */
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_BADWORDS]);
+ }
+ /* reset the value back to 0 - TSL */
+ ci->ttb[TTB_BADWORDS] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else {
+ ci->ttb[TTB_BADWORDS] = 0;
+ }
+ ci->botflags |= BS_KICK_BADWORDS;
+ if (ci->ttb[TTB_BADWORDS])
+ notice_lang(s_BotServ, u, BOT_KICK_BADWORDS_ON_BAN,
+ ci->ttb[TTB_BADWORDS]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_BADWORDS_ON);
+ } else {
+ ci->botflags &= ~BS_KICK_BADWORDS;
+ notice_lang(s_BotServ, u, BOT_KICK_BADWORDS_OFF);
+ }
+ } else if (!stricmp(option, "BOLDS")) {
+ if (!stricmp(value, "ON")) {
+ if (ttb) {
+ ci->ttb[TTB_BOLDS] = strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_BOLDS] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_BOLDS]);
+ }
+ ci->ttb[TTB_BOLDS] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_BOLDS] = 0;
+ ci->botflags |= BS_KICK_BOLDS;
+ if (ci->ttb[TTB_BOLDS])
+ notice_lang(s_BotServ, u, BOT_KICK_BOLDS_ON_BAN,
+ ci->ttb[TTB_BOLDS]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_BOLDS_ON);
+ } else {
+ ci->botflags &= ~BS_KICK_BOLDS;
+ notice_lang(s_BotServ, u, BOT_KICK_BOLDS_OFF);
+ }
+ } else if (!stricmp(option, "CAPS")) {
+ if (!stricmp(value, "ON")) {
+ char *min = strtok(NULL, " ");
+ char *percent = strtok(NULL, " ");
+
+ if (ttb) {
+ ci->ttb[TTB_CAPS] = strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_CAPS] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_CAPS]);
+ }
+ ci->ttb[TTB_CAPS] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_CAPS] = 0;
+
+ if (!min)
+ ci->capsmin = 10;
+ else
+ ci->capsmin = atol(min);
+ if (ci->capsmin < 1)
+ ci->capsmin = 10;
+
+ if (!percent)
+ ci->capspercent = 25;
+ else
+ ci->capspercent = atol(percent);
+ if (ci->capspercent < 1 || ci->capspercent > 100)
+ ci->capspercent = 25;
+
+ ci->botflags |= BS_KICK_CAPS;
+ if (ci->ttb[TTB_CAPS])
+ notice_lang(s_BotServ, u, BOT_KICK_CAPS_ON_BAN,
+ ci->capsmin, ci->capspercent,
+ ci->ttb[TTB_CAPS]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_CAPS_ON,
+ ci->capsmin, ci->capspercent);
+ } else {
+ ci->botflags &= ~BS_KICK_CAPS;
+ notice_lang(s_BotServ, u, BOT_KICK_CAPS_OFF);
+ }
+ } else if (!stricmp(option, "COLORS")) {
+ if (!stricmp(value, "ON")) {
+ if (ttb) {
+ ci->ttb[TTB_COLORS] = strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_COLORS] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_COLORS]);
+ }
+ ci->ttb[TTB_COLORS] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_COLORS] = 0;
+ ci->botflags |= BS_KICK_COLORS;
+ if (ci->ttb[TTB_COLORS])
+ notice_lang(s_BotServ, u, BOT_KICK_COLORS_ON_BAN,
+ ci->ttb[TTB_COLORS]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_COLORS_ON);
+ } else {
+ ci->botflags &= ~BS_KICK_COLORS;
+ notice_lang(s_BotServ, u, BOT_KICK_COLORS_OFF);
+ }
+ } else if (!stricmp(option, "FLOOD")) {
+ if (!stricmp(value, "ON")) {
+ char *lines = strtok(NULL, " ");
+ char *secs = strtok(NULL, " ");
+
+ if (ttb) {
+ ci->ttb[TTB_FLOOD] = strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_FLOOD] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_FLOOD]);
+ }
+ ci->ttb[TTB_FLOOD] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_FLOOD] = 0;
+
+ if (!lines)
+ ci->floodlines = 6;
+ else
+ ci->floodlines = atol(lines);
+ if (ci->floodlines < 2)
+ ci->floodlines = 6;
+
+ if (!secs)
+ ci->floodsecs = 10;
+ else
+ ci->floodsecs = atol(secs);
+ if (ci->floodsecs < 1 || ci->floodsecs > BSKeepData)
+ ci->floodsecs = 10;
+
+ ci->botflags |= BS_KICK_FLOOD;
+ if (ci->ttb[TTB_FLOOD])
+ notice_lang(s_BotServ, u, BOT_KICK_FLOOD_ON_BAN,
+ ci->floodlines, ci->floodsecs,
+ ci->ttb[TTB_FLOOD]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_FLOOD_ON,
+ ci->floodlines, ci->floodsecs);
+ } else {
+ ci->botflags &= ~BS_KICK_FLOOD;
+ notice_lang(s_BotServ, u, BOT_KICK_FLOOD_OFF);
+ }
+ } else if (!stricmp(option, "REPEAT")) {
+ if (!stricmp(value, "ON")) {
+ char *times = strtok(NULL, " ");
+
+ if (ttb) {
+ ci->ttb[TTB_REPEAT] = strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_REPEAT] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_REPEAT]);
+ }
+ ci->ttb[TTB_REPEAT] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_REPEAT] = 0;
+
+ if (!times)
+ ci->repeattimes = 3;
+ else
+ ci->repeattimes = atol(times);
+ if (ci->repeattimes < 2)
+ ci->repeattimes = 3;
+
+ ci->botflags |= BS_KICK_REPEAT;
+ if (ci->ttb[TTB_REPEAT])
+ notice_lang(s_BotServ, u, BOT_KICK_REPEAT_ON_BAN,
+ ci->repeattimes, ci->ttb[TTB_REPEAT]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_REPEAT_ON,
+ ci->repeattimes);
+ } else {
+ ci->botflags &= ~BS_KICK_REPEAT;
+ notice_lang(s_BotServ, u, BOT_KICK_REPEAT_OFF);
+ }
+ } else if (!stricmp(option, "REVERSES")) {
+ if (!stricmp(value, "ON")) {
+ if (ttb) {
+ ci->ttb[TTB_REVERSES] =
+ strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_REVERSES] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_REVERSES]);
+ }
+ ci->ttb[TTB_REVERSES] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_REVERSES] = 0;
+ ci->botflags |= BS_KICK_REVERSES;
+ if (ci->ttb[TTB_REVERSES])
+ notice_lang(s_BotServ, u, BOT_KICK_REVERSES_ON_BAN,
+ ci->ttb[TTB_REVERSES]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_REVERSES_ON);
+ } else {
+ ci->botflags &= ~BS_KICK_REVERSES;
+ notice_lang(s_BotServ, u, BOT_KICK_REVERSES_OFF);
+ }
+ } else if (!stricmp(option, "UNDERLINES")) {
+ if (!stricmp(value, "ON")) {
+ if (ttb) {
+ ci->ttb[TTB_UNDERLINES] =
+ strtol(ttb, (char **) NULL, 10);
+ if (errno == ERANGE || errno == EINVAL
+ || ci->ttb[TTB_UNDERLINES] < 0) {
+ if (debug) {
+ alog("debug: errno is %d ERANGE %d EINVAL %d ttb %d", errno, ERANGE, EINVAL, ci->ttb[TTB_UNDERLINES]);
+ }
+ ci->ttb[TTB_UNDERLINES] = 0;
+ notice_lang(s_BotServ, u, BOT_KICK_BAD_TTB, ttb);
+ return MOD_CONT;
+ }
+ } else
+ ci->ttb[TTB_UNDERLINES] = 0;
+ ci->botflags |= BS_KICK_UNDERLINES;
+ if (ci->ttb[TTB_UNDERLINES])
+ notice_lang(s_BotServ, u, BOT_KICK_UNDERLINES_ON_BAN,
+ ci->ttb[TTB_UNDERLINES]);
+ else
+ notice_lang(s_BotServ, u, BOT_KICK_UNDERLINES_ON);
+ } else {
+ ci->botflags &= ~BS_KICK_UNDERLINES;
+ notice_lang(s_BotServ, u, BOT_KICK_UNDERLINES_OFF);
+ }
+ } else
+ notice_help(s_BotServ, u, BOT_KICK_UNKNOWN, option);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_say.c b/src/core/bs_say.c
new file mode 100644
index 000000000..508efe320
--- /dev/null
+++ b/src/core/bs_say.c
@@ -0,0 +1,97 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_say(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("SAY", do_say, NULL, BOT_HELP_SAY, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_SAY);
+}
+
+/**
+ * The /bs say command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_say(User * u)
+{
+ ChannelInfo *ci;
+
+ char *chan = strtok(NULL, " ");
+ char *text = strtok(NULL, "");
+
+ if (!chan || !text)
+ syntax_error(s_BotServ, u, "SAY", BOT_SAY_SYNTAX);
+ else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if (!ci->bi)
+ notice_help(s_BotServ, u, BOT_NOT_ASSIGNED);
+ else if (!ci->c || ci->c->usercount < BSMinUsers)
+ notice_lang(s_BotServ, u, BOT_NOT_ON_CHANNEL, ci->name);
+ else if (!check_access(u, ci, CA_SAY))
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ else {
+ if (text[0] != '\001') {
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%s", text);
+ ci->bi->lastmsg = time(NULL);
+ if (LogBot && LogChannel && logchan && !debug && findchan(LogChannel))
+ anope_cmd_privmsg(ci->bi->nick, LogChannel,
+ "SAY %s %s %s", u->nick, ci->name, text);
+ } else {
+ syntax_error(s_BotServ, u, "SAY", BOT_SAY_SYNTAX);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_set.c b/src/core/bs_set.c
new file mode 100644
index 000000000..4126603d4
--- /dev/null
+++ b/src/core/bs_set.c
@@ -0,0 +1,208 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_set(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", do_set, NULL, BOT_HELP_SET, -1, -1,
+ BOT_SERVADMIN_HELP_SET, BOT_SERVADMIN_HELP_SET);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET DONTKICKOPS", NULL, NULL,
+ BOT_HELP_SET_DONTKICKOPS, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET DONTKICKVOICES", NULL, NULL,
+ BOT_HELP_SET_DONTKICKVOICES, -1, -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET FANTASY", NULL, NULL, BOT_HELP_SET_FANTASY, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET GREET", NULL, NULL, BOT_HELP_SET_GREET, -1, -1,
+ -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SYMBIOSIS", NULL, NULL, BOT_HELP_SET_SYMBIOSIS,
+ -1, -1, -1, -1);
+ c->help_param1 = s_ChanServ;
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET NOBOT", NULL, NULL, -1, -1, -1,
+ BOT_SERVADMIN_HELP_SET_NOBOT,
+ BOT_SERVADMIN_HELP_SET_NOBOT);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PRIVATE", NULL, NULL, -1, -1, -1,
+ BOT_SERVADMIN_HELP_SET_PRIVATE,
+ BOT_SERVADMIN_HELP_SET_PRIVATE);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_SET);
+}
+
+/**
+ * The /bs set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *option = strtok(NULL, " ");
+ char *value = strtok(NULL, " ");
+ int is_servadmin = is_services_admin(u);
+
+ ChannelInfo *ci;
+
+ if (readonly)
+ notice_lang(s_BotServ, u, BOT_SET_DISABLED);
+ else if (!chan || !option || !value)
+ syntax_error(s_BotServ, u, "SET", BOT_SET_SYNTAX);
+ else if (is_servadmin && !stricmp(option, "PRIVATE")) {
+ BotInfo *bi;
+
+ if ((bi = findbot(chan))) {
+ if (!stricmp(value, "ON")) {
+ bi->flags |= BI_PRIVATE;
+ notice_lang(s_BotServ, u, BOT_SET_PRIVATE_ON, bi->nick);
+ } else if (!stricmp(value, "OFF")) {
+ bi->flags &= ~BI_PRIVATE;
+ notice_lang(s_BotServ, u, BOT_SET_PRIVATE_OFF, bi->nick);
+ } else {
+ syntax_error(s_BotServ, u, "SET PRIVATE",
+ BOT_SET_PRIVATE_SYNTAX);
+ }
+ } else {
+ notice_lang(s_BotServ, u, BOT_DOES_NOT_EXIST, chan);
+ }
+ return MOD_CONT;
+ } else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if (!is_servadmin && !check_access(u, ci, CA_SET))
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ else {
+ if (!stricmp(option, "DONTKICKOPS")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_DONTKICKOPS;
+ notice_lang(s_BotServ, u, BOT_SET_DONTKICKOPS_ON,
+ ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_DONTKICKOPS;
+ notice_lang(s_BotServ, u, BOT_SET_DONTKICKOPS_OFF,
+ ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET DONTKICKOPS",
+ BOT_SET_DONTKICKOPS_SYNTAX);
+ }
+ } else if (!stricmp(option, "DONTKICKVOICES")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_DONTKICKVOICES;
+ notice_lang(s_BotServ, u, BOT_SET_DONTKICKVOICES_ON,
+ ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_DONTKICKVOICES;
+ notice_lang(s_BotServ, u, BOT_SET_DONTKICKVOICES_OFF,
+ ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET DONTKICKVOICES",
+ BOT_SET_DONTKICKVOICES_SYNTAX);
+ }
+ } else if (!stricmp(option, "FANTASY")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_FANTASY;
+ notice_lang(s_BotServ, u, BOT_SET_FANTASY_ON, ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_FANTASY;
+ notice_lang(s_BotServ, u, BOT_SET_FANTASY_OFF, ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET FANTASY",
+ BOT_SET_FANTASY_SYNTAX);
+ }
+ } else if (!stricmp(option, "GREET")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_GREET;
+ notice_lang(s_BotServ, u, BOT_SET_GREET_ON, ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_GREET;
+ notice_lang(s_BotServ, u, BOT_SET_GREET_OFF, ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET GREET",
+ BOT_SET_GREET_SYNTAX);
+ }
+ } else if (is_servadmin && !stricmp(option, "NOBOT")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_NOBOT;
+ if (ci->bi)
+ unassign(u, ci);
+ notice_lang(s_BotServ, u, BOT_SET_NOBOT_ON, ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_NOBOT;
+ notice_lang(s_BotServ, u, BOT_SET_NOBOT_OFF, ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET NOBOT",
+ BOT_SET_NOBOT_SYNTAX);
+ }
+ } else if (!stricmp(option, "SYMBIOSIS")) {
+ if (!stricmp(value, "ON")) {
+ ci->botflags |= BS_SYMBIOSIS;
+ notice_lang(s_BotServ, u, BOT_SET_SYMBIOSIS_ON, ci->name);
+ } else if (!stricmp(value, "OFF")) {
+ ci->botflags &= ~BS_SYMBIOSIS;
+ notice_lang(s_BotServ, u, BOT_SET_SYMBIOSIS_OFF, ci->name);
+ } else {
+ syntax_error(s_BotServ, u, "SET SYMBIOSIS",
+ BOT_SET_SYMBIOSIS_SYNTAX);
+ }
+ } else {
+ notice_help(s_BotServ, u, BOT_SET_UNKNOWN, option);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/bs_unassign.c b/src/core/bs_unassign.c
new file mode 100644
index 000000000..a5e0af6bb
--- /dev/null
+++ b/src/core/bs_unassign.c
@@ -0,0 +1,89 @@
+/* BotServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_unassign(User * u);
+void myBotServHelp(User * u);
+
+/**
+ * Create the unassign command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("UNASSIGN", do_unassign, NULL, BOT_HELP_UNASSIGN, -1,
+ -1, -1, -1);
+ moduleAddCommand(BOTSERV, c, MOD_UNIQUE);
+
+ moduleSetBotHelp(myBotServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to Anopes /bs help output.
+ * @param u The user who is requesting help
+ **/
+void myBotServHelp(User * u)
+{
+ notice_lang(s_BotServ, u, BOT_HELP_CMD_UNASSIGN);
+}
+
+/**
+ * The /bs unassign command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_unassign(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ ChannelInfo *ci;
+
+ if (readonly)
+ notice_lang(s_BotServ, u, BOT_ASSIGN_READONLY);
+ else if (!chan)
+ syntax_error(s_BotServ, u, "UNASSIGN", BOT_UNASSIGN_SYNTAX);
+ else if (!(ci = cs_findchan(chan)))
+ notice_lang(s_BotServ, u, CHAN_X_NOT_REGISTERED, chan);
+ else if (ci->flags & CI_VERBOTEN)
+ notice_lang(s_BotServ, u, CHAN_X_FORBIDDEN, chan);
+ else if (!is_services_admin(u) && !check_access(u, ci, CA_ASSIGN))
+ notice_lang(s_BotServ, u, ACCESS_DENIED);
+ else if (!ci->bi)
+ notice_help(s_BotServ, u, BOT_NOT_ASSIGNED);
+ else {
+ unassign(u, ci);
+ notice_lang(s_BotServ, u, BOT_UNASSIGN_UNASSIGNED, ci->name);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/configure b/src/core/configure
new file mode 100755
index 000000000..68d2b7713
--- /dev/null
+++ b/src/core/configure
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+echo2 () {
+ $ECHO2 "$*$ECHO2SUF" # these are defined later
+}
+
+ECHO2SUF=''
+if [ "`echo -n a ; echo -n b`" = "ab" ] ; then
+ ECHO2='echo -n'
+elif [ "`echo 'a\c' ; echo 'b\c'`" = "ab" ] ; then
+ ECHO2='echo' ; ECHO2SUF='\c'
+elif [ "`printf 'a' 2>&1 ; printf 'b' 2>&1`" = "ab" ] ; then
+ ECHO2='printf "%s"'
+else
+ # oh well...
+ ECHO2='echo'
+fi
+export ECHO2 ECHO2SUF
+
+
+echo2 "SRCS=" > ./Makefile.inc
+FIRST=1
+for oldfile in *.c
+do
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$oldfile >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $oldfile >> ./Makefile.inc
+ fi
+ FIRST=0
+done
+echo "" >> ./Makefile.inc
+
+echo2 "SUBS=" >> ./Makefile.inc
+FIRST=1
+for dir in *
+do
+ if [ -d $dir ] ; then
+ if [ -f $dir/Makefile ] ; then
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$dir >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $dir >> ./Makefile.inc
+ fi
+ FIRST=0
+ fi
+ fi
+done
+
+exit 0
+
diff --git a/src/core/cs_access.c b/src/core/cs_access.c
new file mode 100644
index 000000000..f36dda0a0
--- /dev/null
+++ b/src/core/cs_access.c
@@ -0,0 +1,543 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+
+int do_access(User * u);
+int do_levels(User * u);
+
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ACCESS", do_access, NULL, CHAN_HELP_ACCESS, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("ACCESS LEVELS", NULL, NULL, CHAN_HELP_ACCESS_LEVELS,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("LEVELS", do_levels, NULL, CHAN_HELP_LEVELS, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_ACCESS);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_LEVELS);
+}
+
+
+static int access_del(User * u, ChannelInfo *ci, ChanAccess * access, int *perm, int uacc)
+{
+ char *nick;
+ if (!access->in_use)
+ return 0;
+ if (!is_services_admin(u) && uacc <= access->level) {
+ (*perm)++;
+ return 0;
+ }
+ nick = access->nc->display;
+ access->nc = NULL;
+ access->in_use = 0;
+ send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick, nick);
+ return 1;
+}
+
+static int access_del_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *last = va_arg(args, int *);
+ int *perm = va_arg(args, int *);
+ int uacc = va_arg(args, int);
+ if (num < 1 || num > ci->accesscount)
+ return 0;
+ *last = num;
+ return access_del(u, ci, &ci->access[num - 1], perm, uacc);
+}
+
+
+static int access_list(User * u, int index, ChannelInfo * ci,
+ int *sent_header)
+{
+ ChanAccess *access = &ci->access[index];
+ const char *xop;
+
+ if (!access->in_use)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_HEADER, ci->name);
+ *sent_header = 1;
+ }
+
+ if (ci->flags & CI_XOP) {
+ xop = get_xop_level(access->level);
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_XOP_FORMAT, index + 1,
+ xop, access->nc->display);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_AXS_FORMAT, index + 1,
+ access->level, access->nc->display);
+ }
+ return 1;
+}
+
+static int access_list_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *sent_header = va_arg(args, int *);
+ if (num < 1 || num > ci->accesscount)
+ return 0;
+ return access_list(u, num - 1, ci, sent_header);
+}
+
+
+/**
+ * The /cs access command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_access(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ char *s = strtok(NULL, " ");
+ char event_access[BUFSIZE];
+
+ ChannelInfo *ci;
+ NickAlias *na = NULL;
+ NickCore *nc;
+ ChanAccess *access;
+
+ int i;
+ int level = 0, ulev;
+ int is_list = (cmd && stricmp(cmd, "LIST") == 0);
+ int is_servadmin = is_services_admin(u);
+
+ /* If LIST, we don't *require* any parameters, but we can take any.
+ * If DEL, we require a nick and no level.
+ * Else (ADD), we require a level (which implies a nick). */
+ if (!cmd || ((is_list || !stricmp(cmd, "CLEAR")) ? 0 :
+ (stricmp(cmd, "DEL") == 0) ? (!nick || s) : !s)) {
+ syntax_error(s_ChanServ, u, "ACCESS", CHAN_ACCESS_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ /* We still allow LIST in xOP mode, but not others */
+ } else if ((ci->flags & CI_XOP) && !is_list) {
+ if (ircd->halfop)
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_XOP_HOP, s_ChanServ);
+ else
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_XOP, s_ChanServ);
+ } else if (((is_list && !check_access(u, ci, CA_ACCESS_LIST))
+ || (!is_list && !check_access(u, ci, CA_ACCESS_CHANGE)))
+ && !is_servadmin) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (stricmp(cmd, "ADD") == 0) {
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
+ return MOD_CONT;
+ }
+
+ level = atoi(s);
+ ulev = get_access(u, ci);
+
+ if (!is_servadmin && level >= ulev) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (level == 0) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_NONZERO);
+ return MOD_CONT;
+ } else if (level <= ACCESS_INVALID || level >= ACCESS_FOUNDER) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_RANGE,
+ ACCESS_INVALID + 1, ACCESS_FOUNDER - 1);
+ return MOD_CONT;
+ }
+
+ na = findnick(nick);
+ if (!na) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_NICKS_ONLY);
+ return MOD_CONT;
+ }
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+
+ nc = na->nc;
+ for (access = ci->access, i = 0; i < ci->accesscount;
+ access++, i++) {
+ if (access->nc == nc) {
+ /* Don't allow lowering from a level >= ulev */
+ if (!is_servadmin && access->level >= ulev) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ if (access->level == level) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_UNCHANGED,
+ access->nc->display, chan, level);
+ return MOD_CONT;
+ }
+ access->level = level;
+ snprintf(event_access, BUFSIZE, "%d", access->level);
+ send_event(EVENT_ACCESS_CHANGE, 4, ci->name, u->nick,
+ na->nick, event_access);
+ alog("%s: %s!%s@%s (level %d) set access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->username, u->host, ulev, access->level, na->nick, nc->display, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LEVEL_CHANGED,
+ access->nc->display, chan, level);
+ return MOD_CONT;
+ }
+ }
+
+ /* All entries should be in use so we no longer need
+ * to go over the entire list..
+ for (i = 0; i < ci->accesscount; i++) {
+ if (!ci->access[i].in_use)
+ break;
+ }
+ */
+
+ if (i < CSAccessMax) {
+ ci->accesscount++;
+ ci->access =
+ srealloc(ci->access,
+ sizeof(ChanAccess) * ci->accesscount);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_REACHED_LIMIT,
+ CSAccessMax);
+ return MOD_CONT;
+ }
+
+ access = &ci->access[i];
+ access->nc = nc;
+ access->in_use = 1;
+ access->level = level;
+ access->last_seen = 0;
+
+ snprintf(event_access, BUFSIZE, "%d", access->level);
+ send_event(EVENT_ACCESS_ADD, 4, ci->name, u->nick, na->nick,
+ event_access);
+ alog("%s: %s!%s@%s (level %d) set access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->username, u->host, ulev, access->level, na->nick, nc->display, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_ADDED, nc->display,
+ ci->name, access->level);
+ } else if (stricmp(cmd, "DEL") == 0) {
+ int deleted, a, b;
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (ci->accesscount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+
+ /* Special case: is it a number/list? Only do search if it isn't. */
+ if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) {
+ int count, last = -1, perm = 0;
+ deleted = process_numlist(nick, &count, access_del_callback, u,
+ ci, &last, &perm, get_access(u, ci));
+ if (!deleted) {
+ if (perm) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (count == 1) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_NO_SUCH_ENTRY,
+ last, ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_NO_MATCH,
+ ci->name);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DELETED_ONE,
+ ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DELETED_SEVERAL,
+ deleted, ci->name);
+ }
+ } else {
+ na = findnick(nick);
+ if (!na) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+ nc = na->nc;
+ for (i = 0; i < ci->accesscount; i++) {
+ if (ci->access[i].nc == nc)
+ break;
+ }
+ if (i == ci->accesscount) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_NOT_FOUND, nick,
+ chan);
+ return MOD_CONT;
+ }
+ access = &ci->access[i];
+ if (!is_servadmin && get_access(u, ci) <= access->level) {
+ deleted = 0;
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DELETED,
+ access->nc->display, ci->name);
+ alog("%s: %s!%s@%s (level %d) deleted access of %s (group %s) on %s", s_ChanServ, u->nick, u->username, u->host, get_access(u, ci), na->nick, access->nc->display, chan);
+ access->nc = NULL;
+ access->in_use = 0;
+ deleted = 1;
+ }
+ }
+
+ if (deleted) {
+ /* Reordering - DrStein */
+ for (b = 0; b < ci->accesscount; b++) {
+ if (ci->access[b].in_use) {
+ for (a = 0; a < ci->accesscount; a++) {
+ if (a > b)
+ break;
+ if (!ci->access[a].in_use) {
+ ci->access[a].in_use = 1;
+ ci->access[a].level = ci->access[b].level;
+ ci->access[a].nc = ci->access[b].nc;
+ ci->access[a].last_seen =
+ ci->access[b].last_seen;
+ ci->access[b].nc = NULL;
+ ci->access[b].in_use = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ /* After reordering only the entries at the end could still be empty.
+ * We ll free the places no longer in use... */
+ for (i = ci->accesscount - 1; i >= 0; i--) {
+ if (ci->access[i].in_use == 1)
+ break;
+
+ ci->accesscount--;
+ }
+ ci->access =
+ srealloc(ci->access,sizeof(ChanAccess) * ci->accesscount);
+
+ /* We don't know the nick if someone used numbers, so we trigger the event without
+ * nick param. We just do this once, even if someone enters a range. -Certus */
+ if (na)
+ send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick, na->nick);
+ else
+ send_event(EVENT_ACCESS_DEL, 2, ci->name, u->nick);
+ }
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int sent_header = 0;
+
+ if (ci->accesscount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+ if (nick && strspn(nick, "1234567890,-") == strlen(nick)) {
+ process_numlist(nick, NULL, access_list_callback, u, ci,
+ &sent_header);
+ } else {
+ for (i = 0; i < ci->accesscount; i++) {
+ if (nick && ci->access[i].nc
+ && !match_wild_nocase(nick, ci->access[i].nc->display))
+ continue;
+ access_list(u, i, ci, &sent_header);
+ }
+ }
+ if (!sent_header) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_NO_MATCH, chan);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_FOOTER, ci->name);
+ }
+ } else if (stricmp(cmd, "CLEAR") == 0) {
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!is_servadmin && !is_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ free(ci->access);
+ ci->access = NULL;
+ ci->accesscount = 0;
+
+ send_event(EVENT_ACCESS_CLEAR, 2, ci->name, u->nick);
+
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_CLEAR, ci->name);
+ alog("%s: %s!%s@%s (level %d) cleared access list on %s",
+ s_ChanServ, u->nick, u->username, u->host,
+ get_access(u, ci), chan);
+
+ } else {
+ syntax_error(s_ChanServ, u, "ACCESS", CHAN_ACCESS_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+
+int do_levels(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *what = strtok(NULL, " ");
+ char *s = strtok(NULL, " ");
+ char *error;
+
+ ChannelInfo *ci;
+ int level;
+ int i;
+
+ /* If SET, we want two extra parameters; if DIS[ABLE] or FOUNDER, we want only
+ * one; else, we want none.
+ */
+ if (!cmd
+ || ((stricmp(cmd, "SET") == 0) ? !s
+ : ((strnicmp(cmd, "DIS", 3) == 0)) ? (!what || s) : !!what)) {
+ syntax_error(s_ChanServ, u, "LEVELS", CHAN_LEVELS_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (ci->flags & CI_XOP) {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_XOP);
+ } else if (!is_founder(u, ci) && !is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (stricmp(cmd, "SET") == 0) {
+ level = strtol(s, &error, 10);
+
+ if (*error != '\0') {
+ syntax_error(s_ChanServ, u, "LEVELS", CHAN_LEVELS_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (level <= ACCESS_INVALID || level >= ACCESS_FOUNDER) {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_RANGE,
+ ACCESS_INVALID + 1, ACCESS_FOUNDER - 1);
+ return MOD_CONT;
+ }
+
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ if (stricmp(levelinfo[i].name, what) == 0) {
+ ci->levels[levelinfo[i].what] = level;
+
+ alog("%s: %s!%s@%s set level %s on channel %s to %d",
+ s_ChanServ, u->nick, u->username, u->host,
+ levelinfo[i].name, ci->name, level);
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_CHANGED,
+ levelinfo[i].name, chan, level);
+ return MOD_CONT;
+ }
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_UNKNOWN, what, s_ChanServ);
+
+ } else if (stricmp(cmd, "DIS") == 0 || stricmp(cmd, "DISABLE") == 0) {
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ if (stricmp(levelinfo[i].name, what) == 0) {
+ ci->levels[levelinfo[i].what] = ACCESS_INVALID;
+
+ alog("%s: %s!%s@%s disabled level %s on channel %s",
+ s_ChanServ, u->nick, u->username, u->host,
+ levelinfo[i].name, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_DISABLED,
+ levelinfo[i].name, chan);
+ return MOD_CONT;
+ }
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_UNKNOWN, what, s_ChanServ);
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int i;
+
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_LIST_HEADER, chan);
+
+ if (!levelinfo_maxwidth) {
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ int len = strlen(levelinfo[i].name);
+ if (len > levelinfo_maxwidth)
+ levelinfo_maxwidth = len;
+ }
+ }
+
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ int j = ci->levels[levelinfo[i].what];
+
+ if (j == ACCESS_INVALID) {
+ j = levelinfo[i].what;
+
+ if (j == CA_AUTOOP || j == CA_AUTODEOP || j == CA_AUTOVOICE
+ || j == CA_NOJOIN) {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_LIST_DISABLED,
+ levelinfo_maxwidth, levelinfo[i].name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_LIST_DISABLED,
+ levelinfo_maxwidth, levelinfo[i].name);
+ }
+ } else if (j == ACCESS_FOUNDER) {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_LIST_FOUNDER,
+ levelinfo_maxwidth, levelinfo[i].name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_LIST_NORMAL,
+ levelinfo_maxwidth, levelinfo[i].name, j);
+ }
+ }
+
+ } else if (stricmp(cmd, "RESET") == 0) {
+ reset_levels(ci);
+
+ alog("%s: %s!%s@%s reset levels definitions on channel %s",
+ s_ChanServ, u->nick, u->username, u->host, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_LEVELS_RESET, chan);
+ } else {
+ syntax_error(s_ChanServ, u, "LEVELS", CHAN_LEVELS_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_akick.c b/src/core/cs_akick.c
new file mode 100644
index 000000000..14014e054
--- /dev/null
+++ b/src/core/cs_akick.c
@@ -0,0 +1,668 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+
+int do_akick(User * u);
+void myChanServHelp(User * u);
+int get_access_nc(NickCore *nc, ChannelInfo *ci);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("AKICK", do_akick, NULL, CHAN_HELP_AKICK, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_AKICK);
+}
+
+/**
+ * The /cs akick command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+ /* `last' is set to the last index this routine was called with */
+int akick_del(User * u, AutoKick * akick)
+{
+ if (!(akick->flags & AK_USED))
+ return 0;
+ if (akick->flags & AK_ISNICK) {
+ akick->u.nc = NULL;
+ } else {
+ free(akick->u.mask);
+ akick->u.mask = NULL;
+ }
+ if (akick->reason) {
+ free(akick->reason);
+ akick->reason = NULL;
+ }
+ if (akick->creator) {
+ free(akick->creator);
+ akick->creator = NULL;
+ }
+ akick->addtime = 0;
+ akick->flags = 0;
+ return 1;
+}
+
+int akick_del_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *last = va_arg(args, int *);
+
+ *last = num;
+
+ if (num < 1 || num > ci->akickcount)
+ return 0;
+
+ return akick_del(u, &ci->akick[num - 1]);
+}
+
+
+int akick_list(User * u, int index, ChannelInfo * ci, int *sent_header)
+{
+ AutoKick *akick = &ci->akick[index];
+
+ if (!(akick->flags & AK_USED))
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_HEADER, ci->name);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_FORMAT, index + 1,
+ ((akick->flags & AK_ISNICK) ? akick->u.nc->
+ display : akick->u.mask),
+ (akick->reason ? akick->
+ reason : getstring(u->na, NO_REASON)));
+ return 1;
+}
+
+int akick_list_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *sent_header = va_arg(args, int *);
+ if (num < 1 || num > ci->akickcount)
+ return 0;
+ return akick_list(u, num - 1, ci, sent_header);
+}
+
+int akick_view(User * u, int index, ChannelInfo * ci, int *sent_header)
+{
+ AutoKick *akick = &ci->akick[index];
+ char timebuf[64];
+ struct tm tm;
+
+ if (!(akick->flags & AK_USED))
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_HEADER, ci->name);
+ *sent_header = 1;
+ }
+
+ if (akick->addtime) {
+ tm = *localtime(&akick->addtime);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_SHORT_DATE_FORMAT, &tm);
+ } else {
+ snprintf(timebuf, sizeof(timebuf), getstring(u->na, UNKNOWN));
+ }
+
+ notice_lang(s_ChanServ, u,
+ ((akick->
+ flags & AK_STUCK) ? CHAN_AKICK_VIEW_FORMAT_STUCK :
+ CHAN_AKICK_VIEW_FORMAT), index + 1,
+ ((akick->flags & AK_ISNICK) ? akick->u.nc->
+ display : akick->u.mask),
+ akick->creator ? akick->creator : getstring(u->na,
+ UNKNOWN),
+ timebuf,
+ (akick->reason ? akick->
+ reason : getstring(u->na, NO_REASON)));
+ return 1;
+}
+
+int akick_view_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *sent_header = va_arg(args, int *);
+ if (num < 1 || num > ci->akickcount)
+ return 0;
+ return akick_view(u, num - 1, ci, sent_header);
+}
+
+
+
+int do_akick(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *mask = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+ ChannelInfo *ci;
+ AutoKick *akick;
+ int i;
+ Channel *c;
+ struct c_userlist *cu = NULL;
+ struct c_userlist *next;
+ User *u2;
+ char *argv[3];
+ int count = 0;
+
+ if (!cmd || (!mask && (!stricmp(cmd, "ADD") || !stricmp(cmd, "STICK")
+ || !stricmp(cmd, "UNSTICK")
+ || !stricmp(cmd, "DEL")))) {
+
+ syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!check_access(u, ci, CA_AKICK) && !is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (stricmp(cmd, "ADD") == 0) {
+ NickAlias *na = findnick(mask), *na2;
+ NickCore *nc = NULL;
+ char *nick, *user, *host;
+ int freemask = 0;
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!na) {
+ split_usermask(mask, &nick, &user, &host);
+ mask =
+ scalloc(strlen(nick) + strlen(user) + strlen(host) + 3, 1);
+ freemask = 1;
+ sprintf(mask, "%s!%s@%s", nick, user, host);
+ free(nick);
+ free(user);
+ free(host);
+ } else {
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, mask);
+ return MOD_CONT;
+ }
+ nc = na->nc;
+ }
+
+ /* Check excepts BEFORE we get this far */
+ if (ircd->except) {
+ if (is_excepted_mask(ci, mask) == 1) {
+ notice_lang(s_ChanServ, u, CHAN_EXCEPTED, mask, chan);
+ if (freemask)
+ free(mask);
+ return MOD_CONT;
+ }
+ }
+
+ /* Check whether target nick has equal/higher access
+ * or whether the mask matches a user with higher/equal access - Viper */
+ if ((ci->flags & CI_PEACE) && nc) {
+ if ((nc == ci->founder) || (get_access_nc(nc, ci) >= get_access(u, ci))) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ if (freemask)
+ free(mask);
+ return MOD_CONT;
+ }
+ } else if ((ci->flags & CI_PEACE)) {
+ char buf[BUFSIZE];
+ /* Match against all currently online users with equal or
+ * higher access. - Viper */
+ for (i = 0; i < 1024; i++) {
+ for (u2 = userlist[i]; u2; u2 = u2->next) {
+ if (is_founder(u2, ci) || (get_access(u2, ci) >= get_access(u, ci))) {
+ if (match_usermask(mask, u2)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ free(mask);
+ return MOD_CONT;
+ }
+ }
+ }
+ }
+
+ /* Match against the lastusermask of all nickalias's with equal
+ * or higher access. - Viper */
+ for (i = 0; i < 1024; i++) {
+ for (na2 = nalists[i]; na2; na2 = na2->next) {
+ if (na2->status & NS_VERBOTEN)
+ continue;
+
+ if (na2->nc && ((na2->nc == ci->founder) || (get_access_nc(na2->nc, ci)
+ >= get_access(u, ci)))) {
+ snprintf(buf, BUFSIZE, "%s!%s", na2->nick, na2->last_usermask);
+ if (match_wild_nocase(mask, buf)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ free(mask);
+ return MOD_CONT;
+ }
+ }
+ }
+ }
+ }
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ if ((akick->flags & AK_ISNICK) ? akick->u.nc == nc
+ : stricmp(akick->u.mask, mask) == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_ALREADY_EXISTS,
+ (akick->flags & AK_ISNICK) ? akick->u.nc->
+ display : akick->u.mask, chan);
+ if (freemask)
+ free(mask);
+ return MOD_CONT;
+ }
+ }
+
+ /* All entries should be in use so we don't have to go over
+ * the entire list. We simply add new entries at the end. */
+ if (ci->akickcount >= CSAutokickMax) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_REACHED_LIMIT, CSAutokickMax);
+ if (freemask)
+ free(mask);
+ return MOD_CONT;
+ }
+ ci->akickcount++;
+ ci->akick =
+ srealloc(ci->akick, sizeof(AutoKick) * ci->akickcount);
+ akick = &ci->akick[i];
+ akick->flags = AK_USED;
+ if (nc) {
+ akick->flags |= AK_ISNICK;
+ akick->u.nc = nc;
+ } else {
+ akick->u.mask = sstrdup(mask);
+ }
+ akick->creator = sstrdup(u->nick);
+ akick->addtime = time(NULL);
+ if (reason) {
+ if (strlen(reason) > 200)
+ reason[200] = '\0';
+ akick->reason = sstrdup(reason);
+ } else {
+ akick->reason = NULL;
+ }
+
+ /* Auto ENFORCE #63 */
+ c = findchan(ci->name);
+ if (c) {
+ cu = c->users;
+ while (cu) {
+ next = cu->next;
+ if (check_kick(cu->user, c->name, c->creation_time)) {
+ argv[0] = sstrdup(c->name);
+ argv[1] = sstrdup(cu->user->nick);
+ if (akick->reason)
+ argv[2] = sstrdup(akick->reason);
+ else
+ argv[2] = sstrdup("none");
+
+ do_kick(s_ChanServ, 3, argv);
+
+ free(argv[2]);
+ free(argv[1]);
+ free(argv[0]);
+ count++;
+
+ }
+ cu = next;
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_AKICK_ADDED, mask, chan);
+
+ if (count)
+ notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan,
+ count);
+
+ if (freemask)
+ free(mask);
+
+ } else if (stricmp(cmd, "STICK") == 0) {
+ NickAlias *na;
+ NickCore *nc;
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (ci->akickcount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
+ return MOD_CONT;
+ }
+
+ na = findnick(mask);
+ nc = (na ? na->nc : NULL);
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
+ continue;
+ if (!stricmp(akick->u.mask, mask))
+ break;
+ }
+
+ if (i == ci->akickcount) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
+ ci->name);
+ return MOD_CONT;
+ }
+
+ akick->flags |= AK_STUCK;
+ notice_lang(s_ChanServ, u, CHAN_AKICK_STUCK, akick->u.mask,
+ ci->name);
+
+ if (ci->c)
+ stick_mask(ci, akick);
+ } else if (stricmp(cmd, "UNSTICK") == 0) {
+ NickAlias *na;
+ NickCore *nc;
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (ci->akickcount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, ci->name);
+ return MOD_CONT;
+ }
+
+ na = findnick(mask);
+ nc = (na ? na->nc : NULL);
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK))
+ continue;
+ if (!stricmp(akick->u.mask, mask))
+ break;
+ }
+
+ if (i == ci->akickcount) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
+ ci->name);
+ return MOD_CONT;
+ }
+
+ akick->flags &= ~AK_STUCK;
+ notice_lang(s_ChanServ, u, CHAN_AKICK_UNSTUCK, akick->u.mask,
+ ci->name);
+
+ } else if (stricmp(cmd, "DEL") == 0) {
+ int deleted, a, b;
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (ci->akickcount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+
+ /* Special case: is it a number/list? Only do search if it isn't. */
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ int count, last = -1;
+ deleted = process_numlist(mask, &count, akick_del_callback, u,
+ ci, &last);
+ if (!deleted) {
+ if (count == 1) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NO_SUCH_ENTRY,
+ last, ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH,
+ ci->name);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_ONE,
+ ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED_SEVERAL,
+ deleted, ci->name);
+ }
+ } else {
+ NickAlias *na = findnick(mask);
+ NickCore *nc = (na ? na->nc : NULL);
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount;
+ akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ if (((akick->flags & AK_ISNICK) && akick->u.nc == nc)
+ || (!(akick->flags & AK_ISNICK)
+ && stricmp(akick->u.mask, mask) == 0))
+ break;
+ }
+ if (i == ci->akickcount) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NOT_FOUND, mask,
+ chan);
+ return MOD_CONT;
+ }
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DELETED, mask, chan);
+ akick_del(u, akick);
+ deleted = 1;
+ }
+ if (deleted) {
+ /* Reordering - DrStein */
+ for (b = 0; b < ci->akickcount; b++) {
+ if (ci->akick[b].flags & AK_USED) {
+ for (a = 0; a < ci->akickcount; a++) {
+ if (a > b)
+ break;
+ if (!(ci->akick[a].flags & AK_USED)) {
+ ci->akick[a].flags = ci->akick[b].flags;
+ if (ci->akick[b].flags & AK_ISNICK) {
+ ci->akick[a].u.nc = ci->akick[b].u.nc;
+ } else {
+ ci->akick[a].u.mask =
+ sstrdup(ci->akick[b].u.mask);
+ }
+ /* maybe we should first check whether there
+ is a reason before we sstdrup it -Certus */
+ if (ci->akick[b].reason)
+ ci->akick[a].reason =
+ sstrdup(ci->akick[b].reason);
+ else
+ ci->akick[a].reason = NULL;
+ ci->akick[a].creator =
+ sstrdup(ci->akick[b].creator);
+ ci->akick[a].addtime = ci->akick[b].addtime;
+
+ akick_del(u, &ci->akick[b]);
+ break;
+ }
+ }
+ }
+ }
+ /* After reordering only the entries at the end could still be empty.
+ * We ll free the places no longer in use... - Viper */
+ for (i = ci->akickcount - 1; i >= 0; i--) {
+ if (ci->akick[i].flags & AK_USED)
+ break;
+
+ ci->akickcount--;
+ }
+ ci->akick =
+ srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount);
+ }
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int sent_header = 0;
+
+ if (ci->akickcount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+ if (mask && isdigit(*mask) &&
+ strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, akick_list_callback, u, ci,
+ &sent_header);
+ } else {
+ for (akick = ci->akick, i = 0; i < ci->akickcount;
+ akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ if (mask) {
+ if (!(akick->flags & AK_ISNICK)
+ && !match_wild_nocase(mask, akick->u.mask))
+ continue;
+ if ((akick->flags & AK_ISNICK)
+ && !match_wild_nocase(mask, akick->u.nc->display))
+ continue;
+ }
+ akick_list(u, i, ci, &sent_header);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
+
+ } else if (stricmp(cmd, "VIEW") == 0) {
+ int sent_header = 0;
+
+ if (ci->akickcount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+ if (mask && isdigit(*mask) &&
+ strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, akick_view_callback, u, ci,
+ &sent_header);
+ } else {
+ for (akick = ci->akick, i = 0; i < ci->akickcount;
+ akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ if (mask) {
+ if (!(akick->flags & AK_ISNICK)
+ && !match_wild_nocase(mask, akick->u.mask))
+ continue;
+ if ((akick->flags & AK_ISNICK)
+ && !match_wild_nocase(mask, akick->u.nc->display))
+ continue;
+ }
+ akick_view(u, i, ci, &sent_header);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_ChanServ, u, CHAN_AKICK_NO_MATCH, chan);
+
+ } else if (stricmp(cmd, "ENFORCE") == 0) {
+ Channel *c = findchan(ci->name);
+ struct c_userlist *cu = NULL;
+ struct c_userlist *next;
+ char *argv[3];
+ int count = 0;
+
+ if (!c) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, ci->name);
+ return MOD_CONT;
+ }
+
+ cu = c->users;
+
+ while (cu) {
+ next = cu->next;
+ if (check_kick(cu->user, c->name, c->creation_time)) {
+ argv[0] = sstrdup(c->name);
+ argv[1] = sstrdup(cu->user->nick);
+ argv[2] = sstrdup(CSAutokickReason);
+
+ do_kick(s_ChanServ, 3, argv);
+
+ free(argv[2]);
+ free(argv[1]);
+ free(argv[0]);
+
+ count++;
+ }
+ cu = next;
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_AKICK_ENFORCE_DONE, chan, count);
+
+ } else if (stricmp(cmd, "CLEAR") == 0) {
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_AKICK_DISABLED);
+ return MOD_CONT;
+ }
+
+ for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
+ if (!(akick->flags & AK_USED))
+ continue;
+ akick_del(u, akick);
+ }
+
+ free(ci->akick);
+ ci->akick = NULL;
+ ci->akickcount = 0;
+
+ notice_lang(s_ChanServ, u, CHAN_AKICK_CLEAR, ci->name);
+
+ } else {
+ syntax_error(s_ChanServ, u, "AKICK", CHAN_AKICK_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+
+int get_access_nc(NickCore *nc, ChannelInfo *ci)
+{
+ ChanAccess *access;
+ if (!ci || !nc)
+ return 0;
+
+ if ((access = get_access_entry(nc, ci)))
+ return access->level;
+ return 0;
+}
+
+/* EOF */
diff --git a/src/core/cs_ban.c b/src/core/cs_ban.c
new file mode 100644
index 000000000..658fa8809
--- /dev/null
+++ b/src/core/cs_ban.c
@@ -0,0 +1,227 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_unban(User * u);
+int do_ban(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("BAN", do_ban, NULL, CHAN_HELP_BAN, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("UNBAN", do_unban, NULL, CHAN_HELP_UNBAN, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_BAN);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_UNBAN);
+}
+
+/**
+ * The /cs ban command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_ban(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *params = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ Channel *c;
+ ChannelInfo *ci;
+ User *u2;
+
+ int is_same;
+
+ if (!reason) {
+ reason = "Requested";
+ } else {
+ if (strlen(reason) > 200)
+ reason[200] = '\0';
+ }
+
+ if (!chan) {
+ struct u_chanlist *uc, *next;
+
+ /* Bans the user on every channels he is on. */
+
+ for (uc = u->chans; uc; uc = next) {
+ next = uc->next;
+ if ((ci = uc->chan->ci) && !(ci->flags & CI_VERBOTEN)
+ && check_access(u, ci, CA_BANME)) {
+ char *av[3];
+ char mask[BUFSIZE];
+
+ /*
+ * Dont ban/kick the user on channels where he is excepted
+ * to prevent services <-> server wars.
+ */
+ if (ircd->except) {
+ if (is_excepted(ci, u))
+ notice_lang(s_ChanServ, u, CHAN_EXCEPTED,
+ u->nick, ci->name);
+ continue;
+ }
+ if (is_protected(u)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ continue;
+ }
+
+ av[0] = sstrdup("+b");
+ get_idealban(ci, u, mask, sizeof(mask));
+ av[1] = mask;
+ anope_cmd_mode(whosends(ci), uc->chan->name, "+b %s",
+ av[1]);
+ chan_set_modes(s_ChanServ, uc->chan, 2, av, 1);
+ free(av[0]);
+
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(u, ci, CA_SIGNKICK)))
+ anope_cmd_kick(whosends(ci), ci->name, u->nick,
+ "%s (%s)", reason, u->nick);
+ else
+ anope_cmd_kick(whosends(ci), ci->name, u->nick, "%s",
+ reason);
+ av[0] = ci->name;
+ av[1] = u->nick;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ }
+
+ return MOD_CONT;
+ } else if (!params) {
+ params = u->nick;
+ }
+
+ is_same = (params == u->nick) ? 1 : (stricmp(params, u->nick) == 0);
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (is_same ? !(u2 = u) : !(u2 = finduser(params))) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_IN_USE, params);
+ } else if (!is_same ? !check_access(u, ci, CA_BAN) :
+ !check_access(u, ci, CA_BANME)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (!is_same && (ci->flags & CI_PEACE)
+ && (get_access(u2, ci) >= get_access(u, ci))) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ /*
+ * Dont ban/kick the user on channels where he is excepted
+ * to prevent services <-> server wars.
+ */
+ } else if (ircd->except && is_excepted(ci, u2)) {
+ notice_lang(s_ChanServ, u, CHAN_EXCEPTED, u2->nick, ci->name);
+ } else if (ircd->protectedumode && is_protected(u2)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ char *av[3];
+ char mask[BUFSIZE];
+
+ av[0] = sstrdup("+b");
+ get_idealban(ci, u2, mask, sizeof(mask));
+ av[1] = mask;
+ anope_cmd_mode(whosends(ci), c->name, "+b %s", av[1]);
+ chan_set_modes(s_ChanServ, c, 2, av, 1);
+ free(av[0]);
+
+ /* We still allow host banning while not allowing to kick */
+ if (!is_on_chan(c, u2))
+ return MOD_CONT;
+
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(u, ci, CA_SIGNKICK)))
+ anope_cmd_kick(whosends(ci), ci->name, params, "%s (%s)",
+ reason, u->nick);
+ else
+ anope_cmd_kick(whosends(ci), ci->name, params, "%s", reason);
+
+ av[0] = ci->name;
+ av[1] = params;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ return MOD_CONT;
+}
+
+/**
+ * The /cs unban command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_unban(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ Channel *c;
+ ChannelInfo *ci;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "UNBAN", CHAN_UNBAN_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!check_access(u, ci, CA_UNBAN)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ common_unban(ci, u->nick);
+ notice_lang(s_ChanServ, u, CHAN_UNBANNED, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_clear.c b/src/core/cs_clear.c
new file mode 100644
index 000000000..04f5df803
--- /dev/null
+++ b/src/core/cs_clear.c
@@ -0,0 +1,402 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_clear(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("CLEAR", do_clear, NULL, CHAN_HELP_CLEAR, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_CLEAR);
+}
+
+/**
+ * The /cs clear command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_clear(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *what = strtok(NULL, " ");
+ Channel *c;
+ ChannelInfo *ci;
+
+ if (!what) {
+ syntax_error(s_ChanServ, u, "CLEAR", CHAN_CLEAR_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!u || !check_access(u, ci, CA_CLEAR)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (stricmp(what, "bans") == 0) {
+ char *av[2];
+ Entry *ban, *next;
+
+ if (c->bans && c->bans->count) {
+ for (ban = c->bans->entries; ban; ban = next) {
+ next = ban->next;
+ av[0] = sstrdup("-b");
+ av[1] = sstrdup(ban->mask);
+ anope_cmd_mode(whosends(ci), chan, "-b %s", ban->mask);
+ chan_set_modes(whosends(ci), c, 2, av, 0);
+ free(av[0]);
+ free(av[1]);
+ }
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_BANS, chan);
+ } else if (ircd->except && stricmp(what, "excepts") == 0) {
+ char *av[2];
+ Entry *except, *next;
+
+ if (c->excepts && c->excepts->count) {
+ for (except = c->excepts->entries; except; except = next) {
+ next = except->next;
+ av[0] = sstrdup("-e");
+ av[1] = sstrdup(except->mask);
+ anope_cmd_mode(whosends(ci), chan, "-e %s", except->mask);
+ chan_set_modes(whosends(ci), c, 2, av, 0);
+ free(av[0]);
+ free(av[1]);
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_EXCEPTS, chan);
+
+ } else if (ircd->invitemode && stricmp(what, "invites") == 0) {
+ char *av[2];
+ Entry *invite, *next;
+
+ if (c->invites && c->invites->count) {
+ for (invite = c->invites->entries; invite; invite = next) {
+ next = invite->next;
+ av[0] = sstrdup("-I");
+ av[1] = sstrdup(invite->mask);
+ anope_cmd_mode(whosends(ci), chan, "-I %s", invite->mask);
+ chan_set_modes(whosends(ci), c, 2, av, 0);
+ free(av[0]);
+ free(av[1]);
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_INVITES, chan);
+
+ } else if (stricmp(what, "modes") == 0) {
+ char *argv[2];
+
+ if (c->mode) {
+ /* Clear modes the bulk of the modes */
+ anope_cmd_mode(whosends(ci), c->name, "%s",
+ ircd->modestoremove);
+ argv[0] = sstrdup(ircd->modestoremove);
+ chan_set_modes(whosends(ci), c, 1, argv, 0);
+ free(argv[0]);
+
+ /* to prevent the internals from complaining send -k, -L, -f by themselves if we need
+ to send them - TSL */
+ if (c->key) {
+ anope_cmd_mode(whosends(ci), c->name, "-k %s", c->key);
+ argv[0] = sstrdup("-k");
+ argv[1] = c->key;
+ chan_set_modes(whosends(ci), c, 2, argv, 0);
+ free(argv[0]);
+ }
+ if (ircd->Lmode && c->redirect) {
+ anope_cmd_mode(whosends(ci), c->name, "-L %s",
+ c->redirect);
+ argv[0] = sstrdup("-L");
+ argv[1] = c->redirect;
+ chan_set_modes(whosends(ci), c, 2, argv, 0);
+ free(argv[0]);
+ }
+ if (ircd->fmode && c->flood) {
+ if (flood_mode_char_remove) {
+ anope_cmd_mode(whosends(ci), c->name, "%s %s",
+ flood_mode_char_remove, c->flood);
+ argv[0] = sstrdup(flood_mode_char_remove);
+ argv[1] = c->flood;
+ chan_set_modes(whosends(ci), c, 2, argv, 0);
+ free(argv[0]);
+ } else {
+ if (debug) {
+ alog("debug: flood_mode_char_remove was not set unable to remove flood/throttle modes");
+ }
+ }
+ }
+ check_modes(c);
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_MODES, chan);
+ } else if (stricmp(what, "ops") == 0) {
+ char *av[6]; /* The max we have to hold: chan, ts, modes(max3), nick, nick, nick */
+ int ac, isop, isadmin, isown, count, i;
+ char buf[BUFSIZE], tmp[BUFSIZE], tmp2[BUFSIZE];
+ struct c_userlist *cu, *next;
+
+ if (ircd->svsmode_ucmode) {
+ av[0] = chan;
+ anope_cmd_svsmode_chan(av[0], "-o", NULL);
+ if (ircd->owner) {
+ anope_cmd_svsmode_chan(av[0], ircd->ownerunset, NULL);
+ }
+ if (ircd->protect || ircd->admin) {
+ anope_cmd_svsmode_chan(av[0], ircd->adminunset, NULL);
+ }
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ isop = chan_has_user_status(c, cu->user, CUS_OP);
+ isadmin = chan_has_user_status(c, cu->user, CUS_PROTECT);
+ isown = chan_has_user_status(c, cu->user, CUS_OWNER);
+ count = (isop ? 1 : 0) + (isadmin ? 1 : 0) + (isown ? 1 : 0);
+
+ if (!isop && !isadmin && !isown)
+ continue;
+
+ snprintf(tmp, BUFSIZE, "-%s%s%s", (isop ? "o" : ""), (isadmin ?
+ ircd->adminunset+1 : ""), (isown ? ircd->ownerunset+1 : ""));
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[1] = buf;
+ av[2] = tmp;
+ /* We have to give as much nicks as modes.. - Viper */
+ for (i = 0; i < count; i++)
+ av[i+3] = cu->user->nick;
+ ac = 3 + i;
+ } else {
+ av[1] = tmp;
+ /* We have to give as much nicks as modes.. - Viper */
+ for (i = 0; i < count; i++)
+ av[i+2] = cu->user->nick;
+ ac = 2 + i;
+ }
+
+ do_cmode(s_ChanServ, ac, av);
+ }
+ } else {
+ av[0] = chan;
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ isop = chan_has_user_status(c, cu->user, CUS_OP);
+ isadmin = chan_has_user_status(c, cu->user, CUS_PROTECT);
+ isown = chan_has_user_status(c, cu->user, CUS_OWNER);
+ count = (isop ? 1 : 0) + (isadmin ? 1 : 0) + (isown ? 1 : 0);
+
+ if (!isop && !isadmin && !isown)
+ continue;
+
+ snprintf(tmp, BUFSIZE, "-%s%s%s", (isop ? "o" : ""), (isadmin ?
+ ircd->adminunset+1 : ""), (isown ? ircd->ownerunset+1 : ""));
+ /* We need to send the IRCd a nick for every mode.. - Viper */
+ snprintf(tmp2, BUFSIZE, "%s %s %s", (isop ? cu->user->nick : ""),
+ (isadmin ? cu->user->nick : ""), (isown ? cu->user->nick : ""));
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[1] = buf;
+ av[2] = tmp;
+ /* We have to give as much nicks as modes.. - Viper */
+ for (i = 0; i < count; i++)
+ av[i+3] = cu->user->nick;
+ ac = 3 + i;
+
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[2], tmp2);
+ } else {
+ av[1] = tmp;
+ /* We have to give as much nicks as modes.. - Viper */
+ for (i = 0; i < count; i++)
+ av[i+2] = cu->user->nick;
+ ac = 2 + i;
+
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[1], tmp2);
+ }
+
+ do_cmode(s_ChanServ, ac, av);
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_OPS, chan);
+ } else if (ircd->halfop && stricmp(what, "hops") == 0) {
+ char *av[4];
+ int ac;
+ char buf[BUFSIZE];
+ struct c_userlist *cu, *next;
+
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_HALFOP))
+ continue;
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = sstrdup(chan);
+ av[1] = buf;
+ av[2] = sstrdup("-h");
+ av[3] = sstrdup(cu->user->nick);
+ ac = 4;
+ } else {
+ av[0] = sstrdup(chan);
+ av[1] = sstrdup("-h");
+ av[2] = sstrdup(cu->user->nick);
+ ac = 3;
+ }
+
+ if (ircd->svsmode_ucmode) {
+ if (ircdcap->tsmode)
+ anope_cmd_svsmode_chan(av[0], av[2], NULL);
+ else
+ anope_cmd_svsmode_chan(av[0], av[1], NULL);
+
+ do_cmode(s_ChanServ, ac, av);
+ break;
+ } else {
+ if (ircdcap->tsmode)
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[2],
+ av[3]);
+ else
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[1],
+ av[2]);
+ }
+ do_cmode(s_ChanServ, ac, av);
+
+ if (ircdcap->tsmode) {
+ free(av[3]);
+ free(av[2]);
+ free(av[0]);
+ } else {
+ free(av[2]);
+ free(av[1]);
+ free(av[0]);
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_HOPS, chan);
+ } else if (stricmp(what, "voices") == 0) {
+ char *av[4];
+ int ac;
+ char buf[BUFSIZE];
+ struct c_userlist *cu, *next;
+
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_VOICE))
+ continue;
+
+ if (ircdcap->tsmode) {
+ snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
+ av[0] = sstrdup(chan);
+ av[1] = buf;
+ av[2] = sstrdup("-v");
+ av[3] = sstrdup(cu->user->nick);
+ ac = 4;
+ } else {
+ av[0] = sstrdup(chan);
+ av[1] = sstrdup("-v");
+ av[2] = sstrdup(cu->user->nick);
+ ac = 3;
+ }
+
+ if (ircd->svsmode_ucmode) {
+ if (ircdcap->tsmode)
+ anope_cmd_svsmode_chan(av[0], av[2], NULL);
+ else
+ anope_cmd_svsmode_chan(av[0], av[1], NULL);
+
+ do_cmode(s_ChanServ, ac, av);
+ break;
+ } else {
+ if (ircdcap->tsmode) {
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[2],
+ av[3]);
+ } else {
+ anope_cmd_mode(whosends(ci), av[0], "%s %s", av[1],
+ av[2]);
+ }
+ }
+ do_cmode(s_ChanServ, ac, av);
+
+ if (ircdcap->tsmode) {
+ free(av[3]);
+ free(av[2]);
+ free(av[0]);
+ } else {
+ free(av[2]);
+ free(av[1]);
+ free(av[0]);
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_VOICES, chan);
+ } else if (stricmp(what, "users") == 0) {
+ char *av[3];
+ struct c_userlist *cu, *next;
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "CLEAR USERS command from %s", u->nick);
+
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ av[0] = sstrdup(chan);
+ av[1] = sstrdup(cu->user->nick);
+ av[2] = sstrdup(buf);
+ anope_cmd_kick(whosends(ci), av[0], av[1], av[2]);
+ do_kick(s_ChanServ, 3, av);
+ free(av[2]);
+ free(av[1]);
+ free(av[0]);
+ }
+ notice_lang(s_ChanServ, u, CHAN_CLEARED_USERS, chan);
+ } else {
+ syntax_error(s_ChanServ, u, "CLEAR", CHAN_CLEAR_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_drop.c b/src/core/cs_drop.c
new file mode 100644
index 000000000..dff5992e9
--- /dev/null
+++ b/src/core/cs_drop.c
@@ -0,0 +1,128 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_drop(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("DROP", do_drop, NULL, -1, CHAN_HELP_DROP, -1,
+ CHAN_SERVADMIN_HELP_DROP, CHAN_SERVADMIN_HELP_DROP);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DROP);
+}
+
+/**
+ * The /cs command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_drop(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ ChannelInfo *ci;
+ int is_servadmin = is_services_admin(u);
+
+ if (readonly && !is_servadmin) {
+ notice_lang(s_ChanServ, u, CHAN_DROP_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "DROP", CHAN_DROP_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (!is_servadmin && (ci->flags & CI_VERBOTEN)) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!is_servadmin && (ci->flags & CI_SUSPENDED)) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!is_servadmin
+ && (ci->
+ flags & CI_SECUREFOUNDER ? !is_real_founder(u,
+ ci) :
+ !is_founder(u, ci))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ int level = get_access(u, ci);
+
+ if (readonly) /* in this case we know they're a Services admin */
+ notice_lang(s_ChanServ, u, READ_ONLY_MODE);
+
+ if (ci->c) {
+ if (ircd->regmode) {
+ ci->c->mode &= ~ircd->regmode;
+ anope_cmd_mode(whosends(ci), ci->name, "-r");
+ }
+ }
+
+ if (ircd->chansqline && (ci->flags & CI_VERBOTEN)) {
+ anope_cmd_unsqline(ci->name);
+ }
+
+ alog("%s: Channel %s dropped by %s!%s@%s (founder: %s)",
+ s_ChanServ, ci->name, u->nick, u->username,
+ u->host, (ci->founder ? ci->founder->display : "(none)"));
+
+ delchan(ci);
+
+ /* We must make sure that the Services admin has not normally the right to
+ * drop the channel before issuing the wallops.
+ */
+ if (WallDrop && is_servadmin && level < ACCESS_FOUNDER)
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 used DROP on channel \2%s\2", u->nick,
+ chan);
+
+ notice_lang(s_ChanServ, u, CHAN_DROPPED, chan);
+ send_event(EVENT_CHAN_DROP, 1, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_forbid.c b/src/core/cs_forbid.c
new file mode 100644
index 000000000..cd7a0e584
--- /dev/null
+++ b/src/core/cs_forbid.c
@@ -0,0 +1,139 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_forbid(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("FORBID", do_forbid, is_services_admin, -1, -1, -1,
+ CHAN_SERVADMIN_HELP_FORBID,
+ CHAN_SERVADMIN_HELP_FORBID);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_FORBID);
+ }
+}
+
+/**
+ * The /cs forbid command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_forbid(User * u)
+{
+ ChannelInfo *ci;
+ char *chan = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ Channel *c;
+
+ /* Assumes that permission checking has already been done. */
+ if (!chan || (ForceForbidReason && !reason)) {
+ syntax_error(s_ChanServ, u, "FORBID",
+ (ForceForbidReason ? CHAN_FORBID_SYNTAX_REASON :
+ CHAN_FORBID_SYNTAX));
+ return MOD_CONT;
+ }
+ if (*chan != '#') {
+ notice_lang(s_ChanServ, u, CHAN_SYMBOL_REQUIRED);
+ return MOD_CONT;
+ } else if (!anope_valid_chan(chan)) {
+ notice_lang(s_ChanServ, u, CHAN_X_INVALID, chan);
+ return MOD_CONT;
+ }
+ if (readonly)
+ notice_lang(s_ChanServ, u, READ_ONLY_MODE);
+ if ((ci = cs_findchan(chan)) != NULL)
+ delchan(ci);
+ ci = makechan(chan);
+ if (ci) {
+ ci->flags |= CI_VERBOTEN;
+ ci->forbidby = sstrdup(u->nick);
+ if (reason)
+ ci->forbidreason = sstrdup(reason);
+
+ if ((c = findchan(ci->name))) {
+ struct c_userlist *cu, *next;
+ char *av[3];
+
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+
+ if (is_oper(cu->user))
+ continue;
+
+ av[0] = c->name;
+ av[1] = cu->user->nick;
+ av[2] = reason ? reason : "CHAN_FORBID_REASON";
+ anope_cmd_kick(s_ChanServ, av[0], av[1], av[2]);
+ do_kick(s_ChanServ, 3, av);
+ }
+ }
+
+ if (WallForbid)
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 used FORBID on channel \2%s\2",
+ u->nick, ci->name);
+
+ if (ircd->chansqline) {
+ anope_cmd_sqline(ci->name, ((reason) ? reason : "Forbidden"));
+ }
+
+ 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, 1, chan);
+ } else {
+ alog("%s: Valid FORBID for %s by %s failed", s_ChanServ, ci->name,
+ u->nick);
+ notice_lang(s_ChanServ, u, CHAN_FORBID_FAILED, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_getkey.c b/src/core/cs_getkey.c
new file mode 100644
index 000000000..e869e795e
--- /dev/null
+++ b/src/core/cs_getkey.c
@@ -0,0 +1,88 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_getkey(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GETKEY", do_getkey, NULL, CHAN_HELP_GETKEY, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_GETKEY);
+}
+
+/**
+ * The /cs getkey command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_getkey(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ ChannelInfo *ci;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "GETKEY", CHAN_GETKEY_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!check_access(u, ci, CA_GETKEY)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (!ci->c || !ci->c->key) {
+ notice_lang(s_ChanServ, u, CHAN_GETKEY_NOKEY, chan);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_GETKEY_KEY, chan, ci->c->key);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/cs_getpass.c b/src/core/cs_getpass.c
new file mode 100644
index 000000000..458488cf0
--- /dev/null
+++ b/src/core/cs_getpass.c
@@ -0,0 +1,102 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_getpass(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GETPASS", do_getpass, is_services_admin, -1, -1, -1,
+ CHAN_SERVADMIN_HELP_GETPASS,
+ CHAN_SERVADMIN_HELP_GETPASS);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_GETPASS);
+ }
+}
+
+/**
+ * The /cs getpass command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+
+int do_getpass(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char tmp_pass[PASSMAX];
+ ChannelInfo *ci;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "GETPASS", CHAN_GETPASS_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (CSRestrictGetPass && !is_services_root(u)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ if(enc_decrypt(ci->founderpass, tmp_pass, PASSMAX - 1)==1) {
+ alog("%s: %s!%s@%s used GETPASS on %s",
+ s_ChanServ, u->nick, u->username, u->host, ci->name);
+ if (WallGetpass) {
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 used GETPASS on channel \2%s\2",
+ u->nick, chan);
+ }
+ notice_lang(s_ChanServ, u, CHAN_GETPASS_PASSWORD_IS,
+ chan, tmp_pass);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_GETPASS_UNAVAILABLE);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_help.c b/src/core/cs_help.c
new file mode 100644
index 000000000..208009038
--- /dev/null
+++ b/src/core/cs_help.c
@@ -0,0 +1,84 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * The /cs help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_ChanServ, u, CHAN_HELP);
+ moduleDisplayHelp(2, u);
+ if (CSExpire >= 86400)
+ notice_help(s_ChanServ, u, CHAN_HELP_EXPIRES,
+ CSExpire / 86400);
+ if (is_services_oper(u))
+ notice_help(s_ChanServ, u, CHAN_SERVADMIN_HELP);
+ } else if (stricmp(cmd, "LEVELS DESC") == 0) {
+ int i;
+ notice_help(s_ChanServ, u, CHAN_HELP_LEVELS_DESC);
+ if (!levelinfo_maxwidth) {
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ int len = strlen(levelinfo[i].name);
+ if (len > levelinfo_maxwidth)
+ levelinfo_maxwidth = len;
+ }
+ }
+ for (i = 0; levelinfo[i].what >= 0; i++) {
+ notice_help(s_ChanServ, u, CHAN_HELP_LEVELS_DESC_FORMAT,
+ levelinfo_maxwidth, levelinfo[i].name,
+ getstring(u->na, levelinfo[i].desc));
+ }
+ } else {
+ mod_help_cmd(s_ChanServ, u, CHANSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_identify.c b/src/core/cs_identify.c
new file mode 100644
index 000000000..bde224a4a
--- /dev/null
+++ b/src/core/cs_identify.c
@@ -0,0 +1,117 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_identify(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("IDENTIFY", do_identify, NULL, CHAN_HELP_IDENTIFY,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ c = createCommand("ID", do_identify, NULL, CHAN_HELP_IDENTIFY, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_IDENTIFY);
+}
+
+/**
+ * The /cs command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_identify(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ ChannelInfo *ci;
+ struct u_chaninfolist *uc;
+
+ if (!pass) {
+ syntax_error(s_ChanServ, u, "IDENTIFY", CHAN_IDENTIFY_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!nick_identified(u)) {
+ notice_lang(s_ChanServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (is_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, NICK_ALREADY_IDENTIFIED);
+ } else {
+ int res;
+
+ if ((res = enc_check_password(pass, ci->founderpass)) == 1) {
+ if (!is_identified(u, ci)) {
+ uc = scalloc(sizeof(*uc), 1);
+ uc->next = u->founder_chans;
+ if (u->founder_chans)
+ u->founder_chans->prev = uc;
+ u->founder_chans = uc;
+ uc->chan = ci;
+ alog("%s: %s!%s@%s identified for %s", s_ChanServ, u->nick,
+ u->username, u->host, ci->name);
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_IDENTIFY_SUCCEEDED, chan);
+ } else if (res < 0) {
+ alog("%s: check_password failed for %s", s_ChanServ, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_IDENTIFY_FAILED);
+ } else {
+ alog("%s: Failed IDENTIFY for %s by %s!%s@%s",
+ s_ChanServ, ci->name, u->nick, u->username, u->host);
+ notice_lang(s_ChanServ, u, PASSWORD_INCORRECT);
+ bad_password(u);
+ }
+
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_info.c b/src/core/cs_info.c
new file mode 100644
index 000000000..0be9a8854
--- /dev/null
+++ b/src/core/cs_info.c
@@ -0,0 +1,249 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_info(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("INFO", do_info, NULL, CHAN_HELP_INFO, -1,
+ CHAN_SERVADMIN_HELP_INFO, CHAN_SERVADMIN_HELP_INFO,
+ CHAN_SERVADMIN_HELP_INFO);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_INFO);
+}
+
+/**
+ * The /cs info command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_info(User * u)
+{
+/* SADMINS and users, who have identified for a channel, can now cause it's
+ * Enstry Message and Successor to be displayed by supplying the ALL parameter.
+ * Syntax: INFO channel [ALL]
+ * -TheShadow (29 Mar 1999)
+ */
+ char *chan = strtok(NULL, " ");
+ char *param = strtok(NULL, " ");
+ ChannelInfo *ci;
+ char buf[BUFSIZE], *end;
+ struct tm *tm;
+ int need_comma = 0;
+ const char *commastr = getstring(u->na, COMMA_SPACE);
+ int is_servadmin = is_services_admin(u);
+ int show_all = 0;
+ time_t expt;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "INFO", CHAN_INFO_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ if (is_oper(u) && ci->forbidby)
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN_OPER, chan,
+ ci->forbidby,
+ (ci->forbidreason ? ci->
+ forbidreason : getstring(u->na, NO_REASON)));
+ else
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!ci->founder) {
+ /* Paranoia... this shouldn't be able to happen */
+ delchan(ci);
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else {
+
+ /* Should we show all fields? Only for sadmins and identified users */
+ if (param && stricmp(param, "ALL") == 0 &&
+ (check_access(u, ci, CA_INFO) || is_servadmin))
+ show_all = 1;
+
+ notice_lang(s_ChanServ, u, CHAN_INFO_HEADER, chan);
+ notice_lang(s_ChanServ, u, CHAN_INFO_NO_FOUNDER,
+ ci->founder->display);
+
+ if (show_all && ci->successor)
+ notice_lang(s_ChanServ, u, CHAN_INFO_NO_SUCCESSOR,
+ ci->successor->display);
+
+ notice_lang(s_ChanServ, u, CHAN_INFO_DESCRIPTION, ci->desc);
+ tm = localtime(&ci->time_registered);
+ strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_ChanServ, u, CHAN_INFO_TIME_REGGED, buf);
+ tm = localtime(&ci->last_used);
+ strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_ChanServ, u, CHAN_INFO_LAST_USED, buf);
+ if (ci->last_topic
+ && (show_all || (!(ci->mlock_on & anope_get_secret_mode())
+ && (!ci->c
+ || !(ci->c->
+ mode & anope_get_secret_mode()))))) {
+ notice_lang(s_ChanServ, u, CHAN_INFO_LAST_TOPIC,
+ ci->last_topic);
+ notice_lang(s_ChanServ, u, CHAN_INFO_TOPIC_SET_BY,
+ ci->last_topic_setter);
+ }
+
+ if (ci->entry_message && show_all)
+ notice_lang(s_ChanServ, u, CHAN_INFO_ENTRYMSG,
+ ci->entry_message);
+ if (ci->url)
+ notice_lang(s_ChanServ, u, CHAN_INFO_URL, ci->url);
+ if (ci->email)
+ notice_lang(s_ChanServ, u, CHAN_INFO_EMAIL, ci->email);
+
+ if (show_all) {
+ notice_lang(s_ChanServ, u, CHAN_INFO_BANTYPE, ci->bantype);
+
+ end = buf;
+ *end = 0;
+ if (ci->flags & CI_KEEPTOPIC) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s",
+ getstring(u->na, CHAN_INFO_OPT_KEEPTOPIC));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_OPNOTICE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_OPNOTICE));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_PEACE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_PEACE));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_PRIVATE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_PRIVATE));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_RESTRICTED) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na,
+ CHAN_INFO_OPT_RESTRICTED));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_SECURE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_SECURE));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_SECUREOPS) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_SECUREOPS));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_SECUREFOUNDER) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na,
+ CHAN_INFO_OPT_SECUREFOUNDER));
+ need_comma = 1;
+ }
+ if ((ci->flags & CI_SIGNKICK)
+ || (ci->flags & CI_SIGNKICK_LEVEL)) {
+ end +=
+ snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "", getstring(u->na,
+ CHAN_INFO_OPT_SIGNKICK));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_TOPICLOCK) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_TOPICLOCK));
+ need_comma = 1;
+ }
+ if (ci->flags & CI_XOP) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, CHAN_INFO_OPT_XOP));
+ need_comma = 1;
+ }
+ notice_lang(s_ChanServ, u, CHAN_INFO_OPTIONS,
+ *buf ? buf : getstring(u->na, CHAN_INFO_OPT_NONE));
+ notice_lang(s_ChanServ, u, CHAN_INFO_MODE_LOCK,
+ get_mlock_modes(ci, 1));
+
+ }
+ if (show_all) {
+ if (ci->flags & CI_NO_EXPIRE) {
+ notice_lang(s_ChanServ, u, CHAN_INFO_NO_EXPIRE);
+ } else {
+ if (is_servadmin) {
+ expt = ci->last_used + CSExpire;
+ tm = localtime(&expt);
+ strftime_lang(buf, sizeof(buf), u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_ChanServ, u, CHAN_INFO_EXPIRE, buf);
+ }
+ }
+ }
+ if (ci->flags & CI_SUSPENDED) {
+ notice_lang(s_ChanServ, u, CHAN_X_SUSPENDED, ci->forbidby,
+ (ci->forbidreason ? ci->
+ forbidreason : getstring(u->na, NO_REASON)));
+ }
+
+ if (!show_all && (check_access(u, ci, CA_INFO) || is_servadmin))
+ notice_lang(s_ChanServ, u, NICK_INFO_FOR_MORE, s_ChanServ,
+ ci->name);
+
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_invite.c b/src/core/cs_invite.c
new file mode 100644
index 000000000..a5b76fce2
--- /dev/null
+++ b/src/core/cs_invite.c
@@ -0,0 +1,90 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+void myChanServHelp(User * u);
+int do_invite(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("INVITE", do_invite, NULL, CHAN_HELP_INVITE, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_INVITE);
+}
+
+/**
+ * The /cs invite command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_invite(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ Channel *c;
+ ChannelInfo *ci;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "INVITE", CHAN_INVITE_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (ci->flags & CI_SUSPENDED) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!u || !check_access(u, ci, CA_INVITE)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ anope_cmd_invite(whosends(ci), chan, u->nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_kick.c b/src/core/cs_kick.c
new file mode 100644
index 000000000..25ce396ff
--- /dev/null
+++ b/src/core/cs_kick.c
@@ -0,0 +1,152 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_cs_kick(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("KICK", do_cs_kick, NULL, CHAN_HELP_KICK, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_KICK);
+}
+
+/**
+ * The /cs kick command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_cs_kick(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *params = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ Channel *c;
+ ChannelInfo *ci;
+ User *u2;
+
+ int is_same;
+
+ if (!reason) {
+ reason = "Requested";
+ } else {
+ if (strlen(reason) > 200)
+ reason[200] = '\0';
+ }
+
+ if (!chan) {
+ struct u_chanlist *uc, *next;
+
+ /* Kicks the user on every channels he is on. */
+
+ for (uc = u->chans; uc; uc = next) {
+ next = uc->next;
+ if ((ci = uc->chan->ci) && !(ci->flags & CI_VERBOTEN)
+ && check_access(u, ci, CA_KICKME)) {
+ char *av[3];
+
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(u, ci, CA_SIGNKICK)))
+ anope_cmd_kick(whosends(ci), ci->name, u->nick,
+ "%s (%s)", reason, u->nick);
+ else
+ anope_cmd_kick(whosends(ci), ci->name, u->nick, "%s",
+ reason);
+ av[0] = ci->name;
+ av[1] = u->nick;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ }
+
+ return MOD_CONT;
+ } else if (!params) {
+ params = u->nick;
+ }
+
+ is_same = (params == u->nick) ? 1 : (stricmp(params, u->nick) == 0);
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (is_same ? !(u2 = u) : !(u2 = finduser(params))) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_IN_USE, params);
+ } else if (!is_on_chan(c, u2)) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_ON_CHAN, u2->nick, c->name);
+ } else if (!is_same ? !check_access(u, ci, CA_KICK) :
+ !check_access(u, ci, CA_KICKME)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (!is_same && (ci->flags & CI_PEACE)
+ && (get_access(u2, ci) >= get_access(u, ci))) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (is_protected(u2)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ char *av[3];
+
+ if ((ci->flags & CI_SIGNKICK)
+ || ((ci->flags & CI_SIGNKICK_LEVEL)
+ && !check_access(u, ci, CA_SIGNKICK)))
+ anope_cmd_kick(whosends(ci), ci->name, params, "%s (%s)",
+ reason, u->nick);
+ else
+ anope_cmd_kick(whosends(ci), ci->name, params, "%s", reason);
+ av[0] = ci->name;
+ av[1] = params;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_list.c b/src/core/cs_list.c
new file mode 100644
index 000000000..0dcda53dc
--- /dev/null
+++ b/src/core/cs_list.c
@@ -0,0 +1,199 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_list(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("LIST", do_list, NULL, -1, CHAN_HELP_LIST,
+ CHAN_SERVADMIN_HELP_LIST,
+ CHAN_SERVADMIN_HELP_LIST, CHAN_SERVADMIN_HELP_LIST);
+
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (!CSListOpersOnly || (is_oper(u))) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_LIST);
+ }
+}
+
+/**
+ * The /cs list command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_list(User * u)
+{
+ char *pattern = strtok(NULL, " ");
+ int spattern_size;
+ char *spattern;
+ ChannelInfo *ci;
+ int nchans, i;
+ char buf[BUFSIZE];
+ int is_servadmin = is_services_admin(u);
+ int count = 0, from = 0, to = 0, tofree = 0;
+ char *tmp = NULL;
+ char *s = NULL;
+ char *keyword;
+ int32 matchflags = 0;
+
+ if (!(!CSListOpersOnly || (is_oper(u)))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ return MOD_STOP;
+ }
+
+ if (!pattern) {
+ syntax_error(s_ChanServ, u, "LIST",
+ is_servadmin ? CHAN_LIST_SERVADMIN_SYNTAX :
+ CHAN_LIST_SYNTAX);
+ } else {
+
+ if (pattern) {
+ if (pattern[0] == '#') {
+ tmp = myStrGetOnlyToken((pattern + 1), '-', 0); /* Read FROM out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ notice_lang(s_ChanServ, u, CS_LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ notice_lang(s_ChanServ, u, CS_LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ from = atoi(tmp);
+ free(tmp);
+ tmp = myStrGetTokenRemainder(pattern, '-', 1); /* Read TO out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ notice_lang(s_ChanServ, u, CS_LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ notice_lang(s_ChanServ, u, CS_LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ to = atoi(tmp);
+ free(tmp);
+ pattern = sstrdup("*");
+ tofree = 1;
+ }
+ }
+
+ nchans = 0;
+
+ while (is_servadmin && (keyword = strtok(NULL, " "))) {
+ if (stricmp(keyword, "FORBIDDEN") == 0)
+ matchflags |= CI_VERBOTEN;
+ if (stricmp(keyword, "SUSPENDED") == 0)
+ matchflags |= CI_SUSPENDED;
+ if (stricmp(keyword, "NOEXPIRE") == 0)
+ matchflags |= CI_NO_EXPIRE;
+ }
+
+ spattern_size = (strlen(pattern) + 2) * sizeof(char);
+ spattern = smalloc(spattern_size);
+ snprintf(spattern, spattern_size, "#%s", pattern);
+
+
+ notice_lang(s_ChanServ, u, CHAN_LIST_HEADER, pattern);
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ if (!is_servadmin && ((ci->flags & CI_PRIVATE)
+ || (ci->flags & CI_VERBOTEN)))
+ continue;
+ if ((matchflags != 0) && !(ci->flags & matchflags))
+ continue;
+
+ if ((stricmp(pattern, ci->name) == 0)
+ || (stricmp(spattern, ci->name) == 0)
+ || match_wild_nocase(pattern, ci->name)
+ || match_wild_nocase(spattern, ci->name)) {
+ if ((((count + 1 >= from) && (count + 1 <= to))
+ || ((from == 0) && (to == 0)))
+ && (++nchans <= CSListMax)) {
+ char noexpire_char = ' ';
+ if (is_servadmin && (ci->flags & CI_NO_EXPIRE))
+ noexpire_char = '!';
+
+ if (ci->flags & CI_VERBOTEN) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [Forbidden]", ci->name);
+ } else if (ci->flags & CI_SUSPENDED) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [Suspended]", ci->name);
+ } else {
+ snprintf(buf, sizeof(buf), "%-20s %s",
+ ci->name, ci->desc ? ci->desc : "");
+ }
+
+ notice_user(s_ChanServ, u, " %c%s",
+ noexpire_char, buf);
+ }
+ count++;
+ }
+ }
+ }
+ notice_lang(s_ChanServ, u, CHAN_LIST_END,
+ nchans > CSListMax ? CSListMax : nchans, nchans);
+ free(spattern);
+ }
+ if (tofree)
+ free(pattern);
+ return MOD_CONT;
+
+}
diff --git a/src/core/cs_logout.c b/src/core/cs_logout.c
new file mode 100644
index 000000000..2d963065c
--- /dev/null
+++ b/src/core/cs_logout.c
@@ -0,0 +1,131 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_logout(User * u);
+void myChanServHelp(User * u);
+void make_unidentified(User * u, ChannelInfo * ci);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("LOGOUT", do_logout, NULL, -1, CHAN_HELP_LOGOUT, -1,
+ CHAN_SERVADMIN_HELP_LOGOUT,
+ CHAN_SERVADMIN_HELP_LOGOUT);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_LOGOUT);
+}
+
+/**
+ * The /cs command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_logout(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ ChannelInfo *ci;
+ User *u2 = NULL;
+ int is_servadmin = is_services_admin(u);
+
+ if (!chan || (!nick && !is_servadmin)) {
+ syntax_error(s_ChanServ, u, "LOGOUT",
+ (!is_servadmin ? CHAN_LOGOUT_SYNTAX :
+ CHAN_LOGOUT_SERVADMIN_SYNTAX));
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (!is_servadmin && (ci->flags & CI_VERBOTEN)) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (nick && !(u2 = finduser(nick))) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (!is_servadmin && u2 != u && !is_real_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ /* Since founders can not logout we should tell them -katsklaw */
+ } else if (u2 == u && is_real_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, CHAN_LOGOUT_FOUNDER_FAILED, chan);
+ } else {
+ if (u2) {
+ make_unidentified(u2, ci);
+ notice_lang(s_ChanServ, u, CHAN_LOGOUT_SUCCEEDED, nick, chan);
+ alog("%s: User %s!%s@%s has been logged out of channel %s.",
+ s_ChanServ, u2->nick, u2->username, u2->host, chan);
+ } else {
+ int i;
+ for (i = 0; i < 1024; i++)
+ for (u2 = userlist[i]; u2; u2 = u2->next)
+ make_unidentified(u2, ci);
+ notice_lang(s_ChanServ, u, CHAN_LOGOUT_ALL_SUCCEEDED, chan);
+ alog("%s: All users identified have been logged out of channel %s.", s_ChanServ, chan);
+ }
+
+ }
+ return MOD_CONT;
+}
+
+void make_unidentified(User * u, ChannelInfo * ci)
+{
+ struct u_chaninfolist *uci;
+
+ if (!u || !ci)
+ return;
+
+ for (uci = u->founder_chans; uci; uci = uci->next) {
+ if (uci->chan == ci) {
+ if (uci->next)
+ uci->next->prev = uci->prev;
+ if (uci->prev)
+ uci->prev->next = uci->next;
+ else
+ u->founder_chans = uci->next;
+ free(uci);
+ break;
+ }
+ }
+}
diff --git a/src/core/cs_modes.c b/src/core/cs_modes.c
new file mode 100644
index 000000000..824764941
--- /dev/null
+++ b/src/core/cs_modes.c
@@ -0,0 +1,392 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+void myChanServHelp(User * u);
+int do_util(User * u, CSModeUtil * util);
+int do_op(User * u);
+int do_deop(User * u);
+int do_voice(User * u);
+int do_devoice(User * u);
+int do_halfop(User * u);
+int do_dehalfop(User * u);
+int do_protect(User * u);
+int do_deprotect(User * u);
+int do_owner(User * u);
+int do_deowner(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("OP", do_op, NULL, CHAN_HELP_OP, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEOP", do_deop, NULL, CHAN_HELP_DEOP, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("VOICE", do_voice, NULL, CHAN_HELP_VOICE, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEVOICE", do_devoice, NULL, CHAN_HELP_DEVOICE, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ if (ircd->halfop) {
+ c = createCommand("HALFOP", do_halfop, NULL, CHAN_HELP_HALFOP, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEHALFOP", do_dehalfop, NULL,
+ CHAN_HELP_DEHALFOP, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ }
+ if (ircd->protect) {
+ c = createCommand("PROTECT", do_protect, NULL, CHAN_HELP_PROTECT,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEPROTECT", do_deprotect, NULL,
+ CHAN_HELP_DEPROTECT, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ }
+ if (ircd->owner) {
+ c = createCommand("OWNER", do_owner, NULL, CHAN_HELP_OWNER, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEOWNER", do_deowner, NULL, CHAN_HELP_DEOWNER,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ }
+ if (ircd->admin) {
+ c = createCommand("ADMIN", do_protect, NULL, CHAN_HELP_PROTECT, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("DEADMIN", do_deprotect, NULL,
+ CHAN_HELP_DEPROTECT, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ }
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (ircd->owner) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_OWNER);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEOWNER);
+ }
+ if (ircd->protect) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_PROTECT);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEPROTECT);
+ } else if (ircd->admin) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_ADMIN);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEADMIN);
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_OP);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEOP);
+ if (ircd->halfop) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_HALFOP);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEHALFOP);
+ }
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_VOICE);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_DEVOICE);
+}
+
+/**
+ * The /cs op/deop/voice/devoice etc.. commands.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+
+int do_op(User * u)
+{
+ return do_util(u, &csmodeutils[MUT_OP]);
+}
+
+/*************************************************************************/
+
+int do_deop(User * u)
+{
+ return do_util(u, &csmodeutils[MUT_DEOP]);
+}
+
+/*************************************************************************/
+
+int do_voice(User * u)
+{
+ return do_util(u, &csmodeutils[MUT_VOICE]);
+}
+
+/*************************************************************************/
+
+int do_devoice(User * u)
+{
+ return do_util(u, &csmodeutils[MUT_DEVOICE]);
+}
+
+/*************************************************************************/
+
+int do_halfop(User * u)
+{
+ if (ircd->halfop) {
+ return do_util(u, &csmodeutils[MUT_HALFOP]);
+ } else {
+ return MOD_CONT;
+ }
+}
+
+/*************************************************************************/
+
+int do_dehalfop(User * u)
+{
+ if (ircd->halfop) {
+ return do_util(u, &csmodeutils[MUT_DEHALFOP]);
+ } else {
+ return MOD_CONT;
+ }
+}
+
+/*************************************************************************/
+
+int do_protect(User * u)
+{
+ if (ircd->protect || ircd->admin) {
+ return do_util(u, &csmodeutils[MUT_PROTECT]);
+ } else {
+ return MOD_CONT;
+ }
+}
+
+/*************************************************************************/
+
+int do_deprotect(User * u)
+{
+ if (ircd->protect || ircd->admin) {
+ return do_util(u, &csmodeutils[MUT_DEPROTECT]);
+ } else {
+ return MOD_CONT;
+ }
+}
+
+/*************************************************************************/
+
+int do_owner(User * u)
+{
+ char *av[2];
+ char *chan = strtok(NULL, " ");
+
+ Channel *c;
+ ChannelInfo *ci;
+ struct u_chanlist *uc;
+
+ if (!ircd->owner) {
+ return MOD_CONT;
+ }
+
+ if (!chan) {
+ av[0] = sstrdup(ircd->ownerset);
+ av[1] = u->nick;
+
+ /* Sets the mode to the user on every channels he is on. */
+
+ for (uc = u->chans; uc; uc = uc->next) {
+ if ((ci = uc->chan->ci) && !(ci->flags & CI_VERBOTEN)
+ && is_founder(u, ci)) {
+ anope_cmd_mode(whosends(ci), uc->chan->name, "%s %s",
+ av[0], u->nick);
+ chan_set_modes(s_ChanServ, uc->chan, 2, av, 1);
+ }
+ }
+
+ free(av[0]);
+ return MOD_CONT;
+ }
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (!is_on_chan(c, u)) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_ON_CHAN, u->nick, c->name);
+ } else if (!is_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ anope_cmd_mode(whosends(ci), c->name, "%s %s", ircd->ownerset,
+ u->nick);
+
+ av[0] = sstrdup(ircd->ownerset);
+ av[1] = u->nick;
+ chan_set_modes(s_ChanServ, c, 2, av, 1);
+ free(av[0]);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_deowner(User * u)
+{
+ char *av[2];
+ char *chan = strtok(NULL, " ");
+
+ Channel *c;
+ ChannelInfo *ci;
+ struct u_chanlist *uc;
+
+ if (!ircd->owner) {
+ return MOD_CONT;
+ }
+
+ if (!chan) {
+ av[0] = sstrdup(ircd->ownerunset);
+ av[1] = u->nick;
+
+ /* Sets the mode to the user on every channels he is on. */
+
+ for (uc = u->chans; uc; uc = uc->next) {
+ if ((ci = uc->chan->ci) && !(ci->flags & CI_VERBOTEN)
+ && is_founder(u, ci)) {
+ anope_cmd_mode(whosends(ci), uc->chan->name, "%s %s",
+ av[0], u->nick);
+ chan_set_modes(s_ChanServ, uc->chan, 2, av, 1);
+ }
+ }
+
+ free(av[0]);
+ return MOD_CONT;
+ }
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (!is_on_chan(c, u)) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_ON_CHAN, u->nick, c->name);
+ } else if (!is_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ anope_cmd_mode(whosends(ci), c->name, "%s %s", ircd->ownerunset,
+ u->nick);
+
+ av[0] = sstrdup(ircd->ownerunset);
+ av[1] = u->nick;
+ chan_set_modes(s_ChanServ, c, 2, av, 1);
+ free(av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* do_util: not a command, but does the job of other */
+
+int do_util(User * u, CSModeUtil * util)
+{
+ char *av[2];
+ char *chan = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+
+ Channel *c;
+ ChannelInfo *ci;
+ User *u2;
+
+ int is_same;
+
+ if (!chan) {
+ struct u_chanlist *uc;
+
+ av[0] = util->mode;
+ av[1] = u->nick;
+
+ /* Sets the mode to the user on every channels he is on. */
+
+ for (uc = u->chans; uc; uc = uc->next) {
+ if ((ci = uc->chan->ci) && !(ci->flags & CI_VERBOTEN)
+ && check_access(u, ci, util->levelself)) {
+ anope_cmd_mode(whosends(ci), uc->chan->name, "%s %s",
+ util->mode, u->nick);
+ chan_set_modes(s_ChanServ, uc->chan, 2, av, 2);
+
+ if (util->notice && ci->flags & util->notice)
+ notice(whosends(ci), uc->chan->name,
+ "%s command used for %s by %s", util->name,
+ u->nick, u->nick);
+ }
+ }
+
+ return MOD_CONT;
+ } else if (!nick) {
+ nick = u->nick;
+ }
+
+ is_same = (nick == u->nick) ? 1 : (stricmp(nick, u->nick) == 0);
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (is_same ? !(u2 = u) : !(u2 = finduser(nick))) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (!is_on_chan(c, u2)) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_ON_CHAN, u2->nick, c->name);
+ } else if (is_same ? !check_access(u, ci, util->levelself) :
+ !check_access(u, ci, util->level)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (*util->mode == '-' && !is_same && (ci->flags & CI_PEACE)
+ && (get_access(u2, ci) >= get_access(u, ci))) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (*util->mode == '-' && is_protected(u2) && !is_same) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ anope_cmd_mode(whosends(ci), c->name, "%s %s", util->mode,
+ u2->nick);
+
+ av[0] = util->mode;
+ av[1] = u2->nick;
+ chan_set_modes(s_ChanServ, c, 2, av, 2);
+
+ if (util->notice && ci->flags & util->notice)
+ notice(whosends(ci), c->name, "%s command used for %s by %s",
+ util->name, u2->nick, u->nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_register.c b/src/core/cs_register.c
new file mode 100644
index 000000000..d8cf4e817
--- /dev/null
+++ b/src/core/cs_register.c
@@ -0,0 +1,192 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_register(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("REGISTER", do_register, NULL, CHAN_HELP_REGISTER,
+ -1, -1, -1, -1);
+ c->help_param1 = s_NickServ;
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_REGISTER);
+}
+
+/**
+ * The /cs register command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_register(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ char *desc = strtok(NULL, "");
+ NickCore *nc;
+ Channel *c;
+ ChannelInfo *ci;
+ struct u_chaninfolist *uc;
+ int is_servadmin = is_services_admin(u);
+ char founderpass[PASSMAX];
+ char tmp_pass[PASSMAX];
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_REGISTER_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (checkDefCon(DEFCON_NO_NEW_CHANNELS)) {
+ notice_lang(s_ChanServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ }
+
+ if (!desc) {
+ syntax_error(s_ChanServ, u, "REGISTER", CHAN_REGISTER_SYNTAX);
+ } else if (*chan == '&') {
+ notice_lang(s_ChanServ, u, CHAN_REGISTER_NOT_LOCAL);
+ } else if (*chan != '#') {
+ notice_lang(s_ChanServ, u, CHAN_SYMBOL_REQUIRED);
+ } else if (!anope_valid_chan(chan)) {
+ notice_lang(s_ChanServ, u, CHAN_X_INVALID, chan);
+ } else if (!u->na || !(nc = u->na->nc)) {
+ notice_lang(s_ChanServ, u, CHAN_MUST_REGISTER_NICK, s_NickServ);
+ } else if (!nick_recognized(u)) {
+ notice_lang(s_ChanServ, u, CHAN_MUST_IDENTIFY_NICK, s_NickServ,
+ s_NickServ);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_REGISTER_NONE_CHANNEL, chan);
+ } else if ((ci = cs_findchan(chan)) != NULL) {
+ if (ci->flags & CI_VERBOTEN) {
+ alog("%s: Attempt to register FORBIDden channel %s by %s!%s@%s", s_ChanServ, ci->name, u->nick, u->username, u->host);
+ notice_lang(s_ChanServ, u, CHAN_MAY_NOT_BE_REGISTERED, chan);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_ALREADY_REGISTERED, chan);
+ }
+ } else if (!stricmp(chan, "#")) {
+ notice_lang(s_ChanServ, u, CHAN_MAY_NOT_BE_REGISTERED, chan);
+ } else if (!chan_has_user_status(c, u, CUS_OP)) {
+ notice_lang(s_ChanServ, u, CHAN_MUST_BE_CHANOP);
+
+ } else if (!is_servadmin && nc->channelmax > 0
+ && nc->channelcount >= nc->channelmax) {
+ notice_lang(s_ChanServ, u, nc->channelcount >
+ nc->channelmax ? CHAN_EXCEEDED_CHANNEL_LIMIT :
+ CHAN_REACHED_CHANNEL_LIMIT, nc->channelmax);
+ } else if (stricmp(u->nick, pass) == 0
+ || (StrictPasswords && strlen(pass) < 5)) {
+ notice_lang(s_ChanServ, u, MORE_OBSCURE_PASSWORD);
+ } else if(enc_encrypt_check_len(strlen(pass), PASSMAX - 1)) {
+ notice_lang(s_ChanServ, u, PASSWORD_TOO_LONG);
+ } else if (!(ci = makechan(chan))) {
+ alog("%s: makechan() failed for REGISTER %s", s_ChanServ, chan);
+ notice_lang(s_ChanServ, u, CHAN_REGISTRATION_FAILED);
+
+ } else if (strscpy(founderpass, pass, PASSMAX),
+ enc_encrypt_in_place(founderpass, PASSMAX) < 0) {
+ alog("%s: Couldn't encrypt password for %s (REGISTER)",
+ s_ChanServ, chan);
+ notice_lang(s_ChanServ, u, CHAN_REGISTRATION_FAILED);
+ delchan(ci);
+ } else {
+ c->ci = ci;
+ ci->c = c;
+ ci->bantype = CSDefBantype;
+ ci->flags = CSDefFlags;
+ ci->mlock_on = ircd->defmlock;
+ ci->memos.memomax = MSMaxMemos;
+ ci->last_used = ci->time_registered;
+ ci->founder = nc;
+
+ memset(pass, 0, strlen(pass));
+ memcpy(ci->founderpass, founderpass, PASSMAX);
+ ci->desc = sstrdup(desc);
+ if (c->topic) {
+ ci->last_topic = sstrdup(c->topic);
+ strscpy(ci->last_topic_setter, c->topic_setter, NICKMAX);
+ ci->last_topic_time = c->topic_time;
+ } else {
+ /* Set this to something, otherwise it will maliform the topic */
+ strscpy(ci->last_topic_setter, s_ChanServ, NICKMAX);
+ }
+ ci->bi = NULL;
+ ci->botflags = BSDefFlags;
+ ci->founder->channelcount++;
+ alog("%s: Channel '%s' registered by %s!%s@%s", s_ChanServ, chan,
+ u->nick, u->username, u->host);
+ notice_lang(s_ChanServ, u, CHAN_REGISTERED, chan, u->nick);
+
+ if(enc_decrypt(ci->founderpass,tmp_pass,PASSMAX - 1) == 1) {
+ notice_lang(s_ChanServ, u, CHAN_PASSWORD_IS, tmp_pass);
+ }
+
+ uc = scalloc(sizeof(*uc), 1);
+ uc->next = u->founder_chans;
+ uc->prev = NULL;
+ if (u->founder_chans)
+ u->founder_chans->prev = uc;
+ u->founder_chans = uc;
+ uc->chan = ci;
+ /* Implement new mode lock */
+ check_modes(c);
+ /* On most ircds you do not receive the admin/owner mode till its registered */
+ if (ircd->admin) {
+ anope_cmd_mode(s_ChanServ, chan, "%s %s", ircd->adminset,
+ u->nick);
+ }
+ if (ircd->owner && ircd->ownerset) {
+ anope_cmd_mode(s_ChanServ, chan, "%s %s", ircd->ownerset,
+ u->nick);
+ }
+ send_event(EVENT_CHAN_REGISTERED, 1, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_sendpass.c b/src/core/cs_sendpass.c
new file mode 100644
index 000000000..ff3bb1cff
--- /dev/null
+++ b/src/core/cs_sendpass.c
@@ -0,0 +1,125 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_sendpass(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SENDPASS", do_sendpass, NULL, CHAN_HELP_SENDPASS,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ if (UseMail) {
+ return MOD_CONT;
+ } else {
+ return MOD_STOP;
+ }
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_SENDPASS);
+}
+
+/**
+ * The /cs sendpass command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_sendpass(User * u)
+{
+
+ char *chan = strtok(NULL, " ");
+ ChannelInfo *ci;
+ NickCore *founder;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "SENDPASS", CHAN_SENDPASS_SYNTAX);
+ } else if (RestrictMail && !is_services_oper(u)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (!(ci = cs_findchan(chan)) || !(founder = ci->founder)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else {
+ char buf[BUFSIZE];
+ char tmp_pass[PASSMAX];
+ if(enc_decrypt(ci->founderpass,tmp_pass,PASSMAX - 1)==1) {
+ MailInfo *mail;
+
+ snprintf(buf, sizeof(buf),
+ getstring2(founder, CHAN_SENDPASS_SUBJECT), ci->name);
+ mail = MailBegin(u, founder, buf, s_ChanServ);
+ if (!mail)
+ return MOD_CONT;
+
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_HEAD));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_LINE_1),
+ ci->name);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_LINE_2),
+ tmp_pass);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_LINE_3));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_LINE_4));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(founder, CHAN_SENDPASS_LINE_5),
+ NetworkName);
+ fprintf(mail->pipe, "\n.\n");
+
+ MailEnd(mail);
+
+ alog("%s: %s!%s@%s used SENDPASS on %s", s_ChanServ, u->nick,
+ u->username, u->host, chan);
+ notice_lang(s_ChanServ, u, CHAN_SENDPASS_OK, chan);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_SENDPASS_UNAVAILABLE);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_set.c b/src/core/cs_set.c
new file mode 100644
index 000000000..ccdf1e9bb
--- /dev/null
+++ b/src/core/cs_set.c
@@ -0,0 +1,837 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+#include "encrypt.h"
+
+int do_set(User * u);
+int do_set_founder(User * u, ChannelInfo * ci, char *param);
+int do_set_successor(User * u, ChannelInfo * ci, char *param);
+int do_set_password(User * u, ChannelInfo * ci, char *param);
+int do_set_desc(User * u, ChannelInfo * ci, char *param);
+int do_set_url(User * u, ChannelInfo * ci, char *param);
+int do_set_email(User * u, ChannelInfo * ci, char *param);
+int do_set_entrymsg(User * u, ChannelInfo * ci, char *param);
+int do_set_bantype(User * u, ChannelInfo * ci, char *param);
+int do_set_mlock(User * u, ChannelInfo * ci, char *param);
+int do_set_keeptopic(User * u, ChannelInfo * ci, char *param);
+int do_set_topiclock(User * u, ChannelInfo * ci, char *param);
+int do_set_private(User * u, ChannelInfo * ci, char *param);
+int do_set_secureops(User * u, ChannelInfo * ci, char *param);
+int do_set_securefounder(User * u, ChannelInfo * ci, char *param);
+int do_set_restricted(User * u, ChannelInfo * ci, char *param);
+int do_set_secure(User * u, ChannelInfo * ci, char *param);
+int do_set_signkick(User * u, ChannelInfo * ci, char *param);
+int do_set_opnotice(User * u, ChannelInfo * ci, char *param);
+int do_set_xop(User * u, ChannelInfo * ci, char *param);
+int do_set_peace(User * u, ChannelInfo * ci, char *param);
+int do_set_noexpire(User * u, ChannelInfo * ci, char *param);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", do_set, NULL, CHAN_HELP_SET, -1, -1,
+ CHAN_SERVADMIN_HELP_SET, CHAN_SERVADMIN_HELP_SET);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET FOUNDER", NULL, NULL, CHAN_HELP_SET_FOUNDER, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SUCCESSOR", NULL, NULL, CHAN_HELP_SET_SUCCESSOR,
+ -1, -1, -1, -1);
+ c->help_param1 = (char *) (long) CSMaxReg;
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PASSWORD", NULL, NULL, CHAN_HELP_SET_PASSWORD,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET DESC", NULL, NULL, CHAN_HELP_SET_DESC, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET URL", NULL, NULL, CHAN_HELP_SET_URL, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET EMAIL", NULL, NULL, CHAN_HELP_SET_EMAIL, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET ENTRYMSG", NULL, NULL, CHAN_HELP_SET_ENTRYMSG,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET BANTYPE", NULL, NULL, CHAN_HELP_SET_BANTYPE, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PRIVATE", NULL, NULL, CHAN_HELP_SET_PRIVATE, -1,
+ -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET KEEPTOPIC", NULL, NULL, CHAN_HELP_SET_KEEPTOPIC,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET TOPICLOCK", NULL, NULL, CHAN_HELP_SET_TOPICLOCK,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET MLOCK", NULL, NULL, CHAN_HELP_SET_MLOCK, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET RESTRICTED", NULL, NULL,
+ CHAN_HELP_SET_RESTRICTED, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SECURE", NULL, NULL, CHAN_HELP_SET_SECURE, -1,
+ -1, -1, -1);
+ c->help_param1 = s_NickServ;
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SECUREOPS", NULL, NULL, CHAN_HELP_SET_SECUREOPS,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SECUREFOUNDER", NULL, NULL,
+ CHAN_HELP_SET_SECUREFOUNDER, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SIGNKICK", NULL, NULL, CHAN_HELP_SET_SIGNKICK,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET OPNOTICE", NULL, NULL, CHAN_HELP_SET_OPNOTICE,
+ -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET XOP", NULL, NULL, CHAN_HELP_SET_XOP, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PEACE", NULL, NULL, CHAN_HELP_SET_PEACE, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("SET NOEXPIRE", NULL, NULL, -1, -1, -1,
+ CHAN_SERVADMIN_HELP_SET_NOEXPIRE,
+ CHAN_SERVADMIN_HELP_SET_NOEXPIRE);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_SET);
+}
+
+/**
+ * The /cs set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+
+/* Main SET routine. Calls other routines as follows:
+ * do_set_command(User *command_sender, ChannelInfo *ci, char *param);
+ * The parameter passed is the first space-delimited parameter after the
+ * option name, except in the case of DESC, TOPIC, and ENTRYMSG, in which
+ * it is the entire remainder of the line. Additional parameters beyond
+ * the first passed in the function call can be retrieved using
+ * strtok(NULL, toks).
+ */
+int do_set(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *param;
+ ChannelInfo *ci;
+ int is_servadmin = is_services_admin(u);
+
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_SET_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (cmd) {
+ if (stricmp(cmd, "DESC") == 0 || stricmp(cmd, "ENTRYMSG") == 0)
+ param = strtok(NULL, "");
+ else
+ param = strtok(NULL, " ");
+ } else {
+ param = NULL;
+ }
+
+ if (!param && (!cmd || (stricmp(cmd, "SUCCESSOR") != 0 &&
+ stricmp(cmd, "URL") != 0 &&
+ stricmp(cmd, "EMAIL") != 0 &&
+ stricmp(cmd, "ENTRYMSG") != 0))) {
+ syntax_error(s_ChanServ, u, "SET", CHAN_SET_SYNTAX);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!is_servadmin && !check_access(u, ci, CA_SET)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (stricmp(cmd, "FOUNDER") == 0) {
+ if (!is_servadmin
+ && (ci->
+ flags & CI_SECUREFOUNDER ? !is_real_founder(u,
+ ci) :
+ !is_founder(u, ci))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ do_set_founder(u, ci, param);
+ }
+ } else if (stricmp(cmd, "SUCCESSOR") == 0) {
+ if (!is_servadmin
+ && (ci->
+ flags & CI_SECUREFOUNDER ? !is_real_founder(u,
+ ci) :
+ !is_founder(u, ci))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ do_set_successor(u, ci, param);
+ }
+ } else if (stricmp(cmd, "PASSWORD") == 0) {
+ if (!is_servadmin
+ && (ci->
+ flags & CI_SECUREFOUNDER ? !is_real_founder(u,
+ ci) :
+ !is_founder(u, ci))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ do_set_password(u, ci, param);
+ }
+ } else if (stricmp(cmd, "DESC") == 0) {
+ do_set_desc(u, ci, param);
+ } else if (stricmp(cmd, "URL") == 0) {
+ do_set_url(u, ci, param);
+ } else if (stricmp(cmd, "EMAIL") == 0) {
+ do_set_email(u, ci, param);
+ } else if (stricmp(cmd, "ENTRYMSG") == 0) {
+ do_set_entrymsg(u, ci, param);
+ } else if (stricmp(cmd, "TOPIC") == 0) {
+ notice_lang(s_ChanServ, u, OBSOLETE_COMMAND, "TOPIC");
+ } else if (stricmp(cmd, "BANTYPE") == 0) {
+ do_set_bantype(u, ci, param);
+ } else if (stricmp(cmd, "MLOCK") == 0) {
+ do_set_mlock(u, ci, param);
+ } else if (stricmp(cmd, "KEEPTOPIC") == 0) {
+ do_set_keeptopic(u, ci, param);
+ } else if (stricmp(cmd, "TOPICLOCK") == 0) {
+ do_set_topiclock(u, ci, param);
+ } else if (stricmp(cmd, "PRIVATE") == 0) {
+ do_set_private(u, ci, param);
+ } else if (stricmp(cmd, "SECUREOPS") == 0) {
+ do_set_secureops(u, ci, param);
+ } else if (stricmp(cmd, "SECUREFOUNDER") == 0) {
+ if (!is_servadmin
+ && (ci->
+ flags & CI_SECUREFOUNDER ? !is_real_founder(u,
+ ci) :
+ !is_founder(u, ci))) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else {
+ do_set_securefounder(u, ci, param);
+ }
+ } else if (stricmp(cmd, "RESTRICTED") == 0) {
+ do_set_restricted(u, ci, param);
+ } else if (stricmp(cmd, "SECURE") == 0) {
+ do_set_secure(u, ci, param);
+ } else if (stricmp(cmd, "SIGNKICK") == 0) {
+ do_set_signkick(u, ci, param);
+ } else if (stricmp(cmd, "OPNOTICE") == 0) {
+ do_set_opnotice(u, ci, param);
+ } else if (stricmp(cmd, "XOP") == 0) {
+ if (!(findModule("cs_xop"))) {
+ notice_lang(s_ChanServ, u, CHAN_XOP_NOT_AVAILABLE, cmd);
+ } else {
+ do_set_xop(u, ci, param);
+ }
+ } else if (stricmp(cmd, "PEACE") == 0) {
+ do_set_peace(u, ci, param);
+ } else if (stricmp(cmd, "NOEXPIRE") == 0) {
+ do_set_noexpire(u, ci, param);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_SET_UNKNOWN_OPTION, cmd);
+ notice_lang(s_ChanServ, u, MORE_INFO, s_ChanServ, "SET");
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_founder(User * u, ChannelInfo * ci, char *param)
+{
+ NickAlias *na = findnick(param);
+ NickCore *nc, *nc0 = ci->founder;
+
+ if (!na) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_REGISTERED, param);
+ return MOD_CONT;
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, param);
+ return MOD_CONT;
+ }
+
+ nc = na->nc;
+ if (nc->channelmax > 0 && nc->channelcount >= nc->channelmax
+ && !is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, CHAN_SET_FOUNDER_TOO_MANY_CHANS, param);
+ return MOD_CONT;
+ }
+
+ alog("%s: Changing founder of %s from %s to %s by %s!%s@%s",
+ s_ChanServ, ci->name, ci->founder->display, nc->display, u->nick,
+ u->username, u->host);
+
+ /* Founder and successor must not be the same group */
+ if (nc == ci->successor)
+ ci->successor = NULL;
+
+ nc0->channelcount--;
+ ci->founder = nc;
+ nc->channelcount++;
+
+ notice_lang(s_ChanServ, u, CHAN_FOUNDER_CHANGED, ci->name, param);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_successor(User * u, ChannelInfo * ci, char *param)
+{
+ NickAlias *na;
+ NickCore *nc;
+
+ if (param) {
+ na = findnick(param);
+
+ if (!na) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_REGISTERED, param);
+ return MOD_CONT;
+ }
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, param);
+ return MOD_CONT;
+ }
+ if (na->nc == ci->founder) {
+ notice_lang(s_ChanServ, u, CHAN_SUCCESSOR_IS_FOUNDER, param,
+ ci->name);
+ return MOD_CONT;
+ }
+ nc = na->nc;
+
+ } else {
+ nc = NULL;
+ }
+
+ alog("%s: Changing successor of %s from %s to %s by %s!%s@%s",
+ s_ChanServ, ci->name,
+ (ci->successor ? ci->successor->display : "none"),
+ (nc ? nc->display : "none"), u->nick, u->username, u->host);
+
+ ci->successor = nc;
+
+ if (nc)
+ notice_lang(s_ChanServ, u, CHAN_SUCCESSOR_CHANGED, ci->name,
+ param);
+ else
+ notice_lang(s_ChanServ, u, CHAN_SUCCESSOR_UNSET, ci->name);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_password(User * u, ChannelInfo * ci, char *param)
+{
+ int len = strlen(param);
+
+ if (stricmp(u->nick, param) == 0 || (StrictPasswords && len < 5)) {
+ notice_lang(s_ChanServ, u, MORE_OBSCURE_PASSWORD);
+ return MOD_CONT;
+ }
+
+ if (enc_encrypt_check_len(len ,PASSMAX - 1)) {
+ notice_lang(s_ChanServ, u, PASSWORD_TOO_LONG);
+ return MOD_CONT;
+ }
+
+ if (enc_encrypt(param, len, ci->founderpass, PASSMAX -1) < 0) {
+ memset(param, 0, strlen(param));
+ alog("%s: Failed to encrypt password for %s (set)", s_ChanServ,
+ ci->name);
+ notice_lang(s_ChanServ, u, CHAN_SET_PASSWORD_FAILED);
+ return MOD_CONT;
+ }
+
+ memset(param, 0, strlen(param));
+ notice_lang(s_ChanServ, u, CHAN_PASSWORD_CHANGED, ci->name);
+
+ if (get_access(u, ci) < ACCESS_FOUNDER) {
+ alog("%s: %s!%s@%s set password as Services admin for %s",
+ s_ChanServ, u->nick, u->username, u->host, ci->name);
+ if (WallSetpass)
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 set password as Services admin for channel \2%s\2",
+ u->nick, ci->name);
+ } else {
+ alog("%s: %s!%s@%s changed password of %s (founder: %s)",
+ s_ChanServ, u->nick, u->username, u->host,
+ ci->name, ci->founder->display);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_desc(User * u, ChannelInfo * ci, char *param)
+{
+ if (ci->desc)
+ free(ci->desc);
+ ci->desc = sstrdup(param);
+ notice_lang(s_ChanServ, u, CHAN_DESC_CHANGED, ci->name, param);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_url(User * u, ChannelInfo * ci, char *param)
+{
+ if (ci->url)
+ free(ci->url);
+ if (param) {
+ ci->url = sstrdup(param);
+ notice_lang(s_ChanServ, u, CHAN_URL_CHANGED, ci->name, param);
+ } else {
+ ci->url = NULL;
+ notice_lang(s_ChanServ, u, CHAN_URL_UNSET, ci->name);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_email(User * u, ChannelInfo * ci, char *param)
+{
+ if (ci->email)
+ free(ci->email);
+ if (param) {
+ ci->email = sstrdup(param);
+ notice_lang(s_ChanServ, u, CHAN_EMAIL_CHANGED, ci->name, param);
+ } else {
+ ci->email = NULL;
+ notice_lang(s_ChanServ, u, CHAN_EMAIL_UNSET, ci->name);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_entrymsg(User * u, ChannelInfo * ci, char *param)
+{
+ if (ci->entry_message)
+ free(ci->entry_message);
+ if (param) {
+ ci->entry_message = sstrdup(param);
+ notice_lang(s_ChanServ, u, CHAN_ENTRY_MSG_CHANGED, ci->name,
+ param);
+ } else {
+ ci->entry_message = NULL;
+ notice_lang(s_ChanServ, u, CHAN_ENTRY_MSG_UNSET, ci->name);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_mlock(User * u, ChannelInfo * ci, char *param)
+{
+ int add = -1; /* 1 if adding, 0 if deleting, -1 if neither */
+ unsigned char mode;
+ CBMode *cbm;
+
+ if (checkDefCon(DEFCON_NO_MLOCK_CHANGE)) {
+ notice_lang(s_ChanServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ }
+
+ /* Reinitialize everything */
+ if (ircd->chanreg) {
+ ci->mlock_on = ircd->regmode;
+ } else {
+ ci->mlock_on = 0;
+ }
+ ci->mlock_off = ci->mlock_limit = 0;
+ ci->mlock_key = NULL;
+ if (ircd->fmode) {
+ ci->mlock_flood = NULL;
+ }
+ if (ircd->Lmode) {
+ ci->mlock_redirect = NULL;
+ }
+
+ while ((mode = *param++)) {
+ switch (mode) {
+ case '+':
+ add = 1;
+ continue;
+ case '-':
+ add = 0;
+ continue;
+ default:
+ if (add < 0)
+ continue;
+ }
+
+ if ((int) mode < 128 && (cbm = &cbmodes[(int) mode])->flag != 0) {
+ if ((cbm->flags & CBM_NO_MLOCK)
+ || ((cbm->flags & CBM_NO_USER_MLOCK) && !is_oper(u))) {
+ notice_lang(s_ChanServ, u, CHAN_SET_MLOCK_IMPOSSIBLE_CHAR,
+ mode);
+ } else if (add) {
+ ci->mlock_on |= cbm->flag;
+ ci->mlock_off &= ~cbm->flag;
+ if (cbm->cssetvalue)
+ cbm->cssetvalue(ci, strtok(NULL, " "));
+ } else {
+ ci->mlock_off |= cbm->flag;
+ if (ci->mlock_on & cbm->flag) {
+ ci->mlock_on &= ~cbm->flag;
+ if (cbm->cssetvalue)
+ cbm->cssetvalue(ci, NULL);
+ }
+ }
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_SET_MLOCK_UNKNOWN_CHAR, mode);
+ }
+ } /* while (*param) */
+
+ if (ircd->Lmode) {
+ /* We can't mlock +L if +l is not mlocked as well. */
+ if ((ci->mlock_on & ircd->chan_lmode)
+ && !(ci->mlock_on & anope_get_limit_mode())) {
+ ci->mlock_on &= ~ircd->chan_lmode;
+ free(ci->mlock_redirect);
+ notice_lang(s_ChanServ, u, CHAN_SET_MLOCK_L_REQUIRED);
+ }
+ }
+
+ /* Some ircd we can't set NOKNOCK without INVITE */
+ /* So check if we need there is a NOKNOCK MODE and that we need INVITEONLY */
+ if (ircd->noknock && ircd->knock_needs_i) {
+ if ((ci->mlock_on & ircd->noknock)
+ && !(ci->mlock_on & anope_get_invite_mode())) {
+ ci->mlock_on &= ~ircd->noknock;
+ notice_lang(s_ChanServ, u, CHAN_SET_MLOCK_K_REQUIRED);
+ }
+ }
+
+ /* Since we always enforce mode r there is no way to have no
+ * mode lock at all.
+ */
+ if (get_mlock_modes(ci, 0)) {
+ notice_lang(s_ChanServ, u, CHAN_MLOCK_CHANGED, ci->name,
+ get_mlock_modes(ci, 0));
+ }
+
+ /* Implement the new lock. */
+ if (ci->c)
+ check_modes(ci->c);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_bantype(User * u, ChannelInfo * ci, char *param)
+{
+ char *endptr;
+
+ int16 bantype = strtol(param, &endptr, 10);
+
+ if (*endptr != 0 || bantype < 0 || bantype > 3) {
+ notice_lang(s_ChanServ, u, CHAN_SET_BANTYPE_INVALID, param);
+ } else {
+ ci->bantype = bantype;
+ notice_lang(s_ChanServ, u, CHAN_SET_BANTYPE_CHANGED, ci->name,
+ ci->bantype);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_keeptopic(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_KEEPTOPIC;
+ notice_lang(s_ChanServ, u, CHAN_SET_KEEPTOPIC_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_KEEPTOPIC;
+ notice_lang(s_ChanServ, u, CHAN_SET_KEEPTOPIC_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET KEEPTOPIC",
+ CHAN_SET_KEEPTOPIC_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_topiclock(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_TOPICLOCK;
+ notice_lang(s_ChanServ, u, CHAN_SET_TOPICLOCK_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_TOPICLOCK;
+ notice_lang(s_ChanServ, u, CHAN_SET_TOPICLOCK_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET TOPICLOCK",
+ CHAN_SET_TOPICLOCK_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_private(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_PRIVATE;
+ notice_lang(s_ChanServ, u, CHAN_SET_PRIVATE_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_PRIVATE;
+ notice_lang(s_ChanServ, u, CHAN_SET_PRIVATE_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET PRIVATE",
+ CHAN_SET_PRIVATE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_secureops(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_SECUREOPS;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECUREOPS_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_SECUREOPS;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECUREOPS_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET SECUREOPS",
+ CHAN_SET_SECUREOPS_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_securefounder(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_SECUREFOUNDER;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECUREFOUNDER_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_SECUREFOUNDER;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECUREFOUNDER_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET SECUREFOUNDER",
+ CHAN_SET_SECUREFOUNDER_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_restricted(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_RESTRICTED;
+ if (ci->levels[CA_NOJOIN] < 0)
+ ci->levels[CA_NOJOIN] = 0;
+ notice_lang(s_ChanServ, u, CHAN_SET_RESTRICTED_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_RESTRICTED;
+ if (ci->levels[CA_NOJOIN] >= 0)
+ ci->levels[CA_NOJOIN] = -2;
+ notice_lang(s_ChanServ, u, CHAN_SET_RESTRICTED_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET RESTRICTED",
+ CHAN_SET_RESTRICTED_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_secure(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_SECURE;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECURE_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_SECURE;
+ notice_lang(s_ChanServ, u, CHAN_SET_SECURE_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET SECURE", CHAN_SET_SECURE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_signkick(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_SIGNKICK;
+ ci->flags &= ~CI_SIGNKICK_LEVEL;
+ notice_lang(s_ChanServ, u, CHAN_SET_SIGNKICK_ON, ci->name);
+ } else if (stricmp(param, "LEVEL") == 0) {
+ ci->flags |= CI_SIGNKICK_LEVEL;
+ ci->flags &= ~CI_SIGNKICK;
+ notice_lang(s_ChanServ, u, CHAN_SET_SIGNKICK_LEVEL, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~(CI_SIGNKICK | CI_SIGNKICK_LEVEL);
+ notice_lang(s_ChanServ, u, CHAN_SET_SIGNKICK_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET SIGNKICK",
+ CHAN_SET_SIGNKICK_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_opnotice(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_OPNOTICE;
+ notice_lang(s_ChanServ, u, CHAN_SET_OPNOTICE_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_OPNOTICE;
+ notice_lang(s_ChanServ, u, CHAN_SET_OPNOTICE_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET OPNOTICE",
+ CHAN_SET_OPNOTICE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+#define CHECKLEV(lev) ((ci->levels[(lev)] != ACCESS_INVALID) && (access->level >= ci->levels[(lev)]))
+
+int do_set_xop(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ if (!(ci->flags & CI_XOP)) {
+ int i;
+ ChanAccess *access;
+
+ for (access = ci->access, i = 0; i < ci->accesscount;
+ access++, i++) {
+ if (!access->in_use)
+ continue;
+ /* This will probably cause wrong levels to be set, but hey,
+ * it's better than losing it altogether.
+ */
+ if (CHECKLEV(CA_AKICK) || CHECKLEV(CA_SET)) {
+ access->level = ACCESS_SOP;
+ } else if (CHECKLEV(CA_AUTOOP) || CHECKLEV(CA_OPDEOP)
+ || CHECKLEV(CA_OPDEOPME)) {
+ access->level = ACCESS_AOP;
+ } else if (ircd->halfop) {
+ if (CHECKLEV(CA_AUTOHALFOP) || CHECKLEV(CA_HALFOP)
+ || CHECKLEV(CA_HALFOPME)) {
+ access->level = ACCESS_HOP;
+ }
+ } else if (CHECKLEV(CA_AUTOVOICE) || CHECKLEV(CA_VOICE)
+ || CHECKLEV(CA_VOICEME)) {
+ access->level = ACCESS_VOP;
+ } else {
+ access->in_use = 0;
+ access->nc = NULL;
+ }
+ }
+
+ reset_levels(ci);
+ ci->flags |= CI_XOP;
+ }
+
+ alog("%s: %s!%s@%s enabled XOP for %s", s_ChanServ, u->nick,
+ u->username, u->host, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_SET_XOP_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_XOP;
+
+ alog("%s: %s!%s@%s disabled XOP for %s", s_ChanServ, u->nick,
+ u->username, u->host, ci->name);
+ notice_lang(s_ChanServ, u, CHAN_SET_XOP_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET XOP", CHAN_SET_XOP_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+#undef CHECKLEV
+
+/*************************************************************************/
+
+int do_set_peace(User * u, ChannelInfo * ci, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_PEACE;
+ notice_lang(s_ChanServ, u, CHAN_SET_PEACE_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_PEACE;
+ notice_lang(s_ChanServ, u, CHAN_SET_PEACE_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET PEACE", CHAN_SET_PEACE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_set_noexpire(User * u, ChannelInfo * ci, char *param)
+{
+ if (!is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ if (stricmp(param, "ON") == 0) {
+ ci->flags |= CI_NO_EXPIRE;
+ notice_lang(s_ChanServ, u, CHAN_SET_NOEXPIRE_ON, ci->name);
+ } else if (stricmp(param, "OFF") == 0) {
+ ci->flags &= ~CI_NO_EXPIRE;
+ notice_lang(s_ChanServ, u, CHAN_SET_NOEXPIRE_OFF, ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, "SET NOEXPIRE",
+ CHAN_SET_NOEXPIRE_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_status.c b/src/core/cs_status.c
new file mode 100644
index 000000000..b52efbcdb
--- /dev/null
+++ b/src/core/cs_status.c
@@ -0,0 +1,102 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_status(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("STATUS", do_status, is_services_admin, -1, -1, -1,
+ CHAN_SERVADMIN_HELP_STATUS,
+ CHAN_SERVADMIN_HELP_STATUS);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_STATUS);
+ }
+}
+
+/**
+ * The /cs status command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_status(User * u)
+{
+ ChannelInfo *ci;
+ User *u2;
+ char *nick, *chan;
+ char *temp = NULL;
+
+ chan = strtok(NULL, " ");
+ nick = strtok(NULL, " ");
+ if (!nick || strtok(NULL, " ")) {
+ notice_lang(s_ChanServ, u, CHAN_STATUS_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!(ci = cs_findchan(chan))) {
+ temp = chan;
+ chan = nick;
+ nick = temp;
+ ci = cs_findchan(chan);
+ }
+ if (!ci) {
+ notice_lang(s_ChanServ, u, CHAN_STATUS_NOT_REGGED, temp);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_STATUS_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if ((u2 = finduser(nick)) != NULL) {
+ notice_lang(s_ChanServ, u, CHAN_STATUS_INFO, chan, nick,
+ get_access(u2, ci));
+ } else { /* !u2 */
+ notice_lang(s_ChanServ, u, CHAN_STATUS_NOTONLINE, nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_suspend.c b/src/core/cs_suspend.c
new file mode 100644
index 000000000..674861578
--- /dev/null
+++ b/src/core/cs_suspend.c
@@ -0,0 +1,211 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_suspend(User * u);
+int do_unsuspend(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SUSPEND", do_suspend, is_services_oper, -1, -1, -1,
+ CHAN_SERVADMIN_HELP_SUSPEND,
+ CHAN_SERVADMIN_HELP_SUSPEND);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("UNSUSPEND", do_unsuspend, is_services_oper, -1, -1,
+ -1, CHAN_SERVADMIN_HELP_UNSUSPEND,
+ CHAN_SERVADMIN_HELP_UNSUSPEND);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_SUSPEND);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_UNSUSPEND);
+ }
+}
+
+/**
+ * The /cs (un)suspend command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_suspend(User * u)
+{
+ ChannelInfo *ci;
+ char *chan = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ Channel *c;
+
+ /* Assumes that permission checking has already been done. */
+ if (!chan || (ForceForbidReason && !reason)) {
+ syntax_error(s_ChanServ, u, "SUSPEND",
+ (ForceForbidReason ? CHAN_SUSPEND_SYNTAX_REASON :
+ CHAN_SUSPEND_SYNTAX));
+ return MOD_CONT;
+ }
+
+ if (chan[0] != '#') {
+ notice_lang(s_ChanServ, u, CHAN_UNSUSPEND_ERROR);
+ return MOD_CONT;
+ }
+
+ /* Only SUSPEND existing channels, otherwise use FORBID (bug #54) */
+ if ((ci = cs_findchan(chan)) == NULL) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ }
+
+ /* You should not SUSPEND a FORBIDEN channel */
+ if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_MAY_NOT_BE_REGISTERED, chan);
+ return MOD_CONT;
+ }
+
+ if (readonly)
+ notice_lang(s_ChanServ, u, READ_ONLY_MODE);
+
+ if (ci) {
+ ci->flags |= CI_SUSPENDED;
+ ci->forbidby = sstrdup(u->nick);
+ if (reason)
+ ci->forbidreason = sstrdup(reason);
+
+ if ((c = findchan(ci->name))) {
+ struct c_userlist *cu, *next;
+ char *av[3];
+
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+
+ if (is_oper(cu->user))
+ continue;
+
+ av[0] = c->name;
+ av[1] = cu->user->nick;
+ av[2] = reason ? reason : "CHAN_SUSPEND_REASON";
+ anope_cmd_kick(s_ChanServ, av[0], av[1], av[2]);
+ do_kick(s_ChanServ, 3, av);
+ }
+ }
+
+ if (WallForbid)
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 used SUSPEND on channel \2%s\2",
+ u->nick, ci->name);
+
+ 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, 1, chan);
+ } else {
+ alog("%s: Valid SUSPEND for %s by %s failed", s_ChanServ, ci->name,
+ u->nick);
+ notice_lang(s_ChanServ, u, CHAN_SUSPEND_FAILED, chan);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_unsuspend(User * u)
+{
+ ChannelInfo *ci;
+ char *chan = strtok(NULL, " ");
+
+ /* Assumes that permission checking has already been done. */
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "UNSUSPEND", CHAN_UNSUSPEND_SYNTAX);
+ return MOD_CONT;
+ }
+ if (chan[0] != '#') {
+ notice_lang(s_ChanServ, u, CHAN_UNSUSPEND_ERROR);
+ return MOD_CONT;
+ }
+ if (readonly)
+ notice_lang(s_ChanServ, u, READ_ONLY_MODE);
+
+ /* Only UNSUSPEND already suspended channels */
+ if ((ci = cs_findchan(chan)) == NULL) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ }
+
+ if (!(ci->flags & CI_SUSPENDED))
+ {
+ notice_lang(s_ChanServ, u, CHAN_UNSUSPEND_FAILED, chan);
+ return MOD_CONT;
+ }
+
+ if (ci) {
+ ci->flags &= ~CI_SUSPENDED;
+ if (ci->forbidreason)
+ {
+ free(ci->forbidreason);
+ ci->forbidreason = NULL;
+ }
+ if (ci->forbidby)
+ {
+ free(ci->forbidby);
+ ci->forbidby = NULL;
+ }
+
+ if (WallForbid)
+ anope_cmd_global(s_ChanServ,
+ "\2%s\2 used UNSUSPEND on channel \2%s\2",
+ u->nick, ci->name);
+
+ 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, 1, chan);
+ } else {
+ alog("%s: Valid UNSUSPEND for %s by %s failed", s_ChanServ,
+ chan, u->nick);
+ notice_lang(s_ChanServ, u, CHAN_UNSUSPEND_FAILED, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_topic.c b/src/core/cs_topic.c
new file mode 100644
index 000000000..dd5a15cb8
--- /dev/null
+++ b/src/core/cs_topic.c
@@ -0,0 +1,119 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_cs_topic(User * u);
+void myChanServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("TOPIC", do_cs_topic, NULL, CHAN_HELP_TOPIC, -1, -1,
+ -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_TOPIC);
+}
+
+/**
+ * The /cs topic command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_cs_topic(User * u)
+{
+ char *chan = strtok(NULL, " ");
+ char *topic = strtok(NULL, "");
+
+ Channel *c;
+ ChannelInfo *ci;
+
+ if (!chan) {
+ syntax_error(s_ChanServ, u, "TOPIC", CHAN_TOPIC_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (!is_services_admin(u) && !check_access(u, ci, CA_TOPIC)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ if (ci->last_topic)
+ free(ci->last_topic);
+ ci->last_topic = topic ? sstrdup(topic) : NULL;
+ strscpy(ci->last_topic_setter, u->nick, NICKMAX);
+ ci->last_topic_time = time(NULL);
+
+ if (c->topic)
+ free(c->topic);
+ c->topic = topic ? sstrdup(topic) : NULL;
+ strscpy(c->topic_setter, u->nick, NICKMAX);
+ if (ircd->topictsbackward) {
+ c->topic_time = c->topic_time - 1;
+ } else {
+ c->topic_time = ci->last_topic_time;
+ }
+
+ if (is_services_admin(u) && !check_access(u, ci, CA_TOPIC))
+ alog("%s: %s!%s@%s changed topic of %s as services admin.",
+ s_ChanServ, u->nick, u->username, u->host, c->name);
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_join(s_ChanServ, c->name, c->creation_time);
+ anope_cmd_mode(NULL, c->name, "+o %s", s_ChanServ);
+ }
+ }
+ anope_cmd_topic(whosends(ci), c->name, u->nick, topic ? topic : "",
+ c->topic_time);
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_part(s_ChanServ, c->name, NULL);
+ }
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/cs_xop.c b/src/core/cs_xop.c
new file mode 100644
index 000000000..37d3711fd
--- /dev/null
+++ b/src/core/cs_xop.c
@@ -0,0 +1,509 @@
+/* ChanServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_xop(User * u, char *xname, int xlev, int *xmsgs);
+int do_aop(User * u);
+int do_hop(User * u);
+int do_sop(User * u);
+int do_vop(User * u);
+
+void myChanServHelp(User * u);
+
+int xop_msgs[4][14] = {
+ {CHAN_AOP_SYNTAX,
+ CHAN_AOP_DISABLED,
+ CHAN_AOP_NICKS_ONLY,
+ CHAN_AOP_ADDED,
+ CHAN_AOP_MOVED,
+ CHAN_AOP_NO_SUCH_ENTRY,
+ CHAN_AOP_NOT_FOUND,
+ CHAN_AOP_NO_MATCH,
+ CHAN_AOP_DELETED,
+ CHAN_AOP_DELETED_ONE,
+ CHAN_AOP_DELETED_SEVERAL,
+ CHAN_AOP_LIST_EMPTY,
+ CHAN_AOP_LIST_HEADER,
+ CHAN_AOP_CLEAR},
+ {CHAN_SOP_SYNTAX,
+ CHAN_SOP_DISABLED,
+ CHAN_SOP_NICKS_ONLY,
+ CHAN_SOP_ADDED,
+ CHAN_SOP_MOVED,
+ CHAN_SOP_NO_SUCH_ENTRY,
+ CHAN_SOP_NOT_FOUND,
+ CHAN_SOP_NO_MATCH,
+ CHAN_SOP_DELETED,
+ CHAN_SOP_DELETED_ONE,
+ CHAN_SOP_DELETED_SEVERAL,
+ CHAN_SOP_LIST_EMPTY,
+ CHAN_SOP_LIST_HEADER,
+ CHAN_SOP_CLEAR},
+ {CHAN_VOP_SYNTAX,
+ CHAN_VOP_DISABLED,
+ CHAN_VOP_NICKS_ONLY,
+ CHAN_VOP_ADDED,
+ CHAN_VOP_MOVED,
+ CHAN_VOP_NO_SUCH_ENTRY,
+ CHAN_VOP_NOT_FOUND,
+ CHAN_VOP_NO_MATCH,
+ CHAN_VOP_DELETED,
+ CHAN_VOP_DELETED_ONE,
+ CHAN_VOP_DELETED_SEVERAL,
+ CHAN_VOP_LIST_EMPTY,
+ CHAN_VOP_LIST_HEADER,
+ CHAN_VOP_CLEAR},
+ {CHAN_HOP_SYNTAX,
+ CHAN_HOP_DISABLED,
+ CHAN_HOP_NICKS_ONLY,
+ CHAN_HOP_ADDED,
+ CHAN_HOP_MOVED,
+ CHAN_HOP_NO_SUCH_ENTRY,
+ CHAN_HOP_NOT_FOUND,
+ CHAN_HOP_NO_MATCH,
+ CHAN_HOP_DELETED,
+ CHAN_HOP_DELETED_ONE,
+ CHAN_HOP_DELETED_SEVERAL,
+ CHAN_HOP_LIST_EMPTY,
+ CHAN_HOP_LIST_HEADER,
+ CHAN_HOP_CLEAR}
+};
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("AOP", do_aop, NULL, CHAN_HELP_AOP, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ if (ircd->halfop) {
+ c = createCommand("HOP", do_hop, NULL, CHAN_HELP_HOP, -1, -1, -1,
+ -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ }
+ c = createCommand("SOP", do_sop, NULL, CHAN_HELP_SOP, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+ c = createCommand("VOP", do_vop, NULL, CHAN_HELP_VOP, -1, -1, -1, -1);
+ moduleAddCommand(CHANSERV, c, MOD_UNIQUE);
+
+ moduleSetChanHelp(myChanServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /cs help output.
+ * @param u The user who is requesting help
+ **/
+void myChanServHelp(User * u)
+{
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_SOP);
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_AOP);
+ if (ircd->halfop) {
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_HOP);
+ }
+ notice_lang(s_ChanServ, u, CHAN_HELP_CMD_VOP);
+}
+
+/**
+ * The /cs xop command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_aop(User * u)
+{
+ return do_xop(u, "AOP", ACCESS_AOP, xop_msgs[0]);
+}
+
+/*************************************************************************/
+
+int do_hop(User * u)
+{
+ return do_xop(u, "HOP", ACCESS_HOP, xop_msgs[3]);
+}
+
+/*************************************************************************/
+
+int do_sop(User * u)
+{
+ return do_xop(u, "SOP", ACCESS_SOP, xop_msgs[1]);
+}
+
+/*************************************************************************/
+
+int do_vop(User * u)
+{
+ return do_xop(u, "VOP", ACCESS_VOP, xop_msgs[2]);
+}
+
+/* `last' is set to the last index this routine was called with
+ * `perm' is incremented whenever a permission-denied error occurs
+ */
+
+int xop_del(User * u, ChannelInfo * ci, ChanAccess * access, int *perm, int uacc, int xlev)
+{
+ char *nick = access->nc->display;
+ if (!access->in_use || access->level != xlev)
+ return 0;
+ if (!is_services_admin(u) && uacc <= access->level) {
+ (*perm)++;
+ return 0;
+ }
+ access->nc = NULL;
+ access->in_use = 0;
+ send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick, nick);
+ return 1;
+}
+
+int xop_del_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *last = va_arg(args, int *);
+ int *perm = va_arg(args, int *);
+ int uacc = va_arg(args, int);
+ int xlev = va_arg(args, int);
+
+ if (num < 1 || num > ci->accesscount)
+ return 0;
+ *last = num;
+
+ return xop_del(u, ci, &ci->access[num - 1], perm, uacc, xlev);
+}
+
+
+int xop_list(User * u, int index, ChannelInfo * ci,
+ int *sent_header, int xlev, int xmsg)
+{
+ ChanAccess *access = &ci->access[index];
+
+ if (!access->in_use || access->level != xlev)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_ChanServ, u, xmsg, ci->name);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_ChanServ, u, CHAN_XOP_LIST_FORMAT, index + 1,
+ access->nc->display);
+ return 1;
+}
+
+int xop_list_callback(User * u, int num, va_list args)
+{
+ ChannelInfo *ci = va_arg(args, ChannelInfo *);
+ int *sent_header = va_arg(args, int *);
+ int xlev = va_arg(args, int);
+ int xmsg = va_arg(args, int);
+
+ if (num < 1 || num > ci->accesscount)
+ return 0;
+
+ return xop_list(u, num - 1, ci, sent_header, xlev, xmsg);
+}
+
+
+int do_xop(User * u, char *xname, int xlev, int *xmsgs)
+{
+ char *chan = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ char event_access[BUFSIZE];
+
+ ChannelInfo *ci;
+ NickAlias *na;
+ NickCore *nc;
+
+ int i;
+ int change = 0;
+ short ulev;
+ int is_list = (cmd && stricmp(cmd, "LIST") == 0);
+ int is_servadmin = is_services_admin(u);
+ ChanAccess *access;
+
+ /* If CLEAR, we don't need any parameters.
+ * If LIST, we don't *require* any parameters, but we can take any.
+ * If DEL or ADD we require a nick. */
+ if (!cmd || ((is_list || !stricmp(cmd, "CLEAR")) ? 0 : !nick)) {
+ syntax_error(s_ChanServ, u, xname, xmsgs[0]);
+ } else if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, chan);
+ } else if (!(ci->flags & CI_XOP)) {
+ notice_lang(s_ChanServ, u, CHAN_XOP_ACCESS, s_ChanServ);
+ } else if (stricmp(cmd, "ADD") == 0) {
+ if (readonly) {
+ notice_lang(s_ChanServ, u, xmsgs[1]);
+ return MOD_CONT;
+ }
+
+ ulev = get_access(u, ci);
+
+ if ((xlev >= ulev || ulev < ACCESS_AOP) && !is_servadmin) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ na = findnick(nick);
+ if (!na) {
+ notice_lang(s_ChanServ, u, xmsgs[2]);
+ return MOD_CONT;
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_ChanServ, u, NICK_X_FORBIDDEN, na->nick);
+ return MOD_CONT;
+ }
+
+ nc = na->nc;
+ for (access = ci->access, i = 0; i < ci->accesscount;
+ access++, i++) {
+ if (access->nc == nc) {
+ /**
+ * Patch provided by PopCorn to prevert AOP's reducing SOP's levels
+ **/
+ if ((access->level >= ulev) && (!is_servadmin)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ change++;
+ break;
+ }
+ }
+
+ if (!change) {
+ /* All entries should be in use so we no longer need
+ * to go over the entire list..
+ for (i = 0; i < ci->accesscount; i++)
+ if (!ci->access[i].in_use)
+ break;
+ */
+
+ if (i < CSAccessMax) {
+ ci->accesscount++;
+ ci->access =
+ srealloc(ci->access,
+ sizeof(ChanAccess) * ci->accesscount);
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_XOP_REACHED_LIMIT,
+ CSAccessMax);
+ return MOD_CONT;
+ }
+
+ access = &ci->access[i];
+ access->nc = nc;
+ }
+
+ access->in_use = 1;
+ access->level = xlev;
+ access->last_seen = 0;
+
+ alog("%s: %s!%s@%s (level %d) %s access level %d to %s (group %s) on channel %s", s_ChanServ, u->nick, u->username, u->host, ulev, change ? "changed" : "set", access->level, na->nick, nc->display, ci->name);
+
+ snprintf(event_access, BUFSIZE, "%d", access->level);
+
+ if (!change) {
+ send_event(EVENT_ACCESS_ADD, 4, ci->name, u->nick, na->nick,
+ event_access);
+ notice_lang(s_ChanServ, u, xmsgs[3], access->nc->display,
+ ci->name);
+ } else {
+ send_event(EVENT_ACCESS_CHANGE, 4, ci->name, u->nick, na->nick,
+ event_access);
+ notice_lang(s_ChanServ, u, xmsgs[4], access->nc->display,
+ ci->name);
+ }
+
+ } else if (stricmp(cmd, "DEL") == 0) {
+ int deleted, a, b;
+ if (readonly) {
+ notice_lang(s_ChanServ, u, xmsgs[1]);
+ return MOD_CONT;
+ }
+
+ if (ci->accesscount == 0) {
+ notice_lang(s_ChanServ, u, xmsgs[11], chan);
+ return MOD_CONT;
+ }
+
+ ulev = get_access(u, ci);
+
+ if ((xlev >= ulev || ulev < ACCESS_AOP) && !is_servadmin) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ /* Special case: is it a number/list? Only do search if it isn't. */
+ if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) {
+ int count, last = -1, perm = 0;
+ deleted =
+ process_numlist(nick, &count, xop_del_callback, u, ci,
+ &last, &perm, ulev, xlev);
+ if (!deleted) {
+ if (perm) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else if (count == 1) {
+ notice_lang(s_ChanServ, u, xmsgs[5], last, ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, xmsgs[7], ci->name);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_ChanServ, u, xmsgs[9], ci->name);
+ } else {
+ notice_lang(s_ChanServ, u, xmsgs[10], deleted, ci->name);
+ }
+ } else {
+ na = findnick(nick);
+ if (!na) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+ nc = na->nc;
+
+ for (i = 0; i < ci->accesscount; i++)
+ if (ci->access[i].nc == nc && ci->access[i].level == xlev)
+ break;
+
+ if (i == ci->accesscount) {
+ notice_lang(s_ChanServ, u, xmsgs[6], nick, chan);
+ return MOD_CONT;
+ }
+
+ access = &ci->access[i];
+ if (!is_servadmin && ulev <= access->level) {
+ deleted = 0;
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ notice_lang(s_ChanServ, u, xmsgs[8], access->nc->display,
+ ci->name);
+ access->nc = NULL;
+ access->in_use = 0;
+ send_event(EVENT_ACCESS_DEL, 3, ci->name, u->nick,
+ na->nick);
+ deleted = 1;
+ }
+ }
+ if (deleted) {
+ /* Reordering - DrStein */
+ for (b = 0; b < ci->accesscount; b++) {
+ if (ci->access[b].in_use) {
+ for (a = 0; a < ci->accesscount; a++) {
+ if (a > b)
+ break;
+ if (!ci->access[a].in_use) {
+ ci->access[a].in_use = 1;
+ ci->access[a].level = ci->access[b].level;
+ ci->access[a].nc = ci->access[b].nc;
+ ci->access[a].last_seen =
+ ci->access[b].last_seen;
+ ci->access[b].nc = NULL;
+ ci->access[b].in_use = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If the patch provided in bug #706 is applied, this should be placed
+ * before sending the events! */
+ /* After reordering only the entries at the end could still be empty.
+ * We ll free the places no longer in use... */
+ for (i = ci->accesscount - 1; i >= 0; i--) {
+ if (ci->access[i].in_use == 1)
+ break;
+
+ ci->accesscount--;
+ }
+ ci->access =
+ srealloc(ci->access,sizeof(ChanAccess) * ci->accesscount);
+ }
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int sent_header = 0;
+
+ ulev = get_access(u, ci);
+
+ if (!is_servadmin && ulev < ACCESS_AOP) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+
+ if (ci->accesscount == 0) {
+ notice_lang(s_ChanServ, u, xmsgs[11], ci->name);
+ return MOD_CONT;
+ }
+
+ if (nick && strspn(nick, "1234567890,-") == strlen(nick)) {
+ process_numlist(nick, NULL, xop_list_callback, u, ci,
+ &sent_header, xlev, xmsgs[12]);
+ } else {
+ for (i = 0; i < ci->accesscount; i++) {
+ if (nick && ci->access[i].nc
+ && !match_wild_nocase(nick, ci->access[i].nc->display))
+ continue;
+ xop_list(u, i, ci, &sent_header, xlev, xmsgs[12]);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_ChanServ, u, xmsgs[7], chan);
+ } else if (stricmp(cmd, "CLEAR") == 0) {
+ if (readonly) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (ci->accesscount == 0) {
+ notice_lang(s_ChanServ, u, CHAN_ACCESS_LIST_EMPTY, chan);
+ return MOD_CONT;
+ }
+
+ if (!is_servadmin && !is_founder(u, ci)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ for (i = 0; i < ci->accesscount; i++) {
+ if (ci->access[i].in_use && ci->access[i].level == xlev) {
+ ci->access[i].nc = NULL;
+ ci->access[i].in_use = 0;
+ }
+ }
+
+ send_event(EVENT_ACCESS_CLEAR, 2, ci->name, u->nick);
+
+ notice_lang(s_ChanServ, u, xmsgs[13], ci->name);
+ } else {
+ syntax_error(s_ChanServ, u, xname, xmsgs[0]);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/dummy/Makefile b/src/core/dummy/Makefile
new file mode 100644
index 000000000..ec93af36d
--- /dev/null
+++ b/src/core/dummy/Makefile
@@ -0,0 +1,6 @@
+all: DUMMY
+
+DUMMY:
+clean:
+distclean:
+install:
diff --git a/src/core/enc_md5.c b/src/core/enc_md5.c
new file mode 100644
index 000000000..69344d7e6
--- /dev/null
+++ b/src/core/enc_md5.c
@@ -0,0 +1,427 @@
+/* Module for encryption using MD5.
+ *
+ * Modified for Anope.
+ * (C) 2003-2008 Anope Team
+ * Contact us at dev@anope.org
+ *
+ * Taken from IRC Services and is copyright (c) 1996-2002 Andrew Church.
+ * E-mail: <achurch@achurch.org>
+ * Parts written by Andrew Kempe and others.
+ * This program is free but copyrighted software; see the file COPYING for
+ * details.
+ */
+
+#include "module.h"
+
+
+/*************************************************************************/
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include <string.h>
+
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+typedef void *POINTER;
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+void MD5Transform (UINT4 [4], unsigned char [64]);
+void Encode (unsigned char *, UINT4 *, unsigned int);
+void Decode (UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/*************************************************************************/
+
+/* Our own high-level routines. See encrypt.h for documentation. */
+
+#define XTOI(c) ((c)>9 ? (c)-'A'+10 : (c)-'0')
+
+int md5_encrypt(const char *src, int len, char *dest, int size)
+{
+ MD5_CTX context;
+ char tmp[33];
+
+ if (size < 16)
+ return -1;
+
+ MD5Init(&context);
+ MD5Update(&context, src, len);
+ MD5Final(dest, &context);
+
+ if(debug) {
+ memset(tmp,0,33);
+ binary_to_hex(dest,tmp,16);
+ /* Dont log source if we were encrypting in place :) */
+ if (memcmp(src, dest, 16) != 0) {
+ alog("enc_md5: hashed from [%s] to [%s]",src,tmp);
+ } else {
+ alog("enc_md5: hashed password to [%s]",tmp);
+ }
+ }
+
+ return 0;
+}
+
+
+int md5_encrypt_in_place(char *buf, int size)
+{
+ return md5_encrypt(buf, strlen(buf), buf, size);
+}
+
+
+int md5_encrypt_check_len(int passlen, int bufsize)
+{
+ if (bufsize < 16)
+ fatal("enc_md5: md5_check_len(): buffer too small (%d)", bufsize);
+ return 0;
+}
+
+
+int md5_decrypt(const char *src, char *dest, int size)
+{
+ return 0;
+}
+
+
+int md5_check_password(const char *plaintext, const char *password)
+{
+ char buf[BUFSIZE];
+
+ if (md5_encrypt(plaintext, strlen(plaintext), buf, sizeof(buf)) < 0)
+ return -1;
+ if (memcmp(buf, password, 16) == 0)
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Module stuff. */
+
+int AnopeInit(int argc, char **argv) {
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(ENCRYPTION);
+
+ encmodule_encrypt(md5_encrypt);
+ encmodule_encrypt_in_place(md5_encrypt_in_place);
+ encmodule_encrypt_check_len(md5_encrypt_check_len);
+ encmodule_decrypt(md5_decrypt);
+ encmodule_check_password(md5_check_password);
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void) {
+ encmodule_encrypt(NULL);
+ encmodule_encrypt_in_place(NULL);
+ encmodule_encrypt_check_len(NULL);
+ encmodule_decrypt(NULL);
+ encmodule_check_password(NULL);
+}
+
+
+
+
+/*************************************************************************/
+
diff --git a/src/core/enc_none.c b/src/core/enc_none.c
new file mode 100644
index 000000000..871a85620
--- /dev/null
+++ b/src/core/enc_none.c
@@ -0,0 +1,78 @@
+/* Module for encryption using MD5.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at dev@anope.org
+ *
+ * This program is free but copyrighted software; see the file COPYING for
+ * details.
+ */
+
+#include "module.h"
+
+int plain_encrypt(const char *src,int len,char *dest,int size);
+int plain_encrypt_in_place(char *buf, int size);
+int plain_encrypt_check_len(int passlen, int bufsize);
+int plain_decrypt(const char *src, char *dest, int size);
+int plain_check_password(const char *plaintext, const char *password);
+
+
+int AnopeInit(int argc, char **argv) {
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(ENCRYPTION);
+
+ encmodule_encrypt(plain_encrypt);
+ encmodule_encrypt_in_place(plain_encrypt_in_place);
+ encmodule_encrypt_check_len(plain_encrypt_check_len);
+ encmodule_decrypt(plain_decrypt);
+ encmodule_check_password(plain_check_password);
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void) {
+ encmodule_encrypt(NULL);
+ encmodule_encrypt_in_place(NULL);
+ encmodule_encrypt_check_len(NULL);
+ encmodule_decrypt(NULL);
+ encmodule_check_password(NULL);
+}
+
+int plain_encrypt(const char *src,int len,char *dest,int size) {
+ if(size>=len) {
+ memset(dest,0,size);
+ strncpy(dest,src,len);
+ dest[len] = '\0';
+ return 0;
+ }
+ return -1;
+}
+
+int plain_encrypt_in_place(char *buf, int size) {
+ return 0;
+}
+
+int plain_encrypt_check_len(int passlen, int bufsize) {
+ if(bufsize>=passlen) {
+ return 0;
+ }
+ return bufsize;
+}
+
+int plain_decrypt(const char *src, char *dest, int size) {
+ memset(dest,0,size);
+ strncpy(dest,src,size);
+ dest[size] = '\0';
+ return 1;
+}
+
+int plain_check_password(const char *plaintext, const char *password) {
+ if(strcmp(plaintext,password)==0) {
+ return 1;
+ }
+ return 0;
+}
+
+/* EOF */
+
diff --git a/src/core/enc_old.c b/src/core/enc_old.c
new file mode 100644
index 000000000..8c7d88e8e
--- /dev/null
+++ b/src/core/enc_old.c
@@ -0,0 +1,451 @@
+/* Include file for high-level encryption routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "module.h"
+
+void binary_to_hex(unsigned char *bin, char *hex, int length)
+{
+ static const char trans[] = "0123456789ABCDEF";
+ int i;
+
+ for(i = 0; i < length; i++)
+ {
+ hex[i << 1] = trans[bin[i] >> 4];
+ hex[(i << 1) + 1] = trans[bin[i] & 0xf];
+ }
+
+ hex[i << 1] = '\0';
+}
+
+
+/*************************************************************************/
+
+/******** Code specific to the type of encryption. ********/
+
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include <string.h>
+
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+typedef void *POINTER;
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4[4], unsigned char[64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define MD5_I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += MD5_I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5Init(context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+static void MD5Update(context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4) inputLen << 3))
+ < ((UINT4) inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4) inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ memcpy
+ ((POINTER) & context->buffer[index], (POINTER) input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ index = 0;
+ } else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy
+ ((POINTER) & context->buffer[index], (POINTER) & input[i],
+ inputLen - i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+static void MD5Final(digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode(bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update(context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update(context, bits, 8);
+ /* Store state in digest */
+ Encode(digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform(state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) x, 0, sizeof(x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode(output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char) (input[i] & 0xff);
+ output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
+ output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
+ output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode(output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
+ (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) <<
+ 24);
+}
+
+/*************************************************************************/
+
+/******** Our own high-level routines. ********/
+
+
+#define XTOI(c) ((c)>9 ? (c)-'A'+10 : (c)-'0')
+
+
+/* Encrypt `src' of length `len' and store the result in `dest'. If the
+ * resulting string would be longer than `size', return -1 and leave `dest'
+ * unchanged; else return 0.
+ */
+int old_encrypt(const char *src, int len, char *dest, int size)
+{
+
+ MD5_CTX context;
+ char digest[33];
+ char tmp[33];
+ int i;
+
+ if (size < 16)
+ return -1;
+
+ memset(&context, 0, sizeof(context));
+ memset(&digest, 0, sizeof(digest));
+
+ MD5Init(&context);
+ MD5Update(&context, src, len);
+ MD5Final(digest, &context);
+ for (i = 0; i < 32; i += 2)
+ dest[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
+
+ if(debug) {
+ memset(tmp,0,33);
+ binary_to_hex(dest,tmp,16);
+ alog("enc_old: Converted [%s] to [%s]",src,tmp);
+ }
+
+ return 0;
+
+}
+
+
+/* Shortcut for encrypting a null-terminated string in place. */
+int old_encrypt_in_place(char *buf, int size)
+{
+ return old_encrypt(buf, strlen(buf), buf, size);
+}
+
+int old_encrypt_check_len(int passlen, int bufsize)
+{
+ if (bufsize < 16)
+ fatal("enc_old: old_check_len(): buffer too small (%d)", bufsize);
+ return 0;
+}
+
+
+/* Compare a plaintext string against an encrypted password. Return 1 if
+ * they match, 0 if not, and -1 if something went wrong. */
+
+int old_check_password(const char *plaintext, const char *password)
+{
+ char buf[BUFSIZE];
+
+ if (old_encrypt(plaintext, strlen(plaintext), buf, sizeof(buf)) < 0)
+ return -1;
+ if (memcmp(buf, password, 16) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+int old_decrypt(const char *src, char *dest, int size)
+{
+ return 0;
+}
+
+int AnopeInit(int argc, char **argv) {
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(ENCRYPTION);
+
+ encmodule_encrypt(old_encrypt);
+ encmodule_encrypt_in_place(old_encrypt_in_place);
+ encmodule_encrypt_check_len(old_encrypt_check_len);
+ encmodule_decrypt(old_decrypt);
+ encmodule_check_password(old_check_password);
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void) {
+ encmodule_encrypt(NULL);
+ encmodule_encrypt_in_place(NULL);
+ encmodule_encrypt_check_len(NULL);
+ encmodule_decrypt(NULL);
+ encmodule_check_password(NULL);
+}
+
+/*************************************************************************/
+
diff --git a/src/core/enc_sha1.c b/src/core/enc_sha1.c
new file mode 100644
index 000000000..6a2f22860
--- /dev/null
+++ b/src/core/enc_sha1.c
@@ -0,0 +1,275 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define LITTLE_ENDIAN * This should be #define'd if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include "module.h"
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ uint32 state[5];
+ uint32 count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32 state[5], unsigned char const buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char const * data, uint32 len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32 state[5], unsigned char const buffer[64])
+{
+uint32 a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ uint32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char const * data, uint32 len)
+{
+ uint32 i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+ uint32 i;
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/*****************************************************************************/
+
+int sha1_encrypt(const char *src, int len, char *dest, int size)
+{
+ SHA1_CTX context;
+ unsigned char tmp[41];
+
+ if (size < 20)
+ return -1;
+
+ memset(dest,0,size);
+
+ SHA1Init(&context);
+ SHA1Update(&context, src, len);
+ SHA1Final(dest, &context);
+
+ if(debug) {
+ memset(tmp,0,41);
+ binary_to_hex(dest,tmp,20);
+ /* Dont log source if we were encrypting in place :) */
+ if (memcmp(src, dest, 20) != 0) {
+ alog("enc_sha1: hashed from [%s] to [%s]",src,tmp);
+ } else {
+ alog("enc_sha1: hashed password to [%s]",tmp);
+ }
+ }
+
+ return 0;
+}
+
+
+int sha1_encrypt_in_place(char *buf, int size)
+{
+ char tmp[41];
+
+ memset(tmp,0,41);
+ if(sha1_encrypt(buf, strlen(buf), tmp, size)==0) {
+ memcpy(buf, tmp, size);
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+int sha1_encrypt_check_len(int passlen, int bufsize)
+{
+ if (bufsize < 20)
+ fatal("enc_sha1: sha1_check_len(): buffer too small (%d)", bufsize);
+ return 0;
+}
+
+
+int sha1_decrypt(const char *src, char *dest, int size)
+{
+ return 0;
+}
+
+
+int sha1_check_password(const char *plaintext, const char *password)
+{
+ char buf[BUFSIZE];
+
+ if (sha1_encrypt(plaintext, strlen(plaintext), buf, sizeof(buf)) < 0)
+ return -1;
+ if (memcmp(buf, password, 20) == 0)
+ return 1;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Module stuff. */
+
+int AnopeInit(int argc, char **argv) {
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(ENCRYPTION);
+
+ encmodule_encrypt(sha1_encrypt);
+ encmodule_encrypt_in_place(sha1_encrypt_in_place);
+ encmodule_encrypt_check_len(sha1_encrypt_check_len);
+ encmodule_decrypt(sha1_decrypt);
+ encmodule_check_password(sha1_check_password);
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void) {
+ encmodule_encrypt(NULL);
+ encmodule_encrypt_in_place(NULL);
+ encmodule_encrypt_check_len(NULL);
+ encmodule_decrypt(NULL);
+ encmodule_check_password(NULL);
+}
+
+/* EOF */
+
diff --git a/src/core/he_help.c b/src/core/he_help.c
new file mode 100644
index 000000000..220df6455
--- /dev/null
+++ b/src/core/he_help.c
@@ -0,0 +1,76 @@
+/* HelpServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the help command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(HELPSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Display the HelpServ help.
+ * This core function has been embed in the source for a long time, but
+ * it moved into it's own file so we now all can enjoy the joy of
+ * modules for HelpServ.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ */
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_HelpServ, u, HELP_HELP, s_NickServ, s_ChanServ,
+ s_MemoServ);
+ if (s_BotServ) {
+ notice_help(s_HelpServ, u, HELP_HELP_BOT, s_BotServ);
+ }
+ if (s_HostServ) {
+ notice_help(s_HelpServ, u, HELP_HELP_HOST, s_HostServ);
+ }
+ moduleDisplayHelp(7, u);
+ } else {
+ mod_help_cmd(s_HelpServ, u, HELPSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_del.c b/src/core/hs_del.c
new file mode 100644
index 000000000..73af8cc22
--- /dev/null
+++ b/src/core/hs_del.c
@@ -0,0 +1,91 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_del(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("DEL", do_del, is_host_remover, HOST_HELP_DEL, -1,
+ -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ if (is_host_remover(u)) {
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_DEL);
+ }
+}
+
+/**
+ * The /hs del command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_del(User * u)
+{
+ NickAlias *na;
+ char *nick = strtok(NULL, " ");
+ if (nick) {
+ if ((na = findnick(nick))) {
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_HostServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+ alog("vHost for user \002%s\002 deleted by oper \002%s\002",
+ nick, u->nick);
+ delHostCore(nick);
+ notice_lang(s_HostServ, u, HOST_DEL, nick);
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOREG, nick);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_DEL_SYNTAX, s_HostServ);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_delall.c b/src/core/hs_delall.c
new file mode 100644
index 000000000..bc26a9032
--- /dev/null
+++ b/src/core/hs_delall.c
@@ -0,0 +1,96 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_delall(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("DELALL", do_delall, is_host_remover,
+ HOST_HELP_DELALL, -1, -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ if (is_host_remover(u)) {
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_DELALL);
+ }
+}
+
+/**
+ * The /hs delall command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_delall(User * u)
+{
+ int i;
+ char *nick = strtok(NULL, " ");
+ NickAlias *na;
+ NickCore *nc;
+ if (!nick) {
+ notice_lang(s_HostServ, u, HOST_DELALL_SYNTAX, s_HostServ);
+ return MOD_CONT;
+ }
+ if ((na = findnick(nick))) {
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_HostServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+ nc = na->nc;
+ for (i = 0; i < nc->aliases.count; i++) {
+ na = nc->aliases.list[i];
+ delHostCore(na->nick);
+ }
+ alog("vHosts for all nicks in group \002%s\002 deleted by oper \002%s\002", nc->display, u->nick);
+ notice_lang(s_HostServ, u, HOST_DELALL, nc->display);
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOREG, nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_group.c b/src/core/hs_group.c
new file mode 100644
index 000000000..a88d772e3
--- /dev/null
+++ b/src/core/hs_group.c
@@ -0,0 +1,124 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_group(User * u);
+void myHostServHelp(User * u);
+extern int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask,
+ char *creator, time_t time);
+
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GROUP", do_group, NULL, HOST_HELP_GROUP, -1, -1, -1,
+ -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_GROUP);
+}
+
+/**
+ * The /hs group command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_group(User * u)
+{
+ NickAlias *na;
+ HostCore *tmp;
+ char *vHost = NULL;
+ char *vIdent = NULL;
+ char *creator = NULL;
+ HostCore *head = NULL;
+ time_t time;
+ boolean found = false;
+
+ head = hostCoreListHead();
+
+ if ((na = findnick(u->nick))) {
+ if (na->status & NS_IDENTIFIED) {
+
+ tmp = findHostCore(head, u->nick, &found);
+ if (found) {
+ if (tmp == NULL) {
+ tmp = head; /* incase first in list */
+ } else if (tmp->next) { /* we dont want the previous entry were not inserting! */
+ tmp = tmp->next; /* jump to the next */
+ }
+
+ vHost = sstrdup(tmp->vHost);
+ if (tmp->vIdent)
+ vIdent = sstrdup(tmp->vIdent);
+ creator = sstrdup(tmp->creator);
+ time = tmp->time;
+
+ do_hs_sync(na->nc, vIdent, vHost, creator, time);
+ if (tmp->vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_GROUP,
+ na->nc->display, vIdent, vHost);
+ } else {
+ notice_lang(s_HostServ, u, HOST_GROUP, na->nc->display,
+ vHost);
+ }
+ free(vHost);
+ if (vIdent)
+ free(vIdent);
+ free(creator);
+
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOT_ASSIGNED);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_ID);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOT_REGED);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_help.c b/src/core/hs_help.c
new file mode 100644
index 000000000..f237016de
--- /dev/null
+++ b/src/core/hs_help.c
@@ -0,0 +1,66 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the help command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * The /hs help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_HostServ, u, HOST_HELP, s_HostServ);
+ moduleDisplayHelp(6, u);
+ } else {
+ mod_help_cmd(s_HostServ, u, HOSTSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_list.c b/src/core/hs_list.c
new file mode 100644
index 000000000..59a7fd8ae
--- /dev/null
+++ b/src/core/hs_list.c
@@ -0,0 +1,187 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int listOut(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("LIST", listOut, is_services_oper, -1, -1,
+ HOST_HELP_LIST, HOST_HELP_LIST, HOST_HELP_LIST);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_LIST);
+ }
+}
+
+/**
+ * The /hs list command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int listOut(User * u)
+{
+ char *key = strtok(NULL, "");
+ struct tm *tm;
+ char buf[BUFSIZE];
+ int counter = 1;
+ int from = 0, to = 0;
+ char *tmp = NULL;
+ char *s = NULL;
+ int display_counter = 0;
+ HostCore *head = NULL;
+ HostCore *current;
+
+ head = hostCoreListHead();
+
+ current = head;
+ if (current == NULL)
+ notice_lang(s_HostServ, u, HOST_EMPTY);
+ else {
+ /**
+ * Do a check for a range here, then in the next loop
+ * we'll only display what has been requested..
+ **/
+ if (key) {
+ if (key[0] == '#') {
+ tmp = myStrGetOnlyToken((key + 1), '-', 0); /* Read FROM out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ from = atoi(tmp);
+ free(tmp);
+ tmp = myStrGetTokenRemainder(key, '-', 1); /* Read TO out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ to = atoi(tmp);
+ free(tmp);
+ key = NULL;
+ }
+ }
+
+ while (current != NULL) {
+ if (key) {
+ if (((match_wild_nocase(key, current->nick))
+ || (match_wild_nocase(key, current->vHost)))
+ && (display_counter < NSListMax)) {
+ display_counter++;
+ tm = localtime(&current->time);
+ strftime_lang(buf, sizeof(buf), u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ if (current->vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_ENTRY,
+ counter, current->nick,
+ current->vIdent, current->vHost,
+ current->creator, buf);
+ } else {
+ notice_lang(s_HostServ, u, HOST_ENTRY, counter,
+ current->nick, current->vHost,
+ current->creator, buf);
+ }
+ }
+ } else {
+ /**
+ * List the host if its in the display range, and not more
+ * than NSListMax records have been displayed...
+ **/
+ if ((((counter >= from) && (counter <= to))
+ || ((from == 0) && (to == 0)))
+ && (display_counter < NSListMax)) {
+ display_counter++;
+ tm = localtime(&current->time);
+ strftime_lang(buf, sizeof(buf), u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ if (current->vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_ENTRY,
+ counter, current->nick,
+ current->vIdent, current->vHost,
+ current->creator, buf);
+ } else {
+ notice_lang(s_HostServ, u, HOST_ENTRY, counter,
+ current->nick, current->vHost,
+ current->creator, buf);
+ }
+ }
+ }
+ counter++;
+ current = current->next;
+ }
+ if (key) {
+ notice_lang(s_HostServ, u, HOST_LIST_KEY_FOOTER, key,
+ display_counter);
+ } else {
+ if (from != 0) {
+ notice_lang(s_HostServ, u, HOST_LIST_RANGE_FOOTER, from,
+ to);
+ } else {
+ notice_lang(s_HostServ, u, HOST_LIST_FOOTER,
+ display_counter);
+ }
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_off.c b/src/core/hs_off.c
new file mode 100644
index 000000000..c2ce6c498
--- /dev/null
+++ b/src/core/hs_off.c
@@ -0,0 +1,87 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_off(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("OFF", do_off, NULL, HOST_HELP_OFF, -1, -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_OFF);
+}
+
+/**
+ * The /hs off command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_off(User * u)
+{
+ NickAlias *na;
+ char *vhost;
+ char *vident = NULL;
+ if ((na = findnick(u->nick))) {
+ if (na->status & NS_IDENTIFIED) {
+ vhost = getvHost(u->nick);
+ vident = getvIdent(u->nick);
+ if (vhost == NULL && vident == NULL)
+ notice_lang(s_HostServ, u, HOST_NOT_ASSIGNED);
+ else
+ anope_cmd_vhost_off(u);
+ } else {
+ notice_lang(s_HostServ, u, HOST_ID);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOT_REGED);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_on.c b/src/core/hs_on.c
new file mode 100644
index 000000000..9ce692377
--- /dev/null
+++ b/src/core/hs_on.c
@@ -0,0 +1,102 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_on(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ON", do_on, NULL, HOST_HELP_ON, -1, -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_ON);
+}
+
+/**
+ * The /hs on command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_on(User * u)
+{
+ NickAlias *na;
+ char *vHost;
+ char *vIdent = NULL;
+ if ((na = findnick(u->nick))) {
+ if (na->status & NS_IDENTIFIED) {
+ vHost = getvHost(u->nick);
+ vIdent = getvIdent(u->nick);
+ if (vHost == NULL) {
+ notice_lang(s_HostServ, u, HOST_NOT_ASSIGNED);
+ } else {
+ if (vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_ACTIVATED,
+ vIdent, vHost);
+ } else {
+ notice_lang(s_HostServ, u, HOST_ACTIVATED, vHost);
+ }
+ anope_cmd_vhost_on(u->nick, vIdent, vHost);
+ if (ircd->vhost) {
+ u->vhost = sstrdup(vHost);
+ }
+ if (ircd->vident) {
+ if (vIdent)
+ u->vident = sstrdup(vIdent);
+ }
+ set_lastmask(u);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_ID);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOT_REGED);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_set.c b/src/core/hs_set.c
new file mode 100644
index 000000000..d236830d0
--- /dev/null
+++ b/src/core/hs_set.c
@@ -0,0 +1,178 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int myDoSet(User * u);
+void myHostServHelp(User * u);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", myDoSet, is_host_setter, HOST_HELP_SET, -1,
+ -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ if (is_host_setter(u)) {
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_SET);
+ }
+}
+
+/**
+ * The /hs set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int myDoSet(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *rawhostmask = strtok(NULL, " ");
+ char *hostmask = smalloc(HOSTMAX);
+
+ NickAlias *na;
+ int32 tmp_time;
+ char *s;
+
+ char *vIdent = NULL;
+
+ if (!nick || !rawhostmask) {
+ notice_lang(s_HostServ, u, HOST_SET_SYNTAX, s_HostServ);
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+ vIdent = myStrGetOnlyToken(rawhostmask, '@', 0); /* Get the first substring, @ as delimiter */
+ if (vIdent) {
+ rawhostmask = myStrGetTokenRemainder(rawhostmask, '@', 1); /* get the remaining string */
+ if (!rawhostmask) {
+ notice_lang(s_HostServ, u, HOST_SET_SYNTAX, s_HostServ);
+ free(vIdent);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ if (strlen(vIdent) > USERMAX - 1) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENTTOOLONG, USERMAX);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ } else {
+ for (s = vIdent; *s; s++) {
+ if (!isvalidchar(*s)) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENT_ERROR);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ }
+ }
+ if (!ircd->vident) {
+ notice_lang(s_HostServ, u, HOST_NO_VIDENT);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ }
+ if (strlen(rawhostmask) < HOSTMAX - 1)
+ snprintf(hostmask, HOSTMAX - 1, "%s", rawhostmask);
+ else {
+ notice_lang(s_HostServ, u, HOST_SET_TOOLONG, HOSTMAX);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+ if (!isValidHost(hostmask, 3)) {
+ notice_lang(s_HostServ, u, HOST_SET_ERROR);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+
+ tmp_time = time(NULL);
+
+ if ((na = findnick(nick))) {
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_HostServ, u, NICK_X_FORBIDDEN, nick);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+ if (vIdent && ircd->vident) {
+ alog("vHost for user \002%s\002 set to \002%s@%s\002 by oper \002%s\002", nick, vIdent, hostmask, u->nick);
+ } else {
+ alog("vHost for user \002%s\002 set to \002%s\002 by oper \002%s\002", nick, hostmask, u->nick);
+ }
+ addHostCore(nick, vIdent, hostmask, u->nick, tmp_time);
+ if (vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_SET, nick, vIdent,
+ hostmask);
+ } else {
+ notice_lang(s_HostServ, u, HOST_SET, nick, hostmask);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOREG, nick);
+ }
+ free(hostmask);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/hs_setall.c b/src/core/hs_setall.c
new file mode 100644
index 000000000..9f355b1f7
--- /dev/null
+++ b/src/core/hs_setall.c
@@ -0,0 +1,180 @@
+/* HostServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_setall(User * u);
+void myHostServHelp(User * u);
+extern int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask,
+ char *creator, time_t time);
+
+/**
+ * Create the off command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SETALL", do_setall, is_host_setter,
+ HOST_HELP_SETALL, -1, -1, -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_UNIQUE);
+ moduleSetHostHelp(myHostServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myHostServHelp(User * u)
+{
+ if (is_host_setter(u)) {
+ notice_lang(s_HostServ, u, HOST_HELP_CMD_SETALL);
+ }
+}
+
+/**
+ * The /hs setall command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_setall(User * u)
+{
+
+ char *nick = strtok(NULL, " ");
+ char *rawhostmask = strtok(NULL, " ");
+ char *hostmask = smalloc(HOSTMAX);
+
+ NickAlias *na;
+ int32 tmp_time;
+ char *s;
+
+ char *vIdent = NULL;
+
+ if (!nick || !rawhostmask) {
+ notice_lang(s_HostServ, u, HOST_SETALL_SYNTAX, s_HostServ);
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+ vIdent = myStrGetOnlyToken(rawhostmask, '@', 0); /* Get the first substring, @ as delimiter */
+ if (vIdent) {
+ rawhostmask = myStrGetTokenRemainder(rawhostmask, '@', 1); /* get the remaining string */
+ if (!rawhostmask) {
+ notice_lang(s_HostServ, u, HOST_SETALL_SYNTAX, s_HostServ);
+ free(vIdent);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ if (strlen(vIdent) > USERMAX - 1) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENTTOOLONG, USERMAX);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ } else {
+ for (s = vIdent; *s; s++) {
+ if (!isvalidchar(*s)) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENT_ERROR);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ }
+ }
+ if (!ircd->vident) {
+ notice_lang(s_HostServ, u, HOST_NO_VIDENT);
+ free(vIdent);
+ free(rawhostmask);
+ free(hostmask);
+ return MOD_CONT;
+ }
+ }
+
+ if (strlen(rawhostmask) < HOSTMAX - 1)
+ snprintf(hostmask, HOSTMAX - 1, "%s", rawhostmask);
+ else {
+ notice_lang(s_HostServ, u, HOST_SET_TOOLONG, HOSTMAX);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+ if (!isValidHost(hostmask, 3)) {
+ notice_lang(s_HostServ, u, HOST_SET_ERROR);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+
+ tmp_time = time(NULL);
+
+ if ((na = findnick(nick))) {
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_HostServ, u, NICK_X_FORBIDDEN, nick);
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+ }
+ if (vIdent && ircd->vident) {
+ alog("vHost for all nicks in group \002%s\002 set to \002%s@%s\002 by oper \002%s\002", nick, vIdent, hostmask, u->nick);
+ } else {
+ alog("vHost for all nicks in group \002%s\002 set to \002%s\002 by oper \002%s\002", nick, hostmask, u->nick);
+ }
+ do_hs_sync(na->nc, vIdent, hostmask, u->nick, tmp_time);
+ if (vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_SETALL, nick, vIdent,
+ hostmask);
+ } else {
+ notice_lang(s_HostServ, u, HOST_SETALL, nick, hostmask);
+ }
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOREG, nick);
+ }
+ if (vIdent) {
+ free(vIdent);
+ free(rawhostmask);
+ }
+ free(hostmask);
+ return MOD_CONT;
+}
diff --git a/src/core/ms_cancel.c b/src/core/ms_cancel.c
new file mode 100644
index 000000000..568a05310
--- /dev/null
+++ b/src/core/ms_cancel.c
@@ -0,0 +1,105 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_cancel(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the cancel command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("CANCEL", do_cancel, NULL, MEMO_HELP_CANCEL, -1, -1,
+ -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_CANCEL);
+}
+
+/**
+ * The /ms cancel command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_cancel(User * u)
+{
+ int ischan;
+ int isforbid;
+ char *name = strtok(NULL, " ");
+ MemoInfo *mi;
+
+ if (!name) {
+ syntax_error(s_MemoServ, u, "CANCEL", MEMO_CANCEL_SYNTAX);
+
+ } else if (!nick_recognized(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+
+ } else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) {
+ if (isforbid) {
+ notice_lang(s_MemoServ, u,
+ ischan ? CHAN_X_FORBIDDEN :
+ NICK_X_FORBIDDEN, name);
+ } else {
+ notice_lang(s_MemoServ, u,
+ ischan ? CHAN_X_NOT_REGISTERED :
+ NICK_X_NOT_REGISTERED, name);
+ }
+ } else {
+ int i;
+
+ for (i = mi->memocount - 1; i >= 0; i--) {
+ if ((mi->memos[i].flags & MF_UNREAD)
+ && !stricmp(mi->memos[i].sender, u->na->nc->display)
+ && (!(mi->memos[i].flags & MF_NOTIFYS))) {
+ delmemo(mi, mi->memos[i].number);
+ notice_lang(s_MemoServ, u, MEMO_CANCELLED, name);
+ return MOD_CONT;
+ }
+ }
+
+ notice_lang(s_MemoServ, u, MEMO_CANCEL_NONE);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ms_check.c b/src/core/ms_check.c
new file mode 100644
index 000000000..661a5c1ab
--- /dev/null
+++ b/src/core/ms_check.c
@@ -0,0 +1,118 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_memocheck(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("CHECK", do_memocheck, NULL, MEMO_HELP_CHECK, -1, -1,
+ -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_CHECK);
+}
+
+/**
+ * The /ms check command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_memocheck(User * u)
+{
+ NickAlias *na = NULL;
+ MemoInfo *mi = NULL;
+ int i, found = 0;
+ char *recipient = strtok(NULL, "");
+ struct tm *tm;
+ char timebuf[64];
+
+ if (!recipient) {
+ syntax_error(s_MemoServ, u, "CHECK", MEMO_CHECK_SYNTAX);
+ return MOD_CONT;
+ } else if (!nick_recognized(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ } else if (!(na = findnick(recipient))) {
+ notice_lang(s_MemoServ, u, NICK_X_NOT_REGISTERED, recipient);
+ return MOD_CONT;
+ }
+
+ if ((na->status & NS_VERBOTEN)) {
+ notice_lang(s_MemoServ, u, NICK_X_FORBIDDEN, recipient);
+ return MOD_CONT;
+ }
+
+ mi = &na->nc->memos;
+
+/* Okay, I know this looks strange but we wanna get the LAST memo, so we
+ have to loop backwards */
+
+ for (i = (mi->memocount - 1); i >= 0; i--) {
+ if (!stricmp(mi->memos[i].sender, u->na->nc->display)) {
+ found = 1; /* Yes, we've found the memo */
+
+ tm = localtime(&mi->memos[i].time);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+
+ if (mi->memos[i].flags & MF_UNREAD)
+ notice_lang(s_MemoServ, u, MEMO_CHECK_NOT_READ, na->nick,
+ timebuf);
+ else
+ notice_lang(s_MemoServ, u, MEMO_CHECK_READ, na->nick,
+ timebuf);
+ break;
+ }
+ }
+
+ if (!found)
+ notice_lang(s_MemoServ, u, MEMO_CHECK_NO_MEMO, na->nick);
+
+ return MOD_CONT;
+}
diff --git a/src/core/ms_del.c b/src/core/ms_del.c
new file mode 100644
index 000000000..f8a294f3e
--- /dev/null
+++ b/src/core/ms_del.c
@@ -0,0 +1,202 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_del(User * u);
+int del_memo_callback(User * u, int num, va_list args);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("DEL", do_del, NULL, MEMO_HELP_DEL, -1, -1, -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_DEL);
+}
+
+/**
+ * The /ms del command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_del(User * u)
+{
+ MemoInfo *mi;
+ ChannelInfo *ci;
+ char *numstr = strtok(NULL, ""), *chan = NULL;
+ int last, last0, i;
+ char buf[BUFSIZE], *end;
+ int delcount, count, left;
+
+ if (numstr && *numstr == '#') {
+ chan = strtok(numstr, " ");
+ numstr = strtok(NULL, "");
+ if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ } else if (readonly) {
+ notice_lang(s_MemoServ, u, READ_ONLY_MODE);
+ return MOD_CONT;
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_MemoServ, u, CHAN_X_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if (!check_access(u, ci, CA_MEMO)) {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+ mi = &ci->memos;
+ } else {
+ if (!nick_identified(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ }
+ mi = &u->na->nc->memos;
+ }
+ if (!numstr
+ || (!isdigit(*numstr) && stricmp(numstr, "ALL") != 0
+ && stricmp(numstr, "LAST") != 0)) {
+ syntax_error(s_MemoServ, u, "DEL", MEMO_DEL_SYNTAX);
+ } else if (mi->memocount == 0) {
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HAVE_NO_MEMOS);
+ } else {
+ if (isdigit(*numstr)) {
+ /* Delete a specific memo or memos. */
+ last = -1; /* Last memo deleted */
+ last0 = -1; /* Beginning of range of last memos deleted */
+ end = buf;
+ left = sizeof(buf);
+ delcount =
+ process_numlist(numstr, &count, del_memo_callback, u, mi,
+ &last, &last0, &end, &left);
+ if (last != -1) {
+ /* Some memos got deleted; tell them which ones. */
+ if (delcount > 1) {
+ if (last0 != last)
+ end += snprintf(end, sizeof(buf) - (end - buf),
+ ",%d-%d", last0, last);
+ else
+ end += snprintf(end, sizeof(buf) - (end - buf),
+ ",%d", last);
+ /* "buf+1" here because *buf == ',' */
+ notice_lang(s_MemoServ, u, MEMO_DELETED_SEVERAL,
+ buf + 1);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_DELETED_ONE, last);
+ }
+ } else {
+ /* No memos were deleted. Tell them so. */
+ if (count == 1)
+ notice_lang(s_MemoServ, u, MEMO_DOES_NOT_EXIST,
+ atoi(numstr));
+ else
+ notice_lang(s_MemoServ, u, MEMO_DELETED_NONE);
+ }
+ } else if (stricmp(numstr, "LAST") == 0) {
+ /* Delete last memo. */
+ for (i = 0; i < mi->memocount; i++)
+ last = mi->memos[i].number;
+ delmemo(mi, last);
+ notice_lang(s_MemoServ, u, MEMO_DELETED_ONE, last);
+ } else {
+ /* Delete all memos. */
+ for (i = 0; i < mi->memocount; i++) {
+ free(mi->memos[i].text);
+ moduleCleanStruct(&mi->memos[i].moduleData);
+ }
+ free(mi->memos);
+ mi->memos = NULL;
+ mi->memocount = 0;
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_CHAN_DELETED_ALL, chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_DELETED_ALL);
+ }
+
+ /* Reset the order */
+ for (i = 0; i < mi->memocount; i++)
+ mi->memos[i].number = i + 1;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Delete a single memo from a MemoInfo. callback function
+ * @param u User Struct
+ * @param int Number
+ * @param va_list Variable Arguemtns
+ * @return 1 if successful, 0 if it fails
+ */
+int del_memo_callback(User * u, int num, va_list args)
+{
+ MemoInfo *mi = va_arg(args, MemoInfo *);
+ int *last = va_arg(args, int *);
+ int *last0 = va_arg(args, int *);
+ char **end = va_arg(args, char **);
+ int *left = va_arg(args, int *);
+
+ if (delmemo(mi, num)) {
+ if (num != (*last) + 1) {
+ if (*last != -1) {
+ int len;
+ if (*last0 != *last)
+ len = snprintf(*end, *left, ",%d-%d", *last0, *last);
+ else
+ len = snprintf(*end, *left, ",%d", *last);
+ *end += len;
+ *left -= len;
+ }
+ *last0 = num;
+ }
+ *last = num;
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/src/core/ms_help.c b/src/core/ms_help.c
new file mode 100644
index 000000000..7b49aa43c
--- /dev/null
+++ b/src/core/ms_help.c
@@ -0,0 +1,66 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the help command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * The /ms help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_MemoServ, u, MEMO_HELP_HEADER);
+ moduleDisplayHelp(3, u);
+ notice_help(s_MemoServ, u, MEMO_HELP_FOOTER, s_ChanServ);
+ } else {
+ mod_help_cmd(s_MemoServ, u, MEMOSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ms_info.c b/src/core/ms_info.c
new file mode 100644
index 000000000..2e4e91b46
--- /dev/null
+++ b/src/core/ms_info.c
@@ -0,0 +1,231 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_info(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("INFO", do_info, NULL, -1, MEMO_HELP_INFO, -1,
+ MEMO_SERVADMIN_HELP_INFO, MEMO_SERVADMIN_HELP_INFO);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_INFO);
+}
+
+/**
+ * The /ms info command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_info(User * u)
+{
+ MemoInfo *mi;
+ NickAlias *na = NULL;
+ ChannelInfo *ci = NULL;
+ char *name = strtok(NULL, " ");
+ int is_servadmin = is_services_admin(u);
+ int hardmax = 0;
+
+ if (is_servadmin && name && *name != '#') {
+ na = findnick(name);
+ if (!na) {
+ notice_lang(s_MemoServ, u, NICK_X_NOT_REGISTERED, name);
+ return MOD_CONT;
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_MemoServ, u, NICK_X_FORBIDDEN, name);
+ return MOD_CONT;
+ }
+ mi = &na->nc->memos;
+ hardmax = na->nc->flags & NI_MEMO_HARDMAX ? 1 : 0;
+ } else if (name && *name == '#') {
+ ci = cs_findchan(name);
+ if (!ci) {
+ notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, name);
+ return MOD_CONT;
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_MemoServ, u, CHAN_X_FORBIDDEN, name);
+ return MOD_CONT;
+ } else if (!check_access(u, ci, CA_MEMO)) {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+ mi = &ci->memos;
+ hardmax = ci->flags & CI_MEMO_HARDMAX ? 1 : 0;
+ } else if (name) { /* It's not a chan and we aren't services admin */
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ } else { /* !name */
+ if (!nick_identified(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ }
+ mi = &u->na->nc->memos;
+ hardmax = u->na->nc->flags & NI_MEMO_HARDMAX ? 1 : 0;
+ }
+
+ if (name && (ci || na->nc != u->na->nc)) {
+
+ if (!mi->memocount) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NO_MEMOS, name);
+ } else if (mi->memocount == 1) {
+ if (mi->memos[0].flags & MF_UNREAD)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMO_UNREAD, name);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMO, name);
+ } else {
+ int count = 0, i;
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].flags & MF_UNREAD)
+ count++;
+ }
+ if (count == mi->memocount)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMOS_ALL_UNREAD,
+ name, count);
+ else if (count == 0)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMOS, name,
+ mi->memocount);
+ else if (count == 1)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMOS_ONE_UNREAD,
+ name, mi->memocount);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_MEMOS_SOME_UNREAD,
+ name, mi->memocount, count);
+ }
+ if (mi->memomax == 0) {
+ if (hardmax)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_HARD_LIMIT, name,
+ mi->memomax);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_LIMIT, name,
+ mi->memomax);
+ } else if (mi->memomax > 0) {
+ if (hardmax)
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_HARD_LIMIT, name,
+ mi->memomax);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_LIMIT, name,
+ mi->memomax);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NO_LIMIT, name);
+ }
+
+ /* I ripped this code out of ircservices 4.4.5, since I didn't want
+ to rewrite the whole thing (it pisses me off). */
+ if (na) {
+ if ((na->nc->flags & NI_MEMO_RECEIVE)
+ && (na->nc->flags & NI_MEMO_SIGNON)) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NOTIFY_ON, name);
+ } else if (na->nc->flags & NI_MEMO_RECEIVE) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NOTIFY_RECEIVE,
+ name);
+ } else if (na->nc->flags & NI_MEMO_SIGNON) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NOTIFY_SIGNON,
+ name);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_INFO_X_NOTIFY_OFF, name);
+ }
+ }
+
+ } else { /* !name || (!ci || na->nc == u->na->nc) */
+
+ if (!mi->memocount) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NO_MEMOS);
+ } else if (mi->memocount == 1) {
+ if (mi->memos[0].flags & MF_UNREAD)
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMO_UNREAD);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMO);
+ } else {
+ int count = 0, i;
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].flags & MF_UNREAD)
+ count++;
+ }
+ if (count == mi->memocount)
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMOS_ALL_UNREAD,
+ count);
+ else if (count == 0)
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMOS, mi->memocount);
+ else if (count == 1)
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMOS_ONE_UNREAD,
+ mi->memocount);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_MEMOS_SOME_UNREAD,
+ mi->memocount, count);
+ }
+
+ if (mi->memomax == 0) {
+ if (!is_servadmin && hardmax)
+ notice_lang(s_MemoServ, u, MEMO_INFO_HARD_LIMIT_ZERO);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_LIMIT_ZERO);
+ } else if (mi->memomax > 0) {
+ if (!is_servadmin && hardmax)
+ notice_lang(s_MemoServ, u, MEMO_INFO_HARD_LIMIT,
+ mi->memomax);
+ else
+ notice_lang(s_MemoServ, u, MEMO_INFO_LIMIT, mi->memomax);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NO_LIMIT);
+ }
+
+ /* Ripped too. But differently because of a seg fault (loughs) */
+ if ((u->na->nc->flags & NI_MEMO_RECEIVE)
+ && (u->na->nc->flags & NI_MEMO_SIGNON)) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NOTIFY_ON);
+ } else if (u->na->nc->flags & NI_MEMO_RECEIVE) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NOTIFY_RECEIVE);
+ } else if (u->na->nc->flags & NI_MEMO_SIGNON) {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NOTIFY_SIGNON);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_INFO_NOTIFY_OFF);
+ }
+ }
+ return MOD_CONT; /* if (name && (ci || na->nc != u->na->nc)) */
+}
diff --git a/src/core/ms_list.c b/src/core/ms_list.c
new file mode 100644
index 000000000..b0a203afd
--- /dev/null
+++ b/src/core/ms_list.c
@@ -0,0 +1,197 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+int do_list(User * u);
+int list_memo_callback(User * u, int num, va_list args);
+int list_memo(User * u, int index, MemoInfo * mi, int *sent_header,
+ int new, const char *chan);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("LIST", do_list, NULL, MEMO_HELP_LIST, -1, -1, -1,
+ -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_LIST);
+}
+
+/**
+ * List the memos (if any) for the source nick or given channel.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_list(User * u)
+{
+ char *param = strtok(NULL, " "), *chan = NULL;
+ ChannelInfo *ci;
+ MemoInfo *mi;
+ Memo *m;
+ int i;
+
+ if (param && *param == '#') {
+ chan = param;
+ param = strtok(NULL, " ");
+ if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_MemoServ, u, CHAN_X_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if (!check_access(u, ci, CA_MEMO)) {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+ mi = &ci->memos;
+ } else {
+ if (!nick_identified(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ }
+ mi = &u->na->nc->memos;
+ }
+ if (param && !isdigit(*param) && stricmp(param, "NEW") != 0) {
+ syntax_error(s_MemoServ, u, "LIST", MEMO_LIST_SYNTAX);
+ } else if (mi->memocount == 0) {
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HAVE_NO_MEMOS);
+ } else {
+ int sent_header = 0;
+ if (param && isdigit(*param)) {
+ process_numlist(param, NULL, list_memo_callback, u,
+ mi, &sent_header, chan);
+ } else {
+ if (param) {
+ for (i = 0, m = mi->memos; i < mi->memocount; i++, m++) {
+ if (m->flags & MF_UNREAD)
+ break;
+ }
+ if (i == mi->memocount) {
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_NEW_MEMOS,
+ chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HAVE_NO_NEW_MEMOS);
+ return MOD_CONT;
+ }
+ }
+ for (i = 0, m = mi->memos; i < mi->memocount; i++, m++) {
+ if (param && !(m->flags & MF_UNREAD))
+ continue;
+ list_memo(u, i, mi, &sent_header, param != NULL, chan);
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+/**
+ * list memno callback function
+ * @param u User Struct
+ * @param int Memo number
+ * @param va_list List of arguements
+ * @return result form list_memo()
+ */
+int list_memo_callback(User * u, int num, va_list args)
+{
+ MemoInfo *mi = va_arg(args, MemoInfo *);
+ int *sent_header = va_arg(args, int *);
+ const char *chan = va_arg(args, const char *);
+ int i;
+
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].number == num)
+ break;
+ }
+ /* Range checking done by list_memo() */
+ return list_memo(u, i, mi, sent_header, 0, chan);
+}
+
+/**
+ * Display a single memo entry, possibly printing the header first.
+ * @param u User Struct
+ * @param int Memo index
+ * @param mi MemoInfo Struct
+ * @param send_header If we are to send the headers
+ * @param new If we are listing new memos
+ * @param chan Channel name
+ * @return MOD_CONT
+ */
+int list_memo(User * u, int index, MemoInfo * mi, int *sent_header,
+ int new, const char *chan)
+{
+ Memo *m;
+ char timebuf[64];
+ struct tm tm;
+
+ if (index < 0 || index >= mi->memocount)
+ return 0;
+ if (!*sent_header) {
+ if (chan) {
+ notice_lang(s_MemoServ, u,
+ new ? MEMO_LIST_CHAN_NEW_MEMOS :
+ MEMO_LIST_CHAN_MEMOS, chan, s_MemoServ, chan);
+ } else {
+ notice_lang(s_MemoServ, u,
+ new ? MEMO_LIST_NEW_MEMOS : MEMO_LIST_MEMOS,
+ u->nick, s_MemoServ);
+ }
+ notice_lang(s_MemoServ, u, MEMO_LIST_HEADER);
+ *sent_header = 1;
+ }
+ m = &mi->memos[index];
+ tm = *localtime(&m->time);
+ strftime_lang(timebuf, sizeof(timebuf),
+ u, STRFTIME_DATE_TIME_FORMAT, &tm);
+ timebuf[sizeof(timebuf) - 1] = 0; /* just in case */
+ notice_lang(s_MemoServ, u, MEMO_LIST_FORMAT,
+ (m->flags & MF_UNREAD) ? '*' : ' ',
+ m->number, m->sender, timebuf);
+ return 1;
+}
diff --git a/src/core/ms_read.c b/src/core/ms_read.c
new file mode 100644
index 000000000..3588ac9f0
--- /dev/null
+++ b/src/core/ms_read.c
@@ -0,0 +1,203 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_read(User * u);
+int read_memo_callback(User * u, int num, va_list args);
+int read_memo(User * u, int index, MemoInfo * mi, const char *chan);
+void myMemoServHelp(User * u);
+extern void rsend_notify(User * u, Memo * m, const char *chan);
+
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("READ", do_read, NULL, MEMO_HELP_READ, -1, -1, -1,
+ -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_READ);
+}
+
+/**
+ * The /ms read command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_read(User * u)
+{
+ MemoInfo *mi;
+ ChannelInfo *ci;
+ char *numstr = strtok(NULL, " "), *chan = NULL;
+ int num, count;
+
+ if (numstr && *numstr == '#') {
+ chan = numstr;
+ numstr = strtok(NULL, " ");
+ if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_MemoServ, u, CHAN_X_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if (!check_access(u, ci, CA_MEMO)) {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+ mi = &ci->memos;
+ } else {
+ if (!nick_identified(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ }
+ mi = &u->na->nc->memos;
+ }
+ num = numstr ? atoi(numstr) : -1;
+ if (!numstr
+ || (stricmp(numstr, "LAST") != 0 && stricmp(numstr, "NEW") != 0
+ && num <= 0)) {
+ syntax_error(s_MemoServ, u, "READ", MEMO_READ_SYNTAX);
+
+ } else if (mi->memocount == 0) {
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HAVE_NO_MEMOS);
+
+ } else {
+ int i;
+
+ if (stricmp(numstr, "NEW") == 0) {
+ int readcount = 0;
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].flags & MF_UNREAD) {
+ read_memo(u, i, mi, chan);
+ readcount++;
+ }
+ }
+ if (!readcount) {
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_NEW_MEMOS,
+ chan);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HAVE_NO_NEW_MEMOS);
+ }
+ } else if (stricmp(numstr, "LAST") == 0) {
+ for (i = 0; i < mi->memocount - 1; i++);
+ read_memo(u, i, mi, chan);
+ } else { /* number[s] */
+ if (!process_numlist(numstr, &count, read_memo_callback, u,
+ mi, chan)) {
+ if (count == 1)
+ notice_lang(s_MemoServ, u, MEMO_DOES_NOT_EXIST, num);
+ else
+ notice_lang(s_MemoServ, u, MEMO_LIST_NOT_FOUND,
+ numstr);
+ }
+ }
+
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Read a memo callback function
+ * @param u User Struct
+ * @param int Index number
+ * @param va_list variable arguements
+ * @return result of read_memo()
+ */
+int read_memo_callback(User * u, int num, va_list args)
+{
+ MemoInfo *mi = va_arg(args, MemoInfo *);
+ const char *chan = va_arg(args, const char *);
+ int i;
+
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].number == num)
+ break;
+ }
+ /* Range check done in read_memo */
+ return read_memo(u, i, mi, chan);
+}
+
+/**
+ * Read a memo
+ * @param u User Struct
+ * @param int Index number
+ * @param mi MemoInfo struct
+ * @param chan Channel Name
+ * @return 1 on success, 0 if failed
+ */
+int read_memo(User * u, int index, MemoInfo * mi, const char *chan)
+{
+ Memo *m;
+ char timebuf[64];
+ struct tm tm;
+
+ if (index < 0 || index >= mi->memocount)
+ return 0;
+ m = &mi->memos[index];
+ tm = *localtime(&m->time);
+ strftime_lang(timebuf, sizeof(timebuf),
+ u, STRFTIME_DATE_TIME_FORMAT, &tm);
+ timebuf[sizeof(timebuf) - 1] = 0;
+ if (chan)
+ notice_lang(s_MemoServ, u, MEMO_CHAN_HEADER, m->number,
+ m->sender, timebuf, s_MemoServ, chan, m->number);
+ else
+ notice_lang(s_MemoServ, u, MEMO_HEADER, m->number,
+ m->sender, timebuf, s_MemoServ, m->number);
+ notice_lang(s_MemoServ, u, MEMO_TEXT, m->text);
+ m->flags &= ~MF_UNREAD;
+
+ /* Check if a receipt notification was requested */
+ if (m->flags & MF_RECEIPT) {
+ rsend_notify(u, m, chan);
+ }
+
+ return 1;
+}
diff --git a/src/core/ms_rsend.c b/src/core/ms_rsend.c
new file mode 100644
index 000000000..4baf81c00
--- /dev/null
+++ b/src/core/ms_rsend.c
@@ -0,0 +1,120 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_rsend(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("RSEND", do_rsend, NULL, MEMO_HELP_RSEND, -1, -1, -1,
+ -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ if (!MSMemoReceipt) {
+ return MOD_STOP;
+ }
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ if (((MSMemoReceipt == 1) && (is_services_oper(u)))
+ || (MSMemoReceipt == 2)) {
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_RSEND);
+ }
+}
+
+/**
+ * The /ms rsend command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_rsend(User * u)
+{
+ char *name = strtok(NULL, " ");
+ char *text = strtok(NULL, "");
+ NickAlias *na = NULL;
+ int z = 3;
+
+
+
+ /* check if the variables are here */
+ if (!name || !text) {
+ notice_lang(s_MemoServ, u, MEMO_RSEND_SYNTAX);
+ return MOD_CONT;
+ }
+
+ /* prevent user from rsend to themselves */
+ if ((na = findnick(name))) {
+ if (u->na) {
+ if (stricmp(na->nc->display, u->na->nc->display) == 0) {
+ notice_lang(s_MemoServ, u, MEMO_NO_RSEND_SELF);
+ return MOD_CONT;
+ }
+ } else {
+ notice_lang(s_MemoServ, u, NICK_X_NOT_REGISTERED, name);
+ return MOD_CONT;
+ }
+ }
+
+ if (MSMemoReceipt == 1) {
+ /* Services opers and above can use rsend */
+ if (is_services_oper(u)) {
+ memo_send(u, name, text, z);
+ } else {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ }
+ } else if (MSMemoReceipt == 2) {
+ /* Everybody can use rsend */
+ memo_send(u, name, text, z);
+ } else {
+ /* rsend has been disabled */
+ if (debug) {
+ alog("debug: MSMemoReceipt is set misconfigured to %d",
+ MSMemoReceipt);
+ }
+ notice_lang(s_MemoServ, u, MEMO_RSEND_DISABLED);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/ms_send.c b/src/core/ms_send.c
new file mode 100644
index 000000000..3ea195262
--- /dev/null
+++ b/src/core/ms_send.c
@@ -0,0 +1,74 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_send(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("SEND", do_send, NULL, MEMO_HELP_SEND, -1, -1, -1,
+ -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_SEND);
+}
+
+/**
+ * The /ms send command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_send(User * u)
+{
+ char *name = strtok(NULL, " ");
+ char *text = strtok(NULL, "");
+ int z = 0;
+ memo_send(u, name, text, z);
+ return MOD_CONT;
+}
diff --git a/src/core/ms_sendall.c b/src/core/ms_sendall.c
new file mode 100644
index 000000000..fd0e32454
--- /dev/null
+++ b/src/core/ms_sendall.c
@@ -0,0 +1,96 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_sendall(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("SENDALL", do_sendall, is_services_admin, -1, -1, -1,
+ MEMO_HELP_SENDALL, MEMO_HELP_SENDALL);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_SENDALL);
+ }
+}
+
+/**
+ * The /ms sendall command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_sendall(User * u)
+{
+ int i, z = 1;
+ NickCore *nc;
+ char *text = strtok(NULL, "");
+
+ if (readonly) {
+ notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED);
+ return MOD_CONT;
+ } else if (checkDefCon(DEFCON_NO_NEW_MEMOS)) {
+ notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ } else if (!text) {
+ syntax_error(s_MemoServ, u, "SENDALL", MEMO_SEND_SYNTAX);
+ return MOD_CONT;
+ }
+
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ if (stricmp(u->nick, nc->display) != 0)
+ memo_send(u, nc->display, text, z);
+ } /* /nc */
+ } /* /i */
+
+ notice_lang(s_MemoServ, u, MEMO_MASS_SENT);
+ return MOD_CONT;
+}
diff --git a/src/core/ms_set.c b/src/core/ms_set.c
new file mode 100644
index 000000000..699a949c7
--- /dev/null
+++ b/src/core/ms_set.c
@@ -0,0 +1,266 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_set(User * u);
+int do_set_notify(User * u, MemoInfo * mi, char *param);
+int do_set_limit(User * u, MemoInfo * mi, char *param);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", do_set, NULL, MEMO_HELP_SET, -1, -1, -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+
+ c = createCommand("SET NOTIFY", NULL, NULL, MEMO_HELP_SET_NOTIFY, -1,
+ -1, -1, -1);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+
+ c = createCommand("SET LIMIT", NULL, NULL, -1, MEMO_HELP_SET_LIMIT,
+ MEMO_SERVADMIN_HELP_SET_LIMIT,
+ MEMO_SERVADMIN_HELP_SET_LIMIT,
+ MEMO_SERVADMIN_HELP_SET_LIMIT);
+ c->help_param1 = (char *) (long) MSMaxMemos;
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /hs help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_SET);
+}
+
+/**
+ * The /ms set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *param = strtok(NULL, "");
+ MemoInfo *mi = &u->na->nc->memos;
+
+ if (readonly) {
+ notice_lang(s_MemoServ, u, MEMO_SET_DISABLED);
+ return MOD_CONT;
+ }
+ if (!param) {
+ syntax_error(s_MemoServ, u, "SET", MEMO_SET_SYNTAX);
+ } else if (!nick_identified(u)) {
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ return MOD_CONT;
+ } else if (stricmp(cmd, "NOTIFY") == 0) {
+ do_set_notify(u, mi, param);
+ } else if (stricmp(cmd, "LIMIT") == 0) {
+ do_set_limit(u, mi, param);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_SET_UNKNOWN_OPTION, cmd);
+ notice_lang(s_MemoServ, u, MORE_INFO, s_MemoServ, "SET");
+ }
+ return MOD_CONT;
+}
+
+/**
+ * The /ms set notify command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set_notify(User * u, MemoInfo * mi, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ u->na->nc->flags |= NI_MEMO_SIGNON | NI_MEMO_RECEIVE;
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_ON, s_MemoServ);
+ } else if (stricmp(param, "LOGON") == 0) {
+ u->na->nc->flags |= NI_MEMO_SIGNON;
+ u->na->nc->flags &= ~NI_MEMO_RECEIVE;
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_LOGON, s_MemoServ);
+ } else if (stricmp(param, "NEW") == 0) {
+ u->na->nc->flags &= ~NI_MEMO_SIGNON;
+ u->na->nc->flags |= NI_MEMO_RECEIVE;
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_NEW, s_MemoServ);
+ } else if (stricmp(param, "MAIL") == 0) {
+ if (u->na->nc->email) {
+ u->na->nc->flags |= NI_MEMO_MAIL;
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_MAIL);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_INVALIDMAIL);
+ }
+ } else if (stricmp(param, "NOMAIL") == 0) {
+ u->na->nc->flags &= ~NI_MEMO_MAIL;
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_NOMAIL);
+ } else if (stricmp(param, "OFF") == 0) {
+ u->na->nc->flags &= ~(NI_MEMO_SIGNON | NI_MEMO_RECEIVE);
+ notice_lang(s_MemoServ, u, MEMO_SET_NOTIFY_OFF, s_MemoServ);
+ } else {
+ syntax_error(s_MemoServ, u, "SET NOTIFY", MEMO_SET_NOTIFY_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/**
+ * The /ms set limit command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set_limit(User * u, MemoInfo * mi, char *param)
+{
+ char *p1 = strtok(param, " ");
+ char *p2 = strtok(NULL, " ");
+ char *p3 = strtok(NULL, " ");
+ char *user = NULL, *chan = NULL;
+ int32 limit;
+ NickAlias *na = u->na;
+ ChannelInfo *ci = NULL;
+ int is_servadmin = is_services_admin(u);
+
+ if (p1 && *p1 == '#') {
+ chan = p1;
+ p1 = p2;
+ p2 = p3;
+ p3 = strtok(NULL, " ");
+ if (!(ci = cs_findchan(chan))) {
+ notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, chan);
+ return MOD_CONT;
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_MemoServ, u, CHAN_X_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if (!is_servadmin && !check_access(u, ci, CA_MEMO)) {
+ notice_lang(s_MemoServ, u, ACCESS_DENIED);
+ return MOD_CONT;
+ }
+ mi = &ci->memos;
+ }
+ if (is_servadmin) {
+ if (p2 && stricmp(p2, "HARD") != 0 && !chan) {
+ if (!(na = findnick(p1))) {
+ notice_lang(s_MemoServ, u, NICK_X_NOT_REGISTERED, p1);
+ return MOD_CONT;
+ }
+ user = p1;
+ mi = &na->nc->memos;
+ p1 = p2;
+ p2 = p3;
+ } else if (!p1) {
+ syntax_error(s_MemoServ, u, "SET LIMIT",
+ MEMO_SET_LIMIT_SERVADMIN_SYNTAX);
+ return MOD_CONT;
+ }
+ if ((!isdigit(*p1) && stricmp(p1, "NONE") != 0) ||
+ (p2 && stricmp(p2, "HARD") != 0)) {
+ syntax_error(s_MemoServ, u, "SET LIMIT",
+ MEMO_SET_LIMIT_SERVADMIN_SYNTAX);
+ return MOD_CONT;
+ }
+ if (chan) {
+ if (p2)
+ ci->flags |= CI_MEMO_HARDMAX;
+ else
+ ci->flags &= ~CI_MEMO_HARDMAX;
+ } else {
+ if (p2)
+ na->nc->flags |= NI_MEMO_HARDMAX;
+ else
+ na->nc->flags &= ~NI_MEMO_HARDMAX;
+ }
+ limit = atoi(p1);
+ if (limit < 0 || limit > 32767) {
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT_OVERFLOW, 32767);
+ limit = 32767;
+ }
+ if (stricmp(p1, "NONE") == 0)
+ limit = -1;
+ } else {
+ if (!p1 || p2 || !isdigit(*p1)) {
+ syntax_error(s_MemoServ, u, "SET LIMIT",
+ MEMO_SET_LIMIT_SYNTAX);
+ return MOD_CONT;
+ }
+ if (chan && (ci->flags & CI_MEMO_HARDMAX)) {
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT_FORBIDDEN, chan);
+ return MOD_CONT;
+ } else if (!chan && (na->nc->flags & NI_MEMO_HARDMAX)) {
+ notice_lang(s_MemoServ, u, MEMO_SET_YOUR_LIMIT_FORBIDDEN);
+ return MOD_CONT;
+ }
+ limit = atoi(p1);
+ /* The first character is a digit, but we could still go negative
+ * from overflow... watch out! */
+ if (limit < 0 || (MSMaxMemos > 0 && limit > MSMaxMemos)) {
+ if (chan) {
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT_TOO_HIGH,
+ chan, MSMaxMemos);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_SET_YOUR_LIMIT_TOO_HIGH,
+ MSMaxMemos);
+ }
+ return MOD_CONT;
+ } else if (limit > 32767) {
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT_OVERFLOW, 32767);
+ limit = 32767;
+ }
+ }
+ mi->memomax = limit;
+ if (limit > 0) {
+ if (!chan && na->nc == u->na->nc)
+ notice_lang(s_MemoServ, u, MEMO_SET_YOUR_LIMIT, limit);
+ else
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT,
+ chan ? chan : user, limit);
+ } else if (limit == 0) {
+ if (!chan && na->nc == u->na->nc)
+ notice_lang(s_MemoServ, u, MEMO_SET_YOUR_LIMIT_ZERO);
+ else
+ notice_lang(s_MemoServ, u, MEMO_SET_LIMIT_ZERO,
+ chan ? chan : user);
+ } else {
+ if (!chan && na->nc == u->na->nc)
+ notice_lang(s_MemoServ, u, MEMO_UNSET_YOUR_LIMIT);
+ else
+ notice_lang(s_MemoServ, u, MEMO_UNSET_LIMIT,
+ chan ? chan : user);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ms_staff.c b/src/core/ms_staff.c
new file mode 100644
index 000000000..e6462c975
--- /dev/null
+++ b/src/core/ms_staff.c
@@ -0,0 +1,93 @@
+/* MemoServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_staff(User * u);
+void myMemoServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("STAFF", do_staff, is_services_oper, -1, -1,
+ MEMO_HELP_STAFF, MEMO_HELP_STAFF, MEMO_HELP_STAFF);
+ moduleAddCommand(MEMOSERV, c, MOD_UNIQUE);
+ moduleSetMemoHelp(myMemoServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ms help output.
+ * @param u The user who is requesting help
+ **/
+void myMemoServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_MemoServ, u, MEMO_HELP_CMD_STAFF);
+ }
+}
+
+/**
+ * The /ms staff command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_staff(User * u)
+{
+ NickCore *nc;
+ int i, z = 0;
+ char *text = strtok(NULL, "");
+
+ if (readonly) {
+ notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED);
+ return MOD_CONT;
+ } else if (checkDefCon(DEFCON_NO_NEW_MEMOS)) {
+ notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ } else if (text == NULL) {
+ syntax_error(s_MemoServ, u, "SEND", MEMO_SEND_SYNTAX);
+ return MOD_CONT;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ if (nick_is_services_oper(nc))
+ memo_send(u, nc->display, text, z);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_access.c b/src/core/ns_access.c
new file mode 100644
index 000000000..40e925012
--- /dev/null
+++ b/src/core/ns_access.c
@@ -0,0 +1,189 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_access(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ACCESS", do_access, NULL, NICK_HELP_ACCESS, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_ACCESS);
+}
+
+/**
+ * The /ns access command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_access(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *mask = strtok(NULL, " ");
+ NickAlias *na;
+ int i;
+ char **access;
+
+ if (cmd && stricmp(cmd, "LIST") == 0 && mask && is_services_admin(u)
+ && (na = findnick(mask))) {
+
+ if (na->nc->accesscount == 0) {
+ notice_lang(s_NickServ, u, NICK_ACCESS_LIST_X_EMPTY, na->nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ return MOD_CONT;
+ }
+
+ if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ return MOD_CONT;
+ }
+
+
+ notice_lang(s_NickServ, u, NICK_ACCESS_LIST_X, mask);
+ mask = strtok(NULL, " ");
+ for (access = na->nc->access, i = 0; i < na->nc->accesscount;
+ access++, i++) {
+ if (mask && !match_wild(mask, *access))
+ continue;
+ notice_user(s_NickServ, u, " %s", *access);
+ }
+
+ } else if (!cmd || ((stricmp(cmd, "LIST") == 0) ? !!mask : !mask)) {
+ syntax_error(s_NickServ, u, "ACCESS", NICK_ACCESS_SYNTAX);
+
+ } else if (mask && !strchr(mask, '@')) {
+ notice_lang(s_NickServ, u, BAD_USERHOST_MASK);
+ notice_lang(s_NickServ, u, MORE_INFO, s_NickServ, "ACCESS");
+
+ } else if (!(na = u->na)) {
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
+
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+
+ } else if (!nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+
+ } else if (stricmp(cmd, "ADD") == 0) {
+ if (na->nc->accesscount >= NSAccessMax) {
+ notice_lang(s_NickServ, u, NICK_ACCESS_REACHED_LIMIT,
+ NSAccessMax);
+ return MOD_CONT;
+ }
+
+ for (access = na->nc->access, i = 0; i < na->nc->accesscount;
+ access++, i++) {
+ if (strcmp(*access, mask) == 0) {
+ notice_lang(s_NickServ, u, NICK_ACCESS_ALREADY_PRESENT,
+ *access);
+ return MOD_CONT;
+ }
+ }
+
+ na->nc->accesscount++;
+ na->nc->access =
+ srealloc(na->nc->access, sizeof(char *) * na->nc->accesscount);
+ na->nc->access[na->nc->accesscount - 1] = sstrdup(mask);
+ notice_lang(s_NickServ, u, NICK_ACCESS_ADDED, mask);
+
+ } else if (stricmp(cmd, "DEL") == 0) {
+
+ for (access = na->nc->access, i = 0; i < na->nc->accesscount;
+ access++, i++) {
+ if (stricmp(*access, mask) == 0)
+ break;
+ }
+ if (i == na->nc->accesscount) {
+ notice_lang(s_NickServ, u, NICK_ACCESS_NOT_FOUND, mask);
+ return MOD_CONT;
+ }
+
+ notice_lang(s_NickServ, u, NICK_ACCESS_DELETED, *access);
+ free(*access);
+ na->nc->accesscount--;
+ if (i < na->nc->accesscount) /* if it wasn't the last entry... */
+ memmove(access, access + 1,
+ (na->nc->accesscount - i) * sizeof(char *));
+ if (na->nc->accesscount) /* if there are any entries left... */
+ na->nc->access =
+ srealloc(na->nc->access,
+ na->nc->accesscount * sizeof(char *));
+ else {
+ free(na->nc->access);
+ na->nc->access = NULL;
+ }
+ } else if (stricmp(cmd, "LIST") == 0) {
+ if (na->nc->accesscount == 0) {
+ notice_lang(s_NickServ, u, NICK_ACCESS_LIST_EMPTY, u->nick);
+ return MOD_CONT;
+ }
+
+ notice_lang(s_NickServ, u, NICK_ACCESS_LIST);
+ for (access = na->nc->access, i = 0; i < na->nc->accesscount;
+ access++, i++) {
+ if (mask && !match_wild(mask, *access))
+ continue;
+ notice_user(s_NickServ, u, " %s", *access);
+ }
+ } else {
+ syntax_error(s_NickServ, u, "ACCESS", NICK_ACCESS_SYNTAX);
+
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_alist.c b/src/core/ns_alist.c
new file mode 100644
index 000000000..8090531d2
--- /dev/null
+++ b/src/core/ns_alist.c
@@ -0,0 +1,186 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_alist(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ALIST", do_alist, NULL, -1, NICK_HELP_ALIST, -1,
+ NICK_SERVADMIN_HELP_ALIST,
+ NICK_SERVADMIN_HELP_ALIST);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_ALIST);
+}
+
+/**
+ * The /ns alist command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_alist(User * u)
+{
+
+/*
+ * List the channels that the given nickname has access on
+ *
+ * /ns ALIST [level]
+ * /ns ALIST [nickname] [level]
+ *
+ * -jester
+ */
+
+ char *nick = NULL;
+ char *lev = NULL;
+
+ NickAlias *na;
+
+ int min_level = 0;
+ int is_servadmin = is_services_admin(u);
+
+ if (!is_servadmin) {
+ /* Non service admins can only see their own levels */
+ na = u->na;
+ } else {
+ /* Services admins can request ALIST on nicks.
+ * The first argument for service admins must
+ * always be a nickname.
+ */
+ nick = strtok(NULL, " ");
+
+ /* If an argument was passed, use it as the nick to see levels
+ * for, else check levels for the user calling the command */
+ if (nick) {
+ na = findnick(nick);
+ } else {
+ na = u->na;
+ }
+ }
+
+ /* If available, get level from arguments */
+ lev = strtok(NULL, " ");
+
+ /* if a level was given, make sure it's an int for later */
+ if (lev) {
+ if (stricmp(lev, "FOUNDER") == 0) {
+ min_level = ACCESS_FOUNDER;
+ } else if (stricmp(lev, "SOP") == 0) {
+ min_level = ACCESS_SOP;
+ } else if (stricmp(lev, "AOP") == 0) {
+ min_level = ACCESS_AOP;
+ } else if (stricmp(lev, "HOP") == 0) {
+ min_level = ACCESS_HOP;
+ } else if (stricmp(lev, "VOP") == 0) {
+ min_level = ACCESS_VOP;
+ } else {
+ min_level = atoi(lev);
+ }
+ }
+
+ if (!nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (is_servadmin && nick && !na) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (min_level <= ACCESS_INVALID || min_level > ACCESS_FOUNDER) {
+ notice_lang(s_NickServ, u, CHAN_ACCESS_LEVEL_RANGE,
+ ACCESS_INVALID + 1, ACCESS_FOUNDER - 1);
+ } else {
+ int i, level;
+ int chan_count = 0;
+ int match_count = 0;
+ ChannelInfo *ci;
+
+ notice_lang(s_NickServ, u, (is_servadmin ? NICK_ALIST_HEADER_X :
+ NICK_ALIST_HEADER), na->nick);
+
+ for (i = 0; i < 256; i++) {
+ for ((ci = chanlists[i]); ci; (ci = ci->next)) {
+
+ if ((level = get_access_level(ci, na))) {
+ chan_count++;
+
+ if (min_level > level) {
+ continue;
+ }
+
+ match_count++;
+
+ if ((ci->flags & CI_XOP) || (level == ACCESS_FOUNDER)) {
+ const char *xop;
+
+ xop = get_xop_level(level);
+
+ notice_lang(s_NickServ, u, NICK_ALIST_XOP_FORMAT,
+ match_count,
+ ((ci->
+ flags & CI_NO_EXPIRE) ? '!' : ' '),
+ ci->name, xop,
+ (ci->desc ? ci->desc : ""));
+ } else {
+ notice_lang(s_NickServ, u,
+ NICK_ALIST_ACCESS_FORMAT, match_count,
+ ((ci->
+ flags & CI_NO_EXPIRE) ? '!' : ' '),
+ ci->name, level,
+ (ci->desc ? ci->desc : ""));
+
+ }
+ }
+ }
+ }
+
+ notice_lang(s_NickServ, u, NICK_ALIST_FOOTER, match_count,
+ chan_count);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_drop.c b/src/core/ns_drop.c
new file mode 100644
index 000000000..e0434d7e0
--- /dev/null
+++ b/src/core/ns_drop.c
@@ -0,0 +1,156 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_drop(User * u);
+int do_unlink(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("DROP", do_drop, NULL, -1, NICK_HELP_DROP, -1,
+ NICK_SERVADMIN_HELP_DROP, NICK_SERVADMIN_HELP_DROP);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("UNLINK", do_unlink, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_DROP);
+}
+
+/**
+ * The /ns drop command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_drop(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ NickAlias *na;
+ NickRequest *nr = NULL;
+ int is_servadmin = is_services_admin(u);
+ int is_mine; /* Does the nick being dropped belong to the user that is dropping? */
+ char *my_nick = NULL;
+
+ if (readonly && !is_servadmin) {
+ notice_lang(s_NickServ, u, NICK_DROP_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!(na = (nick ? findnick(nick) : u->na))) {
+ if (nick) {
+ if ((nr = findrequestnick(nick)) && is_servadmin) {
+ if (readonly)
+ notice_lang(s_NickServ, u, READ_ONLY_MODE);
+ if (WallDrop)
+ anope_cmd_global(s_NickServ,
+ "\2%s\2 used DROP on \2%s\2", u->nick,
+ nick);
+ alog("%s: %s!%s@%s dropped nickname %s (e-mail: %s)",
+ s_NickServ, u->nick, u->username, u->host,
+ nr->nick, nr->email);
+ delnickrequest(nr);
+ notice_lang(s_NickServ, u, NICK_X_DROPPED, nick);
+ } else {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ }
+ } else
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
+ return MOD_CONT;
+ }
+
+ is_mine = (u->na && (u->na->nc == na->nc));
+ if (is_mine && !nick)
+ my_nick = sstrdup(na->nick);
+
+ if (is_mine && !nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (!is_mine && !is_servadmin) {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ } else if (NSSecureAdmins && !is_mine && nick_is_services_admin(na->nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ } else {
+ if (readonly)
+ notice_lang(s_NickServ, u, READ_ONLY_MODE);
+
+ if (ircd->sqline && (na->status & NS_VERBOTEN)) {
+ anope_cmd_unsqline(na->nick);
+ }
+
+ alog("%s: %s!%s@%s dropped nickname %s (group %s) (e-mail: %s)",
+ s_NickServ, u->nick, u->username, u->host,
+ na->nick, na->nc->display,
+ (na->nc->email ? na->nc->email : "none"));
+ delnick(na);
+ send_event(EVENT_NICK_DROPPED, 1, (my_nick ? my_nick : nick));
+
+ if (!is_mine) {
+ if (WallDrop)
+ anope_cmd_global(s_NickServ, "\2%s\2 used DROP on \2%s\2",
+ u->nick, nick);
+ notice_lang(s_NickServ, u, NICK_X_DROPPED, nick);
+ } else {
+ if (nick)
+ notice_lang(s_NickServ, u, NICK_X_DROPPED, nick);
+ else
+ notice_lang(s_NickServ, u, NICK_DROPPED);
+ if (my_nick) {
+ free(my_nick);
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+
+int do_unlink(User * u)
+{
+ notice_lang(s_NickServ, u, OBSOLETE_COMMAND, "DROP");
+ return MOD_CONT;
+}
diff --git a/src/core/ns_forbid.c b/src/core/ns_forbid.c
new file mode 100644
index 000000000..b3ecc5531
--- /dev/null
+++ b/src/core/ns_forbid.c
@@ -0,0 +1,155 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_forbid(User * u);
+void myNickServHelp(User * u);
+NickAlias *makenick(const char *nick);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("FORBID", do_forbid, is_services_admin, -1, -1, -1,
+ NICK_SERVADMIN_HELP_FORBID,
+ NICK_SERVADMIN_HELP_FORBID);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_FORBID);
+ }
+}
+
+/**
+ * The /ns forbid command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_forbid(User * u)
+{
+ NickAlias *na;
+ char *nick = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ /* Assumes that permission checking has already been done. */
+ if (!nick || (ForceForbidReason && !reason)) {
+ syntax_error(s_NickServ, u, "FORBID",
+ (ForceForbidReason ? NICK_FORBID_SYNTAX_REASON :
+ NICK_FORBID_SYNTAX));
+ return MOD_CONT;
+ }
+
+ if (readonly)
+ notice_lang(s_NickServ, u, READ_ONLY_MODE);
+ if (!anope_valid_nick(nick)) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+ if ((na = findnick(nick)) != NULL) {
+ if (NSSecureAdmins && nick_is_services_admin(na->nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ delnick(na);
+ }
+ na = makenick(nick);
+ if (na) {
+ na->status |= NS_VERBOTEN;
+ na->last_usermask = sstrdup(u->nick);
+ if (reason)
+ na->last_realname = sstrdup(reason);
+
+ na->u = finduser(na->nick);
+ if (na->u)
+ na->u->na = na;
+
+ if (na->u) {
+ notice_lang(s_NickServ, na->u, FORCENICKCHANGE_NOW);
+ collide(na, 0);
+ }
+
+
+ if (ircd->sqline) {
+ anope_cmd_sqline(na->nick, ((reason) ? reason : "Forbidden"));
+ }
+
+ if (WallForbid)
+ anope_cmd_global(s_NickServ, "\2%s\2 used FORBID on \2%s\2",
+ u->nick, nick);
+
+ 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, 1, nick);
+ } else {
+ alog("%s: Valid FORBID for %s by %s failed", s_NickServ, nick,
+ u->nick);
+ notice_lang(s_NickServ, u, NICK_FORBID_FAILED, nick);
+ }
+ return MOD_CONT;
+}
+
+NickAlias *makenick(const char *nick)
+{
+ NickAlias *na;
+ NickCore *nc;
+
+ /* First make the core */
+ nc = scalloc(1, sizeof(NickCore));
+ nc->display = sstrdup(nick);
+ slist_init(&nc->aliases);
+ insert_core(nc);
+ alog("%s: group %s has been created", s_NickServ, nc->display);
+
+ /* Then make the alias */
+ na = scalloc(1, sizeof(NickAlias));
+ na->nick = sstrdup(nick);
+ na->nc = nc;
+ slist_add(&nc->aliases, na);
+ alpha_insert_alias(na);
+ return na;
+}
diff --git a/src/core/ns_getemail.c b/src/core/ns_getemail.c
new file mode 100644
index 000000000..5dc8b08bc
--- /dev/null
+++ b/src/core/ns_getemail.c
@@ -0,0 +1,102 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ *
+ * A simple call to check for all emails that a user may have registered
+ * with. It returns the nicks that match the email you provide. Wild
+ * Cards are not excepted. Must use user@email-host.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_getemail(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GETEMAIL", do_getemail, is_services_admin, -1, -1,
+ -1, NICK_SERVADMIN_HELP_GETEMAIL,
+ NICK_SERVADMIN_HELP_GETEMAIL);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_GETEMAIL);
+ }
+}
+
+/**
+ * The /ns getemail command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_getemail(User * u)
+{
+ char *email = strtok(NULL, " ");
+ int i, j = 0;
+ NickCore *nc;
+
+ if (!email) {
+ syntax_error(s_NickServ, u, "GETMAIL", NICK_GETEMAIL_SYNTAX);
+ return MOD_CONT;
+ }
+ alog("%s: %s!%s@%s used GETEMAIL on %s", s_NickServ, u->nick,
+ u->username, u->host, email);
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ if (nc->email) {
+ if (stricmp(nc->email, email) == 0) {
+ j++;
+ notice_lang(s_NickServ, u, NICK_GETEMAIL_EMAILS_ARE,
+ nc->display, email);
+ }
+ }
+ }
+ }
+ if (j <= 0) {
+ notice_lang(s_NickServ, u, NICK_GETEMAIL_NOT_USED, email);
+ return MOD_CONT;
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_getpass.c b/src/core/ns_getpass.c
new file mode 100644
index 000000000..946102389
--- /dev/null
+++ b/src/core/ns_getpass.c
@@ -0,0 +1,112 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_getpass(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GETPASS", do_getpass, is_services_admin, -1, -1, -1,
+ NICK_SERVADMIN_HELP_GETPASS,
+ NICK_SERVADMIN_HELP_GETPASS);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_GETPASS);
+ }
+}
+
+/**
+ * The /ns getpass command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_getpass(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char tmp_pass[PASSMAX];
+ NickAlias *na;
+ NickRequest *nr = NULL;
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "GETPASS", NICK_GETPASS_SYNTAX);
+ } else if (!(na = findnick(nick))) {
+ if ((nr = findrequestnick(nick))) {
+ alog("%s: %s!%s@%s used GETPASS on %s", s_NickServ, u->nick,
+ u->username, u->host, nick);
+ if (WallGetpass)
+ anope_cmd_global(s_NickServ,
+ "\2%s\2 used GETPASS on \2%s\2", u->nick,
+ nick);
+ notice_lang(s_NickServ, u, NICK_GETPASS_PASSCODE_IS, nick,
+ nr->passcode);
+ } else {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ }
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (NSSecureAdmins && nick_is_services_admin(na->nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ } else if (NSRestrictGetPass && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ } else {
+ if(enc_decrypt(na->nc->pass,tmp_pass,PASSMAX - 1)==1) {
+ alog("%s: %s!%s@%s used GETPASS on %s", s_NickServ, u->nick,
+ u->username, u->host, nick);
+ if (WallGetpass)
+ anope_cmd_global(s_NickServ, "\2%s\2 used GETPASS on \2%s\2",
+ u->nick, nick);
+ notice_lang(s_NickServ, u, NICK_GETPASS_PASSWORD_IS, nick,
+ tmp_pass);
+ } else {
+ notice_lang(s_NickServ, u, NICK_GETPASS_UNAVAILABLE);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_ghost.c b/src/core/ns_ghost.c
new file mode 100644
index 000000000..07736bec7
--- /dev/null
+++ b/src/core/ns_ghost.c
@@ -0,0 +1,118 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_ghost(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GHOST", do_ghost, NULL, NICK_HELP_GHOST, -1, -1, -1,
+ -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_GHOST);
+}
+
+/**
+ * The /ns ghost command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_ghost(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ NickAlias *na;
+ User *u2;
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "GHOST", NICK_GHOST_SYNTAX);
+ } else if (!(u2 = finduser(nick))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (!(na = u2->na)) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (stricmp(nick, u->nick) == 0) {
+ notice_lang(s_NickServ, u, NICK_NO_GHOST_SELF);
+ } else if (pass) {
+ int res = enc_check_password(pass, na->nc->pass);
+ if (res == 1) {
+ char buf[NICKMAX + 32];
+ snprintf(buf, sizeof(buf), "GHOST command used by %s",
+ u->nick);
+
+ kill_user(s_NickServ, nick, buf);
+ notice_lang(s_NickServ, u, NICK_GHOST_KILLED, nick);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ if (res == 0) {
+ alog("%s: GHOST: invalid password for %s by %s!%s@%s",
+ s_NickServ, nick, u->nick, u->username, u->host);
+ bad_password(u);
+ }
+ }
+ } else {
+ if (group_identified(u, na->nc)
+ || (!(na->nc->flags & NI_SECURE) && is_on_access(u, na->nc))) {
+ char buf[NICKMAX + 32];
+ snprintf(buf, sizeof(buf), "GHOST command used by %s",
+ u->nick);
+
+ kill_user(s_NickServ, nick, buf);
+ notice_lang(s_NickServ, u, NICK_GHOST_KILLED, nick);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_group.c b/src/core/ns_group.c
new file mode 100644
index 000000000..926d062f0
--- /dev/null
+++ b/src/core/ns_group.c
@@ -0,0 +1,337 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_group(User * u);
+void myNickServHelp(User * u);
+int do_glist(User * u);
+int do_listlinks(User * u);
+
+NickAlias *makealias(const char *nick, NickCore * nc);
+
+/* Obsolete commands */
+int do_link(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GROUP", do_group, NULL, NICK_HELP_GROUP, -1, -1, -1,
+ -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ c = createCommand("LINK", do_link, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ c = createCommand("GLIST", do_glist, NULL, -1, NICK_HELP_GLIST, -1,
+ NICK_SERVADMIN_HELP_GLIST,
+ NICK_SERVADMIN_HELP_GLIST);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ c = createCommand("LISTLINKS", do_listlinks, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_GROUP);
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_GLIST);
+}
+
+/**
+ * The /ns group command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+/* Register a nick in a specified group. */
+
+int do_group(User * u)
+{
+ NickAlias *na, *target;
+ NickCore *nc;
+ char *nick = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ int i;
+ char tsbuf[16];
+ char modes[512];
+ int len;
+
+ if (NSEmailReg && (findrequestnick(u->nick))) {
+ notice_lang(s_NickServ, u, NICK_REQUESTED);
+ return MOD_CONT;
+ }
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, NICK_GROUP_DISABLED);
+ return MOD_CONT;
+ }
+ if (checkDefCon(DEFCON_NO_NEW_NICKS)) {
+ notice_lang(s_NickServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ }
+
+ if (RestrictOperNicks) {
+ for (i = 0; i < RootNumber; i++) {
+ if (stristr(u->nick, ServicesRoots[i]) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ for (i = 0; i < servadmins.count && (nc = servadmins.list[i]); i++) {
+ if (stristr(u->nick, nc->display) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ for (i = 0; i < servopers.count && (nc = servopers.list[i]); i++) {
+ if (stristr(u->nick, nc->display) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ }
+
+ if (!nick || !pass) {
+ syntax_error(s_NickServ, u, "GROUP", NICK_GROUP_SYNTAX);
+ } else if (!(target = findnick(nick))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (time(NULL) < u->lastnickreg + NSRegDelay) {
+ notice_lang(s_NickServ, u, NICK_GROUP_PLEASE_WAIT, NSRegDelay);
+ } else if (u->na && (u->na->status & NS_VERBOTEN)) {
+ alog("%s: %s@%s tried to use GROUP from FORBIDden nick %s",
+ s_NickServ, u->username, u->host, u->nick);
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, u->nick);
+ } else if (u->na && (u->na->nc->flags & NI_SUSPENDED)) {
+ alog("%s: %s!%s@%s tried to use GROUP from SUSPENDED nick %s",
+ s_NickServ, u->nick, u->username, u->host, target->nick);
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, u->nick);
+ } else if (u->na && NSNoGroupChange) {
+ notice_lang(s_NickServ, u, NICK_GROUP_CHANGE_DISABLED, s_NickServ);
+ } else if (u->na && !nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (target && (target->nc->flags & NI_SUSPENDED)) {
+ alog("%s: %s!%s@%s tried to use GROUP from SUSPENDED nick %s",
+ s_NickServ, u->nick, u->username, u->host, target->nick);
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, target->nick);
+ } else if (target->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, nick);
+ } else if (u->na && target->nc == u->na->nc) {
+ notice_lang(s_NickServ, u, NICK_GROUP_SAME, target->nick);
+ } else if (NSMaxAliases && (target->nc->aliases.count >= NSMaxAliases)
+ && !nick_is_services_admin(target->nc)) {
+ notice_lang(s_NickServ, u, NICK_GROUP_TOO_MANY, target->nick,
+ s_NickServ, s_NickServ);
+ } else if (enc_check_password(pass, target->nc->pass) != 1) {
+ alog("%s: Failed GROUP for %s!%s@%s (invalid password)",
+ s_NickServ, u->nick, u->username, u->host);
+ notice_lang(s_NickServ, u, PASSWORD_INCORRECT);
+ bad_password(u);
+ } else {
+ /* If the nick is already registered, drop it.
+ * If not, check that it is valid.
+ */
+ if (u->na) {
+ delnick(u->na);
+ } else {
+ int prefixlen = strlen(NSGuestNickPrefix);
+ int nicklen = strlen(u->nick);
+
+ if (nicklen <= prefixlen + 7 && nicklen >= prefixlen + 1
+ && stristr(u->nick, NSGuestNickPrefix) == u->nick
+ && strspn(u->nick + prefixlen,
+ "1234567890") == nicklen - prefixlen) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ na = makealias(u->nick, target->nc);
+
+ if (na) {
+ na->last_usermask =
+ scalloc(strlen(common_get_vident(u)) +
+ strlen(common_get_vhost(u)) + 2, 1);
+ sprintf(na->last_usermask, "%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+ na->last_realname = sstrdup(u->realname);
+ na->time_registered = na->last_seen = time(NULL);
+ na->status = (int16) (NS_IDENTIFIED | NS_RECOGNIZED);
+
+ if (!(na->nc->flags & NI_SERVICES_ROOT)) {
+ for (i = 0; i < RootNumber; i++) {
+ if (!stricmp(ServicesRoots[i], u->nick)) {
+ na->nc->flags |= NI_SERVICES_ROOT;
+ break;
+ }
+ }
+ }
+
+ u->na = na;
+ na->u = u;
+
+#ifdef USE_RDB
+ /* Is this really needed? Since this is a new alias it will get
+ * its unique id on the next update, since it was previously
+ * deleted by delnick. Must observe...
+ */
+ if (rdb_open()) {
+ rdb_save_ns_alias(na);
+ rdb_close();
+ }
+#endif
+ send_event(EVENT_GROUP, 1, u->nick);
+ alog("%s: %s!%s@%s makes %s join group of %s (%s) (e-mail: %s)", s_NickServ, u->nick, u->username, u->host, u->nick, target->nick, target->nc->display, (target->nc->email ? target->nc->email : "none"));
+ notice_lang(s_NickServ, u, NICK_GROUP_JOINED, target->nick);
+
+ u->lastnickreg = time(NULL);
+ snprintf(tsbuf, sizeof(tsbuf), "%lu",
+ (unsigned long int) u->timestamp);
+ if (ircd->modeonreg) {
+ len = strlen(ircd->modeonreg);
+ strncpy(modes,ircd->modeonreg,512);
+ if(ircd->rootmodeonid && is_services_root(u)) {
+ strncat(modes,ircd->rootmodeonid,512-len);
+ } else if(ircd->adminmodeonid && is_services_admin(u)) {
+ strncat(modes,ircd->adminmodeonid,512-len);
+ } else if(ircd->opermodeonid && is_services_oper(u)) {
+ strncat(modes,ircd->opermodeonid,512-len);
+ }
+ if (ircd->tsonmode) {
+ common_svsmode(u, modes, tsbuf);
+ } else {
+ common_svsmode(u, modes, NULL);
+ }
+ }
+
+ check_memos(u);
+ } else {
+ alog("%s: makealias(%s) failed", s_NickServ, u->nick);
+ notice_lang(s_NickServ, u, NICK_GROUP_FAILED);
+ }
+ }
+ return MOD_CONT;
+}
+
+
+/* Creates a new alias in NickServ database. */
+
+NickAlias *makealias(const char *nick, NickCore * nc)
+{
+ NickAlias *na;
+
+ /* Just need to make the alias */
+ na = scalloc(1, sizeof(NickAlias));
+ na->nick = sstrdup(nick);
+ na->nc = nc;
+ slist_add(&nc->aliases, na);
+ alpha_insert_alias(na);
+ return na;
+}
+
+
+int do_link(User * u)
+{
+ notice_lang(s_NickServ, u, OBSOLETE_COMMAND, "GROUP");
+ return MOD_CONT;
+}
+
+int do_glist(User * u)
+{
+ char *nick = strtok(NULL, " ");
+
+ NickAlias *na, *na2;
+ int is_servadmin = is_services_admin(u);
+ int nick_ided = nick_identified(u);
+ int i;
+
+ if ((nick ? (stricmp(nick, u->nick) ? !is_servadmin : !nick_ided)
+ : !nick_ided)) {
+ notice_lang(s_NickServ, u,
+ (nick_ided ? ACCESS_DENIED :
+ NICK_IDENTIFY_REQUIRED), s_NickServ);
+ } else if ((!nick ? !(na = u->na) : !(na = findnick(nick)))) {
+ notice_lang(s_NickServ, u,
+ (!nick ? NICK_NOT_REGISTERED : NICK_X_NOT_REGISTERED),
+ nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else {
+ time_t expt;
+ struct tm *tm;
+ char buf[BUFSIZE];
+ int wont_expire;
+
+ notice_lang(s_NickServ, u,
+ nick ? NICK_GLIST_HEADER_X : NICK_GLIST_HEADER,
+ na->nc->display);
+ for (i = 0; i < na->nc->aliases.count; i++) {
+ na2 = na->nc->aliases.list[i];
+ if (na2->nc == na->nc) {
+ if (!(wont_expire = na2->status & NS_NO_EXPIRE)) {
+ expt = na2->last_seen + NSExpire;
+ tm = localtime(&expt);
+ strftime_lang(buf, sizeof(buf), na2->u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ }
+ notice_lang(s_NickServ, u,
+ ((is_services_admin(u) && !wont_expire)
+ ? NICK_GLIST_REPLY_ADMIN : NICK_GLIST_REPLY),
+ (wont_expire ? '!' : ' '), na2->nick, buf);
+ }
+ }
+ notice_lang(s_NickServ, u, NICK_GLIST_FOOTER,
+ na->nc->aliases.count);
+ }
+ return MOD_CONT;
+}
+
+
+int do_listlinks(User * u)
+{
+ notice_lang(s_NickServ, u, OBSOLETE_COMMAND, "GLIST");
+ return MOD_CONT;
+}
diff --git a/src/core/ns_help.c b/src/core/ns_help.c
new file mode 100644
index 000000000..e65d9dbf5
--- /dev/null
+++ b/src/core/ns_help.c
@@ -0,0 +1,79 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * The /ns help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_NickServ, u, NICK_HELP);
+ moduleDisplayHelp(1, u);
+ if (is_services_admin(u)) {
+ notice_help(s_NickServ, u, NICK_SERVADMIN_HELP);
+ }
+ if (NSExpire >= 86400)
+ notice_help(s_NickServ, u, NICK_HELP_EXPIRES,
+ NSExpire / 86400);
+ notice_help(s_NickServ, u, NICK_HELP_FOOTER);
+ } else if (stricmp(cmd, "SET LANGUAGE") == 0) {
+ int i;
+ notice_help(s_NickServ, u, NICK_HELP_SET_LANGUAGE);
+ for (i = 0; i < NUM_LANGS && langlist[i] >= 0; i++)
+ notice_user(s_NickServ, u, " %2d) %s", i + 1,
+ langnames[langlist[i]]);
+ } else {
+ mod_help_cmd(s_NickServ, u, NICKSERV, cmd);
+ }
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/ns_identify.c b/src/core/ns_identify.c
new file mode 100644
index 000000000..cbeb7705e
--- /dev/null
+++ b/src/core/ns_identify.c
@@ -0,0 +1,171 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define TO_COLLIDE 0 /* Collide the user with this nick */
+#define TO_RELEASE 1 /* Release a collided nick */
+
+int do_identify(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ID", do_identify, NULL, NICK_HELP_IDENTIFY, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("IDENTIFY", do_identify, NULL, NICK_HELP_IDENTIFY,
+ -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SIDENTIFY", do_identify, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_IDENTIFY);
+}
+
+/**
+ * The /ns identify command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_identify(User * u)
+{
+ char *pass = strtok(NULL, " ");
+ NickAlias *na;
+ NickRequest *nr;
+ int res;
+ char tsbuf[16];
+ char modes[512];
+ int len;
+
+ if (!pass) {
+ syntax_error(s_NickServ, u, "IDENTIFY", NICK_IDENTIFY_SYNTAX);
+ } else if (!(na = u->na)) {
+ if ((nr = findrequestnick(u->nick))) {
+ notice_lang(s_NickServ, u, NICK_IS_PREREG);
+ } else {
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
+ }
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_ALREADY_IDENTIFIED);
+ } else if (!(res = enc_check_password(pass, na->nc->pass))) {
+ alog("%s: Failed IDENTIFY for %s!%s@%s", s_NickServ, u->nick,
+ u->username, u->host);
+ notice_lang(s_NickServ, u, PASSWORD_INCORRECT);
+ bad_password(u);
+ } else if (res == -1) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_FAILED);
+ } else {
+ if (!(na->status & NS_IDENTIFIED) && !(na->status & NS_RECOGNIZED)) {
+ if (na->last_usermask)
+ free(na->last_usermask);
+ na->last_usermask =
+ scalloc(strlen(common_get_vident(u)) +
+ strlen(common_get_vhost(u)) + 2, 1);
+ sprintf(na->last_usermask, "%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+ if (na->last_realname)
+ free(na->last_realname);
+ na->last_realname = sstrdup(u->realname);
+ }
+
+ na->status |= NS_IDENTIFIED;
+ na->last_seen = time(NULL);
+ snprintf(tsbuf, sizeof(tsbuf), "%lu",
+ (unsigned long int) u->timestamp);
+
+ if (ircd->modeonreg) {
+ len = strlen(ircd->modeonreg);
+ strncpy(modes,ircd->modeonreg,512);
+ if(ircd->rootmodeonid && is_services_root(u)) {
+ strncat(modes,ircd->rootmodeonid,512-len);
+ } else if(ircd->adminmodeonid && is_services_admin(u)) {
+ strncat(modes,ircd->adminmodeonid,512-len);
+ } else if(ircd->opermodeonid && is_services_oper(u)) {
+ strncat(modes,ircd->opermodeonid,512-len);
+ }
+ if (ircd->tsonmode) {
+ common_svsmode(u, modes, tsbuf);
+ } else {
+ common_svsmode(u, modes, "");
+ }
+ }
+ send_event(EVENT_NICK_IDENTIFY, 1, u->nick);
+ alog("%s: %s!%s@%s identified for nick %s", s_NickServ, u->nick,
+ u->username, u->host, u->nick);
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_SUCCEEDED);
+ if (ircd->vhost) {
+ do_on_id(u);
+ }
+ if (NSModeOnID) {
+ do_setmodes(u);
+ }
+
+ if (NSForceEmail && u->na && !u->na->nc->email) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_EMAIL_REQUIRED);
+ notice_help(s_NickServ, u, NICK_IDENTIFY_EMAIL_HOWTO);
+ }
+
+ if (!(na->status & NS_RECOGNIZED))
+ check_memos(u);
+
+ /* Enable nick tracking if enabled */
+ if (NSNickTracking)
+ nsStartNickTracking(u);
+
+ /* Clear any timers */
+ if (na->nc->flags & NI_KILLPROTECT) {
+ del_ns_timeout(na, TO_COLLIDE);
+ }
+
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_info.c b/src/core/ns_info.c
new file mode 100644
index 000000000..ecc2b3bb8
--- /dev/null
+++ b/src/core/ns_info.c
@@ -0,0 +1,284 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+static int do_info(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("INFO", do_info, NULL, NICK_HELP_INFO, -1,
+ NICK_HELP_INFO, NICK_SERVADMIN_HELP_INFO,
+ NICK_SERVADMIN_HELP_INFO);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_INFO);
+}
+
+/**
+ * The /ns info command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_info(User * u)
+{
+
+/* Show hidden info to nick owners and sadmins when the "ALL" parameter is
+ * supplied. If a nick is online, the "Last seen address" changes to "Is
+ * online from".
+ * Syntax: INFO <nick> {ALL}
+ * -TheShadow (13 Mar 1999)
+ */
+
+ char *nick = strtok(NULL, " ");
+ char *param = strtok(NULL, " ");
+
+ NickAlias *na;
+ NickRequest *nr = NULL;
+ /* Being an oper is enough from now on -GD */
+ int is_servadmin = is_services_oper(u);
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "INFO", NICK_INFO_SYNTAX);
+ } else if (!(na = findnick(nick))) {
+ if ((nr = findrequestnick(nick))) {
+ notice_lang(s_NickServ, u, NICK_IS_PREREG);
+ if (param && stricmp(param, "ALL") == 0 && is_servadmin) {
+ notice_lang(s_NickServ, u, NICK_INFO_EMAIL, nr->email);
+ } else {
+ if (is_servadmin) {
+ notice_lang(s_NickServ, u, NICK_INFO_FOR_MORE,
+ s_NickServ, nr->nick);
+ }
+ }
+ } else if (nickIsServices(nick, 1)) {
+ notice_lang(s_NickServ, u, NICK_X_IS_SERVICES, nick);
+ } else {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ }
+ } else if (na->status & NS_VERBOTEN) {
+ if (is_oper(u) && na->last_usermask)
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN_OPER, nick,
+ na->last_usermask,
+ (na->last_realname ? na->
+ last_realname : getstring(u->na, NO_REASON)));
+ else
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, nick);
+ } else {
+ struct tm *tm;
+ char buf[BUFSIZE], *end;
+ const char *commastr = getstring(u->na, COMMA_SPACE);
+ int need_comma = 0;
+ int nick_online = 0;
+ int show_hidden = 0;
+ time_t expt;
+
+ /* Is the real owner of the nick we're looking up online? -TheShadow */
+ if (na->status & (NS_RECOGNIZED | NS_IDENTIFIED))
+ nick_online = 1;
+
+ /* Only show hidden fields to owner and sadmins and only when the ALL
+ * parameter is used. -TheShadow */
+ if (param && stricmp(param, "ALL") == 0 && u->na
+ && ((nick_identified(u) && (na->nc == u->na->nc))
+ || is_servadmin))
+ show_hidden = 1;
+
+ notice_lang(s_NickServ, u, NICK_INFO_REALNAME, na->nick,
+ na->last_realname);
+
+ if ((nick_identified(u) && (na->nc == u->na->nc)) || is_servadmin) {
+
+ if (nick_is_services_root(na->nc))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_ROOT,
+ na->nick);
+ else if (nick_is_services_admin(na->nc))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_ADMIN,
+ na->nick);
+ else if (nick_is_services_oper(na->nc))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_OPER,
+ na->nick);
+
+ } else {
+
+ if (nick_is_services_root(na->nc)
+ && !(na->nc->flags & NI_HIDE_STATUS))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_ROOT,
+ na->nick);
+ else if (nick_is_services_admin(na->nc)
+ && !(na->nc->flags & NI_HIDE_STATUS))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_ADMIN,
+ na->nick);
+ else if (nick_is_services_oper(na->nc)
+ && !(na->nc->flags & NI_HIDE_STATUS))
+ notice_lang(s_NickServ, u, NICK_INFO_SERVICES_OPER,
+ na->nick);
+
+ }
+
+ if (nick_online) {
+ if (show_hidden || !(na->nc->flags & NI_HIDE_MASK))
+ notice_lang(s_NickServ, u, NICK_INFO_ADDRESS_ONLINE,
+ na->last_usermask);
+ else
+ notice_lang(s_NickServ, u, NICK_INFO_ADDRESS_ONLINE_NOHOST,
+ na->nick);
+ } else {
+ if (show_hidden || !(na->nc->flags & NI_HIDE_MASK))
+ notice_lang(s_NickServ, u, NICK_INFO_ADDRESS,
+ na->last_usermask);
+ }
+
+ tm = localtime(&na->time_registered);
+ strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_NickServ, u, NICK_INFO_TIME_REGGED, buf);
+
+ if (!nick_online) {
+ tm = localtime(&na->last_seen);
+ strftime_lang(buf, sizeof(buf), u, STRFTIME_DATE_TIME_FORMAT,
+ tm);
+ notice_lang(s_NickServ, u, NICK_INFO_LAST_SEEN, buf);
+ }
+
+ if (na->last_quit
+ && (show_hidden || !(na->nc->flags & NI_HIDE_QUIT)))
+ notice_lang(s_NickServ, u, NICK_INFO_LAST_QUIT, na->last_quit);
+
+ if (na->nc->url)
+ notice_lang(s_NickServ, u, NICK_INFO_URL, na->nc->url);
+ if (na->nc->email
+ && (show_hidden || !(na->nc->flags & NI_HIDE_EMAIL)))
+ notice_lang(s_NickServ, u, NICK_INFO_EMAIL, na->nc->email);
+ if (na->nc->icq)
+ notice_lang(s_NickServ, u, NICK_INFO_ICQ, na->nc->icq);
+
+ if (show_hidden) {
+ if (s_HostServ && ircd->vhost) {
+ if (getvHost(na->nick) != NULL) {
+ if (ircd->vident && getvIdent(na->nick) != NULL) {
+ notice_lang(s_NickServ, u, NICK_INFO_VHOST2,
+ getvIdent(na->nick),
+ getvHost(na->nick));
+ } else {
+ notice_lang(s_NickServ, u, NICK_INFO_VHOST,
+ getvHost(na->nick));
+ }
+ }
+ }
+ if (na->nc->greet)
+ notice_lang(s_NickServ, u, NICK_INFO_GREET, na->nc->greet);
+
+ *buf = 0;
+ end = buf;
+
+ if (na->nc->flags & NI_KILLPROTECT) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s",
+ getstring(u->na, NICK_INFO_OPT_KILL));
+ need_comma = 1;
+ }
+ if (na->nc->flags & NI_SECURE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, NICK_INFO_OPT_SECURE));
+ need_comma = 1;
+ }
+ if (na->nc->flags & NI_PRIVATE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, NICK_INFO_OPT_PRIVATE));
+ need_comma = 1;
+ }
+ if (na->nc->flags & NI_MSG) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, NICK_INFO_OPT_MSG));
+ need_comma = 1;
+ }
+ if (!(na->nc->flags & NI_AUTOOP)) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%s%s",
+ need_comma ? commastr : "",
+ getstring(u->na, NICK_INFO_OPT_AUTOOP));
+ need_comma = 1;
+ }
+
+ notice_lang(s_NickServ, u, NICK_INFO_OPTIONS,
+ *buf ? buf : getstring(u->na, NICK_INFO_OPT_NONE));
+
+ if (na->nc->flags & NI_SUSPENDED) {
+ if (na->last_quit) {
+ notice_lang(s_NickServ, u, NICK_INFO_SUSPENDED,
+ na->last_quit);
+ } else {
+ notice_lang(s_NickServ, u,
+ NICK_INFO_SUSPENDED_NO_REASON);
+ }
+ }
+
+ if (na->status & NS_NO_EXPIRE) {
+ notice_lang(s_NickServ, u, NICK_INFO_NO_EXPIRE);
+ } else {
+ if (is_services_admin(u)) {
+ expt = na->last_seen + NSExpire;
+ tm = localtime(&expt);
+ strftime_lang(buf, sizeof(buf), na->u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_NickServ, u, NICK_INFO_EXPIRE, buf);
+ }
+ }
+ }
+
+ if (!show_hidden
+ && ((u->na && (na->nc == u->na->nc) && nick_identified(u))
+ || is_servadmin))
+ notice_lang(s_NickServ, u, NICK_INFO_FOR_MORE, s_NickServ,
+ na->nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_list.c b/src/core/ns_list.c
new file mode 100644
index 000000000..6c6639f66
--- /dev/null
+++ b/src/core/ns_list.c
@@ -0,0 +1,247 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_list(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("LIST", do_list, NULL, -1, NICK_HELP_LIST, -1,
+ NICK_SERVADMIN_HELP_LIST, NICK_SERVADMIN_HELP_LIST);
+
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (!NSListOpersOnly || (is_oper(u))) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_LIST);
+ }
+}
+
+/**
+ * The /ns list command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_list(User * u)
+{
+
+/* SADMINS can search for nicks based on their NS_VERBOTEN and NS_NO_EXPIRE
+ * status. The keywords FORBIDDEN and NOEXPIRE represent these two states
+ * respectively. These keywords should be included after the search pattern.
+ * Multiple keywords are accepted and should be separated by spaces. Only one
+ * of the keywords needs to match a nick's state for the nick to be displayed.
+ * Forbidden nicks can be identified by "[Forbidden]" appearing in the last
+ * seen address field. Nicks with NOEXPIRE set are preceeded by a "!". Only
+ * SADMINS will be shown forbidden nicks and the "!" indicator.
+ * Syntax for sadmins: LIST pattern [FORBIDDEN] [NOEXPIRE]
+ * -TheShadow
+ *
+ * UPDATE: SUSPENDED keyword is now accepted as well.
+ */
+
+
+ char *pattern = strtok(NULL, " ");
+ char *keyword;
+ NickAlias *na;
+ NickCore *mync;
+ int nnicks, i;
+ char buf[BUFSIZE];
+ int is_servadmin = is_services_admin(u);
+ int16 matchflags = 0;
+ NickRequest *nr = NULL;
+ int nronly = 0;
+ int susp_keyword = 0;
+ char noexpire_char = ' ';
+ int count = 0, from = 0, to = 0, tofree = 0;
+ char *tmp = NULL;
+ char *s = NULL;
+
+ if (!(!NSListOpersOnly || (is_oper(u)))) { /* reverse the help logic */
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ return MOD_STOP;
+ }
+
+ if (!pattern) {
+ syntax_error(s_NickServ, u, "LIST",
+ is_servadmin ? NICK_LIST_SERVADMIN_SYNTAX :
+ NICK_LIST_SYNTAX);
+ } else {
+
+ if (pattern) {
+ if (pattern[0] == '#') {
+ tmp = myStrGetOnlyToken((pattern + 1), '-', 0); /* Read FROM out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ from = atoi(tmp);
+ free(tmp);
+ tmp = myStrGetTokenRemainder(pattern, '-', 1); /* Read TO out */
+ if (!tmp) {
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ for (s = tmp; *s; s++) {
+ if (!isdigit(*s)) {
+ free(tmp);
+ notice_lang(s_ChanServ, u, LIST_INCORRECT_RANGE);
+ return MOD_CONT;
+ }
+ }
+ to = atoi(tmp);
+ free(tmp);
+ pattern = sstrdup("*");
+ tofree = 1;
+ }
+ }
+
+ nnicks = 0;
+
+ while (is_servadmin && (keyword = strtok(NULL, " "))) {
+ if (stricmp(keyword, "FORBIDDEN") == 0)
+ matchflags |= NS_VERBOTEN;
+ if (stricmp(keyword, "NOEXPIRE") == 0)
+ matchflags |= NS_NO_EXPIRE;
+ if (stricmp(keyword, "SUSPENDED") == 0)
+ susp_keyword = 1;
+ if (stricmp(keyword, "UNCONFIRMED") == 0)
+ nronly = 1;
+ }
+
+ mync = (nick_identified(u) ? u->na->nc : NULL);
+
+ notice_lang(s_NickServ, u, NICK_LIST_HEADER, pattern);
+ if (nronly != 1) {
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ /* Don't show private and forbidden nicks to non-services admins. */
+ if ((na->status & NS_VERBOTEN) && !is_servadmin)
+ continue;
+ if ((na->nc->flags & NI_PRIVATE) && !is_servadmin
+ && na->nc != mync)
+ continue;
+ if ((matchflags != 0) && !(na->status & matchflags) && (susp_keyword == 0))
+ continue;
+ else if ((susp_keyword == 1) && !(na->nc->flags & NI_SUSPENDED))
+ continue;
+
+ /* We no longer compare the pattern against the output buffer.
+ * Instead we build a nice nick!user@host buffer to compare.
+ * The output is then generated separately. -TheShadow */
+ snprintf(buf, sizeof(buf), "%s!%s", na->nick,
+ (na->last_usermask
+ && !(na->status & NS_VERBOTEN)) ? na->
+ last_usermask : "*@*");
+ if (stricmp(pattern, na->nick) == 0
+ || match_wild_nocase(pattern, buf)) {
+
+ if ((((count + 1 >= from) && (count + 1 <= to))
+ || ((from == 0) && (to == 0)))
+ && (++nnicks <= NSListMax)) {
+ if (is_servadmin
+ && (na->status & NS_NO_EXPIRE))
+ noexpire_char = '!';
+ else {
+ noexpire_char = ' ';
+ }
+ if ((na->nc->flags & NI_HIDE_MASK)
+ && !is_servadmin && na->nc != mync) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [Hostname Hidden]",
+ na->nick);
+ } else if (na->status & NS_VERBOTEN) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [Forbidden]", na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [Suspended]", na->nick);
+ } else {
+ snprintf(buf, sizeof(buf), "%-20s %s",
+ na->nick, na->last_usermask);
+ }
+ notice_user(s_NickServ, u, " %c%s",
+ noexpire_char, buf);
+ }
+ count++;
+ }
+ }
+ }
+ }
+
+ if (nronly == 1 || (is_servadmin && matchflags == 0)) {
+ noexpire_char = ' ';
+ for (i = 0; i < 1024; i++) {
+ for (nr = nrlists[i]; nr; nr = nr->next) {
+ snprintf(buf, sizeof(buf), "%s!*@*", nr->nick);
+ if (stricmp(pattern, nr->nick) == 0
+ || match_wild_nocase(pattern, buf)) {
+ if (++nnicks <= NSListMax) {
+ snprintf(buf, sizeof(buf),
+ "%-20s [UNCONFIRMED]", nr->nick);
+ notice_user(s_NickServ, u, " %c%s",
+ noexpire_char, buf);
+ }
+ }
+ }
+ }
+ }
+ notice_lang(s_NickServ, u, NICK_LIST_RESULTS,
+ nnicks > NSListMax ? NSListMax : nnicks, nnicks);
+ }
+ if (tofree)
+ free(pattern);
+ return MOD_CONT;
+}
diff --git a/src/core/ns_logout.c b/src/core/ns_logout.c
new file mode 100644
index 000000000..d2691132a
--- /dev/null
+++ b/src/core/ns_logout.c
@@ -0,0 +1,128 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define TO_COLLIDE 0 /* Collide the user with this nick */
+#define TO_RELEASE 1 /* Release a collided nick */
+
+int do_logout(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("LOGOUT", do_logout, NULL, -1, NICK_HELP_LOGOUT, -1,
+ NICK_SERVADMIN_HELP_LOGOUT,
+ NICK_SERVADMIN_HELP_LOGOUT);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_LOGOUT);
+}
+
+/**
+ * The /ns logout command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_logout(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *param = strtok(NULL, " ");
+ User *u2;
+
+ if (!is_services_admin(u) && nick) {
+ syntax_error(s_NickServ, u, "LOGOUT", NICK_LOGOUT_SYNTAX);
+ } else if (!(u2 = (nick ? finduser(nick) : u))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (!u2->na) {
+ if (nick)
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ else
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
+ } else if (u2->na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, u2->na->nick);
+ } else if (!nick && !nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (nick && is_services_admin(u2)) {
+ notice_lang(s_NickServ, u, NICK_LOGOUT_SERVICESADMIN, nick);
+ } else {
+ if (nick && param && !stricmp(param, "REVALIDATE")) {
+ cancel_user(u2);
+ validate_user(u2);
+ } else {
+ u2->na->status &= ~(NS_IDENTIFIED | NS_RECOGNIZED);
+ }
+
+ if (ircd->modeonreg) {
+ common_svsmode(u2, ircd->modeonunreg, "1");
+ }
+
+ u->isSuperAdmin = 0; /* Dont let people logout and remain a SuperAdmin */
+ alog("%s: %s!%s@%s logged out nickname %s", s_NickServ, u->nick,
+ u->username, u->host, u2->nick);
+
+ if (nick)
+ notice_lang(s_NickServ, u, NICK_LOGOUT_X_SUCCEEDED, nick);
+ else
+ notice_lang(s_NickServ, u, NICK_LOGOUT_SUCCEEDED);
+
+ /* Stop nick tracking if enabled */
+ if (NSNickTracking)
+ /* Shouldn't this be u2? -GD */
+ nsStopNickTracking(u);
+
+ /* Clear any timers again */
+ if (u->na->nc->flags & NI_KILLPROTECT) {
+ del_ns_timeout(u->na, TO_COLLIDE);
+ }
+
+ /* Send out an event */
+ send_event(EVENT_NICK_LOGOUT, 1, u2->nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_recover.c b/src/core/ns_recover.c
new file mode 100644
index 000000000..71aa2b893
--- /dev/null
+++ b/src/core/ns_recover.c
@@ -0,0 +1,137 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+Command *c;
+
+int do_recover(User * u);
+void myNickServHelp(User * u);
+int myHelpResonse(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("RECOVER", do_recover, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ moduleAddHelp(c, myHelpResonse);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_RECOVER);
+}
+
+/**
+ * Show the extended help on the RECOVER command.
+ * @param u The user who is requesting help
+ **/
+int myHelpResonse(User * u)
+{
+ char relstr[192];
+
+ /* Convert NSReleaseTimeout seconds to string format */
+ duration(u->na, relstr, sizeof(relstr), NSReleaseTimeout);
+
+ notice_help(s_NickServ, u, NICK_HELP_RECOVER, relstr);
+ do_help_limited(s_NickServ, u, c);
+
+ return MOD_CONT;
+}
+
+/**
+ * The /ns recover command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_recover(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ NickAlias *na;
+ User *u2;
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "RECOVER", NICK_RECOVER_SYNTAX);
+ } else if (!(u2 = finduser(nick))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (!(na = u2->na)) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (stricmp(nick, u->nick) == 0) {
+ notice_lang(s_NickServ, u, NICK_NO_RECOVER_SELF);
+ } else if (pass) {
+ int res = enc_check_password(pass, na->nc->pass);
+
+ if (res == 1) {
+ char relstr[192];
+
+ notice_lang(s_NickServ, u2, FORCENICKCHANGE_NOW);
+ collide(na, 0);
+
+ /* Convert NSReleaseTimeout seconds to string format */
+ duration(u2->na, relstr, sizeof(relstr), NSReleaseTimeout);
+
+ notice_lang(s_NickServ, u, NICK_RECOVERED, s_NickServ, nick, relstr);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ if (res == 0) {
+ alog("%s: RECOVER: invalid password for %s by %s!%s@%s",
+ s_NickServ, nick, u->nick, u->username, u->host);
+ bad_password(u);
+ }
+ }
+ } else {
+ if (group_identified(u, na->nc)
+ || (!(na->nc->flags & NI_SECURE) && is_on_access(u, na->nc))) {
+ notice_lang(s_NickServ, u2, FORCENICKCHANGE_NOW);
+ collide(na, 0);
+ notice_lang(s_NickServ, u, NICK_RECOVERED, s_NickServ, nick);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ }
+ }
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/ns_register.c b/src/core/ns_register.c
new file mode 100644
index 000000000..6e33e8e08
--- /dev/null
+++ b/src/core/ns_register.c
@@ -0,0 +1,490 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+#include "encrypt.h"
+
+int do_confirm(User * u);
+int do_register(User * u);
+int do_resend(User * u);
+void myNickServHelp(User * u);
+NickRequest *makerequest(const char *nick);
+NickAlias *makenick(const char *nick);
+int do_sendregmail(User * u, NickRequest * nr);
+int ns_do_register(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("REGISTER", do_register, NULL, NICK_HELP_REGISTER,
+ -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ c = createCommand("CONFIRM", do_confirm, NULL, NICK_HELP_CONFIRM, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ c = createCommand("RESEND", do_resend, NULL, NICK_HELP_RESEND, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_REGISTER);
+ if (NSEmailReg) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_CONFIRM);
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_RESEND);
+ }
+}
+
+/**
+ * The /ns register command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_register(User * u)
+{
+ NickRequest *nr = NULL, *anr = NULL;
+ NickCore *nc = NULL;
+ int prefixlen = strlen(NSGuestNickPrefix);
+ int nicklen = strlen(u->nick);
+ char *pass = strtok(NULL, " ");
+ char *email = strtok(NULL, " ");
+ char passcode[11];
+ int idx, min = 1, max = 62, i = 0;
+ int chars[] =
+ { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
+ 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
+ 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+ };
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, NICK_REGISTRATION_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (checkDefCon(DEFCON_NO_NEW_NICKS)) {
+ notice_lang(s_NickServ, u, OPER_DEFCON_DENIED);
+ return MOD_CONT;
+ }
+
+ if (!is_oper(u) && NickRegDelay
+ && ((time(NULL) - u->my_signon) < NickRegDelay)) {
+ notice_lang(s_NickServ, u, NICK_REG_DELAY, NickRegDelay);
+ return MOD_CONT;
+ }
+
+ if ((anr = findrequestnick(u->nick))) {
+ notice_lang(s_NickServ, u, NICK_REQUESTED);
+ return MOD_CONT;
+ }
+ /* Prevent "Guest" nicks from being registered. -TheShadow */
+
+ /* Guest nick can now have a series of between 1 and 7 digits.
+ * --lara
+ */
+ if (nicklen <= prefixlen + 7 && nicklen >= prefixlen + 1 &&
+ stristr(u->nick, NSGuestNickPrefix) == u->nick &&
+ strspn(u->nick + prefixlen, "1234567890") == nicklen - prefixlen) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
+ return MOD_CONT;
+ }
+
+ if (!anope_valid_nick(u->nick)) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, u->nick);
+ return MOD_CONT;
+ }
+
+ if (RestrictOperNicks) {
+ for (i = 0; i < RootNumber; i++) {
+ if (stristr(u->nick, ServicesRoots[i]) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ for (i = 0; i < servadmins.count && (nc = servadmins.list[i]); i++) {
+ if (stristr(u->nick, nc->display) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ for (i = 0; i < servopers.count && (nc = servopers.list[i]); i++) {
+ if (stristr(u->nick, nc->display) && !is_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED,
+ u->nick);
+ return MOD_CONT;
+ }
+ }
+ }
+
+ if (!pass) {
+ if (NSForceEmail) {
+ syntax_error(s_NickServ, u, "REGISTER",
+ NICK_REGISTER_SYNTAX_EMAIL);
+ } else {
+ syntax_error(s_NickServ, u, "REGISTER", NICK_REGISTER_SYNTAX);
+ }
+ } else if (NSForceEmail && !email) {
+ syntax_error(s_NickServ, u, "REGISTER",
+ NICK_REGISTER_SYNTAX_EMAIL);
+ } else if (time(NULL) < u->lastnickreg + NSRegDelay) {
+ notice_lang(s_NickServ, u, NICK_REG_PLEASE_WAIT, NSRegDelay);
+ } else if (u->na) { /* i.e. there's already such a nick regged */
+ if (u->na->status & NS_VERBOTEN) {
+ alog("%s: %s@%s tried to register FORBIDden nick %s",
+ s_NickServ, u->username, u->host, u->nick);
+ notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick);
+ } else {
+ notice_lang(s_NickServ, u, NICK_ALREADY_REGISTERED, u->nick);
+ }
+ } else if (stricmp(u->nick, pass) == 0
+ || (StrictPasswords && strlen(pass) < 5)) {
+ notice_lang(s_NickServ, u, MORE_OBSCURE_PASSWORD);
+ } else if (enc_encrypt_check_len(strlen(pass), PASSMAX - 1)) {
+ notice_lang(s_NickServ, u, PASSWORD_TOO_LONG);
+ } else if (email && !MailValidate(email)) {
+ notice_lang(s_NickServ, u, MAIL_X_INVALID, email);
+ } else {
+ for (idx = 0; idx < 9; idx++) {
+ passcode[idx] =
+ chars[(1 +
+ (int) (((float) (max - min)) * getrandom16() /
+ (65535 + 1.0)) + min)];
+ } passcode[idx] = '\0';
+ nr = makerequest(u->nick);
+ nr->passcode = sstrdup(passcode);
+ strscpy(nr->password, pass, PASSMAX);
+ memset(pass, 0, strlen(pass));
+ /* We are paranoid about keeping a plain text pass in memory, yet we would write
+ * it to a database.. - Viper */
+ enc_encrypt_in_place(nr->password, PASSMAX);
+ if (email) {
+ nr->email = sstrdup(email);
+ }
+ nr->requested = time(NULL);
+ if (NSEmailReg) {
+ if (do_sendregmail(u, nr) == 0) {
+ notice_lang(s_NickServ, u, NICK_ENTER_REG_CODE, email,
+ s_NickServ);
+ alog("%s: sent registration verification code to %s",
+ s_NickServ, nr->email);
+ } else {
+ alog("%s: Unable to send registration verification mail",
+ s_NickServ);
+ notice_lang(s_NickServ, u, NICK_REG_UNABLE);
+ delnickrequest(nr); /* Delete the NickRequest if we couldnt send the mail */
+ return MOD_CONT;
+ }
+ } else {
+ do_confirm(u);
+ }
+
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int ns_do_register(User * u)
+{
+ return do_register(u);
+}
+
+
+int do_confirm(User * u)
+{
+
+ NickRequest *nr = NULL;
+ NickAlias *na = NULL;
+ char *passcode = strtok(NULL, " ");
+ char *email = NULL;
+ int forced = 0;
+ User *utmp = NULL;
+ char modes[512];
+ int len;
+
+ nr = findrequestnick(u->nick);
+
+ if (NSEmailReg) {
+ if (!passcode) {
+ notice_lang(s_NickServ, u, NICK_CONFIRM_INVALID);
+ return MOD_CONT;
+ }
+
+ if (!nr) {
+ if (is_services_admin(u)) {
+/* If an admin, their nick is obviously already regged, so look at the passcode to get the nick
+ of the user they are trying to validate, and push that user through regardless of passcode */
+ nr = findrequestnick(passcode);
+ if (nr) {
+ utmp = finduser(passcode);
+ if (utmp) {
+ sprintf(passcode,
+ "FORCE_ACTIVATION_DUE_TO_OPER_CONFIRM %s",
+ nr->passcode);
+ passcode = strtok(passcode, " ");
+ notice_lang(s_NickServ, u, NICK_FORCE_REG,
+ nr->nick);
+ do_confirm(utmp);
+ return MOD_CONT;
+ } else {
+ passcode = sstrdup(nr->passcode);
+ forced = 1;
+ }
+ } else {
+ notice_lang(s_NickServ, u, NICK_CONFIRM_NOT_FOUND,
+ s_NickServ);
+ return MOD_CONT;
+ }
+ } else {
+ notice_lang(s_NickServ, u, NICK_CONFIRM_NOT_FOUND,
+ s_NickServ);
+ return MOD_CONT;
+ }
+ }
+
+ if (stricmp(nr->passcode, passcode) != 0) {
+ notice_lang(s_NickServ, u, NICK_CONFIRM_INVALID);
+ return MOD_CONT;
+ }
+ }
+
+ if (!nr) {
+ notice_lang(s_NickServ, u, NICK_REGISTRATION_FAILED);
+ return MOD_CONT;
+ }
+
+ if (nr->email) {
+ email = sstrdup(nr->email);
+ }
+ na = makenick(nr->nick);
+
+ if (na) {
+ int i;
+ char tsbuf[16];
+ char tmp_pass[PASSMAX];
+
+ memcpy(na->nc->pass, nr->password, PASSMAX);
+ na->status = (int16) (NS_IDENTIFIED | NS_RECOGNIZED);
+/* na->nc->flags |= NI_ENCRYPTEDPW; */
+
+ na->nc->flags |= NSDefFlags;
+ for (i = 0; i < RootNumber; i++) {
+ if (!stricmp(ServicesRoots[i], nr->nick)) {
+ na->nc->flags |= NI_SERVICES_ROOT;
+ break;
+ }
+ }
+ na->nc->memos.memomax = MSMaxMemos;
+ na->nc->channelmax = CSMaxReg;
+ if (forced == 1) {
+ na->last_usermask = sstrdup("*@*");
+ na->last_realname = sstrdup("unknown");
+ } else {
+ na->last_usermask =
+ scalloc(strlen(common_get_vident(u)) +
+ strlen(common_get_vhost(u)) + 2, 1);
+ sprintf(na->last_usermask, "%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+ na->last_realname = sstrdup(u->realname);
+ }
+ na->time_registered = na->last_seen = time(NULL);
+ if (NSAddAccessOnReg) {
+ na->nc->accesscount = 1;
+ na->nc->access = scalloc(sizeof(char *), 1);
+ na->nc->access[0] = create_mask(u);
+ } else {
+ na->nc->accesscount = 0;
+ na->nc->access = NULL;
+ }
+ na->nc->language = NSDefLanguage;
+ if (email)
+ na->nc->email = sstrdup(email);
+ if (forced != 1) {
+ u->na = na;
+ na->u = u;
+ alog("%s: '%s' registered by %s@%s (e-mail: %s)", s_NickServ,
+ u->nick, u->username, u->host, (email ? email : "none"));
+ if (NSAddAccessOnReg)
+ notice_lang(s_NickServ, u, NICK_REGISTERED, u->nick,
+ na->nc->access[0]);
+ else
+ notice_lang(s_NickServ, u, NICK_REGISTERED_NO_MASK,
+ u->nick);
+ send_event(EVENT_NICK_REGISTERED, 1, u->nick);
+
+ if(enc_decrypt(na->nc->pass, tmp_pass, PASSMAX - 1)==1)
+ notice_lang(s_NickServ, u, NICK_PASSWORD_IS, tmp_pass);
+
+ u->lastnickreg = time(NULL);
+ if (ircd->modeonreg) {
+ len = strlen(ircd->modeonreg);
+ strncpy(modes,ircd->modeonreg,512);
+ if(ircd->rootmodeonid && is_services_root(u)) {
+ strncat(modes,ircd->rootmodeonid,512-len);
+ } else if(ircd->adminmodeonid && is_services_admin(u)) {
+ strncat(modes,ircd->adminmodeonid,512-len);
+ } else if(ircd->opermodeonid && is_services_oper(u)) {
+ strncat(modes,ircd->opermodeonid,512-len);
+ }
+
+ if (ircd->tsonmode) {
+ snprintf(tsbuf, sizeof(tsbuf), "%lu",
+ (unsigned long int) u->timestamp);
+ common_svsmode(u, modes, tsbuf);
+ } else {
+ common_svsmode(u, modes, NULL);
+ }
+ }
+
+ } else {
+ notice_lang(s_NickServ, u, NICK_FORCE_REG, nr->nick);
+ }
+ delnickrequest(nr); /* remove the nick request */
+ } else {
+ alog("%s: makenick(%s) failed", s_NickServ, u->nick);
+ notice_lang(s_NickServ, u, NICK_REGISTRATION_FAILED);
+ }
+
+ /* Enable nick tracking if enabled */
+ if (NSNickTracking)
+ nsStartNickTracking(u);
+
+ return MOD_CONT;
+}
+
+NickRequest *makerequest(const char *nick)
+{
+ NickRequest *nr;
+
+ nr = scalloc(1, sizeof(NickRequest));
+ nr->nick = sstrdup(nick);
+ insert_requestnick(nr);
+ alog("%s: Nick %s has been requested", s_NickServ, nr->nick);
+ return nr;
+}
+
+/* Creates a full new nick (alias + core) in NickServ database. */
+
+NickAlias *makenick(const char *nick)
+{
+ NickAlias *na;
+ NickCore *nc;
+
+ /* First make the core */
+ nc = scalloc(1, sizeof(NickCore));
+ nc->display = sstrdup(nick);
+ slist_init(&nc->aliases);
+ insert_core(nc);
+ alog("%s: group %s has been created", s_NickServ, nc->display);
+
+ /* Then make the alias */
+ na = scalloc(1, sizeof(NickAlias));
+ na->nick = sstrdup(nick);
+ na->nc = nc;
+ slist_add(&nc->aliases, na);
+ alpha_insert_alias(na);
+ return na;
+}
+
+/* Register a nick. */
+
+int do_resend(User * u)
+{
+ NickRequest *nr = NULL;
+ if (NSEmailReg) {
+ if ((nr = findrequestnick(u->nick))) {
+ if (time(NULL) < nr->lastmail + NSResendDelay) {
+ notice_lang(s_NickServ, u, MAIL_LATER);
+ return MOD_CONT;
+ }
+ if (do_sendregmail(u, nr) == 0) {
+ nr->lastmail = time(NULL);
+ notice_lang(s_NickServ, u, NICK_REG_RESENT, nr->email);
+ alog("%s: re-sent registration verification code for %s to %s", s_NickServ, nr->nick, nr->email);
+ } else {
+ alog("%s: Unable to re-send registration verification mail for %s", s_NickServ, nr->nick);
+ return MOD_CONT;
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+int do_sendregmail(User * u, NickRequest * nr)
+{
+ MailInfo *mail = NULL;
+ char buf[BUFSIZE];
+
+ if (!(nr || u)) {
+ return -1;
+ }
+ snprintf(buf, sizeof(buf), getstring2(NULL, NICK_REG_MAIL_SUBJECT),
+ nr->nick);
+ mail = MailRegBegin(u, nr, buf, s_NickServ);
+ if (!mail) {
+ return -1;
+ }
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_HEAD));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_LINE_1), nr->nick);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_LINE_2), s_NickServ,
+ nr->passcode);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_LINE_3));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_LINE_4));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, NICK_REG_MAIL_LINE_5),
+ NetworkName);
+ fprintf(mail->pipe, "\n.\n");
+ MailEnd(mail);
+ return 0;
+}
+
diff --git a/src/core/ns_release.c b/src/core/ns_release.c
new file mode 100644
index 000000000..e2820b0e9
--- /dev/null
+++ b/src/core/ns_release.c
@@ -0,0 +1,127 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+Command *c;
+
+int do_release(User * u);
+void myNickServHelp(User * u);
+int myHelpResonse(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("RELEASE", do_release, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ moduleAddHelp(c, myHelpResonse);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_RELEASE);
+}
+
+/**
+ * Show the extended help on the RELEASE command.
+ * @param u The user who is requesting help
+ **/
+int myHelpResonse(User * u)
+{
+ char relstr[192];
+
+ /* Convert NSReleaseTimeout seconds to string format */
+ duration(u->na, relstr, sizeof(relstr), NSReleaseTimeout);
+
+ notice_help(s_NickServ, u, NICK_HELP_RELEASE, relstr);
+ do_help_limited(s_NickServ, u, c);
+
+ return MOD_CONT;
+}
+
+/**
+ * The /ns release command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_release(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *pass = strtok(NULL, " ");
+ NickAlias *na;
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "RELEASE", NICK_RELEASE_SYNTAX);
+ } else if (!(na = findnick(nick))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (!(na->status & NS_KILL_HELD)) {
+ notice_lang(s_NickServ, u, NICK_RELEASE_NOT_HELD, nick);
+ } else if (pass) {
+ int res = enc_check_password(pass, na->nc->pass);
+ if (res == 1) {
+ release(na, 0);
+ notice_lang(s_NickServ, u, NICK_RELEASED);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ if (res == 0) {
+ alog("%s: RELEASE: invalid password for %s by %s!%s@%s",
+ s_NickServ, nick, u->nick, u->username, u->host);
+ bad_password(u);
+ }
+ }
+ } else {
+ if (group_identified(u, na->nc)
+ || (!(na->nc->flags & NI_SECURE) && is_on_access(u, na->nc))) {
+ release(na, 0);
+ notice_lang(s_NickServ, u, NICK_RELEASED);
+ } else {
+ notice_lang(s_NickServ, u, ACCESS_DENIED);
+ }
+ }
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/ns_saset.c b/src/core/ns_saset.c
new file mode 100644
index 000000000..133fb098d
--- /dev/null
+++ b/src/core/ns_saset.c
@@ -0,0 +1,533 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+#include "encrypt.h"
+
+int do_saset(User * u);
+int do_saset_display(User * u, NickCore * nc, char *param);
+int do_saset_password(User * u, NickCore * nc, char *param);
+int do_saset_url(User * u, NickCore * nc, char *param);
+int do_saset_email(User * u, NickCore * nc, char *param);
+int do_saset_greet(User * u, NickCore * nc, char *param);
+int do_saset_icq(User * u, NickCore * nc, char *param);
+int do_saset_kill(User * u, NickCore * nc, char *param);
+int do_saset_secure(User * u, NickCore * nc, char *param);
+int do_saset_private(User * u, NickCore * nc, char *param);
+int do_saset_msg(User * u, NickCore * nc, char *param);
+int do_saset_hide(User * u, NickCore * nc, char *param);
+int do_saset_noexpire(User * u, NickAlias * nc, char *param);
+int do_saset_autoop(User * u, NickCore * nc, char *param);
+int do_saset_language(User * u, NickCore * nc, char *param);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SASET", do_saset, is_services_oper, -1, -1, -1,
+ NICK_HELP_SASET, NICK_HELP_SASET);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET DISPLAY", NULL, is_services_oper,
+ NICK_HELP_SASET_DISPLAY, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET PASSWORD", NULL, is_services_oper,
+ NICK_HELP_SASET_PASSWORD, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET URL", NULL, is_services_oper,
+ NICK_HELP_SASET_URL, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET EMAIL", NULL, is_services_oper,
+ NICK_HELP_SASET_EMAIL, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET ICQ", NULL, is_services_oper,
+ NICK_HELP_SASET_ICQ, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET GREET", NULL, is_services_oper,
+ NICK_HELP_SASET_GREET, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET KILL", NULL, is_services_oper,
+ NICK_HELP_SASET_KILL, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET SECURE", NULL, is_services_oper,
+ NICK_HELP_SASET_SECURE, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET PRIVATE", NULL, is_services_oper,
+ NICK_HELP_SASET_PRIVATE, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET MSG", NULL, is_services_oper,
+ NICK_HELP_SASET_MSG, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET HIDE", NULL, is_services_oper,
+ NICK_HELP_SASET_HIDE, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET NOEXPIRE", NULL, is_services_oper, -1, -1,
+ -1, NICK_HELP_SASET_NOEXPIRE,
+ NICK_HELP_SASET_NOEXPIRE);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET AUTOOP", NULL, is_services_oper, -1, -1,
+ -1, NICK_HELP_SASET_AUTOOP,
+ NICK_HELP_SASET_AUTOOP);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SASET LANGUAGE", NULL, is_services_oper,
+ -1, -1, -1, -1, NICK_HELP_SASET_LANGUAGE);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (is_services_oper(u))
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_SASET);
+}
+
+/**
+ * The /ns saset command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_saset(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *cmd = strtok(NULL, " ");
+ char *param = strtok(NULL, " ");
+
+ NickAlias *na;
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, NICK_SASET_DISABLED);
+ return MOD_CONT;
+ }
+ if (!nick) {
+ syntax_error(s_NickServ, u, "SASET", NICK_SASET_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!(na = findnick(nick))) {
+ notice_lang(s_NickServ, u, NICK_SASET_BAD_NICK, nick);
+ return MOD_CONT;
+ }
+
+ if (!param
+ && (!cmd
+ || (stricmp(cmd, "URL") != 0 && stricmp(cmd, "EMAIL") != 0
+ && stricmp(cmd, "GREET") != 0
+ && stricmp(cmd, "ICQ") != 0))) {
+ syntax_error(s_NickServ, u, "SASET", NICK_SASET_SYNTAX);
+ } else if (!na) {
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (stricmp(cmd, "DISPLAY") == 0) {
+ do_saset_display(u, na->nc, param);
+ } else if (stricmp(cmd, "PASSWORD") == 0) {
+ do_saset_password(u, na->nc, param);
+ } else if (stricmp(cmd, "URL") == 0) {
+ do_saset_url(u, na->nc, param);
+ } else if (stricmp(cmd, "EMAIL") == 0) {
+ do_saset_email(u, na->nc, param);
+ } else if (stricmp(cmd, "ICQ") == 0) {
+ do_saset_icq(u, na->nc, param);
+ } else if (stricmp(cmd, "GREET") == 0) {
+ do_saset_greet(u, na->nc, param);
+ } else if (stricmp(cmd, "KILL") == 0) {
+ do_saset_kill(u, na->nc, param);
+ } else if (stricmp(cmd, "SECURE") == 0) {
+ do_saset_secure(u, na->nc, param);
+ } else if (stricmp(cmd, "PRIVATE") == 0) {
+ do_saset_private(u, na->nc, param);
+ } else if (stricmp(cmd, "MSG") == 0) {
+ do_saset_msg(u, na->nc, param);
+ } else if (stricmp(cmd, "HIDE") == 0) {
+ do_saset_hide(u, na->nc, param);
+ } else if (stricmp(cmd, "NOEXPIRE") == 0) {
+ do_saset_noexpire(u, na, param);
+ } else if (stricmp(cmd, "AUTOOP") == 0) {
+ do_saset_autoop(u, na->nc, param);
+ } else if (stricmp(cmd, "LANGUAGE") == 0) {
+ do_saset_language(u, na->nc, param);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SASET_UNKNOWN_OPTION, cmd);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_display(User * u, NickCore * nc, char *param)
+{
+ int i;
+ NickAlias *na;
+
+ /* First check whether param is a valid nick of the group */
+ for (i = 0; i < nc->aliases.count; i++) {
+ na = nc->aliases.list[i];
+ if (stricmp(na->nick, param) == 0) {
+ param = na->nick; /* Because case may differ */
+ break;
+ }
+ }
+
+ if (i == nc->aliases.count) {
+ notice_lang(s_NickServ, u, NICK_SASET_DISPLAY_INVALID,
+ nc->display);
+ return MOD_CONT;
+ }
+
+ change_core_display(nc, param);
+ notice_lang(s_NickServ, u, NICK_SASET_DISPLAY_CHANGED, nc->display);
+
+ /* Enable nick tracking if enabled */
+ if (NSNickTracking)
+ nsStartNickTracking(u);
+
+ return MOD_CONT;
+}
+
+int do_saset_password(User * u, NickCore * nc, char *param)
+{
+ int len = strlen(param);
+ char tmp_pass[PASSMAX];
+
+ if (NSSecureAdmins && u->na->nc != nc && nick_is_services_admin(nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ } else if (stricmp(nc->display, param) == 0
+ || (StrictPasswords && len < 5)) {
+ notice_lang(s_NickServ, u, MORE_OBSCURE_PASSWORD);
+ return MOD_CONT;
+ } else if (enc_encrypt_check_len(len ,PASSMAX - 1)) {
+ notice_lang(s_NickServ, u, PASSWORD_TOO_LONG);
+ return MOD_CONT;
+ }
+
+ if (enc_encrypt(param, len, nc->pass, PASSMAX - 1) < 0) {
+ memset(param, 0, len);
+ alog("%s: Failed to encrypt password for %s (set)", s_NickServ,
+ nc->display);
+ notice_lang(s_NickServ, u, NICK_SASET_PASSWORD_FAILED,
+ nc->display);
+ return MOD_CONT;
+ }
+ memset(param, 0, len);
+
+ if(enc_decrypt(nc->pass,tmp_pass,PASSMAX - 1)==1) {
+ notice_lang(s_NickServ, u, NICK_SASET_PASSWORD_CHANGED_TO, nc->display,
+ tmp_pass);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SASET_PASSWORD_CHANGED, nc->display);
+ }
+
+ alog("%s: %s!%s@%s used SASET PASSWORD on %s (e-mail: %s)", s_NickServ,
+ u->nick, u->username, u->host, nc->display,
+ (nc->email ? nc->email : "none"));
+ if (WallSetpass)
+ anope_cmd_global(s_NickServ,
+ "\2%s\2 used SASET PASSWORD on \2%s\2",
+ u->nick, nc->display);
+ return MOD_CONT;
+}
+
+int do_saset_url(User * u, NickCore * nc, char *param)
+{
+ if (nc->url)
+ free(nc->url);
+
+ if (param) {
+ nc->url = sstrdup(param);
+ notice_lang(s_NickServ, u, NICK_SASET_URL_CHANGED, nc->display,
+ param);
+ } else {
+ nc->url = NULL;
+ notice_lang(s_NickServ, u, NICK_SASET_URL_UNSET, nc->display);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_email(User * u, NickCore * nc, char *param)
+{
+ if (!param && NSForceEmail) {
+ notice_lang(s_NickServ, u, NICK_SASET_EMAIL_UNSET_IMPOSSIBLE);
+ return MOD_CONT;
+ } else if (NSSecureAdmins && u->na->nc != nc
+ && nick_is_services_admin(nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ } else if (param && !MailValidate(param)) {
+ notice_lang(s_NickServ, u, MAIL_X_INVALID, param);
+ return MOD_CONT;
+ }
+
+ alog("%s: %s!%s@%s used SASET EMAIL on %s (e-mail: %s)", s_NickServ,
+ u->nick, u->username, u->host, nc->display,
+ (nc->email ? nc->email : "none"));
+
+ if (nc->email)
+ free(nc->email);
+
+ if (param) {
+ nc->email = sstrdup(param);
+ notice_lang(s_NickServ, u, NICK_SASET_EMAIL_CHANGED, nc->display,
+ param);
+ } else {
+ nc->email = NULL;
+ notice_lang(s_NickServ, u, NICK_SASET_EMAIL_UNSET, nc->display);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_icq(User * u, NickCore * nc, char *param)
+{
+ if (param) {
+ int32 tmp = atol(param);
+ if (tmp == 0) {
+ notice_lang(s_NickServ, u, NICK_SASET_ICQ_INVALID, param);
+ } else {
+ nc->icq = tmp;
+ notice_lang(s_NickServ, u, NICK_SASET_ICQ_CHANGED, nc->display,
+ param);
+ }
+ } else {
+ nc->icq = 0;
+ notice_lang(s_NickServ, u, NICK_SASET_ICQ_UNSET, nc->display);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_greet(User * u, NickCore * nc, char *param)
+{
+ if (nc->greet)
+ free(nc->greet);
+
+ if (param) {
+ char buf[BUFSIZE];
+ char *end = strtok(NULL, "");
+
+ snprintf(buf, sizeof(buf), "%s%s%s", param, (end ? " " : ""),
+ (end ? end : ""));
+
+ nc->greet = sstrdup(buf);
+ notice_lang(s_NickServ, u, NICK_SASET_GREET_CHANGED, nc->display,
+ buf);
+ } else {
+ nc->greet = NULL;
+ notice_lang(s_NickServ, u, NICK_SASET_GREET_UNSET, nc->display);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_kill(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_KILLPROTECT;
+ nc->flags &= ~(NI_KILL_QUICK | NI_KILL_IMMED);
+ notice_lang(s_NickServ, u, NICK_SASET_KILL_ON, nc->display);
+ } else if (stricmp(param, "QUICK") == 0) {
+ nc->flags |= NI_KILLPROTECT | NI_KILL_QUICK;
+ nc->flags &= ~NI_KILL_IMMED;
+ notice_lang(s_NickServ, u, NICK_SASET_KILL_QUICK, nc->display);
+ } else if (stricmp(param, "IMMED") == 0) {
+ if (NSAllowKillImmed) {
+ nc->flags |= NI_KILLPROTECT | NI_KILL_IMMED;
+ nc->flags &= ~NI_KILL_QUICK;
+ notice_lang(s_NickServ, u, NICK_SASET_KILL_IMMED, nc->display);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SASET_KILL_IMMED_DISABLED);
+ }
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~(NI_KILLPROTECT | NI_KILL_QUICK | NI_KILL_IMMED);
+ notice_lang(s_NickServ, u, NICK_SASET_KILL_OFF, nc->display);
+ } else {
+ syntax_error(s_NickServ, u, "SASET KILL",
+ NSAllowKillImmed ? NICK_SASET_KILL_IMMED_SYNTAX :
+ NICK_SASET_KILL_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_secure(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_SECURE;
+ notice_lang(s_NickServ, u, NICK_SASET_SECURE_ON, nc->display);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_SECURE;
+ notice_lang(s_NickServ, u, NICK_SASET_SECURE_OFF, nc->display);
+ } else {
+ syntax_error(s_NickServ, u, "SASET SECURE",
+ NICK_SASET_SECURE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_private(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_PRIVATE;
+ notice_lang(s_NickServ, u, NICK_SASET_PRIVATE_ON, nc->display);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_PRIVATE;
+ notice_lang(s_NickServ, u, NICK_SASET_PRIVATE_OFF, nc->display);
+ } else {
+ syntax_error(s_NickServ, u, "SASET PRIVATE",
+ NICK_SASET_PRIVATE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_msg(User * u, NickCore * nc, char *param)
+{
+ if (!UsePrivmsg) {
+ notice_lang(s_NickServ, u, NICK_SASET_OPTION_DISABLED, "MSG");
+ return MOD_CONT;
+ }
+
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_MSG;
+ notice_lang(s_NickServ, u, NICK_SASET_MSG_ON, nc->display);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_MSG;
+ notice_lang(s_NickServ, u, NICK_SASET_MSG_OFF, nc->display);
+ } else {
+ syntax_error(s_NickServ, u, "SASET MSG", NICK_SASET_MSG_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_hide(User * u, NickCore * nc, char *param)
+{
+ int flag, onmsg, offmsg;
+
+ if (stricmp(param, "EMAIL") == 0) {
+ flag = NI_HIDE_EMAIL;
+ onmsg = NICK_SASET_HIDE_EMAIL_ON;
+ offmsg = NICK_SASET_HIDE_EMAIL_OFF;
+ } else if (stricmp(param, "USERMASK") == 0) {
+ flag = NI_HIDE_MASK;
+ onmsg = NICK_SASET_HIDE_MASK_ON;
+ offmsg = NICK_SASET_HIDE_MASK_OFF;
+ } else if (stricmp(param, "STATUS") == 0) {
+ flag = NI_HIDE_STATUS;
+ onmsg = NICK_SASET_HIDE_STATUS_ON;
+ offmsg = NICK_SASET_HIDE_STATUS_OFF;
+ } else if (stricmp(param, "QUIT") == 0) {
+ flag = NI_HIDE_QUIT;
+ onmsg = NICK_SASET_HIDE_QUIT_ON;
+ offmsg = NICK_SASET_HIDE_QUIT_OFF;
+ } else {
+ syntax_error(s_NickServ, u, "SASET HIDE", NICK_SASET_HIDE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ param = strtok(NULL, " ");
+ if (!param) {
+ syntax_error(s_NickServ, u, "SASET HIDE", NICK_SASET_HIDE_SYNTAX);
+ } else if (stricmp(param, "ON") == 0) {
+ nc->flags |= flag;
+ notice_lang(s_NickServ, u, onmsg, nc->display, s_NickServ);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~flag;
+ notice_lang(s_NickServ, u, offmsg, nc->display, s_NickServ);
+ } else {
+ syntax_error(s_NickServ, u, "SASET HIDE", NICK_SASET_HIDE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_noexpire(User * u, NickAlias * na, char *param)
+{
+ if (!param) {
+ syntax_error(s_NickServ, u, "SASET NOEXPIRE",
+ NICK_SASET_NOEXPIRE_SYNTAX);
+ return MOD_CONT;
+ }
+ if (stricmp(param, "ON") == 0) {
+ na->status |= NS_NO_EXPIRE;
+ notice_lang(s_NickServ, u, NICK_SASET_NOEXPIRE_ON, na->nick);
+ } else if (stricmp(param, "OFF") == 0) {
+ na->status &= ~NS_NO_EXPIRE;
+ notice_lang(s_NickServ, u, NICK_SASET_NOEXPIRE_OFF, na->nick);
+ } else {
+ syntax_error(s_NickServ, u, "SASET NOEXPIRE",
+ NICK_SASET_NOEXPIRE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_saset_autoop(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags &= ~NI_AUTOOP;
+ notice_lang(s_NickServ, u, NICK_SASET_AUTOOP_ON, nc->display);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags |= NI_AUTOOP;
+ notice_lang(s_NickServ, u, NICK_SASET_AUTOOP_OFF, nc->display);
+ } else {
+ syntax_error(s_NickServ, u, "SET AUTOOP", NICK_SASET_AUTOOP_SYNTAX);
+ }
+
+ return MOD_CONT;
+}
+
+int do_saset_language(User * u, NickCore * nc, char *param)
+{
+ int langnum;
+
+ if (param[strspn(param, "0123456789")] != 0) { /* i.e. not a number */
+ syntax_error(s_NickServ, u, "SASET LANGUAGE",
+ NICK_SASET_LANGUAGE_SYNTAX);
+ return MOD_CONT;
+ }
+ langnum = atoi(param) - 1;
+ if (langnum < 0 || langnum >= NUM_LANGS || langlist[langnum] < 0) {
+ notice_lang(s_NickServ, u, NICK_SASET_LANGUAGE_UNKNOWN, langnum + 1,
+ s_NickServ);
+ return MOD_CONT;
+ }
+ nc->language = langlist[langnum];
+ notice_lang(s_NickServ, u, NICK_SASET_LANGUAGE_CHANGED);
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/ns_sendpass.c b/src/core/ns_sendpass.c
new file mode 100644
index 000000000..ce1834167
--- /dev/null
+++ b/src/core/ns_sendpass.c
@@ -0,0 +1,122 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_sendpass(User * u);
+
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SENDPASS", do_sendpass, NULL, NICK_HELP_SENDPASS,
+ -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+ if (!UseMail) {
+ return MOD_STOP;
+ }
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_SENDPASS);
+}
+
+/**
+ * The /ns sendpass command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_sendpass(User * u)
+{
+
+ char *nick = strtok(NULL, " ");
+ NickAlias *na;
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "SENDPASS", NICK_SENDPASS_SYNTAX);
+ } else if (RestrictMail && !is_services_oper(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ } else if (!(na = findnick(nick))) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else {
+ char buf[BUFSIZE];
+ char tmp_pass[PASSMAX];
+ if(enc_decrypt(na->nc->pass,tmp_pass,PASSMAX - 1)==1) {
+ MailInfo *mail;
+
+ snprintf(buf, sizeof(buf), getstring(na, NICK_SENDPASS_SUBJECT),
+ na->nick);
+ mail = MailBegin(u, na->nc, buf, s_NickServ);
+ if (!mail)
+ return MOD_CONT;
+
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_HEAD));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_LINE_1), na->nick);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_LINE_2),
+ tmp_pass);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_LINE_3));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_LINE_4));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring(na, NICK_SENDPASS_LINE_5),
+ NetworkName);
+ fprintf(mail->pipe, "\n.\n");
+
+ MailEnd(mail);
+
+ alog("%s: %s!%s@%s used SENDPASS on %s", s_NickServ, u->nick,
+ u->username, u->host, nick);
+ notice_lang(s_NickServ, u, NICK_SENDPASS_OK, nick);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SENDPASS_UNAVAILABLE);
+ }
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/ns_set.c b/src/core/ns_set.c
new file mode 100644
index 000000000..09f78560d
--- /dev/null
+++ b/src/core/ns_set.c
@@ -0,0 +1,475 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+#include "encrypt.h"
+
+int do_set(User * u);
+int do_set_display(User * u, NickCore * nc, char *param);
+int do_set_password(User * u, NickCore * nc, char *param);
+int do_set_language(User * u, NickCore * nc, char *param);
+int do_set_url(User * u, NickCore * nc, char *param);
+int do_set_email(User * u, NickCore * nc, char *param);
+int do_set_greet(User * u, NickCore * nc, char *param);
+int do_set_icq(User * u, NickCore * nc, char *param);
+int do_set_kill(User * u, NickCore * nc, char *param);
+int do_set_secure(User * u, NickCore * nc, char *param);
+int do_set_private(User * u, NickCore * nc, char *param);
+int do_set_msg(User * u, NickCore * nc, char *param);
+int do_set_hide(User * u, NickCore * nc, char *param);
+int do_set_autoop(User *u, NickCore *nc, char *param);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", do_set, NULL, NICK_HELP_SET, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET DISPLAY", NULL, NULL, NICK_HELP_SET_DISPLAY, -1,
+ -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PASSWORD", NULL, NULL, NICK_HELP_SET_PASSWORD,
+ -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET URL", NULL, NULL, NICK_HELP_SET_URL, -1, -1, -1,
+ -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET EMAIL", NULL, NULL, NICK_HELP_SET_EMAIL, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET ICQ", NULL, NULL, NICK_HELP_SET_ICQ, -1, -1, -1,
+ -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET GREET", NULL, NULL, NICK_HELP_SET_GREET, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET KILL", NULL, NULL, NICK_HELP_SET_KILL, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SECURE", NULL, NULL, NICK_HELP_SET_SECURE, -1,
+ -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET PRIVATE", NULL, NULL, NICK_HELP_SET_PRIVATE, -1,
+ -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET MSG", NULL, NULL, NICK_HELP_SET_MSG, -1, -1, -1,
+ -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET HIDE", NULL, NULL, NICK_HELP_SET_HIDE, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("SET AUTOOP", NULL, NULL, NICK_HELP_SET_AUTOOP, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_SET);
+}
+
+/**
+ * The /ns set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *param = strtok(NULL, " ");
+ NickAlias *na = u->na;
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, NICK_SET_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!param
+ && (!cmd
+ || (stricmp(cmd, "URL") != 0 && stricmp(cmd, "EMAIL") != 0
+ && stricmp(cmd, "GREET") != 0
+ && stricmp(cmd, "ICQ") != 0))) {
+ syntax_error(s_NickServ, u, "SET", NICK_SET_SYNTAX);
+ } else if (!na) {
+ notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
+ } else if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ } else if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick);
+ } else if (!nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else if (stricmp(cmd, "DISPLAY") == 0) {
+ do_set_display(u, na->nc, param);
+ } else if (stricmp(cmd, "PASSWORD") == 0) {
+ do_set_password(u, na->nc, param);
+ } else if (stricmp(cmd, "LANGUAGE") == 0) {
+ do_set_language(u, na->nc, param);
+ } else if (stricmp(cmd, "URL") == 0) {
+ do_set_url(u, na->nc, param);
+ } else if (stricmp(cmd, "EMAIL") == 0) {
+ do_set_email(u, na->nc, param);
+ } else if (stricmp(cmd, "ICQ") == 0) {
+ do_set_icq(u, na->nc, param);
+ } else if (stricmp(cmd, "GREET") == 0) {
+ do_set_greet(u, na->nc, param);
+ } else if (stricmp(cmd, "KILL") == 0) {
+ do_set_kill(u, na->nc, param);
+ } else if (stricmp(cmd, "SECURE") == 0) {
+ do_set_secure(u, na->nc, param);
+ } else if (stricmp(cmd, "PRIVATE") == 0) {
+ do_set_private(u, na->nc, param);
+ } else if (stricmp(cmd, "MSG") == 0) {
+ do_set_msg(u, na->nc, param);
+ } else if (stricmp(cmd, "HIDE") == 0) {
+ do_set_hide(u, na->nc, param);
+ } else if (stricmp(cmd, "AUTOOP") == 0) {
+ do_set_autoop(u, na->nc, param);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SET_UNKNOWN_OPTION, cmd);
+ }
+ return MOD_CONT;
+}
+
+int do_set_display(User * u, NickCore * nc, char *param)
+{
+ int i;
+ NickAlias *na;
+
+ /* First check whether param is a valid nick of the group */
+ for (i = 0; i < nc->aliases.count; i++) {
+ na = nc->aliases.list[i];
+ if (!stricmp(na->nick, param)) {
+ param = na->nick; /* Because case may differ */
+ break;
+ }
+ }
+
+ if (i == nc->aliases.count) {
+ notice_lang(s_NickServ, u, NICK_SET_DISPLAY_INVALID);
+ return MOD_CONT;
+ }
+
+ change_core_display(nc, param);
+ notice_lang(s_NickServ, u, NICK_SET_DISPLAY_CHANGED, nc->display);
+
+ /* Enable nick tracking if enabled */
+ if (NSNickTracking)
+ nsStartNickTracking(u);
+
+ return MOD_CONT;
+}
+
+int do_set_password(User * u, NickCore * nc, char *param)
+{
+ int len = strlen(param);
+ char tmp_pass[PASSMAX];
+
+ if (stricmp(nc->display, param) == 0 || (StrictPasswords && len < 5)) {
+ notice_lang(s_NickServ, u, MORE_OBSCURE_PASSWORD);
+ return MOD_CONT;
+ } else if (enc_encrypt_check_len(len ,PASSMAX - 1)) {
+ notice_lang(s_NickServ, u, PASSWORD_TOO_LONG);
+ return MOD_CONT;
+ }
+
+ if (enc_encrypt(param, len, nc->pass, PASSMAX - 1) < 0) {
+ memset(param, 0, len);
+ alog("%s: Failed to encrypt password for %s (set)", s_NickServ,
+ nc->display);
+ notice_lang(s_NickServ, u, NICK_SET_PASSWORD_FAILED);
+ return MOD_CONT;
+ }
+ memset(param, 0, len);
+
+ if(enc_decrypt(nc->pass,tmp_pass,PASSMAX - 1)==1) {
+ notice_lang(s_NickServ, u, NICK_SET_PASSWORD_CHANGED_TO, tmp_pass);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SET_PASSWORD_CHANGED);
+ }
+
+ alog("%s: %s!%s@%s (e-mail: %s) changed its password.", s_NickServ,
+ u->nick, u->username, u->host, (nc->email ? nc->email : "none"));
+
+ return MOD_CONT;
+}
+
+int do_set_language(User * u, NickCore * nc, char *param)
+{
+ int langnum;
+
+ if (param[strspn(param, "0123456789")] != 0) { /* i.e. not a number */
+ syntax_error(s_NickServ, u, "SET LANGUAGE",
+ NICK_SET_LANGUAGE_SYNTAX);
+ return MOD_CONT;
+ }
+ langnum = atoi(param) - 1;
+ if (langnum < 0 || langnum >= NUM_LANGS || langlist[langnum] < 0) {
+ notice_lang(s_NickServ, u, NICK_SET_LANGUAGE_UNKNOWN, langnum + 1,
+ s_NickServ);
+ return MOD_CONT;
+ }
+ nc->language = langlist[langnum];
+ notice_lang(s_NickServ, u, NICK_SET_LANGUAGE_CHANGED);
+ return MOD_CONT;
+}
+
+int do_set_url(User * u, NickCore * nc, char *param)
+{
+ if (nc->url)
+ free(nc->url);
+
+ if (param) {
+ nc->url = sstrdup(param);
+ notice_lang(s_NickServ, u, NICK_SET_URL_CHANGED, param);
+ } else {
+ nc->url = NULL;
+ notice_lang(s_NickServ, u, NICK_SET_URL_UNSET);
+ }
+ return MOD_CONT;
+}
+
+int do_set_email(User * u, NickCore * nc, char *param)
+{
+ if (!param && NSForceEmail) {
+ notice_lang(s_NickServ, u, NICK_SET_EMAIL_UNSET_IMPOSSIBLE);
+ return MOD_CONT;
+ } else if (param && !MailValidate(param)) {
+ notice_lang(s_NickServ, u, MAIL_X_INVALID, param);
+ return MOD_CONT;
+ }
+
+ alog("%s: %s!%s@%s (e-mail: %s) changed its e-mail to %s.",
+ s_NickServ, u->nick, u->username, u->host,
+ (nc->email ? nc->email : "none"), (param ? param : "none"));
+
+ if (nc->email)
+ free(nc->email);
+
+ if (param) {
+ nc->email = sstrdup(param);
+ notice_lang(s_NickServ, u, NICK_SET_EMAIL_CHANGED, param);
+ } else {
+ nc->email = NULL;
+ notice_lang(s_NickServ, u, NICK_SET_EMAIL_UNSET);
+ }
+ return MOD_CONT;
+}
+
+int do_set_icq(User * u, NickCore * nc, char *param)
+{
+ if (param) {
+ int32 tmp = atol(param);
+ if (!tmp) {
+ notice_lang(s_NickServ, u, NICK_SET_ICQ_INVALID, param);
+ } else {
+ nc->icq = tmp;
+ notice_lang(s_NickServ, u, NICK_SET_ICQ_CHANGED, param);
+ }
+ } else {
+ nc->icq = 0;
+ notice_lang(s_NickServ, u, NICK_SET_ICQ_UNSET);
+ }
+ return MOD_CONT;
+}
+
+int do_set_greet(User * u, NickCore * nc, char *param)
+{
+ if (nc->greet)
+ free(nc->greet);
+
+ if (param) {
+ char buf[BUFSIZE];
+ char *end = strtok(NULL, "");
+
+ snprintf(buf, sizeof(buf), "%s%s%s", param, (end ? " " : ""),
+ (end ? end : ""));
+
+ nc->greet = sstrdup(buf);
+ notice_lang(s_NickServ, u, NICK_SET_GREET_CHANGED, buf);
+ } else {
+ nc->greet = NULL;
+ notice_lang(s_NickServ, u, NICK_SET_GREET_UNSET);
+ }
+ return MOD_CONT;
+}
+
+int do_set_kill(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_KILLPROTECT;
+ nc->flags &= ~(NI_KILL_QUICK | NI_KILL_IMMED);
+ notice_lang(s_NickServ, u, NICK_SET_KILL_ON);
+ } else if (stricmp(param, "QUICK") == 0) {
+ nc->flags |= NI_KILLPROTECT | NI_KILL_QUICK;
+ nc->flags &= ~NI_KILL_IMMED;
+ notice_lang(s_NickServ, u, NICK_SET_KILL_QUICK);
+ } else if (stricmp(param, "IMMED") == 0) {
+ if (NSAllowKillImmed) {
+ nc->flags |= NI_KILLPROTECT | NI_KILL_IMMED;
+ nc->flags &= ~NI_KILL_QUICK;
+ notice_lang(s_NickServ, u, NICK_SET_KILL_IMMED);
+ } else {
+ notice_lang(s_NickServ, u, NICK_SET_KILL_IMMED_DISABLED);
+ }
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~(NI_KILLPROTECT | NI_KILL_QUICK | NI_KILL_IMMED);
+ notice_lang(s_NickServ, u, NICK_SET_KILL_OFF);
+ } else {
+ syntax_error(s_NickServ, u, "SET KILL",
+ NSAllowKillImmed ? NICK_SET_KILL_IMMED_SYNTAX :
+ NICK_SET_KILL_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_set_secure(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_SECURE;
+ notice_lang(s_NickServ, u, NICK_SET_SECURE_ON);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_SECURE;
+ notice_lang(s_NickServ, u, NICK_SET_SECURE_OFF);
+ } else {
+ syntax_error(s_NickServ, u, "SET SECURE", NICK_SET_SECURE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_set_private(User * u, NickCore * nc, char *param)
+{
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_PRIVATE;
+ notice_lang(s_NickServ, u, NICK_SET_PRIVATE_ON);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_PRIVATE;
+ notice_lang(s_NickServ, u, NICK_SET_PRIVATE_OFF);
+ } else {
+ syntax_error(s_NickServ, u, "SET PRIVATE",
+ NICK_SET_PRIVATE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_set_msg(User * u, NickCore * nc, char *param)
+{
+ if (!UsePrivmsg) {
+ notice_lang(s_NickServ, u, NICK_SET_OPTION_DISABLED, "MSG");
+ return MOD_CONT;
+ }
+
+ if (stricmp(param, "ON") == 0) {
+ nc->flags |= NI_MSG;
+ notice_lang(s_NickServ, u, NICK_SET_MSG_ON);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~NI_MSG;
+ notice_lang(s_NickServ, u, NICK_SET_MSG_OFF);
+ } else {
+ syntax_error(s_NickServ, u, "SET MSG", NICK_SET_MSG_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_set_hide(User * u, NickCore * nc, char *param)
+{
+ int flag, onmsg, offmsg;
+
+ if (stricmp(param, "EMAIL") == 0) {
+ flag = NI_HIDE_EMAIL;
+ onmsg = NICK_SET_HIDE_EMAIL_ON;
+ offmsg = NICK_SET_HIDE_EMAIL_OFF;
+ } else if (stricmp(param, "USERMASK") == 0) {
+ flag = NI_HIDE_MASK;
+ onmsg = NICK_SET_HIDE_MASK_ON;
+ offmsg = NICK_SET_HIDE_MASK_OFF;
+ } else if (stricmp(param, "STATUS") == 0) {
+ flag = NI_HIDE_STATUS;
+ onmsg = NICK_SET_HIDE_STATUS_ON;
+ offmsg = NICK_SET_HIDE_STATUS_OFF;
+ } else if (stricmp(param, "QUIT") == 0) {
+ flag = NI_HIDE_QUIT;
+ onmsg = NICK_SET_HIDE_QUIT_ON;
+ offmsg = NICK_SET_HIDE_QUIT_OFF;
+ } else {
+ syntax_error(s_NickServ, u, "SET HIDE", NICK_SET_HIDE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ param = strtok(NULL, " ");
+ if (!param) {
+ syntax_error(s_NickServ, u, "SET HIDE", NICK_SET_HIDE_SYNTAX);
+ } else if (stricmp(param, "ON") == 0) {
+ nc->flags |= flag;
+ notice_lang(s_NickServ, u, onmsg, s_NickServ);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags &= ~flag;
+ notice_lang(s_NickServ, u, offmsg, s_NickServ);
+ } else {
+ syntax_error(s_NickServ, u, "SET HIDE", NICK_SET_HIDE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int do_set_autoop(User *u, NickCore *nc, char *param) {
+
+ /**
+ * This works the other way around, the absence of this flag denotes ON
+ * This is so when people upgrade, and dont have the flag
+ * the default is on
+ **/
+ if (stricmp(param, "ON") == 0) {
+ nc->flags &= ~NI_AUTOOP;
+ notice_lang(s_NickServ, u, NICK_SET_AUTOOP_ON);
+ } else if (stricmp(param, "OFF") == 0) {
+ nc->flags |= NI_AUTOOP;
+ notice_lang(s_NickServ, u, NICK_SET_AUTOOP_OFF);
+ } else {
+ syntax_error(s_NickServ, u, "SET AUTOOP", NICK_SET_AUTOOP_SYNTAX);
+ }
+
+ return MOD_CONT;
+}
+
+
+/* EOF */
diff --git a/src/core/ns_status.c b/src/core/ns_status.c
new file mode 100644
index 000000000..86963b4a3
--- /dev/null
+++ b/src/core/ns_status.c
@@ -0,0 +1,94 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_status(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("STATUS", do_status, NULL, NICK_HELP_STATUS, -1, -1,
+ -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_STATUS);
+}
+
+/**
+ * The /ns status command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_status(User * u)
+{
+ User *u2;
+ NickAlias *na = NULL;
+ int i = 0;
+ char *nick = strtok(NULL, " ");
+
+ /* If no nickname is given, we assume that the user
+ * is asking for himself */
+ if (!nick)
+ nick = u->nick;
+
+ while (nick && (i++ < 16)) {
+ if (!(u2 = finduser(nick))) /* Nick is not online */
+ notice_lang(s_NickServ, u, NICK_STATUS_0, nick);
+ else if (nick_identified(u2)) /* Nick is identified */
+ notice_lang(s_NickServ, u, NICK_STATUS_3, nick);
+ else if (nick_recognized(u2)) /* Nick is recognised, but NOT identified */
+ notice_lang(s_NickServ, u, NICK_STATUS_2, nick);
+ else if ((na = findnick(nick)) == NULL) /* Nick is online, but NOT a registered */
+ notice_lang(s_NickServ, u, NICK_STATUS_0, nick);
+ else
+ notice_lang(s_NickServ, u, NICK_STATUS_1, nick);
+
+ /* Get the next nickname */
+ nick = strtok(NULL, " ");
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/ns_suspend.c b/src/core/ns_suspend.c
new file mode 100644
index 000000000..a2961e060
--- /dev/null
+++ b/src/core/ns_suspend.c
@@ -0,0 +1,193 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_suspend(User * u);
+int do_unsuspend(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SUSPEND", do_suspend, is_services_oper, -1, -1, -1,
+ NICK_SERVADMIN_HELP_SUSPEND,
+ NICK_SERVADMIN_HELP_SUSPEND);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+ c = createCommand("UNSUSPEND", do_unsuspend, is_services_oper, -1, -1,
+ -1, NICK_SERVADMIN_HELP_UNSUSPEND,
+ NICK_SERVADMIN_HELP_UNSUSPEND);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_SUSPEND);
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_UNSUSPEND);
+ }
+}
+
+/**
+ * The /ns suspend command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_suspend(User * u)
+{
+ NickAlias *na, *na2;
+ char *nick = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+ int i;
+
+ if (!nick || !reason) {
+ syntax_error(s_NickServ, u, "SUSPEND", NICK_SUSPEND_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, READ_ONLY_MODE);
+ return MOD_CONT;
+ }
+
+ if ((na = findnick(nick)) == NULL) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ return MOD_CONT;
+ }
+
+ if (NSSecureAdmins && nick_is_services_admin(na->nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (na) {
+ na->nc->flags |= NI_SUSPENDED;
+ na->nc->flags |= NI_SECURE;
+ na->nc->flags &= ~(NI_KILLPROTECT | NI_KILL_QUICK | NI_KILL_IMMED);
+
+ for (i = 0; i < na->nc->aliases.count; i++) {
+ na2 = na->nc->aliases.list[i];
+ if (na2->nc == na->nc) {
+ na2->status &= ~(NS_IDENTIFIED | NS_RECOGNIZED);
+ na2->last_quit = sstrdup(reason);
+ }
+ }
+
+ if (WallForbid)
+ anope_cmd_global(s_NickServ, "\2%s\2 used SUSPEND on \2%s\2",
+ u->nick, nick);
+
+ alog("%s: %s set SUSPEND for nick %s", s_NickServ, u->nick, nick);
+ notice_lang(s_NickServ, u, NICK_SUSPEND_SUCCEEDED, nick);
+ send_event(EVENT_NICK_SUSPENDED, 1, nick);
+
+ } else {
+
+ alog("%s: Valid SUSPEND for %s by %s failed", s_NickServ, nick,
+ u->nick);
+ notice_lang(s_NickServ, u, NICK_SUSPEND_FAILED, nick);
+
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int do_unsuspend(User * u)
+{
+ NickAlias *na;
+ char *nick = strtok(NULL, " ");
+
+ if (!nick) {
+ syntax_error(s_NickServ, u, "UNSUSPEND", NICK_UNSUSPEND_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (readonly) {
+ notice_lang(s_NickServ, u, READ_ONLY_MODE);
+ return MOD_CONT;
+ }
+
+ if ((na = findnick(nick)) == NULL) {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
+ return MOD_CONT;
+ }
+ if (NSSecureAdmins && nick_is_services_admin(na->nc)
+ && !is_services_root(u)) {
+ notice_lang(s_NickServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (na) {
+ na->nc->flags &= ~NI_SUSPENDED;
+
+ if (WallForbid)
+ anope_cmd_global(s_NickServ, "\2%s\2 used UNSUSPEND on \2%s\2",
+ u->nick, nick);
+
+ alog("%s: %s set UNSUSPEND for nick %s", s_NickServ, u->nick,
+ nick);
+ notice_lang(s_NickServ, u, NICK_UNSUSPEND_SUCCEEDED, nick);
+ send_event(EVENT_NICK_UNSUSPEND, 1, nick);
+
+ } else {
+
+ alog("%s: Valid UNSUSPEND for %s by %s failed", s_NickServ, nick,
+ u->nick);
+ notice_lang(s_NickServ, u, NICK_UNSUSPEND_FAILED, nick);
+
+ }
+
+ return MOD_CONT;
+
+}
diff --git a/src/core/ns_update.c b/src/core/ns_update.c
new file mode 100644
index 000000000..140b2ed7f
--- /dev/null
+++ b/src/core/ns_update.c
@@ -0,0 +1,90 @@
+/* NickServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_nickupdate(User * u);
+void myNickServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("UPDATE", do_nickupdate, NULL, NICK_HELP_UPDATE, -1,
+ -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_UNIQUE);
+
+ moduleSetNickHelp(myNickServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /ns help output.
+ * @param u The user who is requesting help
+ **/
+void myNickServHelp(User * u)
+{
+ notice_lang(s_NickServ, u, NICK_HELP_CMD_UPDATE);
+}
+
+/**
+ * The /ns update command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_nickupdate(User * u)
+{
+ NickAlias *na;
+
+ if (!nick_identified(u)) {
+ notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+ } else {
+ na = u->na;
+ if (NSModeOnID)
+ do_setmodes(u);
+ check_memos(u);
+ if (na->last_realname)
+ free(na->last_realname);
+ na->last_realname = sstrdup(u->realname);
+ na->status |= NS_IDENTIFIED;
+ na->last_seen = time(NULL);
+ if (ircd->vhost) {
+ do_on_id(u);
+ }
+ notice_lang(s_NickServ, u, NICK_UPDATE_SUCCESS, s_NickServ);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_admin.c b/src/core/os_admin.c
new file mode 100644
index 000000000..4df67ccd7
--- /dev/null
+++ b/src/core/os_admin.c
@@ -0,0 +1,249 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_admin(User * u);
+int admin_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int admin_list(int number, NickCore * nc, User * u, int *sent_header);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("ADMIN", do_admin, NULL, OPER_HELP_ADMIN, -1, -1,
+ -1, -1);
+ c->help_param1 = s_NickServ;
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_ADMIN);
+}
+
+/**
+ * The /os admin command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_admin(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ NickAlias *na;
+ int res = 0;
+
+ if (skeleton) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_SKELETON);
+ return MOD_CONT;
+ }
+
+ if (!cmd || (!nick && stricmp(cmd, "LIST") && stricmp(cmd, "CLEAR"))) {
+ syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_SYNTAX);
+ } else if (!stricmp(cmd, "ADD")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (!(na = findnick(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+
+ if (na->nc->flags & NI_SERVICES_ADMIN
+ || slist_indexof(&servadmins, na->nc) != -1) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_EXISTS, nick);
+ return MOD_CONT;
+ }
+
+ res = slist_add(&servadmins, na->nc);
+ if (res == -2) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_REACHED_LIMIT, nick);
+ return MOD_CONT;
+ } else {
+ if (na->nc->flags & NI_SERVICES_OPER
+ && (res = slist_indexof(&servopers, na->nc)) != -1) {
+ slist_delete(&servopers, res);
+ na->nc->flags |= NI_SERVICES_ADMIN;
+ notice_lang(s_OperServ, u, OPER_ADMIN_MOVED, nick);
+ } else {
+ na->nc->flags |= NI_SERVICES_ADMIN;
+ notice_lang(s_OperServ, u, OPER_ADMIN_ADDED, nick);
+ }
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else if (!stricmp(cmd, "DEL")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (servadmins.count == 0) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) {
+ /* Deleting a range */
+ res = slist_delete_range(&servadmins, nick, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_ADMIN_DELETED_SEVERAL,
+ res);
+ }
+ } else {
+ if (!(na = findnick(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+
+ if (!(na->nc->flags & NI_SERVICES_ADMIN)
+ || (res = slist_indexof(&servadmins, na->nc)) == -1) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_NOT_FOUND, nick);
+ return MOD_CONT;
+ }
+
+ slist_delete(&servadmins, res);
+ notice_lang(s_OperServ, u, OPER_ADMIN_DELETED, nick);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else if (!stricmp(cmd, "LIST")) {
+ int sent_header = 0;
+
+ if (servadmins.count == 0) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (!nick || (isdigit(*nick)
+ && strspn(nick, "1234567890,-") == strlen(nick))) {
+ res =
+ slist_enum(&servadmins, nick, &admin_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH);
+ return MOD_CONT;
+ } else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Admin");
+ }
+ } else {
+ int i;
+
+ for (i = 0; i < servadmins.count; i++)
+ if (!stricmp
+ (nick, ((NickCore *) servadmins.list[i])->display)
+ || match_wild_nocase(nick,
+ ((NickCore *) servadmins.
+ list[i])->display))
+ admin_list(i + 1, servadmins.list[i], u, &sent_header);
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_ADMIN_NO_MATCH);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Admin");
+ }
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (servadmins.count == 0) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ slist_clear(&servadmins, 1);
+ notice_lang(s_OperServ, u, OPER_ADMIN_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int admin_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return admin_list(number, item, u, sent_header);
+}
+
+int admin_list(int number, NickCore * nc, User * u, int *sent_header)
+{
+ if (!nc)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_ADMIN_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_OperServ, u, OPER_ADMIN_LIST_FORMAT, number,
+ nc->display);
+ return 1;
+}
diff --git a/src/core/os_akill.c b/src/core/os_akill.c
new file mode 100644
index 000000000..8233eec93
--- /dev/null
+++ b/src/core/os_akill.c
@@ -0,0 +1,386 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_akill(User * u);
+int akill_view_callback(SList * slist, int number, void *item,
+ va_list args);
+int akill_view(int number, Akill * ak, User * u, int *sent_header);
+int akill_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int akill_list(int number, Akill * ak, User * u, int *sent_header);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("AKILL", do_akill, is_services_oper, OPER_HELP_AKILL,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_AKILL);
+ }
+}
+
+/**
+ * The /os command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+/* Manage the AKILL list. */
+
+int do_akill(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char breason[BUFSIZE];
+
+ if (!cmd)
+ cmd = "";
+
+ if (!stricmp(cmd, "ADD")) {
+ int deleted = 0;
+ char *expiry, *mask, *reason;
+ time_t expires;
+
+ mask = strtok(NULL, " ");
+ if (mask && *mask == '+') {
+ expiry = mask;
+ mask = strtok(NULL, " ");
+ } else {
+ expiry = NULL;
+ }
+
+ expires = expiry ? dotime(expiry) : AutokillExpiry;
+ /* If the expiry given does not contain a final letter, it's in days,
+ * said the doc. Ah well.
+ */
+ if (expiry && isdigit(expiry[strlen(expiry) - 1]))
+ expires *= 86400;
+ /* Do not allow less than a minute expiry time */
+ if (expires != 0 && expires < 60) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ if (mask && (reason = strtok(NULL, ""))) {
+ /* We first do some sanity check on the proposed mask. */
+ if (strchr(mask, '!')) {
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_NICK);
+ return MOD_CONT;
+ }
+
+ if (!strchr(mask, '@')) {
+ notice_lang(s_OperServ, u, BAD_USERHOST_MASK);
+ return MOD_CONT;
+ }
+
+ if (mask && strspn(mask, "~@.*?") == strlen(mask)) {
+ notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask);
+ return MOD_CONT;
+ }
+
+ /**
+ * Changed sprintf() to snprintf()and increased the size of
+ * breason to match bufsize
+ * -Rob
+ **/
+ if (AddAkiller) {
+ snprintf(breason, sizeof(breason), "[%s] %s", u->nick,
+ reason);
+ reason = sstrdup(breason);
+ }
+
+ deleted = add_akill(u, mask, u->nick, expires, reason);
+ if (deleted < 0) {
+ if (AddAkiller) {
+ free(reason);
+ }
+ return MOD_CONT;
+ } else if (deleted) {
+ notice_lang(s_OperServ, u, OPER_AKILL_DELETED_SEVERAL,
+ deleted);
+ }
+ notice_lang(s_OperServ, u, OPER_AKILL_ADDED, mask);
+
+ if (WallOSAkill) {
+ char buf[128];
+
+ if (!expires) {
+ strcpy(buf, "does not expire");
+ } else {
+ int wall_expiry = expires - time(NULL);
+ char *s = NULL;
+
+ if (wall_expiry >= 86400) {
+ wall_expiry /= 86400;
+ s = "day";
+ } else if (wall_expiry >= 3600) {
+ wall_expiry /= 3600;
+ s = "hour";
+ } else if (wall_expiry >= 60) {
+ wall_expiry /= 60;
+ s = "minute";
+ }
+
+ snprintf(buf, sizeof(buf), "expires in %d %s%s",
+ wall_expiry, s,
+ (wall_expiry == 1) ? "" : "s");
+ }
+
+ anope_cmd_global(s_OperServ,
+ "%s added an AKILL for %s (%s) (%s)",
+ u->nick, mask, reason, buf);
+ }
+
+ if (readonly) {
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ }
+ if (AddAkiller) {
+ free(reason);
+ }
+ } else {
+ syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX);
+ }
+
+ } else if (!stricmp(cmd, "DEL")) {
+
+ char *mask;
+ int res = 0;
+
+ mask = strtok(NULL, " ");
+
+ if (!mask) {
+ syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (akills.count == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ /* Deleting a range */
+ res = slist_delete_range(&akills, mask, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_AKILL_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_AKILL_DELETED_SEVERAL,
+ res);
+ }
+ } else {
+ if ((res = slist_indexof(&akills, mask)) == -1) {
+ notice_lang(s_OperServ, u, OPER_AKILL_NOT_FOUND, mask);
+ return MOD_CONT;
+ }
+
+ slist_delete(&akills, res);
+ notice_lang(s_OperServ, u, OPER_AKILL_DELETED, mask);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else if (!stricmp(cmd, "LIST")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (akills.count == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, " ");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&akills, mask, &akill_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH);
+ return MOD_CONT;
+ } else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Akill");
+ }
+ } else {
+ int i;
+ char amask[BUFSIZE];
+
+ for (i = 0; i < akills.count; i++) {
+ snprintf(amask, sizeof(amask), "%s@%s",
+ ((Akill *) akills.list[i])->user,
+ ((Akill *) akills.list[i])->host);
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ akill_list(i + 1, akills.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Akill");
+ }
+ }
+ } else if (!stricmp(cmd, "VIEW")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (akills.count == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, " ");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&akills, mask, &akill_view_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char amask[BUFSIZE];
+
+ for (i = 0; i < akills.count; i++) {
+ snprintf(amask, sizeof(amask), "%s@%s",
+ ((Akill *) akills.list[i])->user,
+ ((Akill *) akills.list[i])->host);
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ akill_view(i + 1, akills.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_AKILL_NO_MATCH);
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ slist_clear(&akills, 1);
+ notice_lang(s_OperServ, u, OPER_AKILL_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "AKILL", OPER_AKILL_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int akill_view(int number, Akill * ak, User * u, int *sent_header)
+{
+ char mask[BUFSIZE];
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+
+ if (!ak)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_AKILL_VIEW_HEADER);
+ *sent_header = 1;
+ }
+
+ snprintf(mask, sizeof(mask), "%s@%s", ak->user, ak->host);
+ tm = *localtime(&ak->seton);
+ strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_SHORT_DATE_FORMAT,
+ &tm);
+ expire_left(u->na, expirebuf, sizeof(expirebuf), ak->expires);
+ notice_lang(s_OperServ, u, OPER_AKILL_VIEW_FORMAT, number, mask,
+ ak->by, timebuf, expirebuf, ak->reason);
+
+ return 1;
+}
+
+/* Lists an AKILL entry, prefixing it with the header if needed */
+
+int akill_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return akill_list(number, item, u, sent_header);
+}
+
+/* Callback for enumeration purposes */
+
+int akill_view_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return akill_view(number, item, u, sent_header);
+}
+
+/* Lists an AKILL entry, prefixing it with the header if needed */
+int akill_list(int number, Akill * ak, User * u, int *sent_header)
+{
+ char mask[BUFSIZE];
+
+ if (!ak)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_AKILL_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ snprintf(mask, sizeof(mask), "%s@%s", ak->user, ak->host);
+ notice_lang(s_OperServ, u, OPER_AKILL_LIST_FORMAT, number, mask,
+ ak->reason);
+
+ return 1;
+}
diff --git a/src/core/os_chankill.c b/src/core/os_chankill.c
new file mode 100644
index 000000000..805c7d57f
--- /dev/null
+++ b/src/core/os_chankill.c
@@ -0,0 +1,134 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_chankill(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("CHANKILL", do_chankill, is_services_admin,
+ OPER_HELP_CHANKILL, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_CHANKILL);
+ }
+}
+
+/**
+ * ChanKill - Akill an entire channel (got botnet?)
+ *
+ * /msg OperServ ChanKill +expire #channel reason
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ *
+ **/
+int do_chankill(User * u)
+{
+ char *expiry, *channel, *reason;
+ time_t expires;
+ char breason[BUFSIZE];
+ char mask[USERMAX + HOSTMAX + 2];
+ struct c_userlist *cu, *next;
+ Channel *c;
+
+ channel = strtok(NULL, " ");
+ if (channel && *channel == '+') {
+ expiry = channel;
+ channel = strtok(NULL, " ");
+ } else {
+ expiry = NULL;
+ }
+
+ expires = expiry ? dotime(expiry) : ChankillExpiry;
+ if (expiry && isdigit(expiry[strlen(expiry) - 1]))
+ expires *= 86400;
+ if (expires != 0 && expires < 60) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ if (channel && (reason = strtok(NULL, ""))) {
+
+ if (AddAkiller) {
+ snprintf(breason, sizeof(breason), "[%s] %s", u->nick, reason);
+ reason = sstrdup(breason);
+ }
+
+ if ((c = findchan(channel))) {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (is_oper(cu->user)) {
+ continue;
+ }
+ (void) strncpy(mask, "*@", 3); /* Use *@" for the akill's, */
+ strncat(mask, cu->user->host, HOSTMAX);
+ add_akill(NULL, mask, s_OperServ, expires, reason);
+ check_akill(cu->user->nick, cu->user->username,
+ cu->user->host, NULL, NULL);
+ }
+ if (WallOSAkill) {
+ anope_cmd_global(s_OperServ, "%s used CHANKILL on %s (%s)",
+ u->nick, channel, reason);
+ }
+ } else {
+ notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, channel);
+ }
+ if (AddAkiller) {
+ free(reason);
+ }
+ } else {
+ syntax_error(s_OperServ, u, "CHANKILL", OPER_CHANKILL_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_chanlist.c b/src/core/os_chanlist.c
new file mode 100644
index 000000000..96285b827
--- /dev/null
+++ b/src/core/os_chanlist.c
@@ -0,0 +1,116 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_chanlist(User * u);
+void myOperServHelp(User * u);
+#ifdef _WIN32
+extern MDE int anope_get_private_mode();
+#endif
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("CHANLIST", do_chanlist, is_services_oper,
+ OPER_HELP_CHANLIST, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_CHANLIST);
+}
+
+/**
+ * The /os chanlist command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_chanlist(User * u)
+{
+ char *pattern = strtok(NULL, " ");
+ char *opt = strtok(NULL, " ");
+
+ int modes = 0;
+ User *u2;
+
+ if (opt && !stricmp(opt, "SECRET"))
+ modes |= (anope_get_secret_mode() | anope_get_private_mode());
+
+ if (pattern && (u2 = finduser(pattern))) {
+ struct u_chanlist *uc;
+
+ notice_lang(s_OperServ, u, OPER_CHANLIST_HEADER_USER, u2->nick);
+
+ for (uc = u2->chans; uc; uc = uc->next) {
+ if (modes && !(uc->chan->mode & modes))
+ continue;
+ notice_lang(s_OperServ, u, OPER_CHANLIST_RECORD,
+ uc->chan->name, uc->chan->usercount,
+ chan_get_modes(uc->chan, 1, 1),
+ (uc->chan->topic ? uc->chan->topic : ""));
+ }
+ } else {
+ int i;
+ Channel *c;
+
+ notice_lang(s_OperServ, u, OPER_CHANLIST_HEADER);
+
+ for (i = 0; i < 1024; i++) {
+ for (c = chanlist[i]; c; c = c->next) {
+ if (pattern && !match_wild_nocase(pattern, c->name))
+ continue;
+ if (modes && !(c->mode & modes))
+ continue;
+ notice_lang(s_OperServ, u, OPER_CHANLIST_RECORD, c->name,
+ c->usercount, chan_get_modes(c, 1, 1),
+ (c->topic ? c->topic : ""));
+ }
+ }
+ }
+
+ notice_lang(s_OperServ, u, OPER_CHANLIST_END);
+ return MOD_CONT;
+}
diff --git a/src/core/os_clearmodes.c b/src/core/os_clearmodes.c
new file mode 100644
index 000000000..d6a896166
--- /dev/null
+++ b/src/core/os_clearmodes.c
@@ -0,0 +1,328 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_clearmodes(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("CLEARMODES", do_clearmodes, is_services_oper,
+ OPER_HELP_CLEARMODES, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_CLEARMODES);
+ }
+}
+
+/**
+ * The /os clearmodes command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_clearmodes(User * u)
+{
+ char *s;
+ char *argv[2];
+ char *chan = strtok(NULL, " ");
+ Channel *c;
+ int all = 0;
+ struct c_userlist *cu, *next;
+ Entry *entry, *nexte;
+
+ if (!chan) {
+ syntax_error(s_OperServ, u, "CLEARMODES", OPER_CLEARMODES_SYNTAX);
+ return MOD_CONT;
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);
+ return MOD_CONT;
+ } else if (c->bouncy_modes) {
+ notice_lang(s_OperServ, u, OPER_BOUNCY_MODES_U_LINE);
+ return MOD_CONT;
+ } else {
+ s = strtok(NULL, " ");
+ if (s) {
+ if (stricmp(s, "ALL") == 0) {
+ all = 1;
+ } else {
+ syntax_error(s_OperServ, u, "CLEARMODES",
+ OPER_CLEARMODES_SYNTAX);
+ return MOD_CONT;
+ }
+ }
+
+ if (WallOSClearmodes) {
+ anope_cmd_global(s_OperServ, "%s used CLEARMODES%s on %s",
+ u->nick, all ? " ALL" : "", chan);
+ }
+ if (all) {
+ /* Clear mode +o */
+ if (ircd->svsmode_ucmode) {
+ anope_cmd_svsmode_chan(c->name, "-o", NULL);
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_OP)) {
+ continue;
+ }
+ argv[0] = sstrdup("-o");
+ argv[1] = cu->user->nick;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ } else {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_OP))
+ continue;
+ argv[0] = sstrdup("-o");
+ argv[1] = cu->user->nick;
+ anope_cmd_mode(s_OperServ, c->name, "-o %s",
+ cu->user->nick);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ }
+
+ if (ircd->svsmode_ucmode) {
+ anope_cmd_svsmode_chan(c->name, "-v", NULL);
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_VOICE)) {
+ continue;
+ }
+ argv[0] = sstrdup("-v");
+ argv[1] = cu->user->nick;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ } else {
+ /* Clear mode +v */
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_VOICE))
+ continue;
+ argv[0] = sstrdup("-v");
+ argv[1] = cu->user->nick;
+ anope_cmd_mode(s_OperServ, c->name, "-v %s",
+ cu->user->nick);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ }
+
+ /* Clear mode +h */
+ if (ircd->svsmode_ucmode && ircd->halfop) {
+ anope_cmd_svsmode_chan(c->name, "-h", NULL);
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_HALFOP)) {
+ continue;
+ }
+ argv[0] = sstrdup("-h");
+ argv[1] = cu->user->nick;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ } else {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_HALFOP))
+ continue;
+ argv[0] = sstrdup("-h");
+ argv[1] = cu->user->nick;
+ anope_cmd_mode(s_OperServ, c->name, "-h %s",
+ cu->user->nick);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ }
+ /* Clear mode Owners */
+ if (ircd->svsmode_ucmode && ircd->owner) {
+ anope_cmd_svsmode_chan(c->name, ircd->ownerunset, NULL);
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_HALFOP)) {
+ continue;
+ }
+ argv[0] = sstrdup(ircd->ownerunset);
+ argv[1] = cu->user->nick;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ } else {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_OWNER))
+ continue;
+ argv[0] = sstrdup(ircd->ownerunset);
+ argv[1] = cu->user->nick;
+ anope_cmd_mode(s_OperServ, c->name, "%s %s",
+ ircd->ownerunset, cu->user->nick);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ }
+ /* Clear mode protected or admins */
+ if (ircd->svsmode_ucmode && (ircd->protect || ircd->admin)) {
+
+ anope_cmd_svsmode_chan(c->name, ircd->adminunset, NULL);
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_HALFOP)) {
+ continue;
+ }
+ argv[0] = sstrdup(ircd->adminunset);
+ argv[1] = cu->user->nick;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ } else {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (!chan_has_user_status(c, cu->user, CUS_PROTECT))
+ continue;
+ argv[0] = sstrdup(ircd->adminunset);
+ argv[1] = cu->user->nick;
+ anope_cmd_mode(s_OperServ, c->name, "%s %s",
+ ircd->adminunset, cu->user->nick);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ }
+
+
+ }
+
+ if (c->mode) {
+ /* Clear modes the bulk of the modes */
+ anope_cmd_mode(s_OperServ, c->name, "%s", ircd->modestoremove);
+ argv[0] = sstrdup(ircd->modestoremove);
+ chan_set_modes(s_OperServ, c, 1, argv, 0);
+ free(argv[0]);
+
+ /* to prevent the internals from complaining send -k, -L, -f by themselves if we need
+ to send them - TSL */
+ if (c->key) {
+ anope_cmd_mode(s_OperServ, c->name, "-k %s", c->key);
+ argv[0] = sstrdup("-k");
+ argv[1] = c->key;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ if (ircd->Lmode && c->redirect) {
+ anope_cmd_mode(s_OperServ, c->name, "-L %s", c->redirect);
+ argv[0] = sstrdup("-L");
+ argv[1] = c->redirect;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ }
+ if (ircd->fmode && c->flood) {
+ if (flood_mode_char_remove) {
+ anope_cmd_mode(s_OperServ, c->name, "%s %s",
+ flood_mode_char_remove, c->flood);
+ argv[0] = sstrdup(flood_mode_char_remove);
+ argv[1] = c->flood;
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ } else {
+ if (debug) {
+ alog("debug: flood_mode_char_remove was not set unable to remove flood/throttle modes");
+ }
+ }
+ }
+ }
+
+ /* Clear bans */
+ if (c->bans && c->bans->count) {
+ for (entry = c->bans->entries; entry; entry = nexte) {
+ nexte = entry->next;
+ argv[0] = sstrdup("-b");
+ argv[1] = sstrdup(entry->mask);
+ anope_cmd_mode(s_OperServ, c->name, "-b %s", entry->mask);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ free(argv[1]);
+ }
+ }
+
+ /* Clear excepts */
+ if (ircd->except && c->excepts && c->excepts->count) {
+ for (entry = c->excepts->entries; entry; entry = nexte) {
+ nexte = entry->next;
+ argv[0] = sstrdup("-e");
+ argv[1] = sstrdup(entry->mask);
+ anope_cmd_mode(s_OperServ, c->name, "-e %s", entry->mask);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ free(argv[1]);
+ }
+ }
+
+ /* Clear invites */
+ if (ircd->invitemode && c->invites && c->invites->count) {
+ for (entry = c->invites->entries; entry; entry = nexte) {
+ nexte = entry->next;
+ argv[0] = sstrdup("-I");
+ argv[1] = sstrdup(entry->mask);
+ anope_cmd_mode(s_OperServ, c->name, "-I %s", entry->mask);
+ chan_set_modes(s_OperServ, c, 2, argv, 0);
+ free(argv[0]);
+ free(argv[1]);
+ }
+ }
+ }
+
+ if (all) {
+ notice_lang(s_OperServ, u, OPER_CLEARMODES_ALL_DONE, chan);
+ } else {
+ notice_lang(s_OperServ, u, OPER_CLEARMODES_DONE, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_defcon.c b/src/core/os_defcon.c
new file mode 100644
index 000000000..1f926e720
--- /dev/null
+++ b/src/core/os_defcon.c
@@ -0,0 +1,169 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#ifdef _WIN32
+extern MDE time_t DefContimer;
+extern MDE void runDefCon(void);
+#endif
+int do_defcon(User * u);
+void defcon_sendlvls(User * u);
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("DEFCON", do_defcon, is_services_admin,
+ OPER_HELP_DEFCON, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_DEFCON);
+ }
+}
+
+/**
+ * Defcon - A method of impelemting various stages of securty, the hope is this will help serives
+ * protect a network during an attack, allowing admins to choose the precautions taken at each
+ * level.
+ *
+ * /msg OperServ DefCon [level]
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ *
+ **/
+int do_defcon(User * u)
+{
+ char *lvl = strtok(NULL, " ");
+ int newLevel = 0;
+ char *langglobal;
+ langglobal = getstring(NULL, DEFCON_GLOBAL);
+
+ if (!DefConLevel) { /* If we dont have a .conf setting! */
+ notice_lang(s_OperServ, u, OPER_DEFCON_NO_CONF);
+ return MOD_CONT;
+ }
+
+ if (!lvl) {
+ notice_lang(s_OperServ, u, OPER_DEFCON_CHANGED, DefConLevel);
+ defcon_sendlvls(u);
+ return MOD_CONT;
+ }
+ newLevel = atoi(lvl);
+ if (newLevel < 1 || newLevel > 5) {
+ notice_lang(s_OperServ, u, OPER_DEFCON_SYNTAX);
+ return MOD_CONT;
+ }
+ DefConLevel = newLevel;
+ send_event(EVENT_DEFCON_LEVEL, 1, lvl);
+ DefContimer = time(NULL);
+ notice_lang(s_OperServ, u, OPER_DEFCON_CHANGED, DefConLevel);
+ defcon_sendlvls(u);
+ alog("Defcon level changed to %d by Oper %s", newLevel, u->nick);
+ anope_cmd_global(s_OperServ, getstring2(NULL, OPER_DEFCON_WALL),
+ u->nick, newLevel);
+ /* Global notice the user what is happening. Also any Message that
+ the Admin would like to add. Set in config file. */
+ if (GlobalOnDefcon) {
+ if ((DefConLevel == 5) && (DefConOffMessage)) {
+ oper_global(NULL, "%s", DefConOffMessage);
+ } else {
+ oper_global(NULL, langglobal, DefConLevel);
+ }
+ }
+ if (GlobalOnDefconMore) {
+ if ((DefConOffMessage) && DefConLevel == 5) {
+ } else {
+ oper_global(NULL, "%s", DefconMessage);
+ }
+ }
+ /* Run any defcon functions, e.g. FORCE CHAN MODE */
+ runDefCon();
+ return MOD_CONT;
+}
+
+
+
+/**
+ * Send a message to the oper about which precautions are "active" for this level
+ **/
+void defcon_sendlvls(User * u)
+{
+ if (checkDefCon(DEFCON_NO_NEW_CHANNELS)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_NO_NEW_CHANNELS);
+ }
+ if (checkDefCon(DEFCON_NO_NEW_NICKS)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_NO_NEW_NICKS);
+ }
+ if (checkDefCon(DEFCON_NO_MLOCK_CHANGE)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_NO_MLOCK_CHANGE);
+ }
+ if (checkDefCon(DEFCON_FORCE_CHAN_MODES) && (DefConChanModes)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_FORCE_CHAN_MODES,
+ DefConChanModes);
+ }
+ if (checkDefCon(DEFCON_REDUCE_SESSION)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_REDUCE_SESSION,
+ DefConSessionLimit);
+ }
+ if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_NO_NEW_CLIENTS);
+ }
+ if (checkDefCon(DEFCON_OPER_ONLY)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_OPER_ONLY);
+ }
+ if (checkDefCon(DEFCON_SILENT_OPER_ONLY)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_SILENT_OPER_ONLY);
+ }
+ if (checkDefCon(DEFCON_AKILL_NEW_CLIENTS)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_AKILL_NEW_CLIENTS);
+ }
+ if (checkDefCon(DEFCON_NO_NEW_MEMOS)) {
+ notice_lang(s_OperServ, u, OPER_HELP_DEFCON_NO_NEW_MEMOS);
+ }
+}
diff --git a/src/core/os_global.c b/src/core/os_global.c
new file mode 100644
index 000000000..ccbabebb9
--- /dev/null
+++ b/src/core/os_global.c
@@ -0,0 +1,82 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_global(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("GLOBAL", do_global, is_services_admin,
+ OPER_HELP_GLOBAL, -1, -1, -1, -1);
+ c->help_param1 = s_GlobalNoticer;
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_GLOBAL);
+ }
+}
+
+/**
+ * The /os global command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_global(User * u)
+{
+ char *msg = strtok(NULL, "");
+
+ if (!msg) {
+ syntax_error(s_OperServ, u, "GLOBAL", OPER_GLOBAL_SYNTAX);
+ return MOD_CONT;
+ }
+ if (WallOSGlobal)
+ anope_cmd_global(s_OperServ, "\2%s\2 just used GLOBAL command.",
+ u->nick);
+ oper_global(u->nick, "%s", msg);
+ return MOD_CONT;
+}
diff --git a/src/core/os_help.c b/src/core/os_help.c
new file mode 100644
index 000000000..822d1dcd0
--- /dev/null
+++ b/src/core/os_help.c
@@ -0,0 +1,66 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_help(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("HELP", do_help, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+
+/**
+ * The /os help command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_help(User * u)
+{
+ const char *cmd = strtok(NULL, "");
+
+ if (!cmd) {
+ notice_help(s_OperServ, u, OPER_HELP);
+ moduleDisplayHelp(5, u);
+ notice_help(s_OperServ, u, OPER_HELP_LOGGED);
+ } else {
+ mod_help_cmd(s_OperServ, u, OPERSERV, cmd);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_ignore.c b/src/core/os_ignore.c
new file mode 100644
index 000000000..a5fb07d1c
--- /dev/null
+++ b/src/core/os_ignore.c
@@ -0,0 +1,146 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_ignorelist(User * u);
+void myOperServHelp(User * u);
+int do_ignoreuser(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("IGNORE", do_ignoreuser, is_services_admin,
+ OPER_HELP_IGNORE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_IGNORE);
+ }
+}
+
+/**
+ * The /os ignore command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_ignoreuser(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ int t;
+
+ if (!cmd) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (!stricmp(cmd, "ADD")) {
+ char *time = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ char *rest = strtok(NULL, "");
+
+ if (!nick) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_SYNTAX);
+ return MOD_CONT;
+ } else if (!time) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_SYNTAX);
+ return MOD_CONT;
+ } else {
+ t = dotime(time);
+ rest = NULL;
+
+ if (t <= -1) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_VALID_TIME);
+ return MOD_CONT;
+ } else if (t == 0) {
+ add_ignore(nick, t);
+ notice_lang(s_OperServ, u, OPER_IGNORE_PERM_DONE, nick);
+ } else {
+ add_ignore(nick, t);
+ notice_lang(s_OperServ, u, OPER_IGNORE_TIME_DONE, nick, time);
+ }
+ }
+ } else if (!stricmp(cmd, "LIST")) {
+ do_ignorelist(u);
+
+ } else if (!stricmp(cmd, "DEL")) {
+ char *nick = strtok(NULL, " ");
+ if (!nick) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_SYNTAX);
+ } else {
+ if (delete_ignore(nick)) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_DEL_DONE, nick);
+ return MOD_CONT;
+ }
+ notice_lang(s_OperServ, u, OPER_IGNORE_LIST_NOMATCH, nick);
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ clear_ignores();
+ notice_lang(s_OperServ, u, OPER_IGNORE_LIST_CLEARED);
+ return MOD_CONT;
+ } else
+ notice_lang(s_OperServ, u, OPER_IGNORE_SYNTAX);
+
+ return MOD_CONT;
+}
+
+/* shows the Services ignore list */
+int do_ignorelist(User * u)
+{
+ IgnoreData *id;
+
+ if (!ignore) {
+ notice_lang(s_OperServ, u, OPER_IGNORE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ notice_lang(s_OperServ, u, OPER_IGNORE_LIST);
+ for (id = ignore; id; id = id->next)
+ notice_user(s_OperServ, u, "%s", id->mask);
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/os_jupe.c b/src/core/os_jupe.c
new file mode 100644
index 000000000..5a3ff8a94
--- /dev/null
+++ b/src/core/os_jupe.c
@@ -0,0 +1,88 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_jupe(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("JUPE", do_jupe, is_services_admin, OPER_HELP_JUPE,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_JUPE);
+ }
+}
+
+/**
+ * The /os jupe command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_jupe(User * u)
+{
+ char *jserver = strtok(NULL, " ");
+ char *reason = strtok(NULL, "");
+
+ if (!jserver) {
+ syntax_error(s_OperServ, u, "JUPE", OPER_JUPE_SYNTAX);
+ } else {
+ if (!isValidHost(jserver, 3)) {
+ notice_lang(s_OperServ, u, OPER_JUPE_HOST_ERROR);
+ } else {
+ anope_cmd_jupe(jserver, u->nick, reason);
+
+ if (WallOSJupe)
+ anope_cmd_global(s_OperServ, "\2%s\2 used JUPE on \2%s\2",
+ u->nick, jserver);
+ }
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_kick.c b/src/core/os_kick.c
new file mode 100644
index 000000000..facab5fc5
--- /dev/null
+++ b/src/core/os_kick.c
@@ -0,0 +1,100 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_os_kick(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("KICK", do_os_kick, is_services_oper, OPER_HELP_KICK,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_KICK);
+ }
+}
+
+/**
+ * The /os kick command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_os_kick(User * u)
+{
+ char *argv[3];
+ char *chan, *nick, *s;
+ Channel *c;
+
+ chan = strtok(NULL, " ");
+ nick = strtok(NULL, " ");
+ s = strtok(NULL, "");
+ if (!chan || !nick || !s) {
+ syntax_error(s_OperServ, u, "KICK", OPER_KICK_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!(c = findchan(chan))) {
+ notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (c->bouncy_modes) {
+ notice_lang(s_OperServ, u, OPER_BOUNCY_MODES_U_LINE);
+ return MOD_CONT;
+ }
+ anope_cmd_kick(s_OperServ, chan, nick, "%s (%s)", u->nick, s);
+ if (WallOSKick)
+ anope_cmd_global(s_OperServ, "%s used KICK on %s/%s", u->nick,
+ nick, chan);
+ argv[0] = sstrdup(chan);
+ argv[1] = sstrdup(nick);
+ argv[2] = sstrdup(s);
+ do_kick(s_OperServ, 3, argv);
+ free(argv[2]);
+ free(argv[1]);
+ free(argv[0]);
+ return MOD_CONT;
+}
diff --git a/src/core/os_logonnews.c b/src/core/os_logonnews.c
new file mode 100644
index 000000000..20516c473
--- /dev/null
+++ b/src/core/os_logonnews.c
@@ -0,0 +1,98 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+Command *c;
+
+void myOperServHelp(User * u);
+int load_config(void);
+int reload_config(int argc, char **argv);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+ char buf[BUFSIZE];
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ /**
+ * For some unknown reason, do_logonnews is actaully defined in news.c
+ * we can look at moving it here later
+ **/
+ c = createCommand("LOGONNEWS", do_logonnews, is_services_admin,
+ NEWS_HELP_LOGON, -1, -1, -1, -1);
+ snprintf(buf, BUFSIZE, "%d", NewsCount),
+ c->help_param1 = sstrdup(buf);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ hook = createEventHook(EVENT_RELOAD, reload_config);
+ if (moduleAddEventHook(hook) != MOD_ERR_OK) {
+ alog("[\002os_logonnews\002] Can't hook to EVENT_RELOAD event");
+ return MOD_STOP;
+ }
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+ free(c->help_param1);
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_LOGONNEWS);
+ }
+}
+
+
+/**
+ * Upon /os reload refresh the count
+ **/
+int reload_config(int argc, char **argv) {
+ char buf[BUFSIZE];
+
+ if (argc >= 1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ free(c->help_param1);
+ snprintf(buf, BUFSIZE, "%d", NewsCount),
+ c->help_param1 = sstrdup(buf);
+ }
+ }
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/os_mode.c b/src/core/os_mode.c
new file mode 100644
index 000000000..c3d5c6624
--- /dev/null
+++ b/src/core/os_mode.c
@@ -0,0 +1,102 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_os_mode(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("MODE", do_os_mode, is_services_oper, OPER_HELP_MODE,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_MODE);
+ }
+}
+
+/**
+ * The /os mode command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_os_mode(User * u)
+{
+ int ac;
+ char **av;
+ char *chan = strtok(NULL, " "), *modes = strtok(NULL, "");
+ Channel *c;
+
+ if (!chan || !modes) {
+ syntax_error(s_OperServ, u, "MODE", OPER_MODE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (c->bouncy_modes) {
+ notice_lang(s_OperServ, u, OPER_BOUNCY_MODES_U_LINE);
+ return MOD_CONT;
+ } else if ((ircd->adminmode) && (!is_services_admin(u))
+ && (c->mode & ircd->adminmode)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ } else {
+ anope_cmd_mode(s_OperServ, chan, "%s", modes);
+
+ ac = split_buf(modes, &av, 1);
+ chan_set_modes(s_OperServ, c, ac, av, -1);
+ free(av);
+
+ if (WallOSMode)
+ anope_cmd_global(s_OperServ, "%s used MODE %s on %s", u->nick,
+ modes, chan);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_modinfo.c b/src/core/os_modinfo.c
new file mode 100644
index 000000000..fde25f0a2
--- /dev/null
+++ b/src/core/os_modinfo.c
@@ -0,0 +1,139 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_modinfo(User * u);
+void myOperServHelp(User * u);
+int showModuleMsgLoaded(MessageHash * msgList, char *mod_name, User * u);
+int showModuleCmdLoaded(CommandHash * cmdList, char *mod_name, User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("MODINFO", do_modinfo, NULL, -1, -1, -1, -1,
+ OPER_HELP_MODINFO);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_MODINFO);
+}
+
+/**
+ * The /os command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_modinfo(User * u)
+{
+ char *file;
+ struct tm tm;
+ char timebuf[64];
+ Module *m;
+ int idx = 0;
+
+ file = strtok(NULL, "");
+ if (!file) {
+ syntax_error(s_OperServ, u, "MODINFO", OPER_MODULE_INFO_SYNTAX);
+ return MOD_CONT;
+ }
+ m = findModule(file);
+ if (m) {
+ tm = *localtime(&m->time);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_DATE_TIME_FORMAT, &tm);
+ notice_lang(s_OperServ, u, OPER_MODULE_INFO_LIST, m->name,
+ m->version ? m->version : "?",
+ m->author ? m->author : "?", timebuf);
+ for (idx = 0; idx < MAX_CMD_HASH; idx++) {
+ showModuleCmdLoaded(HOSTSERV[idx], m->name, u);
+ showModuleCmdLoaded(OPERSERV[idx], m->name, u);
+ showModuleCmdLoaded(NICKSERV[idx], m->name, u);
+ showModuleCmdLoaded(CHANSERV[idx], m->name, u);
+ showModuleCmdLoaded(BOTSERV[idx], m->name, u);
+ showModuleCmdLoaded(MEMOSERV[idx], m->name, u);
+ showModuleCmdLoaded(HELPSERV[idx], m->name, u);
+ showModuleMsgLoaded(IRCD[idx], m->name, u);
+
+ }
+ } else {
+ notice_lang(s_OperServ, u, OPER_MODULE_NO_INFO, file);
+ }
+ return MOD_CONT;
+}
+
+int showModuleCmdLoaded(CommandHash * cmdList, char *mod_name, User * u)
+{
+ Command *c;
+ CommandHash *current;
+ int display = 0;
+
+ for (current = cmdList; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (stricmp(c->mod_name, mod_name) == 0)) {
+ notice_lang(s_OperServ, u, OPER_MODULE_CMD_LIST,
+ c->service, c->name);
+ display++;
+ }
+ }
+ }
+ return display;
+}
+
+int showModuleMsgLoaded(MessageHash * msgList, char *mod_name, User * u)
+{
+ Message *msg;
+ MessageHash *mcurrent;
+ int display = 0;
+ for (mcurrent = msgList; mcurrent; mcurrent = mcurrent->next) {
+ for (msg = mcurrent->m; msg; msg = msg->next) {
+ if ((msg->mod_name) && (stricmp(msg->mod_name, mod_name) == 0)) {
+ notice_lang(s_OperServ, u, OPER_MODULE_MSG_LIST,
+ msg->name);
+ display++;
+ }
+ }
+ }
+ return display;
+}
diff --git a/src/core/os_modlist.c b/src/core/os_modlist.c
new file mode 100644
index 000000000..8feddbea6
--- /dev/null
+++ b/src/core/os_modlist.c
@@ -0,0 +1,195 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_modlist(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("MODLIST", do_modlist, NULL, -1, -1, -1, -1,
+ OPER_HELP_MODLIST);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_MODLIST);
+}
+
+/**
+ * The /os modlist command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_modlist(User * u)
+{
+ int idx;
+ int count = 0;
+ int showCore = 0;
+ int showThird = 1;
+ int showProto = 1;
+ int showEnc = 1;
+ int showSupported = 1;
+ int showQA = 1;
+
+ char *param;
+ ModuleHash *current = NULL;
+
+ char core[] = "Core";
+ char third[] = "3rd";
+ char proto[] = "Protocol";
+ char enc[] = "Encryption";
+ char supported[] = "Supported";
+ char qa[] = "QATested";
+
+ param = strtok(NULL, "");
+ if (param) {
+ if (stricmp(param, core) == 0) {
+ showCore = 1;
+ showThird = 0;
+ showProto = 0;
+ showEnc = 0;
+ showSupported = 0;
+ showQA = 0;
+ } else if (stricmp(param, third) == 0) {
+ showCore = 0;
+ showThird = 1;
+ showSupported = 0;
+ showQA = 0;
+ showProto = 0;
+ showEnc = 0;
+ } else if (stricmp(param, proto) == 0) {
+ showCore = 0;
+ showThird = 0;
+ showProto = 1;
+ showEnc = 0;
+ showSupported = 0;
+ showQA = 0;
+ } else if (stricmp(param, supported) == 0) {
+ showCore = 0;
+ showThird = 0;
+ showProto = 0;
+ showSupported = 1;
+ showEnc = 0;
+ showQA = 0;
+ } else if (stricmp(param, qa) == 0) {
+ showCore = 0;
+ showThird = 0;
+ showProto = 0;
+ showSupported = 0;
+ showEnc = 0;
+ showQA = 1;
+ } else if (stricmp(param, enc) == 0) {
+ showCore = 0;
+ showThird = 0;
+ showProto = 0;
+ showSupported = 0;
+ showEnc = 1;
+ showQA = 0;
+ }
+ }
+
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST_HEADER);
+
+ for (idx = 0; idx != MAX_CMD_HASH; idx++) {
+ for (current = MODULE_HASH[idx]; current; current = current->next) {
+ switch (current->m->type) {
+ case CORE:
+ if (showCore) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version, core);
+ count++;
+ }
+ break;
+ case THIRD:
+ if (showThird) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version, third);
+ count++;
+ }
+ break;
+ case PROTOCOL:
+ if (showProto) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version, proto);
+ count++;
+ }
+ break;
+ case SUPPORTED:
+ if (showSupported) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version,
+ supported);
+ count++;
+ }
+ break;
+ case QATESTED:
+ if (showQA) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version, qa);
+ count++;
+ }
+ break;
+ case ENCRYPTION:
+ if (showEnc) {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST,
+ current->name, current->m->version, enc);
+ count++;
+ }
+ break;
+
+ }
+
+ }
+ }
+ if (count == 0) {
+ notice_lang(s_OperServ, u, OPER_MODULE_NO_LIST);
+ } else {
+ notice_lang(s_OperServ, u, OPER_MODULE_LIST_FOOTER, count);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/core/os_modload.c b/src/core/os_modload.c
new file mode 100644
index 000000000..bcb70c551
--- /dev/null
+++ b/src/core/os_modload.c
@@ -0,0 +1,83 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_modload(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("MODLOAD", do_modload, is_services_root, -1, -1, -1,
+ -1, OPER_HELP_MODLOAD);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_MODLOAD);
+ }
+}
+
+/**
+ * The /os modload command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_modload(User * u)
+{
+ char *name;
+
+ name = strtok(NULL, "");
+ if (!name) {
+ syntax_error(s_OperServ, u, "MODLOAD", OPER_MODULE_LOAD_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!queueModuleLoad(name, u))
+ notice_lang(s_OperServ, u, OPER_MODULE_LOAD_FAIL, name);
+
+ return MOD_CONT;
+}
diff --git a/src/core/os_modunload.c b/src/core/os_modunload.c
new file mode 100644
index 000000000..a27c5ba6a
--- /dev/null
+++ b/src/core/os_modunload.c
@@ -0,0 +1,85 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_modunload(User * u);
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("MODUNLOAD", do_modunload, is_services_root, -1, -1,
+ -1, -1, OPER_HELP_MODUNLOAD);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_MODUNLOAD);
+ }
+}
+
+/**
+ * The /os modunload command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_modunload(User * u)
+{
+ char *name;
+
+ name = strtok(NULL, "");
+ if (!name) {
+ syntax_error(s_OperServ, u, "MODUNLOAD",
+ OPER_MODULE_UNLOAD_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!queueModuleUnload(name, u))
+ notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, name);
+
+ return MOD_CONT;
+}
diff --git a/src/core/os_noop.c b/src/core/os_noop.c
new file mode 100644
index 000000000..1d2b19d0e
--- /dev/null
+++ b/src/core/os_noop.c
@@ -0,0 +1,106 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_noop(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("NOOP", do_noop, is_services_admin, OPER_HELP_NOOP,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_NOOP);
+ }
+}
+
+/**
+ * The /os noop command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_noop(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *server = strtok(NULL, " ");
+
+ if (!cmd || !server) {
+ syntax_error(s_OperServ, u, "NOOP", OPER_NOOP_SYNTAX);
+ } else if (!stricmp(cmd, "SET")) {
+ User *u2;
+ User *u3 = NULL;
+ char reason[NICKMAX + 32];
+
+ /* Remove the O:lines */
+ anope_cmd_svsnoop(server, 1);
+
+ snprintf(reason, sizeof(reason), "NOOP command used by %s",
+ u->nick);
+ if (WallOSNoOp)
+ anope_cmd_global(s_OperServ, "\2%s\2 used NOOP on \2%s\2",
+ u->nick, server);
+ notice_lang(s_OperServ, u, OPER_NOOP_SET, server);
+
+ /* Kill all the IRCops of the server */
+ for (u2 = firstuser(); u2; u2 = u3) {
+ u3 = nextuser();
+ if ((u2) && is_oper(u2) && (u2->server->name)
+ && match_wild(server, u2->server->name)) {
+ kill_user(s_OperServ, u2->nick, reason);
+ }
+ }
+ } else if (!stricmp(cmd, "REVOKE")) {
+ anope_cmd_svsnoop(server, 0);
+ notice_lang(s_OperServ, u, OPER_NOOP_REVOKE, server);
+ } else {
+ syntax_error(s_OperServ, u, "NOOP", OPER_NOOP_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_oline.c b/src/core/os_oline.c
new file mode 100644
index 000000000..8e8b18730
--- /dev/null
+++ b/src/core/os_oline.c
@@ -0,0 +1,108 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+int do_operoline(User * u);
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("OLINE", do_operoline, is_services_root,
+ OPER_HELP_OLINE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ if (!ircd->omode) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u) && u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_OLINE);
+ }
+}
+
+/**
+ * The /os oline command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_operoline(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *flags = strtok(NULL, "");
+ User *u2 = NULL;
+
+ /* Only allow this if SuperAdmin is enabled */
+ if (!u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_ONLY);
+ return MOD_CONT;
+ }
+
+ if (!nick || !flags) {
+ syntax_error(s_OperServ, u, "OLINE", OPER_OLINE_SYNTAX);
+ return MOD_CONT;
+ } else {
+ /* let's check whether the user is online */
+ if (!(u2 = finduser(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (u2 && flags[0] == '+') {
+ anope_cmd_svso(s_OperServ, nick, flags);
+ anope_cmd_mode(s_OperServ, nick, "+o");
+ common_svsmode(u2, "+o", NULL);
+ notice_lang(s_OperServ, u2, OPER_OLINE_IRCOP);
+ notice_lang(s_OperServ, u, OPER_OLINE_SUCCESS, flags, nick);
+ anope_cmd_global(s_OperServ, "\2%s\2 used OLINE for %s",
+ u->nick, nick);
+ } else if (u2 && flags[0] == '-') {
+ anope_cmd_svso(s_OperServ, nick, flags);
+ notice_lang(s_OperServ, u, OPER_OLINE_SUCCESS, flags, nick);
+ anope_cmd_global(s_OperServ, "\2%s\2 used OLINE for %s",
+ u->nick, nick);
+ } else
+ syntax_error(s_OperServ, u, "OLINE", OPER_OLINE_SYNTAX);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_oper.c b/src/core/os_oper.c
new file mode 100644
index 000000000..a0ab70919
--- /dev/null
+++ b/src/core/os_oper.c
@@ -0,0 +1,252 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_oper(User * u);
+int oper_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int oper_list(int number, NickCore * nc, User * u, int *sent_header);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("OPER", do_oper, NULL, OPER_HELP_OPER, -1, -1, -1,
+ -1);
+ c->help_param1 = s_NickServ;
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_OPER);
+}
+
+/**
+ * The /os oper command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_oper(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *nick = strtok(NULL, " ");
+ NickAlias *na;
+ int res = 0;
+
+ if (skeleton) {
+ notice_lang(s_OperServ, u, OPER_OPER_SKELETON);
+ return MOD_CONT;
+ }
+
+ if (!cmd || (!nick && stricmp(cmd, "LIST") && stricmp(cmd, "CLEAR"))) {
+ syntax_error(s_OperServ, u, "OPER", OPER_OPER_SYNTAX);
+ } else if (!stricmp(cmd, "ADD")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (!(na = findnick(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+
+ if (na->nc->flags & NI_SERVICES_OPER
+ || slist_indexof(&servopers, na->nc) != -1) {
+ notice_lang(s_OperServ, u, OPER_OPER_EXISTS, nick);
+ return MOD_CONT;
+ }
+
+ res = slist_add(&servopers, na->nc);
+ if (res == -2) {
+ notice_lang(s_OperServ, u, OPER_OPER_REACHED_LIMIT, nick);
+ return MOD_CONT;
+ } else {
+ if (na->nc->flags & NI_SERVICES_ADMIN
+ && (res = slist_indexof(&servadmins, na->nc)) != -1) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+ slist_delete(&servadmins, res);
+ na->nc->flags |= NI_SERVICES_OPER;
+ notice_lang(s_OperServ, u, OPER_OPER_MOVED, nick);
+ } else {
+ na->nc->flags |= NI_SERVICES_OPER;
+ notice_lang(s_OperServ, u, OPER_OPER_ADDED, nick);
+ }
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else if (!stricmp(cmd, "DEL")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*nick) && strspn(nick, "1234567890,-") == strlen(nick)) {
+ /* Deleting a range */
+ res = slist_delete_range(&servopers, nick, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_OPER_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_OPER_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_OPER_DELETED_SEVERAL, res);
+ }
+ } else {
+ if (!(na = findnick(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);
+ return MOD_CONT;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, nick);
+ return MOD_CONT;
+ }
+
+ if (!(na->nc->flags & NI_SERVICES_OPER)
+ || (res = slist_indexof(&servopers, na->nc)) == -1) {
+ notice_lang(s_OperServ, u, OPER_OPER_NOT_FOUND, nick);
+ return MOD_CONT;
+ }
+
+ slist_delete(&servopers, res);
+ notice_lang(s_OperServ, u, OPER_OPER_DELETED, nick);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else if (!stricmp(cmd, "LIST")) {
+ int sent_header = 0;
+
+ if (!is_oper(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (servopers.count == 0) {
+ notice_lang(s_OperServ, u, OPER_OPER_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (!nick || (isdigit(*nick)
+ && strspn(nick, "1234567890,-") == strlen(nick))) {
+ res =
+ slist_enum(&servopers, nick, &oper_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_OPER_NO_MATCH);
+ return MOD_CONT;
+ } else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Oper");
+ }
+ } else {
+ int i;
+
+ for (i = 0; i < servopers.count; i++)
+ if (!stricmp
+ (nick, ((NickCore *) servopers.list[i])->display)
+ || match_wild_nocase(nick,
+ ((NickCore *) servopers.list[i])->
+ display))
+ oper_list(i + 1, servopers.list[i], u, &sent_header);
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_OPER_NO_MATCH);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Oper");
+ }
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ if (!is_services_root(u)) {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ return MOD_CONT;
+ }
+
+ if (servopers.count == 0) {
+ notice_lang(s_OperServ, u, OPER_OPER_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ slist_clear(&servopers, 1);
+ notice_lang(s_OperServ, u, OPER_OPER_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "OPER", OPER_OPER_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/* Lists an oper entry, prefixing it with the header if needed */
+
+int oper_list(int number, NickCore * nc, User * u, int *sent_header)
+{
+ if (!nc)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_OPER_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_OperServ, u, OPER_OPER_LIST_FORMAT, number, nc->display);
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int oper_list_callback(SList * slist, int number, void *item, va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return oper_list(number, item, u, sent_header);
+}
diff --git a/src/core/os_opernews.c b/src/core/os_opernews.c
new file mode 100644
index 000000000..dc9b3006a
--- /dev/null
+++ b/src/core/os_opernews.c
@@ -0,0 +1,97 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+Command *c;
+
+void myOperServHelp(User * u);
+int load_config(void);
+int reload_config(int argc, char **argv);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+ char buf[BUFSIZE];
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ /**
+ * For some unknown reason, do_opernews is actaully defined in news.c
+ * we can look at moving it here later
+ **/
+ c = createCommand("OPERNEWS", do_opernews, is_services_admin,
+ NEWS_HELP_OPER, -1, -1, -1, -1);
+ snprintf(buf, BUFSIZE, "%d", NewsCount),
+ c->help_param1 = sstrdup(buf);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ hook = createEventHook(EVENT_RELOAD, reload_config);
+ if (moduleAddEventHook(hook) != MOD_ERR_OK) {
+ alog("[\002os_opernews\002] Can't hook to EVENT_RELOAD event");
+ return MOD_STOP;
+ }
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+ free(c->help_param1);
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_OPERNEWS);
+ }
+}
+
+/**
+ * Upon /os reload refresh the count
+ **/
+int reload_config(int argc, char **argv) {
+ char buf[BUFSIZE];
+
+ if (argc >= 1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ free(c->help_param1);
+ snprintf(buf, BUFSIZE, "%d", NewsCount),
+ c->help_param1 = sstrdup(buf);
+ }
+ }
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/core/os_quit.c b/src/core/os_quit.c
new file mode 100644
index 000000000..65fd31123
--- /dev/null
+++ b/src/core/os_quit.c
@@ -0,0 +1,82 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_os_quit(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("QUIT", do_os_quit, is_services_root,
+ OPER_HELP_QUIT, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_QUIT);
+ }
+}
+
+/**
+ * The /os quit command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_os_quit(User * u)
+{
+ quitmsg = calloc(28 + strlen(u->nick), 1);
+ if (!quitmsg)
+ quitmsg = "QUIT command received, but out of memory!";
+ else
+ sprintf(quitmsg, "QUIT command received from %s", u->nick);
+
+ if (GlobalOnCycle) {
+ oper_global(NULL, "%s", GlobalOnCycleMessage);
+ }
+ quitting = 1;
+ return MOD_CONT;
+}
diff --git a/src/core/os_randomnews.c b/src/core/os_randomnews.c
new file mode 100644
index 000000000..e29cfc796
--- /dev/null
+++ b/src/core/os_randomnews.c
@@ -0,0 +1,66 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ /**
+ * For some unknown reason, do_randomnews is actaully defined in news.c
+ * we can look at moving it here later
+ **/
+ c = createCommand("RANDOMNEWS", do_randomnews, is_services_admin,
+ NEWS_HELP_RANDOM, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_RANDOMNEWS);
+ }
+}
diff --git a/src/core/os_raw.c b/src/core/os_raw.c
new file mode 100644
index 000000000..9832225dd
--- /dev/null
+++ b/src/core/os_raw.c
@@ -0,0 +1,78 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_raw(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(THIRD);
+
+ c = createCommand("RAW", do_raw, is_services_root, OPER_HELP_RAW, -1,
+ -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ if (DisableRaw) {
+ alog("[os_raw] Unloading because DisableRaw is enabled");
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * The /os raw command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_raw(User * u)
+{
+ char *text = strtok(NULL, "");
+ if (!text)
+ syntax_error(s_OperServ, u, "RAW", OPER_RAW_SYNTAX);
+ else {
+ send_cmd(NULL, "%s", text);
+ if (WallOSRaw) {
+ char *kw = strtok(text, " ");
+ while (kw && *kw == ':')
+ kw = strtok(NULL, " ");
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 used RAW command for \2%s\2",
+ u->nick,
+ (kw ? kw : "\2non RFC compliant message\2"));
+ }
+ alog("%s used RAW command for %s", u->nick, text);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_reload.c b/src/core/os_reload.c
new file mode 100644
index 000000000..6f2a4a406
--- /dev/null
+++ b/src/core/os_reload.c
@@ -0,0 +1,84 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_reload(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("RELOAD", do_reload, is_services_root,
+ OPER_HELP_RELOAD, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_RELOAD);
+ }
+}
+
+/**
+ * The /os relaod command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_reload(User * u)
+{
+ if (!read_config(1)) {
+ quitmsg = calloc(28 + strlen(u->nick), 1);
+ if (!quitmsg)
+ quitmsg =
+ "Error during the reload of the configuration file, but out of memory!";
+ else
+ sprintf(quitmsg,
+ "Error during the reload of the configuration file!");
+ quitting = 1;
+ }
+ send_event(EVENT_RELOAD, 1, EVENT_START);
+ notice_lang(s_OperServ, u, OPER_RELOAD);
+ return MOD_CONT;
+}
diff --git a/src/core/os_restart.c b/src/core/os_restart.c
new file mode 100644
index 000000000..d1beec8b1
--- /dev/null
+++ b/src/core/os_restart.c
@@ -0,0 +1,91 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#ifdef _WIN32
+/* OperServ restart needs access to this if were gonna avoid sending ourself a signal */
+extern MDE void do_restart_services(void);
+#endif
+
+int do_restart(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+ c = createCommand("RESTART", do_restart, is_services_root,
+ OPER_HELP_RESTART, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_RESTART);
+ }
+}
+
+/**
+ * The /os restart command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_restart(User * u)
+{
+#ifdef SERVICES_BIN
+ quitmsg = calloc(31 + strlen(u->nick), 1);
+ if (!quitmsg)
+ quitmsg = "RESTART command received, but out of memory!";
+ else
+ sprintf(quitmsg, "RESTART command received from %s", u->nick);
+
+ if (GlobalOnCycle) {
+ oper_global(NULL, "%s", GlobalOnCycleMessage);
+ }
+ /* raise(SIGHUP); */
+ do_restart_services();
+#else
+ notice_lang(s_OperServ, u, OPER_CANNOT_RESTART);
+#endif
+ return MOD_CONT;
+}
diff --git a/src/core/os_session.c b/src/core/os_session.c
new file mode 100644
index 000000000..9c9498a15
--- /dev/null
+++ b/src/core/os_session.c
@@ -0,0 +1,68 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ /**
+ * do_session/do_exception are exported from sessions.c - we just want to provide an interface.
+ **/
+ c = createCommand("SESSION", do_session, is_services_oper,
+ OPER_HELP_SESSION, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("EXCEPTION", do_exception, is_services_oper,
+ OPER_HELP_EXCEPTION, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SESSION);
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_EXCEPTION);
+ }
+}
diff --git a/src/core/os_set.c b/src/core/os_set.c
new file mode 100644
index 000000000..7b533b8f0
--- /dev/null
+++ b/src/core/os_set.c
@@ -0,0 +1,264 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_set(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SET", do_set, is_services_root, OPER_HELP_SET, -1,
+ -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET LIST", NULL, NULL, OPER_HELP_SET_LIST, -1, -1,
+ -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET READONLY", NULL, NULL, OPER_HELP_SET_READONLY,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET LOGCHAN", NULL, NULL, OPER_HELP_SET_LOGCHAN, -1,
+ -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET DEBUG", NULL, NULL, OPER_HELP_SET_DEBUG, -1, -1,
+ -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET NOEXPIRE", NULL, NULL, OPER_HELP_SET_NOEXPIRE,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET IGNORE", NULL, NULL, OPER_HELP_SET_IGNORE, -1,
+ -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("SET SUPERADMIN", NULL, NULL,
+ OPER_HELP_SET_SUPERADMIN, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+#ifdef USE_MYSQL
+ c = createCommand("SET SQL", NULL, NULL, OPER_HELP_SET_SQL, -1, -1, -1,
+ -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+#endif
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SET);
+ }
+}
+
+/**
+ * The /os set command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_set(User * u)
+{
+ char *option = strtok(NULL, " ");
+ char *setting = strtok(NULL, " ");
+ int index;
+ Channel *c;
+
+ if (!option) {
+ syntax_error(s_OperServ, u, "SET", OPER_SET_SYNTAX);
+ } else if (stricmp(option, "LIST") == 0) {
+ index =
+ (allow_ignore ? OPER_SET_LIST_OPTION_ON :
+ OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "IGNORE");
+ index =
+ (readonly ? OPER_SET_LIST_OPTION_ON :
+ OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "READONLY");
+ index =
+ (logchan ? OPER_SET_LIST_OPTION_ON : OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "LOGCHAN");
+ index =
+ (debug ? OPER_SET_LIST_OPTION_ON : OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "DEBUG");
+ index =
+ (noexpire ? OPER_SET_LIST_OPTION_ON :
+ OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "NOEXPIRE");
+#ifdef USE_MYSQL
+ index =
+ (do_mysql ? OPER_SET_LIST_OPTION_ON :
+ OPER_SET_LIST_OPTION_OFF);
+ notice_lang(s_OperServ, u, index, "SQL");
+#endif
+ } else if (!setting) {
+ syntax_error(s_OperServ, u, "SET", OPER_SET_SYNTAX);
+ } else if (stricmp(option, "IGNORE") == 0) {
+ if (stricmp(setting, "on") == 0) {
+ allow_ignore = 1;
+ notice_lang(s_OperServ, u, OPER_SET_IGNORE_ON);
+ } else if (stricmp(setting, "off") == 0) {
+ allow_ignore = 0;
+ notice_lang(s_OperServ, u, OPER_SET_IGNORE_OFF);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_IGNORE_ERROR);
+ }
+#ifdef USE_MYSQL
+ } else if (stricmp(option, "SQL") == 0) {
+ if (stricmp(setting, "on") == 0) {
+ if (!MysqlHost) {
+ notice_lang(s_OperServ, u, OPER_SET_SQL_ERROR_DISABLED);
+ } else {
+ if (rdb_init()) {
+ notice_lang(s_OperServ, u, OPER_SET_SQL_ON);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_SQL_ERROR_INIT);
+ }
+ }
+ } else if (stricmp(setting, "off") == 0) {
+ if (!MysqlHost) {
+ notice_lang(s_OperServ, u, OPER_SET_SQL_ERROR_DISABLED);
+ } else {
+ /* could call rdb_close() but that does nothing - TSL */
+ do_mysql = 0;
+ notice_lang(s_OperServ, u, OPER_SET_SQL_OFF);
+ }
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_SQL_ERROR);
+ }
+#endif
+ } else if (stricmp(option, "READONLY") == 0) {
+ if (stricmp(setting, "on") == 0) {
+ readonly = 1;
+ alog("Read-only mode activated");
+ close_log();
+ notice_lang(s_OperServ, u, OPER_SET_READONLY_ON);
+ } else if (stricmp(setting, "off") == 0) {
+ readonly = 0;
+ open_log();
+ alog("Read-only mode deactivated");
+ notice_lang(s_OperServ, u, OPER_SET_READONLY_OFF);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_READONLY_ERROR);
+ }
+
+ } else if (stricmp(option, "LOGCHAN") == 0) {
+ /* Unlike the other SET commands where only stricmp is necessary,
+ * we also have to ensure that LogChannel is defined or we can't
+ * send to it.
+ *
+ * -jester
+ */
+ if (LogChannel && (stricmp(setting, "on") == 0)) {
+ if (ircd->join2msg) {
+ c = findchan(LogChannel);
+ anope_cmd_join(s_GlobalNoticer, LogChannel, c ? c->creation_time : time(NULL));
+ }
+ logchan = 1;
+ alog("Now sending log messages to %s", LogChannel);
+ notice_lang(s_OperServ, u, OPER_SET_LOGCHAN_ON, LogChannel);
+ } else if (LogChannel && (stricmp(setting, "off") == 0)) {
+ alog("No longer sending log messages to a channel");
+ if (ircd->join2msg) {
+ anope_cmd_part(s_GlobalNoticer, LogChannel, NULL);
+ }
+ logchan = 0;
+ notice_lang(s_OperServ, u, OPER_SET_LOGCHAN_OFF);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_LOGCHAN_ERROR);
+ }
+ /**
+ * Allow the user to turn super admin on/off
+ *
+ * Rob
+ **/
+ } else if (stricmp(option, "SUPERADMIN") == 0) {
+ if (!SuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_NOT_ENABLED);
+ } else if (stricmp(setting, "on") == 0) {
+ u->isSuperAdmin = 1;
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_ON);
+ alog("%s: %s is a SuperAdmin ", s_OperServ, u->nick);
+ anope_cmd_global(s_OperServ,
+ getstring2(NULL, OPER_SUPER_ADMIN_WALL_ON),
+ u->nick);
+ } else if (stricmp(setting, "off") == 0) {
+ u->isSuperAdmin = 0;
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_OFF);
+ alog("%s: %s is no longer a SuperAdmin", s_OperServ, u->nick);
+ anope_cmd_global(s_OperServ,
+ getstring2(NULL, OPER_SUPER_ADMIN_WALL_OFF),
+ u->nick);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_SYNTAX);
+ }
+ } else if (stricmp(option, "DEBUG") == 0) {
+ if (stricmp(setting, "on") == 0) {
+ debug = 1;
+ alog("Debug mode activated");
+ notice_lang(s_OperServ, u, OPER_SET_DEBUG_ON);
+ } else if (stricmp(setting, "off") == 0 ||
+ (*setting == '0' && atoi(setting) == 0)) {
+ alog("Debug mode deactivated");
+ debug = 0;
+ notice_lang(s_OperServ, u, OPER_SET_DEBUG_OFF);
+ } else if (isdigit(*setting) && atoi(setting) > 0) {
+ debug = atoi(setting);
+ alog("Debug mode activated (level %d)", debug);
+ notice_lang(s_OperServ, u, OPER_SET_DEBUG_LEVEL, debug);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_DEBUG_ERROR);
+ }
+
+ } else if (stricmp(option, "NOEXPIRE") == 0) {
+ if (stricmp(setting, "ON") == 0) {
+ noexpire = 1;
+ alog("No expire mode activated");
+ notice_lang(s_OperServ, u, OPER_SET_NOEXPIRE_ON);
+ } else if (stricmp(setting, "OFF") == 0) {
+ noexpire = 0;
+ alog("No expire mode deactivated");
+ notice_lang(s_OperServ, u, OPER_SET_NOEXPIRE_OFF);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_NOEXPIRE_ERROR);
+ }
+ } else {
+ notice_lang(s_OperServ, u, OPER_SET_UNKNOWN_OPTION, option);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_sgline.c b/src/core/os_sgline.c
new file mode 100644
index 000000000..da28cf178
--- /dev/null
+++ b/src/core/os_sgline.c
@@ -0,0 +1,362 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int sgline_view_callback(SList * slist, int number, void *item,
+ va_list args);
+int sgline_view(int number, SXLine * sx, User * u, int *sent_header);
+int sgline_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int sgline_list(int number, SXLine * sx, User * u, int *sent_header);
+int do_sgline(User * u);
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SGLINE", do_sgline, is_services_oper,
+ OPER_HELP_SGLINE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ if (!ircd->sgline) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SGLINE);
+ }
+}
+
+/**
+ * The /os sgline command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_sgline(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+
+ if (!cmd)
+ cmd = "";
+
+ if (!stricmp(cmd, "ADD")) {
+ int deleted = 0;
+ char *expiry, *mask, *reason;
+ time_t expires;
+
+ mask = strtok(NULL, ":");
+ if (mask && *mask == '+') {
+ expiry = mask;
+ mask = strchr(expiry, ' ');
+ if (mask) {
+ *mask = 0;
+ mask++;
+ }
+ } else {
+ expiry = NULL;
+ }
+
+ expires = expiry ? dotime(expiry) : SGLineExpiry;
+ /* If the expiry given does not contain a final letter, it's in days,
+ * said the doc. Ah well.
+ */
+ if (expiry && isdigit(expiry[strlen(expiry) - 1]))
+ expires *= 86400;
+ /* Do not allow less than a minute expiry time */
+ if (expires != 0 && expires < 60) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ if (mask && (reason = strtok(NULL, ""))) {
+ /* Clean up the last character of the mask if it is a space
+ * See bug #761
+ */
+ size_t masklen = strlen(mask);
+ if (mask[masklen - 1] == ' ')
+ mask[masklen - 1] = '\0';
+
+ /* We first do some sanity check on the proposed mask. */
+
+ if (mask && strspn(mask, "*?") == strlen(mask)) {
+ notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask);
+ return MOD_CONT;
+ }
+
+ deleted = add_sgline(u, mask, u->nick, expires, reason);
+ if (deleted < 0)
+ return MOD_CONT;
+ else if (deleted)
+ notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_SEVERAL,
+ deleted);
+ notice_lang(s_OperServ, u, OPER_SGLINE_ADDED, mask);
+
+ if (WallOSSGLine) {
+ char buf[128];
+
+ if (!expires) {
+ strcpy(buf, "does not expire");
+ } else {
+ int wall_expiry = expires - time(NULL);
+ char *s = NULL;
+
+ if (wall_expiry >= 86400) {
+ wall_expiry /= 86400;
+ s = "day";
+ } else if (wall_expiry >= 3600) {
+ wall_expiry /= 3600;
+ s = "hour";
+ } else if (wall_expiry >= 60) {
+ wall_expiry /= 60;
+ s = "minute";
+ }
+
+ snprintf(buf, sizeof(buf), "expires in %d %s%s",
+ wall_expiry, s,
+ (wall_expiry == 1) ? "" : "s");
+ }
+
+ anope_cmd_global(s_OperServ,
+ "%s added an SGLINE for %s (%s)", u->nick,
+ mask, buf);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else {
+ syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX);
+ }
+
+ } else if (!stricmp(cmd, "DEL")) {
+
+ char *mask;
+ int res = 0;
+
+ mask = strtok(NULL, "");
+
+ if (!mask) {
+ syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (sglines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ /* Deleting a range */
+ res = slist_delete_range(&sglines, mask, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SGLINE_DELETED_SEVERAL,
+ res);
+ }
+ } else {
+ if ((res = slist_indexof(&sglines, mask)) == -1) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_NOT_FOUND, mask);
+ return MOD_CONT;
+ }
+
+ slist_delete(&sglines, res);
+ notice_lang(s_OperServ, u, OPER_SGLINE_DELETED, mask);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else if (!stricmp(cmd, "LIST")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (sglines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, "");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&sglines, mask, &sgline_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < sglines.count; i++) {
+ amask = ((SXLine *) sglines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ sgline_list(i + 1, sglines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "SGLine");
+ }
+ }
+ } else if (!stricmp(cmd, "VIEW")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (sglines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, "");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&sglines, mask, &sgline_view_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < sglines.count; i++) {
+ amask = ((SXLine *) sglines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ sgline_view(i + 1, sglines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SGLINE_NO_MATCH);
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ slist_clear(&sglines, 1);
+ notice_lang(s_OperServ, u, OPER_SGLINE_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "SGLINE", OPER_SGLINE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/* Lists an SGLINE entry, prefixing it with the header if needed */
+
+int sgline_view(int number, SXLine * sx, User * u, int *sent_header)
+{
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_VIEW_HEADER);
+ *sent_header = 1;
+ }
+
+ tm = *localtime(&sx->seton);
+ strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_SHORT_DATE_FORMAT,
+ &tm);
+ expire_left(u->na, expirebuf, sizeof(expirebuf), sx->expires);
+ notice_lang(s_OperServ, u, OPER_SGLINE_VIEW_FORMAT, number, sx->mask,
+ sx->by, timebuf, expirebuf, sx->reason);
+
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int sgline_view_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return sgline_view(number, item, u, sent_header);
+}
+
+/* Lists an SGLINE entry, prefixing it with the header if needed */
+
+int sgline_list(int number, SXLine * sx, User * u, int *sent_header)
+{
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SGLINE_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_OperServ, u, OPER_SGLINE_LIST_FORMAT, number, sx->mask,
+ sx->reason);
+
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int sgline_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return sgline_list(number, item, u, sent_header);
+}
diff --git a/src/core/os_shutdown.c b/src/core/os_shutdown.c
new file mode 100644
index 000000000..2031462b8
--- /dev/null
+++ b/src/core/os_shutdown.c
@@ -0,0 +1,83 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_shutdown(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SHUTDOWN", do_shutdown, is_services_root,
+ OPER_HELP_SHUTDOWN, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SHUTDOWN);
+ }
+}
+
+/**
+ * The /os shutdown command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_shutdown(User * u)
+{
+ quitmsg = calloc(32 + strlen(u->nick), 1);
+ if (!quitmsg)
+ quitmsg = "SHUTDOWN command received, but out of memory!";
+ else
+ sprintf(quitmsg, "SHUTDOWN command received from %s", u->nick);
+
+ if (GlobalOnCycle) {
+ oper_global(NULL, "%s", GlobalOnCycleMessage);
+ }
+ save_data = 1;
+ delayed_quit = 1;
+ return MOD_CONT;
+}
diff --git a/src/core/os_sqline.c b/src/core/os_sqline.c
new file mode 100644
index 000000000..57d91f679
--- /dev/null
+++ b/src/core/os_sqline.c
@@ -0,0 +1,355 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_sqline(User * u);
+int sqline_view_callback(SList * slist, int number, void *item,
+ va_list args);
+int sqline_view(int number, SXLine * sx, User * u, int *sent_header);
+int sqline_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int sqline_list(int number, SXLine * sx, User * u, int *sent_header);
+
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SQLINE", do_sqline, is_services_oper,
+ OPER_HELP_SQLINE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+ if (!ircd->sqline) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SQLINE);
+ }
+}
+
+/**
+ * The /os sqline command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_sqline(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+
+ if (!cmd)
+ cmd = "";
+
+ if (!stricmp(cmd, "ADD")) {
+ int deleted = 0;
+ char *expiry, *mask, *reason;
+ time_t expires;
+
+ mask = strtok(NULL, " ");
+ if (mask && *mask == '+') {
+ expiry = mask;
+ mask = strtok(NULL, " ");
+ } else {
+ expiry = NULL;
+ }
+
+ expires = expiry ? dotime(expiry) : SQLineExpiry;
+ /* If the expiry given does not contain a final letter, it's in days,
+ * said the doc. Ah well.
+ */
+ if (expiry && isdigit(expiry[strlen(expiry) - 1]))
+ expires *= 86400;
+ /* Do not allow less than a minute expiry time */
+ if (expires != 0 && expires < 60) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ if (mask && (reason = strtok(NULL, ""))) {
+
+ /* We first do some sanity check on the proposed mask. */
+ if (strspn(mask, "*") == strlen(mask)) {
+ notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask);
+ return MOD_CONT;
+ }
+
+ /* Channel SQLINEs are only supported on Bahamut servers */
+ if (*mask == '#' && !ircd->chansqline) {
+ notice_lang(s_OperServ, u,
+ OPER_SQLINE_CHANNELS_UNSUPPORTED);
+ return MOD_CONT;
+ }
+
+ deleted = add_sqline(u, mask, u->nick, expires, reason);
+ if (deleted < 0)
+ return MOD_CONT;
+ else if (deleted)
+ notice_lang(s_OperServ, u, OPER_SQLINE_DELETED_SEVERAL,
+ deleted);
+ notice_lang(s_OperServ, u, OPER_SQLINE_ADDED, mask);
+
+ if (WallOSSQLine) {
+ char buf[128];
+
+ if (!expires) {
+ strcpy(buf, "does not expire");
+ } else {
+ int wall_expiry = expires - time(NULL);
+ char *s = NULL;
+
+ if (wall_expiry >= 86400) {
+ wall_expiry /= 86400;
+ s = "day";
+ } else if (wall_expiry >= 3600) {
+ wall_expiry /= 3600;
+ s = "hour";
+ } else if (wall_expiry >= 60) {
+ wall_expiry /= 60;
+ s = "minute";
+ }
+
+ snprintf(buf, sizeof(buf), "expires in %d %s%s",
+ wall_expiry, s,
+ (wall_expiry == 1) ? "" : "s");
+ }
+
+ anope_cmd_global(s_OperServ,
+ "%s added an SQLINE for %s (%s)", u->nick,
+ mask, buf);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else {
+ syntax_error(s_OperServ, u, "SQLINE", OPER_SQLINE_SYNTAX);
+ }
+
+ } else if (!stricmp(cmd, "DEL")) {
+
+ char *mask;
+ int res = 0;
+
+ mask = strtok(NULL, "");
+
+ if (!mask) {
+ syntax_error(s_OperServ, u, "SQLINE", OPER_SQLINE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (sqlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ /* Deleting a range */
+ res = slist_delete_range(&sqlines, mask, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SQLINE_DELETED_SEVERAL,
+ res);
+ }
+ } else {
+ if ((res = slist_indexof(&sqlines, mask)) == -1) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_NOT_FOUND, mask);
+ return MOD_CONT;
+ }
+
+ slist_delete(&sqlines, res);
+ notice_lang(s_OperServ, u, OPER_SQLINE_DELETED, mask);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else if (!stricmp(cmd, "LIST")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (sqlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, "");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&sqlines, mask, &sqline_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < sqlines.count; i++) {
+ amask = ((SXLine *) sqlines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ sqline_list(i + 1, sqlines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SQLINE_NO_MATCH);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "SQLine");
+ }
+ }
+ } else if (!stricmp(cmd, "VIEW")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (sqlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, "");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&sqlines, mask, &sqline_view_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < sqlines.count; i++) {
+ amask = ((SXLine *) sqlines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ sqline_view(i + 1, sqlines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SQLINE_NO_MATCH);
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ slist_clear(&sqlines, 1);
+ notice_lang(s_OperServ, u, OPER_SQLINE_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "SQLINE", OPER_SQLINE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+int sqline_view(int number, SXLine * sx, User * u, int *sent_header)
+{
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_VIEW_HEADER);
+ *sent_header = 1;
+ }
+
+ tm = *localtime(&sx->seton);
+ strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_SHORT_DATE_FORMAT,
+ &tm);
+ expire_left(u->na, expirebuf, sizeof(expirebuf), sx->expires);
+ notice_lang(s_OperServ, u, OPER_SQLINE_VIEW_FORMAT, number, sx->mask,
+ sx->by, timebuf, expirebuf, sx->reason);
+
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int sqline_view_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return sqline_view(number, item, u, sent_header);
+}
+
+/* Lists an SQLINE entry, prefixing it with the header if needed */
+
+int sqline_list(int number, SXLine * sx, User * u, int *sent_header)
+{
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SQLINE_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_OperServ, u, OPER_SQLINE_LIST_FORMAT, number, sx->mask,
+ sx->reason);
+
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int sqline_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return sqline_list(number, item, u, sent_header);
+}
diff --git a/src/core/os_staff.c b/src/core/os_staff.c
new file mode 100644
index 000000000..ae9e6d66c
--- /dev/null
+++ b/src/core/os_staff.c
@@ -0,0 +1,156 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_staff(User * u);
+void myOperServHelp(User * u);
+int opers_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int opers_list(int number, NickCore * nc, User * u, char *level);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("STAFF", do_staff, NULL, OPER_HELP_STAFF, -1, -1,
+ -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_STAFF);
+}
+
+/**
+ * The /os staff command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_staff(User * u)
+{
+ int idx = 0;
+ User *au = NULL;
+ NickCore *nc;
+ NickAlias *na;
+ int found;
+ int i;
+
+ notice_lang(s_OperServ, u, OPER_STAFF_LIST_HEADER);
+ slist_enum(&servopers, NULL, &opers_list_callback, u, "OPER");
+ slist_enum(&servadmins, NULL, &opers_list_callback, u, "ADMN");
+
+ for (idx = 0; idx < RootNumber; idx++) {
+ found = 0;
+ if ((au = finduser(ServicesRoots[idx]))) { /* see if user is online */
+ found = 1;
+ notice_lang(s_OperServ, u, OPER_STAFF_FORMAT, '*', "ROOT",
+ ServicesRoots[idx]);
+ } else if ((nc = findcore(ServicesRoots[idx]))) {
+ for (i = 0; i < nc->aliases.count; i++) { /* check all aliases */
+ na = nc->aliases.list[i];
+ if ((au = finduser(na->nick))) { /* see if user is online */
+ found = 1;
+ notice_lang(s_OperServ, u, OPER_STAFF_AFORMAT,
+ '*', "ROOT", ServicesRoots[idx], na->nick);
+ }
+ }
+ }
+
+ if (!found)
+ notice_lang(s_OperServ, u, OPER_STAFF_FORMAT, ' ', "ROOT",
+ ServicesRoots[idx]);
+
+ }
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "Staff");
+ return MOD_CONT;
+}
+
+/**
+ * Function for the enumerator to call
+ **/
+int opers_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ char *level = va_arg(args, char *);
+
+ return opers_list(number, item, u, level);
+}
+
+
+/**
+ * Display an Opers list Entry
+ **/
+int opers_list(int number, NickCore * nc, User * u, char *level)
+{
+ User *au = NULL;
+ NickAlias *na;
+ int found;
+ int i;
+
+ if (!nc)
+ return 0;
+
+ found = 0;
+ if ((au = finduser(nc->display))) { /* see if user is online */
+ found = 1;
+ notice_lang(s_OperServ, u, OPER_STAFF_FORMAT, '*', level,
+ nc->display);
+ } else {
+ for (i = 0; i < nc->aliases.count; i++) { /* check all aliases */
+ na = nc->aliases.list[i];
+ if ((au = finduser(na->nick))) { /* see if user is online */
+ found = 1;
+ notice_lang(s_OperServ, u, OPER_STAFF_AFORMAT, '*', level,
+ nc->display, na->nick);
+ }
+ }
+ }
+
+ if (!found)
+ notice_lang(s_OperServ, u, OPER_STAFF_FORMAT, ' ', level,
+ nc->display);
+
+ return 1;
+}
diff --git a/src/core/os_stats.c b/src/core/os_stats.c
new file mode 100644
index 000000000..e88ac3da1
--- /dev/null
+++ b/src/core/os_stats.c
@@ -0,0 +1,453 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+
+
+int do_stats(User * u);
+void get_operserv_stats(long *nrec, long *memuse);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("STATS", do_stats, NULL, OPER_HELP_STATS,
+ -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+ c = createCommand("UPTIME", do_stats, NULL,
+ OPER_HELP_STATS, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_STATS);
+}
+
+/**
+ * Count servers connected to server s
+ * @param s The server to start counting from
+ * @return Amount of servers connected to server s
+ **/
+int stats_count_servers(Server * s)
+{
+ int count = 0;
+
+ while (s) {
+ count++;
+ if (s->links)
+ count += stats_count_servers(s->links);
+ s = s->next;
+ }
+
+ return count;
+}
+
+/**
+ * The /os stats command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_stats(User * u)
+{
+ time_t uptime = time(NULL) - start_time;
+ char *extra = strtok(NULL, "");
+ int days = uptime / 86400, hours = (uptime / 3600) % 24,
+ mins = (uptime / 60) % 60, secs = uptime % 60;
+ struct tm *tm;
+ char timebuf[64];
+ char buf[512];
+ int buflen;
+ int i;
+
+ if (extra && stricmp(extra, "ALL") != 0) {
+ if (stricmp(extra, "AKILL") == 0) {
+ int timeout;
+ /* AKILLs */
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_COUNT,
+ akills.count);
+ timeout = AutokillExpiry + 59;
+ if (timeout >= 172800)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_DAYS,
+ timeout / 86400);
+ else if (timeout >= 86400)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_DAY);
+ else if (timeout >= 7200)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_HOURS,
+ timeout / 3600);
+ else if (timeout >= 3600)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_HOUR);
+ else if (timeout >= 120)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_MINS,
+ timeout / 60);
+ else if (timeout >= 60)
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_MIN);
+ else
+ notice_lang(s_OperServ, u, OPER_STATS_AKILL_EXPIRE_NONE);
+ if (ircd->sgline) {
+ /* SGLINEs */
+ notice_lang(s_OperServ, u, OPER_STATS_SGLINE_COUNT,
+ sglines.count);
+ timeout = SGLineExpiry + 59;
+ if (timeout >= 172800)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_DAYS,
+ timeout / 86400);
+ else if (timeout >= 86400)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_DAY);
+ else if (timeout >= 7200)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_HOURS,
+ timeout / 3600);
+ else if (timeout >= 3600)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_HOUR);
+ else if (timeout >= 120)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_MINS,
+ timeout / 60);
+ else if (timeout >= 60)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_MIN);
+ else
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SGLINE_EXPIRE_NONE);
+ }
+ if (ircd->sqline) {
+ /* SQLINEs */
+ notice_lang(s_OperServ, u, OPER_STATS_SQLINE_COUNT,
+ sqlines.count);
+ timeout = SQLineExpiry + 59;
+ if (timeout >= 172800)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_DAYS,
+ timeout / 86400);
+ else if (timeout >= 86400)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_DAY);
+ else if (timeout >= 7200)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_HOURS,
+ timeout / 3600);
+ else if (timeout >= 3600)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_HOUR);
+ else if (timeout >= 120)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_MINS,
+ timeout / 60);
+ else if (timeout >= 60)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_MIN);
+ else
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SQLINE_EXPIRE_NONE);
+ }
+ if (ircd->szline) {
+ /* SZLINEs */
+ notice_lang(s_OperServ, u, OPER_STATS_SZLINE_COUNT,
+ szlines.count);
+ timeout = SZLineExpiry + 59;
+ if (timeout >= 172800)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_DAYS,
+ timeout / 86400);
+ else if (timeout >= 86400)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_DAY);
+ else if (timeout >= 7200)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_HOURS,
+ timeout / 3600);
+ else if (timeout >= 3600)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_HOUR);
+ else if (timeout >= 120)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_MINS,
+ timeout / 60);
+ else if (timeout >= 60)
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_MIN);
+ else
+ notice_lang(s_OperServ, u,
+ OPER_STATS_SZLINE_EXPIRE_NONE);
+ }
+ return MOD_CONT;
+ } else if (!stricmp(extra, "RESET")) {
+ if (is_services_admin(u)) {
+ maxusercnt = usercnt;
+ notice_lang(s_OperServ, u, OPER_STATS_RESET);
+ } else {
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+ }
+ return MOD_CONT;
+ } else if (stricmp(extra, "MEMORY") && stricmp(extra, "UPLINK")) {
+ notice_lang(s_OperServ, u, OPER_STATS_UNKNOWN_OPTION, extra);
+ }
+ }
+
+ if (!extra || ((stricmp(extra, "MEMORY") != 0)
+ && (stricmp(extra, "UPLINK") != 0))) {
+ notice_lang(s_OperServ, u, OPER_STATS_CURRENT_USERS, usercnt,
+ opcnt);
+ tm = localtime(&maxusertime);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_OperServ, u, OPER_STATS_MAX_USERS, maxusercnt,
+ timebuf);
+ if (days > 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_DHMS,
+ days, hours, mins, secs);
+ } else if (days == 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1DHMS,
+ days, hours, mins, secs);
+ } else {
+ if (hours > 1) {
+ if (mins != 1) {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_HMS,
+ hours, mins, secs);
+ } else {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_HM1S,
+ hours, mins, secs);
+ }
+ } else {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_H1MS,
+ hours, mins, secs);
+ } else {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_H1M1S,
+ hours, mins, secs);
+ }
+ }
+ } else if (hours == 1) {
+ if (mins != 1) {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1HMS,
+ hours, mins, secs);
+ } else {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1HM1S,
+ hours, mins, secs);
+ }
+ } else {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1H1MS,
+ hours, mins, secs);
+ } else {
+ notice_lang(s_OperServ, u,
+ OPER_STATS_UPTIME_1H1M1S, hours, mins,
+ secs);
+ }
+ }
+ } else {
+ if (mins != 1) {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_MS,
+ mins, secs);
+ } else {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_M1S,
+ mins, secs);
+ }
+ } else {
+ if (secs != 1) {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1MS,
+ mins, secs);
+ } else {
+ notice_lang(s_OperServ, u, OPER_STATS_UPTIME_1M1S,
+ mins, secs);
+ }
+ }
+ }
+ }
+ }
+
+ if (extra && ((stricmp(extra, "ALL") == 0)
+ || (stricmp(extra, "UPLINK") == 0))
+ && is_services_admin(u)) {
+ buf[0] = '\0';
+ buflen = 511; /* How confusing, this is the amount of space left! */
+ for (i = 0; capab_info[i].token; i++) {
+ if (uplink_capab & capab_info[i].flag) {
+ strncat(buf, " ", buflen);
+ buflen--;
+ strncat(buf, capab_info[i].token, buflen);
+ buflen -= strlen(capab_info[i].token);
+ /* Special cases */
+ if (capab_info[i].flag == CAPAB_CHANMODE) {
+ strncat(buf, "=", buflen);
+ buflen--;
+ strncat(buf, ircd->chanmodes, buflen);
+ buflen -= strlen(ircd->chanmodes);
+ }
+ if (capab_info[i].flag == CAPAB_NICKCHARS) {
+ strncat(buf, "=", buflen);
+ buflen--;
+ if (ircd->nickchars) {
+ strncat(buf, ircd->nickchars, buflen);
+ buflen -= strlen(ircd->nickchars);
+ } /* leave blank if it was null */
+ }
+ }
+ }
+ notice_lang(s_OperServ, u, OPER_STATS_UPLINK_SERVER,
+ serv_uplink->name);
+ notice_lang(s_OperServ, u, OPER_STATS_UPLINK_CAPAB, buf);
+ notice_lang(s_OperServ, u, OPER_STATS_UPLINK_SERVER_COUNT,
+ stats_count_servers(serv_uplink));
+ }
+
+ if (extra && ((stricmp(extra, "ALL") == 0)
+ || (stricmp(extra, "MEMORY") == 0))
+ && is_services_admin(u)) {
+ long count, mem;
+
+ notice_lang(s_OperServ, u, OPER_STATS_BYTES_READ,
+ total_read / 1024);
+ notice_lang(s_OperServ, u, OPER_STATS_BYTES_WRITTEN,
+ total_written / 1024);
+
+ get_user_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_USER_MEM, count,
+ (mem + 512) / 1024);
+ get_channel_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_CHANNEL_MEM, count,
+ (mem + 512) / 1024);
+ get_core_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_GROUPS_MEM, count,
+ (mem + 512) / 1024);
+ get_aliases_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_ALIASES_MEM, count,
+ (mem + 512) / 1024);
+ get_chanserv_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_CHANSERV_MEM, count,
+ (mem + 512) / 1024);
+ if (s_BotServ) {
+ get_botserv_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_BOTSERV_MEM, count,
+ (mem + 512) / 1024);
+ }
+ if (s_HostServ) {
+ get_hostserv_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_HOSTSERV_MEM, count,
+ (mem + 512) / 1024);
+ }
+ get_operserv_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_OPERSERV_MEM, count,
+ (mem + 512) / 1024);
+ get_session_stats(&count, &mem);
+ notice_lang(s_OperServ, u, OPER_STATS_SESSIONS_MEM, count,
+ (mem + 512) / 1024);
+ }
+ return MOD_CONT;
+}
+
+void get_operserv_stats(long *nrec, long *memuse)
+{
+ int i;
+ long mem = 0, count = 0, mem2 = 0, count2 = 0;
+ Akill *ak;
+ SXLine *sx;
+
+ count += akills.count;
+ mem += akills.capacity;
+ mem += akills.count * sizeof(Akill);
+
+ for (i = 0; i < akills.count; i++) {
+ ak = akills.list[i];
+ mem += strlen(ak->user) + 1;
+ mem += strlen(ak->host) + 1;
+ mem += strlen(ak->by) + 1;
+ mem += strlen(ak->reason) + 1;
+ }
+
+ if (ircd->sgline) {
+ count += sglines.count;
+ mem += sglines.capacity;
+ mem += sglines.count * sizeof(SXLine);
+
+ for (i = 0; i < sglines.count; i++) {
+ sx = sglines.list[i];
+ mem += strlen(sx->mask) + 1;
+ mem += strlen(sx->by) + 1;
+ mem += strlen(sx->reason) + 1;
+ }
+ }
+ if (ircd->sqline) {
+ count += sqlines.count;
+ mem += sqlines.capacity;
+ mem += sqlines.count * sizeof(SXLine);
+
+ for (i = 0; i < sqlines.count; i++) {
+ sx = sqlines.list[i];
+ mem += strlen(sx->mask) + 1;
+ mem += strlen(sx->by) + 1;
+ mem += strlen(sx->reason) + 1;
+ }
+ }
+ if (ircd->szline) {
+ count += szlines.count;
+ mem += szlines.capacity;
+ mem += szlines.count * sizeof(SXLine);
+
+ for (i = 0; i < szlines.count; i++) {
+ sx = szlines.list[i];
+ mem += strlen(sx->mask) + 1;
+ mem += strlen(sx->by) + 1;
+ mem += strlen(sx->reason) + 1;
+ }
+ }
+
+
+ get_news_stats(&count2, &mem2);
+ count += count2;
+ mem += mem2;
+ get_exception_stats(&count2, &mem2);
+ count += count2;
+ mem += mem2;
+
+ *nrec = count;
+ *memuse = mem;
+}
diff --git a/src/core/os_svsnick.c b/src/core/os_svsnick.c
new file mode 100644
index 000000000..c579d7588
--- /dev/null
+++ b/src/core/os_svsnick.c
@@ -0,0 +1,125 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_svsnick(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SVSNICK", do_svsnick, is_services_root,
+ OPER_HELP_SVSNICK, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+ if (!ircd->svsnick) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u) && u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SVSNICK);
+ }
+}
+
+/**
+ * The /os svsnick command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+/* Forcefully change a user's nickname */
+
+int do_svsnick(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *newnick = strtok(NULL, " ");
+
+ NickAlias *na;
+ char *c;
+
+ /* Only allow this if SuperAdmin is enabled */
+ if (!u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_ONLY);
+ return MOD_CONT;
+ }
+
+ if (!nick || !newnick) {
+ syntax_error(s_OperServ, u, "SVSNICK", OPER_SVSNICK_SYNTAX);
+ return MOD_CONT;
+ }
+
+ /* Truncate long nicknames to NICKMAX-2 characters */
+ if (strlen(newnick) > (NICKMAX - 2)) {
+ notice_lang(s_OperServ, u, NICK_X_TRUNCATED,
+ newnick, NICKMAX - 2, newnick);
+ newnick[NICKMAX - 2] = '\0';
+ }
+
+ /* Check for valid characters */
+ if (*newnick == '-' || isdigit(*newnick)) {
+ notice_lang(s_OperServ, u, NICK_X_ILLEGAL, newnick);
+ return MOD_CONT;
+ }
+ for (c = newnick; *c && (c - newnick) < NICKMAX; c++) {
+ if (!isvalidnick(*c)) {
+ notice_lang(s_OperServ, u, NICK_X_ILLEGAL, newnick);
+ return MOD_CONT;
+ }
+ }
+
+ /* Check for a nick in use or a forbidden/suspended nick */
+ if (!finduser(nick)) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_IN_USE, nick);
+ } else if (finduser(newnick)) {
+ notice_lang(s_OperServ, u, NICK_X_IN_USE, newnick);
+ } else if ((na = findnick(newnick)) && (na->status & NS_VERBOTEN)) {
+ notice_lang(s_OperServ, u, NICK_X_FORBIDDEN, newnick);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SVSNICK_NEWNICK, nick, newnick);
+ anope_cmd_global(s_OperServ, "%s used SVSNICK to change %s to %s",
+ u->nick, nick, newnick);
+ anope_cmd_svsnick(nick, newnick, time(NULL));
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_szline.c b/src/core/os_szline.c
new file mode 100644
index 000000000..5c5e9a466
--- /dev/null
+++ b/src/core/os_szline.c
@@ -0,0 +1,350 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_szline(User * u);
+void myOperServHelp(User * u);
+int szline_view_callback(SList * slist, int number, void *item,
+ va_list args);
+int szline_list_callback(SList * slist, int number, void *item,
+ va_list args);
+int szline_view(int number, SXLine * sx, User * u, int *sent_header);
+int szline_list(int number, SXLine * sx, User * u, int *sent_header);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("SZLINE", do_szline, is_services_oper,
+ OPER_HELP_SZLINE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+ if (!ircd->szline) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_oper(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_SZLINE);
+ }
+}
+
+/**
+ * The /os szline command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_szline(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+
+ if (!cmd)
+ cmd = "";
+
+ if (!stricmp(cmd, "ADD")) {
+ int deleted = 0;
+ char *expiry, *mask, *reason;
+ time_t expires;
+
+ mask = strtok(NULL, " ");
+ if (mask && *mask == '+') {
+ expiry = mask;
+ mask = strtok(NULL, " ");
+ } else {
+ expiry = NULL;
+ }
+
+ expires = expiry ? dotime(expiry) : SZLineExpiry;
+ /* If the expiry given does not contain a final letter, it's in days,
+ * said the doc. Ah well.
+ */
+ if (expiry && isdigit(expiry[strlen(expiry) - 1]))
+ expires *= 86400;
+ /* Do not allow less than a minute expiry time */
+ if (expires != 0 && expires < 60) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ if (mask && (reason = strtok(NULL, ""))) {
+ /* We first do some sanity check on the proposed mask. */
+
+ if (strchr(mask, '!') || strchr(mask, '@')) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_ONLY_IPS);
+ return MOD_CONT;
+ }
+
+ if (strspn(mask, "*?") == strlen(mask)) {
+ notice_lang(s_OperServ, u, USERHOST_MASK_TOO_WIDE, mask);
+ return MOD_CONT;
+ }
+
+ deleted = add_szline(u, mask, u->nick, expires, reason);
+ if (deleted < 0)
+ return MOD_CONT;
+ else if (deleted)
+ notice_lang(s_OperServ, u, OPER_SZLINE_DELETED_SEVERAL,
+ deleted);
+ notice_lang(s_OperServ, u, OPER_SZLINE_ADDED, mask);
+
+ if (WallOSSZLine) {
+ char buf[128];
+
+ if (!expires) {
+ strcpy(buf, "does not expire");
+ } else {
+ int wall_expiry = expires - time(NULL);
+ char *s = NULL;
+
+ if (wall_expiry >= 86400) {
+ wall_expiry /= 86400;
+ s = "day";
+ } else if (wall_expiry >= 3600) {
+ wall_expiry /= 3600;
+ s = "hour";
+ } else if (wall_expiry >= 60) {
+ wall_expiry /= 60;
+ s = "minute";
+ }
+
+ snprintf(buf, sizeof(buf), "expires in %d %s%s",
+ wall_expiry, s,
+ (wall_expiry == 1) ? "" : "s");
+ }
+
+ anope_cmd_global(s_OperServ,
+ "%s added an SZLINE for %s (%s)", u->nick,
+ mask, buf);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else {
+ syntax_error(s_OperServ, u, "SZLINE", OPER_SZLINE_SYNTAX);
+ }
+
+ } else if (!stricmp(cmd, "DEL")) {
+
+ char *mask;
+ int res = 0;
+
+ mask = strtok(NULL, " ");
+
+ if (!mask) {
+ syntax_error(s_OperServ, u, "SZLINE", OPER_SZLINE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (szlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ /* Deleting a range */
+ res = slist_delete_range(&szlines, mask, NULL);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_NO_MATCH);
+ return MOD_CONT;
+ } else if (res == 1) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_SZLINE_DELETED_SEVERAL,
+ res);
+ }
+ } else {
+ if ((res = slist_indexof(&szlines, mask)) == -1) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_NOT_FOUND, mask);
+ return MOD_CONT;
+ }
+
+ slist_delete(&szlines, res);
+ notice_lang(s_OperServ, u, OPER_SZLINE_DELETED, mask);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else if (!stricmp(cmd, "LIST")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (szlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, " ");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&szlines, mask, &szline_list_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < szlines.count; i++) {
+ amask = ((SXLine *) szlines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ szline_list(i + 1, szlines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SZLINE_NO_MATCH);
+ }
+ } else if (!stricmp(cmd, "VIEW")) {
+ char *mask;
+ int res, sent_header = 0;
+
+ if (szlines.count == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_LIST_EMPTY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, " ");
+
+ if (!mask || (isdigit(*mask)
+ && strspn(mask, "1234567890,-") == strlen(mask))) {
+ res =
+ slist_enum(&szlines, mask, &szline_view_callback, u,
+ &sent_header);
+ if (res == 0) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_NO_MATCH);
+ return MOD_CONT;
+ }
+ } else {
+ int i;
+ char *amask;
+
+ for (i = 0; i < szlines.count; i++) {
+ amask = ((SXLine *) szlines.list[i])->mask;
+ if (!stricmp(mask, amask)
+ || match_wild_nocase(mask, amask))
+ szline_view(i + 1, szlines.list[i], u, &sent_header);
+ }
+
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_SZLINE_NO_MATCH);
+ }
+ } else if (!stricmp(cmd, "CLEAR")) {
+ slist_clear(&szlines, 1);
+ notice_lang(s_OperServ, u, OPER_SZLINE_CLEAR);
+ } else {
+ syntax_error(s_OperServ, u, "SZLINE", OPER_SZLINE_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+
+int szline_view(int number, SXLine * sx, User * u, int *sent_header)
+{
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_VIEW_HEADER);
+ *sent_header = 1;
+ }
+
+ tm = *localtime(&sx->seton);
+ strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_SHORT_DATE_FORMAT,
+ &tm);
+ expire_left(u->na, expirebuf, sizeof(expirebuf), sx->expires);
+ notice_lang(s_OperServ, u, OPER_SZLINE_VIEW_FORMAT, number, sx->mask,
+ sx->by, timebuf, expirebuf, sx->reason);
+
+ return 1;
+}
+
+/* Callback for enumeration purposes */
+
+int szline_view_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return szline_view(number, item, u, sent_header);
+}
+
+/* Callback for enumeration purposes */
+
+int szline_list_callback(SList * slist, int number, void *item,
+ va_list args)
+{
+ User *u = va_arg(args, User *);
+ int *sent_header = va_arg(args, int *);
+
+ return szline_list(number, item, u, sent_header);
+}
+
+/* Lists an SZLINE entry, prefixing it with the header if needed */
+
+int szline_list(int number, SXLine * sx, User * u, int *sent_header)
+{
+ if (!sx)
+ return 0;
+
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_SZLINE_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ notice_lang(s_OperServ, u, OPER_SZLINE_LIST_FORMAT, number, sx->mask,
+ sx->reason);
+
+ return 1;
+}
diff --git a/src/core/os_umode.c b/src/core/os_umode.c
new file mode 100644
index 000000000..f81f49151
--- /dev/null
+++ b/src/core/os_umode.c
@@ -0,0 +1,116 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_operumodes(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("UMODE", do_operumodes, is_services_root,
+ OPER_HELP_UMODE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ if (!ircd->umode) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_admin(u) && u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_UMODE);
+ }
+}
+
+/**
+ * Change any user's UMODES
+ *
+ * modified to be part of the SuperAdmin directive -jester
+ * check user flag for SuperAdmin -rob
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ */
+int do_operumodes(User * u)
+{
+ char *nick = strtok(NULL, " ");
+ char *modes = strtok(NULL, "");
+
+ User *u2;
+
+ /* Only allow this if SuperAdmin is enabled */
+ if (!u->isSuperAdmin) {
+ notice_lang(s_OperServ, u, OPER_SUPER_ADMIN_ONLY);
+ return MOD_CONT;
+ }
+
+ if (!nick || !modes) {
+ syntax_error(s_OperServ, u, "UMODE", OPER_UMODE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ /**
+ * Only accept a +/- mode string
+ *-rob
+ **/
+ if ((modes[0] != '+') && (modes[0] != '-')) {
+ syntax_error(s_OperServ, u, "UMODE", OPER_UMODE_SYNTAX);
+ return MOD_CONT;
+ }
+ if (!(u2 = finduser(nick))) {
+ notice_lang(s_OperServ, u, NICK_X_NOT_IN_USE, nick);
+ } else {
+ anope_cmd_mode(s_OperServ, nick, "%s", modes);
+
+ common_svsmode(u2, modes, NULL);
+
+ notice_lang(s_OperServ, u, OPER_UMODE_SUCCESS, nick);
+ notice_lang(s_OperServ, u2, OPER_UMODE_CHANGED, u->nick);
+
+ if (WallOSMode)
+ anope_cmd_global(s_OperServ, "\2%s\2 used UMODE on %s",
+ u->nick, nick);
+ }
+ return MOD_CONT;
+}
diff --git a/src/core/os_update.c b/src/core/os_update.c
new file mode 100644
index 000000000..5b15dbb93
--- /dev/null
+++ b/src/core/os_update.c
@@ -0,0 +1,74 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_update(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("UPDATE", do_update, is_services_root,
+ OPER_HELP_UPDATE, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ if (is_services_root(u)) {
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_UPDATE);
+ }
+}
+
+/**
+ * The /os update command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+int do_update(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_UPDATING);
+ save_data = 1;
+ return MOD_CONT;
+}
diff --git a/src/core/os_userlist.c b/src/core/os_userlist.c
new file mode 100644
index 000000000..d0ca57a33
--- /dev/null
+++ b/src/core/os_userlist.c
@@ -0,0 +1,121 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#ifdef _WIN32
+extern MDE int anope_get_invite_mode();
+extern MDE int anope_get_invis_mode();
+#endif
+
+int do_userlist(User * u);
+void myOperServHelp(User * u);
+
+/**
+ * Create the command, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(CORE);
+
+ c = createCommand("USERLIST", do_userlist, NULL,
+ OPER_HELP_USERLIST, -1, -1, -1, -1);
+ moduleAddCommand(OPERSERV, c, MOD_UNIQUE);
+
+ moduleSetOperHelp(myOperServHelp);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+
+/**
+ * Add the help response to anopes /os help output.
+ * @param u The user who is requesting help
+ **/
+void myOperServHelp(User * u)
+{
+ notice_lang(s_OperServ, u, OPER_HELP_CMD_USERLIST);
+}
+
+/**
+ * The /os userlist command.
+ * @param u The user who issued the command
+ * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing.
+ **/
+
+int do_userlist(User * u)
+{
+ char *pattern = strtok(NULL, " ");
+ char *opt = strtok(NULL, " ");
+
+ Channel *c;
+ int modes = 0;
+
+ if (opt && !stricmp(opt, "INVISIBLE"))
+ modes |= anope_get_invis_mode();
+
+ if (pattern && (c = findchan(pattern))) {
+ struct c_userlist *cu;
+
+ notice_lang(s_OperServ, u, OPER_USERLIST_HEADER_CHAN, pattern);
+
+ for (cu = c->users; cu; cu = cu->next) {
+ if (modes && !(cu->user->mode & modes))
+ continue;
+ notice_lang(s_OperServ, u, OPER_USERLIST_RECORD,
+ cu->user->nick, common_get_vident(cu->user),
+ common_get_vhost(cu->user));
+ }
+ } else {
+ char mask[BUFSIZE];
+ int i;
+ User *u2;
+
+ notice_lang(s_OperServ, u, OPER_USERLIST_HEADER);
+
+ for (i = 0; i < 1024; i++) {
+ for (u2 = userlist[i]; u2; u2 = u2->next) {
+ if (pattern) {
+ snprintf(mask, sizeof(mask), "%s!%s@%s", u2->nick,
+ common_get_vident(u2), common_get_vhost(u2));
+ if (!match_wild_nocase(pattern, mask))
+ continue;
+ if (modes && !(u2->mode & modes))
+ continue;
+ }
+ notice_lang(s_OperServ, u, OPER_USERLIST_RECORD, u2->nick,
+ common_get_vident(u2), common_get_vhost(u2));
+ }
+ }
+ }
+
+ notice_lang(s_OperServ, u, OPER_USERLIST_END);
+ return MOD_CONT;
+}
diff --git a/src/datafiles.c b/src/datafiles.c
new file mode 100644
index 000000000..3af10b1d4
--- /dev/null
+++ b/src/datafiles.c
@@ -0,0 +1,788 @@
+/* Database file handling routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "datafiles.h"
+#include <fcntl.h>
+
+static int curday = 0;
+static time_t lastwarn = 0;
+
+/*************************************************************************/
+
+/**
+ * Return the version number on the file. Return 0 if there is no version
+ * number or the number doesn't make sense (i.e. less than 1 or greater
+ * than FILE_VERSION).
+ * @param f dbFile Struct Member
+ * @return int 0 if failure, 1 > is the version number
+ */
+int get_file_version(dbFILE * f)
+{
+ FILE *fp = f->fp;
+ int version =
+ fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
+ if (ferror(fp)) {
+#ifndef NOT_MAIN
+ log_perror("Error reading version number on %s", f->filename);
+#endif
+ return 0;
+ } else if (feof(fp)) {
+#ifndef NOT_MAIN
+ alog("Error reading version number on %s: End of file detected",
+ f->filename);
+#endif
+ return 0;
+ } else if (version < 1) {
+#ifndef NOT_MAIN
+ alog("Invalid version number (%d) on %s", version, f->filename);
+#endif
+ return 0;
+ }
+ return version;
+}
+
+/*************************************************************************/
+
+/**
+ * Write the current version number to the file.
+ * @param f dbFile Struct Member
+ * @return 0 on error, 1 on success.
+ */
+int write_file_version(dbFILE * f, uint32 version)
+{
+ FILE *fp = f->fp;
+ if (fputc(version >> 24 & 0xFF, fp) < 0 ||
+ fputc(version >> 16 & 0xFF, fp) < 0 ||
+ fputc(version >> 8 & 0xFF, fp) < 0 ||
+ fputc(version & 0xFF, fp) < 0) {
+#ifndef NOT_MAIN
+ log_perror("Error writing version number on %s", f->filename);
+#endif
+ return 0;
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Open the database for reading
+ * @param service If error whom to return the error as
+ * @param filename File to open as the database
+ * @return dbFile struct
+ */
+static dbFILE *open_db_read(const char *service, const char *filename)
+{
+ dbFILE *f;
+ FILE *fp;
+
+ f = scalloc(sizeof(*f), 1);
+ if (!f) {
+#ifndef NOT_MAIN
+ log_perror("Can't read %s database %s", service, filename);
+ if (time(NULL) - lastwarn > WarningTimeout) {
+ anope_cmd_global(NULL,
+ "Write error on %s: Memory allocation failed",
+ filename);
+ lastwarn = time(NULL);
+ }
+#endif
+ return NULL;
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+ f->mode = 'r';
+ fp = fopen(f->filename, "rb");
+ if (!fp) {
+ int errno_save = errno;
+#ifndef NOT_MAIN
+ if (errno != ENOENT)
+ log_perror("Can not read %s database %s", service,
+ f->filename);
+ if (time(NULL) - lastwarn > WarningTimeout) {
+ anope_cmd_global(NULL, "Write error on %s: %s", f->filename,
+ strerror(errno));
+ lastwarn = time(NULL);
+ }
+#endif
+ free(f);
+ errno = errno_save;
+ return NULL;
+ }
+ f->fp = fp;
+ f->backupfp = NULL;
+ return f;
+}
+
+/*************************************************************************/
+
+/**
+ * Open the database for writting
+ * @param service If error whom to return the error as
+ * @param filename File to open as the database
+ * @param version Database Version
+ * @return dbFile struct
+ */
+static dbFILE *open_db_write(const char *service, const char *filename,
+ uint32 version)
+{
+ dbFILE *f;
+ int fd;
+#ifdef _WIN32
+ char buffer[_MAX_PATH];
+ char win32filename[MAXPATHLEN];
+
+ /* Get the current working directory: */
+ if (_getcwd(buffer, _MAX_PATH) == NULL) {
+ alog("Warning: Unable to set Current working directory");
+ }
+#endif
+
+ f = scalloc(sizeof(*f), 1);
+ if (!f) {
+#ifndef NOT_MAIN
+ log_perror("Can not read %s database %s", service, filename);
+#else
+ alog("Can not read %s database %s", service, filename);
+#endif
+ return NULL;
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+#ifndef _WIN32
+ filename = f->filename;
+#else
+ snprintf(win32filename, sizeof(win32filename), "%s\\%s", buffer,
+ f->filename);
+ filename = win32filename;
+#endif
+ f->mode = 'w';
+
+ *f->backupname = 0;
+ snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename);
+ if (!*f->backupname || strcmp(f->backupname, filename) == 0) {
+ int errno_save = errno;
+#ifndef NOT_MAIN
+ alog("Opening %s database %s for write: Filename too long",
+ service, filename);
+#endif
+ free(f);
+ errno = errno_save;
+ return NULL;
+ }
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ f->backupfp = fopen(filename, "rb");
+#ifdef _WIN32
+ if (!MoveFileExA(filename, f->backupname, MOVEFILE_COPY_ALLOWED)
+ && GetLastError() != ENOENT) {
+ int errno_save = GetLastError();
+#else
+ if (rename(filename, f->backupname) < 0 && errno != ENOENT) {
+ int errno_save = errno;
+#endif
+#ifndef NOT_MAIN
+ static int walloped = 0;
+ if (!walloped) {
+ walloped++;
+ anope_cmd_global(NULL, "Can not back up %s database %s",
+ service, filename);
+ }
+#ifdef _WIN32
+ if (debug) {
+ if (errno == ENOENT) {
+ alog("debug: Error %d (ENOENT) : the file or directory does not exist", errno, filename);
+ } else if (errno == EACCES) {
+ alog("debug: Error %d (EACCES) : error while attempting to access file", errno);
+ } else {
+ alog("debug: Error %d", errno);
+ }
+ }
+#else
+ if (debug) {
+ alog("debug: Error %d", errno);
+ }
+#endif
+ errno = errno_save;
+ log_perror("Can not back up %s database %s", service, filename);
+ if (!NoBackupOkay) {
+#endif
+ if (f->backupfp)
+ fclose(f->backupfp);
+ free(f);
+ errno = errno_save;
+ return NULL;
+#ifndef NOT_MAIN
+ }
+#endif
+ *f->backupname = 0;
+ }
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ /* Use open() to avoid people sneaking a new file in under us */
+#ifndef _WIN32
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+#else
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL | _O_BINARY, 0666);
+#endif
+ f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */
+ if (!f->fp || !write_file_version(f, version)) {
+ int errno_save = errno;
+#ifndef NOT_MAIN
+ static int walloped = 0;
+ if (!walloped) {
+ walloped++;
+ anope_cmd_global(NULL, "Can't write to %s database %s",
+ service, filename);
+ }
+ errno = errno_save;
+ log_perror("Can't write to %s database %s", service, filename);
+#endif
+ if (f->fp) {
+ fclose(f->fp);
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ }
+ if (*f->backupname && rename(f->backupname, filename) < 0)
+#ifndef NOT_MAIN
+ log_perror("Cannot restore backup copy of %s", filename);
+#else
+ ;
+#endif
+ /* Then the Lord said unto Moses, thou shalt free what thou hast malloced
+ * -- codemastr */
+ free(f);
+ errno = errno_save;
+ return NULL;
+ }
+ return f;
+}
+
+/*************************************************************************/
+
+/**
+ * Open a database file for reading (*mode == 'r') or writing (*mode == 'w').
+ * Return the stream pointer, or NULL on error. When opening for write, it
+ * is an error for rename() to return an error (when backing up the original
+ * file) other than ENOENT, if NO_BACKUP_OKAY is not defined; it is an error
+ * if the version number cannot be written to the file; and it is a fatal
+ * error if opening the file for write fails and the backup was successfully
+ * made but cannot be restored.
+ * @param service If error whom to return the error as
+ * @param filename File to open as the database
+ * @param mode Mode for writting or reading
+ * @param version Database Version
+ * @return dbFile struct
+ */
+dbFILE *open_db(const char *service, const char *filename,
+ const char *mode, uint32 version)
+{
+ if (*mode == 'r') {
+ return open_db_read(service, filename);
+ } else if (*mode == 'w') {
+ return open_db_write(service, filename, version);
+ } else {
+ errno = EINVAL;
+ return NULL;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Restore the database file to its condition before open_db(). This is
+ * identical to close_db() for files open for reading; however, for files
+ * open for writing, we first attempt to restore any backup file before
+ * closing files.
+ * @param dbFile struct
+ * @return void
+ */
+void restore_db(dbFILE * f)
+{
+ int errno_save = errno;
+
+ if (f->mode == 'w') {
+ int ok = 0; /* Did we manage to restore the old file? */
+ errno = errno_save = 0;
+ if (*f->backupname && strcmp(f->backupname, f->filename) != 0) {
+ if (rename(f->backupname, f->filename) == 0)
+ ok = 1;
+ }
+ if (!ok && f->backupfp) {
+ char buf[1024];
+ int i;
+ ok = 1;
+ if (fseek(f->fp, 0, SEEK_SET) < 0)
+ ok = 0;
+ while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) {
+ if (fwrite(buf, 1, i, f->fp) != i)
+ ok = 0;
+ }
+ if (ok) {
+ fflush(f->fp);
+ ftruncate(fileno(f->fp), ftell(f->fp));
+ }
+ }
+#ifndef NOT_MAIN
+ if (!ok && errno > 0)
+ log_perror("Unable to restore backup of %s", f->filename);
+#endif
+ errno_save = errno;
+ if (f->backupfp)
+ fclose(f->backupfp);
+ if (*f->backupname)
+#ifndef _WIN32
+ unlink(f->backupname);
+#else
+ DeleteFile(f->backupname);
+#endif
+ }
+ fclose(f->fp);
+ if (!errno_save)
+ errno_save = errno;
+ free(f);
+ errno = errno_save;
+}
+
+/*************************************************************************/
+
+/**
+ * Close a database file. If the file was opened for write, remove the
+ * backup we (may have) created earlier.
+ * @param dbFile struct
+ * @return void
+ */
+void close_db(dbFILE * f)
+{
+ if (f->mode == 'w' && *f->backupname
+ && strcmp(f->backupname, f->filename) != 0) {
+ if (f->backupfp)
+ fclose(f->backupfp);
+#ifndef _WIN32
+ unlink(f->backupname);
+#else
+ DeleteFile(f->backupname);
+#endif
+ }
+ fclose(f->fp);
+ free(f);
+}
+
+/*************************************************************************/
+
+/**
+ * Read and write 2- and 4-byte quantities, pointers, and strings. All
+ * multibyte values are stored in big-endian order (most significant byte
+ * first). A pointer is stored as a byte, either 0 if NULL or 1 if not,
+ * and read pointers are returned as either (void *)0 or (void *)1. A
+ * string is stored with a 2-byte unsigned length (including the trailing
+ * \0) first; a length of 0 indicates that the string pointer is NULL.
+ * Written strings are truncated silently at 65534 bytes, and are always
+ * null-terminated.
+ *
+ * @param ret 16bit integer to write
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int read_int16(uint16 * ret, dbFILE * f)
+{
+ int c1, c2;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF)
+ return -1;
+ *ret = c1 << 8 | c2;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Write a 16bit integer
+ *
+ * @param ret 16bit integer to write
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int write_int16(uint16 val, dbFILE * f)
+{
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF
+ || fputc(val & 0xFF, f->fp) == EOF) {
+ return -1;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Read a unsigned 32bit integer
+ *
+ * @param ret unsigned 32bit integer to read
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int read_int32(uint32 * ret, dbFILE * f)
+{
+ int c1, c2, c3, c4;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ c3 = fgetc(f->fp);
+ c4 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
+ return -1;
+ *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Write a unsigned 32bit integer
+ *
+ * @param ret unsigned 32bit integer to write
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int write_int32(uint32 val, dbFILE * f)
+{
+ if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val) & 0xFF, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Read Pointer
+ *
+ * @param ret pointer to read
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int read_ptr(void **ret, dbFILE * f)
+{
+ int c;
+
+ c = fgetc(f->fp);
+ if (c == EOF)
+ return -1;
+ *ret = (c ? (void *) 1 : (void *) 0);
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Write Pointer
+ *
+ * @param ret pointer to write
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int write_ptr(const void *ptr, dbFILE * f)
+{
+ if (fputc(ptr ? 1 : 0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Read String
+ *
+ * @param ret string
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int read_string(char **ret, dbFILE * f)
+{
+ char *s;
+ uint16 len;
+
+ if (read_int16(&len, f) < 0)
+ return -1;
+ if (len == 0) {
+ *ret = NULL;
+ return 0;
+ }
+ s = scalloc(len, 1);
+ if (len != fread(s, 1, len, f->fp)) {
+ free(s);
+ return -1;
+ }
+ *ret = s;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Write String
+ *
+ * @param ret string
+ * @param dbFile struct
+ * @return -1 on error, 0 otherwise.
+ */
+int write_string(const char *s, dbFILE * f)
+{
+ uint32 len;
+
+ if (!s)
+ return write_int16(0, f);
+ len = strlen(s);
+ if (len > 65534)
+ len = 65534;
+ if (write_int16((uint16) (len + 1), f) < 0)
+ return -1;
+ if (len > 0 && fwrite(s, 1, len, f->fp) != len)
+ return -1;
+ if (fputc(0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Renames a database
+ *
+ * @param name Database to name
+ * @param ext Extention
+ * @return void
+ */
+static void rename_database(char *name, char *ext)
+{
+
+ char destpath[PATH_MAX];
+
+ snprintf(destpath, sizeof(destpath), "backups/%s.%s", name, ext);
+ if (rename(name, destpath) != 0) {
+ alog("Backup of %s failed.", name);
+ anope_cmd_global(s_OperServ, "WARNING! Backup of %s failed.",
+ name);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Removes old databases
+ *
+ * @return void
+ */
+static void remove_backups(void)
+{
+
+ char ext[9];
+ char path[PATH_MAX];
+
+ time_t t;
+ struct tm tm;
+
+ time(&t);
+ t -= (60 * 60 * 24 * KeepBackups);
+ tm = *localtime(&t);
+ strftime(ext, sizeof(ext), "%Y%m%d", &tm);
+
+ snprintf(path, sizeof(path), "backups/%s.%s", NickDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ snprintf(path, sizeof(path), "backups/%s.%s", ChanDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ snprintf(path, sizeof(path), "backups/%s.%s", OperDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ snprintf(path, sizeof(path), "backups/%s.%s", NewsDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ snprintf(path, sizeof(path), "backups/%s.%s", ExceptionDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+
+ if (s_BotServ) {
+ snprintf(path, sizeof(path), "backups/%s.%s", BotDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ }
+ if (s_HostServ) {
+ snprintf(path, sizeof(path), "backups/%s.%s", HostDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ }
+ if (NSEmailReg) {
+ snprintf(path, sizeof(path), "backups/%s.%s", PreNickDBName, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Handles database backups.
+ *
+ * @return void
+ */
+void backup_databases(void)
+{
+
+ time_t t;
+ struct tm tm;
+
+ if (!KeepBackups) {
+ return;
+ }
+
+ time(&t);
+ tm = *localtime(&t);
+
+ if (!curday) {
+ curday = tm.tm_yday;
+ return;
+ }
+
+ if (curday != tm.tm_yday) {
+
+ char ext[9];
+
+ send_event(EVENT_DB_BACKUP, 1, EVENT_START);
+ alog("Backing up databases");
+
+ remove_backups();
+
+ curday = tm.tm_yday;
+ strftime(ext, sizeof(ext), "%Y%m%d", &tm);
+
+ if (!skeleton) {
+ rename_database(NickDBName, ext);
+ if (s_BotServ) {
+ rename_database(BotDBName, ext);
+ }
+ rename_database(ChanDBName, ext);
+ if (s_HostServ) {
+ rename_database(HostDBName, ext);
+ }
+ if (NSEmailReg) {
+ rename_database(PreNickDBName, ext);
+ }
+ }
+
+ rename_database(OperDBName, ext);
+ rename_database(NewsDBName, ext);
+ rename_database(ExceptionDBName, ext);
+ send_event(EVENT_DB_BACKUP, 1, EVENT_STOP);
+ }
+}
+
+/*************************************************************************/
+
+void ModuleDatabaseBackup(char *dbname)
+{
+
+ time_t t;
+ struct tm tm;
+
+ if (!KeepBackups) {
+ return;
+ }
+
+ time(&t);
+ tm = *localtime(&t);
+
+ if (!curday) {
+ curday = tm.tm_yday;
+ return;
+ }
+
+ if (curday != tm.tm_yday) {
+
+ char ext[9];
+
+ if (debug) {
+ alog("Module Database Backing up %s", dbname);
+ }
+ ModuleRemoveBackups(dbname);
+ curday = tm.tm_yday;
+ strftime(ext, sizeof(ext), "%Y%m%d", &tm);
+ rename_database(dbname, ext);
+ }
+}
+
+/*************************************************************************/
+
+void ModuleRemoveBackups(char *dbname)
+{
+ char ext[9];
+ char path[PATH_MAX];
+
+ time_t t;
+ struct tm tm;
+
+ time(&t);
+ t -= (60 * 60 * 24 * KeepBackups);
+ tm = *localtime(&t);
+ strftime(ext, sizeof(ext), "%Y%m%d", &tm);
+
+ snprintf(path, sizeof(path), "backups/%s.%s", dbname, ext);
+#ifndef _WIN32
+ unlink(path);
+#else
+ DeleteFile(path);
+#endif
+}
+
+/*************************************************************************/
diff --git a/src/encrypt.c b/src/encrypt.c
new file mode 100644
index 000000000..9b68ca9d7
--- /dev/null
+++ b/src/encrypt.c
@@ -0,0 +1,122 @@
+/* Include file for high-level encryption routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "encrypt.h"
+
+Encryption encryption;
+
+/******************************************************************************/
+void encmodule_encrypt(int (*func)
+ (const char *src, int len, char *dest, int size))
+{
+ encryption.encrypt = func;
+}
+
+void encmodule_encrypt_in_place(int (*func) (char *buf, int size))
+{
+ encryption.encrypt_in_place = func;
+}
+
+void encmodule_encrypt_check_len(int (*func) (int passlen, int bufsize))
+{
+ encryption.encrypt_check_len = func;
+}
+
+void encmodule_decrypt(int (*func) (const char *src, char *dest, int size))
+{
+ encryption.decrypt = func;
+}
+
+void encmodule_check_password(int (*func)
+ (const char *plaintext,
+ const char *password))
+{
+ encryption.check_password = func;
+}
+
+/******************************************************************************/
+
+
+/**
+ * Encrypt string `src' of length `len', placing the result in buffer
+ * `dest' of size `size'. Returns 0 on success, -1 on error.
+ **/
+int enc_encrypt(const char *src, int len, char *dest, int size)
+{
+ if (encryption.encrypt) {
+ return encryption.encrypt(src, len, dest, size);
+ }
+ return -1;
+}
+
+/**
+ * Encrypt null-terminated string stored in buffer `buf' of size `size',
+ * placing the result in the same buffer. Returns 0 on success, -1 on
+ * error.
+ **/
+int enc_encrypt_in_place(char *buf, int size)
+{
+ if (encryption.encrypt_in_place) {
+ return encryption.encrypt_in_place(buf, size);
+ }
+ return -1;
+}
+
+/**
+ * Check whether the result of encrypting a password of length `passlen'
+ * will fit in a buffer of size `bufsize'. Returns 0 if the encrypted
+ * password would fit in the buffer, otherwise returns the maximum length
+ * password that would fit (this value will be smaller than `passlen').
+ * If the result of encrypting even a 1-byte password would exceed the
+ * specified buffer size, generates a fatal error.
+ **/
+int enc_encrypt_check_len(int passlen, int bufsize)
+{
+ if (encryption.encrypt_check_len) {
+ return encryption.encrypt_check_len(passlen, bufsize);
+ }
+ return -1;
+}
+
+/**
+ * Decrypt encrypted string `src' into buffer `dest' of length `len'.
+ * Returns 1 (not 0) on success, 0 if the encryption algorithm does not
+ * allow decryption, and -1 if another failure occurred (e.g. destination
+ * buffer too small).
+ **/
+int enc_decrypt(const char *src, char *dest, int size)
+{
+ if (encryption.decrypt) {
+ return encryption.decrypt(src, dest, size);
+ }
+ return -1;
+}
+
+/**
+ * Check an input password `plaintext' against a stored, encrypted password
+ * `password'. Return value is:
+ * 1 if the password matches
+ * 0 if the password does not match
+ * -1 if an error occurred while checking
+ **/
+int enc_check_password(const char *plaintext, const char *password)
+{
+ if (encryption.check_password) {
+ return encryption.check_password(plaintext, password);
+ }
+ return -1;
+}
+
+/* EOF */
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 000000000..1df4dfe2d
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,787 @@
+/* Events functions.
+ *
+ * (C) 2004-2008 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"
+
+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(const char *name, int argc, ...)
+{
+ va_list va;
+ char *a;
+ int idx = 0;
+ char **argv;
+
+ argv = (char **) malloc(sizeof(char *) * argc);
+ va_start(va, argc);
+ for (idx = 0; idx < argc; idx++) {
+ a = va_arg(va, char *);
+ argv[idx] = sstrdup(a);
+ }
+ va_end(va);
+
+ if (debug)
+ alog("debug: Emitting event \"%s\" (%d args)", name, argc);
+
+ event_process_hook(name, argc, argv);
+
+ /**
+ * Now that the events have seen the message, free it up
+ **/
+ for (idx = 0; idx < argc; idx++) {
+ free(argv[idx]);
+ }
+ free(argv);
+}
+
+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(const char *name, int argc, char **argv)
+{
+ int retVal = 0;
+ EvtHook *current = NULL;
+ EvtHook *evh;
+ if (mod_current_evtbuffer) {
+ free(mod_current_evtbuffer);
+ }
+ /* Do something with the message. */
+ evh = find_eventhook(name);
+ if (evh) {
+ if (evh->func) {
+ mod_current_module_name = evh->mod_name;
+ retVal = evh->func(argc, argv);
+ 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(argc, argv);
+ 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("debug: 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("debug: 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("debug: 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("debug: 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) (int argc, char **argv))
+{
+ 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("debug: 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("debug: 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) == 0) {
+ 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/helpserv.c b/src/helpserv.c
new file mode 100644
index 000000000..eaadf1566
--- /dev/null
+++ b/src/helpserv.c
@@ -0,0 +1,69 @@
+/* HelpServ functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+/*************************************************************************/
+#include "services.h"
+#include "pseudo.h"
+
+void moduleAddHelpServCmds(void);
+
+/*************************************************************************/
+
+/**
+ * Setup the commands for HelpServ
+ * @return void
+ */
+void moduleAddHelpServCmds(void)
+{
+ modules_core_init(HelpServCoreNumber, HelpServCoreModules);
+}
+
+/*************************************************************************/
+
+/**
+ * HelpServ initialization.
+ * @return void
+ */
+void helpserv_init(void)
+{
+ moduleAddHelpServCmds();
+}
+
+/*************************************************************************/
+
+/**
+ * Main HelpServ routine.
+ * @param u User Struct of the user sending the PRIVMSG
+ * @param buf Buffer containing the PRIVMSG data
+ * @return void
+ */
+void helpserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_HelpServ, u->nick, "PING %s", s);
+ } else {
+ mod_run_cmd(s_HelpServ, u, HELPSERV, cmd);
+ }
+}
+
+/*************************************************************************/
diff --git a/src/hostserv.c b/src/hostserv.c
new file mode 100644
index 000000000..bdb6dbba3
--- /dev/null
+++ b/src/hostserv.c
@@ -0,0 +1,655 @@
+/* HostServ functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+/*************************************************************************/
+#include "services.h"
+#include "pseudo.h"
+
+#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
+
+void load_hs_dbase_v1(dbFILE * f);
+void load_hs_dbase_v2(dbFILE * f);
+void load_hs_dbase_v3(dbFILE * f);
+
+HostCore *head = NULL; /* head of the HostCore list */
+
+E int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask,
+ char *creator, time_t time);
+
+E void moduleAddHostServCmds(void);
+
+/*************************************************************************/
+
+void moduleAddHostServCmds(void)
+{
+ modules_core_init(HostServCoreNumber, HostServCoreModules);
+}
+
+/*************************************************************************/
+
+/**
+ * Return information on memory use.
+ * Assumes pointers are valid.
+ **/
+
+void get_hostserv_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i;
+ HostCore *hc;
+
+ for (hc = head; hc; hc = hc->next) {
+ count++;
+ mem += sizeof(*hc);
+ if (hc->nick)
+ mem += strlen(hc->nick) + 1;
+ if (hc->vIdent)
+ mem += strlen(hc->vIdent) + 1;
+ if (hc->vHost)
+ mem += strlen(hc->vHost) + 1;
+ if (hc->creator)
+ mem += strlen(hc->creator) + 1;
+ }
+
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+
+/**
+ * HostServ initialization.
+ * @return void
+ */
+void hostserv_init(void)
+{
+ if (s_HostServ) {
+ moduleAddHostServCmds();
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Main HostServ routine.
+ * @param u User Struct
+ * @param buf Buffer holding the message
+ * @return void
+ */
+void hostserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_HostServ, u->nick, "PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_HostServ, u, SERVICE_OFFLINE, s_HostServ);
+ } else {
+ if (ircd->vhost) {
+ mod_run_cmd(s_HostServ, u, HOSTSERV, cmd);
+ } else {
+ notice_lang(s_HostServ, u, SERVICE_OFFLINE, s_HostServ);
+ }
+ }
+}
+
+/*************************************************************************/
+/* Start of Linked List routines */
+/*************************************************************************/
+
+HostCore *hostCoreListHead()
+{
+ return head;
+}
+
+/**
+ * Create HostCore list member
+ * @param next HostCore next slot
+ * @param nick Nick to add
+ * @param vIdent Virtual Ident
+ * @param vHost Virtual Host
+ * @param creator Person whom set the vhost
+ * @param time Time the vhost was Set
+ * @return HostCore
+ */
+HostCore *createHostCorelist(HostCore * next, char *nick, char *vIdent,
+ char *vHost, char *creator, int32 tmp_time)
+{
+
+ next = malloc(sizeof(HostCore));
+ if (next == NULL) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to create the vHost LL, problems i sense..");
+ } else {
+ next->nick = malloc(sizeof(char) * strlen(nick) + 1);
+ next->vHost = malloc(sizeof(char) * strlen(vHost) + 1);
+ next->creator = malloc(sizeof(char) * strlen(creator) + 1);
+ if (vIdent)
+ next->vIdent = malloc(sizeof(char) * strlen(vIdent) + 1);
+ if ((next->nick == NULL) || (next->vHost == NULL)
+ || (next->creator == NULL)) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to create the vHost LL, problems i sense..");
+ return NULL;
+ }
+ strcpy(next->nick, nick);
+ strcpy(next->vHost, vHost);
+ strcpy(next->creator, creator);
+ if (vIdent) {
+ if ((next->vIdent == NULL)) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to create the vHost LL, problems i sense..");
+ return NULL;
+ }
+ strcpy(next->vIdent, vIdent);
+ } else {
+ next->vIdent = NULL;
+ }
+ next->time = tmp_time;
+ next->next = NULL;
+ return next;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+/**
+ * Returns either NULL for the head, or the location of the *PREVIOUS*
+ * record, this is where we need to insert etc..
+ * @param head HostCore head
+ * @param nick Nick to find
+ * @param found If found
+ * @return HostCore
+ */
+HostCore *findHostCore(HostCore * head, char *nick, boolean * found)
+{
+ HostCore *previous, *current;
+
+ *found = false;
+ current = head;
+ previous = current;
+
+ if (!nick) {
+ return NULL;
+ }
+
+ while (current != NULL) {
+ if (stricmp(nick, current->nick) == 0) {
+ *found = true;
+ break;
+ } else if (stricmp(nick, current->nick) < 0) {
+ /* we know were not gonna find it now.... */
+ break;
+ } else {
+ previous = current;
+ current = current->next;
+ }
+ }
+ if (current == head) {
+ return NULL;
+ } else {
+ return previous;
+ }
+}
+
+/*************************************************************************/
+HostCore *insertHostCore(HostCore * head, HostCore * prev, char *nick,
+ char *vIdent, char *vHost, char *creator,
+ int32 tmp_time)
+{
+
+ HostCore *newCore, *tmp;
+
+ if (!nick || !vHost || !creator) {
+ return NULL;
+ }
+
+ newCore = malloc(sizeof(HostCore));
+ if (newCore == NULL) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to insert into the vHost LL, problems i sense..");
+ return NULL;
+ } else {
+ newCore->nick = malloc(sizeof(char) * strlen(nick) + 1);
+ newCore->vHost = malloc(sizeof(char) * strlen(vHost) + 1);
+ newCore->creator = malloc(sizeof(char) * strlen(creator) + 1);
+ if (vIdent)
+ newCore->vIdent = malloc(sizeof(char) * strlen(vIdent) + 1);
+ if ((newCore->nick == NULL) || (newCore->vHost == NULL)
+ || (newCore->creator == NULL)) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to create the vHost LL, problems i sense..");
+ return NULL;
+ }
+ strcpy(newCore->nick, nick);
+ strcpy(newCore->vHost, vHost);
+ strcpy(newCore->creator, creator);
+ if (vIdent) {
+ if ((newCore->vIdent == NULL)) {
+ anope_cmd_global(s_HostServ,
+ "Unable to allocate memory to create the vHost LL, problems i sense..");
+ return NULL;
+ }
+ strcpy(newCore->vIdent, vIdent);
+ } else {
+ newCore->vIdent = NULL;
+ }
+ newCore->time = tmp_time;
+ if (prev == NULL) {
+ tmp = head;
+ head = newCore;
+ newCore->next = tmp;
+ } else {
+ tmp = prev->next;
+ prev->next = newCore;
+ newCore->next = tmp;
+ }
+ }
+ return head;
+}
+
+/*************************************************************************/
+HostCore *deleteHostCore(HostCore * head, HostCore * prev)
+{
+
+ HostCore *tmp;
+
+ if (prev == NULL) {
+ tmp = head;
+ head = head->next;
+ } else {
+ tmp = prev->next;
+ prev->next = tmp->next;
+ }
+ free(tmp->vHost);
+ free(tmp->nick);
+ free(tmp->creator);
+ if (tmp->vIdent) {
+ free(tmp->vIdent);
+ }
+ free(tmp);
+ return head;
+}
+
+/*************************************************************************/
+void addHostCore(char *nick, char *vIdent, char *vhost, char *creator,
+ int32 tmp_time)
+{
+ HostCore *tmp;
+ boolean found = false;
+
+ if (head == NULL) {
+ head =
+ createHostCorelist(head, nick, vIdent, vhost, creator,
+ tmp_time);
+ } else {
+ tmp = findHostCore(head, nick, &found);
+ if (!found) {
+ head =
+ insertHostCore(head, tmp, nick, vIdent, vhost, creator,
+ tmp_time);
+ } else {
+ head = deleteHostCore(head, tmp); /* delete the old entry */
+ addHostCore(nick, vIdent, vhost, creator, tmp_time); /* recursive call to add new entry */
+ }
+ }
+}
+
+/*************************************************************************/
+char *getvHost(char *nick)
+{
+ HostCore *tmp;
+ boolean found = false;
+ tmp = findHostCore(head, nick, &found);
+ if (found) {
+ if (tmp == NULL)
+ return head->vHost;
+ else
+ return tmp->next->vHost;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+char *getvIdent(char *nick)
+{
+ HostCore *tmp;
+ boolean found = false;
+ tmp = findHostCore(head, nick, &found);
+ if (found) {
+ if (tmp == NULL)
+ return head->vIdent;
+ else
+ return tmp->next->vIdent;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+void delHostCore(char *nick)
+{
+#ifdef USE_RDB
+ static char clause[128];
+ char *q_nick;
+#endif
+ HostCore *tmp;
+ boolean found = false;
+ tmp = findHostCore(head, nick, &found);
+ if (found) {
+ head = deleteHostCore(head, tmp);
+
+#ifdef USE_RDB
+ /* Reflect this change in the database right away. */
+ if (rdb_open()) {
+ q_nick = rdb_quote(nick);
+ snprintf(clause, sizeof(clause), "nick='%s'", q_nick);
+ if (rdb_scrub_table("anope_hs_core", clause) == 0)
+ alog("Unable to scrub table 'anope_hs_core' - HostServ RDB update failed.");
+ rdb_close();
+ free(q_nick);
+ }
+#endif
+
+ }
+
+}
+
+/*************************************************************************/
+/* End of Linked List routines */
+/*************************************************************************/
+/*************************************************************************/
+/* Start of Load/Save routines */
+/*************************************************************************/
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", HostDBName); \
+ failed = 1; \
+ break; \
+ } \
+} while (0)
+
+void load_hs_dbase(void)
+{
+ dbFILE *f;
+ int ver;
+
+ if (!(f = open_db(s_HostServ, HostDBName, "r", HOST_VERSION))) {
+ return;
+ }
+ ver = get_file_version(f);
+
+ if (ver == 1) {
+ load_hs_dbase_v1(f);
+ } else if (ver == 2) {
+ load_hs_dbase_v2(f);
+ } else if (ver == 3) {
+ load_hs_dbase_v3(f);
+ }
+ close_db(f);
+}
+
+void load_hs_dbase_v1(dbFILE * f)
+{
+ int c;
+ int failed = 0;
+ int32 tmp;
+
+ char *nick;
+ char *vHost;
+
+ tmp = time(NULL);
+
+ while (!failed && (c = getc_db(f)) == 1) {
+
+ if (c == 1) {
+ SAFE(read_string(&nick, f));
+ SAFE(read_string(&vHost, f));
+ addHostCore(nick, NULL, vHost, "Unknown", tmp); /* could get a speed increase by not searching the list */
+ free(nick); /* as we know the db is in alphabetical order... */
+ free(vHost);
+ } else {
+ fatal("Invalid format in %s %d", HostDBName, c);
+ }
+ }
+}
+
+void load_hs_dbase_v2(dbFILE * f)
+{
+ int c;
+ int failed = 0;
+
+ char *nick;
+ char *vHost;
+ char *creator;
+ uint32 time;
+
+ while (!failed && (c = getc_db(f)) == 1) {
+
+ if (c == 1) {
+ SAFE(read_string(&nick, f));
+ SAFE(read_string(&vHost, f));
+ SAFE(read_string(&creator, f));
+ SAFE(read_int32(&time, f));
+ addHostCore(nick, NULL, vHost, creator, time); /* could get a speed increase by not searching the list */
+ free(nick); /* as we know the db is in alphabetical order... */
+ free(vHost);
+ free(creator);
+ } else {
+ fatal("Invalid format in %s %d", HostDBName, c);
+ }
+ }
+}
+
+void load_hs_dbase_v3(dbFILE * f)
+{
+ int c;
+ int failed = 0;
+
+ char *nick;
+ char *vHost;
+ char *creator;
+ char *vIdent;
+ uint32 time;
+
+ while (!failed && (c = getc_db(f)) == 1) {
+ if (c == 1) {
+ SAFE(read_string(&nick, f));
+ SAFE(read_string(&vIdent, f));
+ SAFE(read_string(&vHost, f));
+ SAFE(read_string(&creator, f));
+ SAFE(read_int32(&time, f));
+ addHostCore(nick, vIdent, vHost, creator, time); /* could get a speed increase by not searching the list */
+ free(nick); /* as we know the db is in alphabetical order... */
+ free(vHost);
+ free(creator);
+ free(vIdent);
+ } else {
+ fatal("Invalid format in %s %d", HostDBName, c);
+ }
+ }
+}
+
+#undef SAFE
+/*************************************************************************/
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", HostDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", HostDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_hs_dbase(void)
+{
+ dbFILE *f;
+ static time_t lastwarn = 0;
+ HostCore *current;
+
+ if (!(f = open_db(s_HostServ, HostDBName, "w", HOST_VERSION)))
+ return;
+
+ current = head;
+ while (current != NULL) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(current->nick, f));
+ SAFE(write_string(current->vIdent, f));
+ SAFE(write_string(current->vHost, f));
+ SAFE(write_string(current->creator, f));
+ SAFE(write_int32(current->time, f));
+ current = current->next;
+ }
+ SAFE(write_int8(0, f));
+ close_db(f);
+
+}
+
+#undef SAFE
+
+void save_hs_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ HostCore *current;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_hs_core") == 0) {
+ alog("Unable to tag table 'anope_hs_core' - HostServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+
+ current = head;
+ while (current != NULL) {
+ if (rdb_save_hs_core(current) == 0) {
+ alog("Unable to save HostCore for %s - HostServ RDB save failed.", current->nick);
+ rdb_close();
+ return;
+ }
+ current = current->next;
+ }
+
+ if (rdb_clean_table("anope_hs_core") == 0)
+ alog("Unable to clean table 'anope_hs_core' - HostServ RDB save failed.");
+
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+/* End of Load/Save Functions */
+/*************************************************************************/
+/*************************************************************************/
+/* Start of Generic Functions */
+/*************************************************************************/
+
+int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask, char *creator,
+ time_t time)
+{
+ int i;
+ NickAlias *na;
+
+ for (i = 0; i < nc->aliases.count; i++) {
+ na = nc->aliases.list[i];
+ addHostCore(na->nick, vIdent, hostmask, creator, time);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+int do_on_id(User * u)
+{ /* we've assumed that the user exists etc.. */
+ char *vHost; /* as were only gonna call this from nsid routine */
+ char *vIdent;
+ vHost = getvHost(u->nick);
+ vIdent = getvIdent(u->nick);
+ if (vHost != NULL) {
+ if (vIdent) {
+ notice_lang(s_HostServ, u, HOST_IDENT_ACTIVATED, vIdent,
+ vHost);
+ } else {
+ notice_lang(s_HostServ, u, HOST_ACTIVATED, vHost);
+ }
+ anope_cmd_vhost_on(u->nick, vIdent, vHost);
+ if (ircd->vhost) {
+ u->vhost = sstrdup(vHost);
+ }
+ if (ircd->vident) {
+ if (vIdent)
+ u->vident = sstrdup(vIdent);
+ }
+ set_lastmask(u);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+int is_host_setter(User * u)
+{
+ int i, j;
+ NickAlias *na;
+
+ if (is_services_oper(u)) {
+ return 1;
+ }
+ if (!nick_identified(u)) {
+ return 0;
+ }
+
+ /* Look through all user's aliases (0000412) */
+ for (i = 0; i < u->na->nc->aliases.count; i++) {
+ na = u->na->nc->aliases.list[i];
+ for (j = 0; j < HostNumber; j++) {
+ if (stricmp(HostSetters[j], na->nick) == 0) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int is_host_remover(User * u)
+{
+ return is_host_setter(u); /* only here incase we want to split them up later */
+}
+
+/*
+ * Sets the last_usermak properly. Using virtual ident and/or host
+ */
+void set_lastmask(User * u)
+{
+ if (u->na->last_usermask)
+ free(u->na->last_usermask);
+
+ u->na->last_usermask =
+ smalloc(strlen(common_get_vident(u)) +
+ strlen(common_get_vhost(u)) + 2);
+ sprintf(u->na->last_usermask, "%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+
+}
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 000000000..527df792a
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,789 @@
+/* Initalization and related routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+int servernum = 0;
+
+extern void moduleAddMsgs(void);
+extern void moduleAddIRCDMsgs(void);
+
+/*************************************************************************/
+
+void introduce_user(const char *user)
+{
+
+ /* Watch out for infinite loops... */
+#define LTSIZE 20
+ static int lasttimes[LTSIZE];
+ if (lasttimes[0] >= time(NULL) - 3)
+ fatal("introduce_user() loop detected");
+ memmove(lasttimes, lasttimes + 1, sizeof(lasttimes) - sizeof(int));
+ lasttimes[LTSIZE - 1] = time(NULL);
+#undef LTSIZE
+
+ /* Introduce OperServ first because on some IRCd's send
+ * we send data from OperServ before introduction completes.
+ * Patch fixing ratbox RESV support provided by Jobe. */
+ if (!user || stricmp(user, s_OperServ) == 0) {
+ anope_cmd_nick(s_OperServ, desc_OperServ, ircd->operservmode);
+ }
+
+ /* NickServ */
+ if (!user || stricmp(user, s_NickServ) == 0) {
+ anope_cmd_nick(s_NickServ, desc_NickServ, ircd->nickservmode);
+ }
+
+ /* ChanServ */
+ if (!user || stricmp(user, s_ChanServ) == 0) {
+ anope_cmd_nick(s_ChanServ, desc_ChanServ, ircd->chanservmode);
+ }
+ if (s_HostServ && ircd->vhost
+ && (!user || stricmp(user, s_HostServ) == 0)) {
+ anope_cmd_nick(s_HostServ, desc_HostServ, ircd->hostservmode);
+ }
+
+ if (!user || stricmp(user, s_MemoServ) == 0) {
+ anope_cmd_nick(s_MemoServ, desc_MemoServ, ircd->memoservmode);
+ }
+
+ if (s_BotServ && (!user || stricmp(user, s_BotServ) == 0)) {
+ anope_cmd_nick(s_BotServ, desc_BotServ, ircd->botservmode);
+ }
+
+ if (!user || stricmp(user, s_HelpServ) == 0) {
+ anope_cmd_nick(s_HelpServ, desc_HelpServ, ircd->helpservmode);
+ }
+
+ if (s_DevNull && (!user || stricmp(user, s_DevNull) == 0)) {
+ anope_cmd_nick(s_DevNull, desc_DevNull, ircd->devnullmode);
+ }
+
+ if (!user || stricmp(user, s_GlobalNoticer) == 0) {
+ anope_cmd_nick(s_GlobalNoticer, desc_GlobalNoticer,
+ ircd->globalmode);
+ }
+
+ /* We make aliases go online */
+ if (s_NickServAlias && (!user || stricmp(user, s_NickServAlias) == 0)) {
+ anope_cmd_nick(s_NickServAlias, desc_NickServAlias,
+ ircd->nickservaliasmode);
+ }
+
+ if (s_ChanServAlias && (!user || stricmp(user, s_ChanServAlias) == 0)) {
+ anope_cmd_nick(s_ChanServAlias, desc_ChanServAlias,
+ ircd->chanservaliasmode);
+ }
+
+ if (s_MemoServAlias && (!user || stricmp(user, s_MemoServAlias) == 0)) {
+ anope_cmd_nick(s_MemoServAlias, desc_MemoServAlias,
+ ircd->memoservaliasmode);
+ }
+
+ if (s_BotServAlias && (!user || stricmp(user, s_BotServAlias) == 0)) {
+ anope_cmd_nick(s_BotServAlias, desc_BotServAlias,
+ ircd->botservaliasmode);
+ }
+
+ if (s_HelpServAlias && (!user || stricmp(user, s_HelpServAlias) == 0)) {
+ anope_cmd_nick(s_HelpServAlias, desc_HelpServAlias,
+ ircd->helpservaliasmode);
+ }
+
+ if (s_OperServAlias && (!user || stricmp(user, s_OperServAlias) == 0)) {
+ anope_cmd_nick(s_OperServAlias, desc_OperServAlias,
+ ircd->operservaliasmode);
+ }
+
+ if (s_DevNullAlias && (!user || stricmp(user, s_DevNullAlias) == 0)) {
+ anope_cmd_nick(s_DevNullAlias, desc_DevNullAlias,
+ ircd->devnullvaliasmode);
+ }
+ if (s_HostServAlias && ircd->vhost
+ && (!user || stricmp(user, s_HostServAlias) == 0)) {
+ anope_cmd_nick(s_HostServAlias, desc_HostServAlias,
+ ircd->hostservaliasmode);
+ }
+ if (s_GlobalNoticerAlias
+ && (!user || stricmp(user, s_GlobalNoticerAlias) == 0)) {
+ anope_cmd_nick(s_GlobalNoticerAlias, desc_GlobalNoticerAlias,
+ ircd->globalaliasmode);
+ }
+
+ /* We make the bots go online */
+ if (s_BotServ) {
+ BotInfo *bi;
+ int i;
+
+ for (i = 0; i < 256; i++)
+ for (bi = botlists[i]; bi; bi = bi->next) {
+
+ if (!user || !stricmp(user, bi->nick))
+ anope_cmd_bot_nick(bi->nick, bi->user, bi->host,
+ bi->real, ircd->botserv_bot_mode);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Set GID if necessary. Return 0 if successful (or if RUNGROUP not
+ * defined), else print an error message to logfile and return -1.
+ */
+
+static int set_group(void)
+{
+#if defined(RUNGROUP) && defined(HAVE_SETGRENT)
+ struct group *gr;
+
+ setgrent();
+ while ((gr = getgrent()) != NULL) {
+ if (strcmp(gr->gr_name, RUNGROUP) == 0)
+ break;
+ }
+ endgrent();
+ if (gr) {
+ setgid(gr->gr_gid);
+ return 0;
+ } else {
+ alog("Unknown group `%s'\n", RUNGROUP);
+ return -1;
+ }
+#else
+ return 0;
+#endif
+}
+
+/*************************************************************************/
+
+/* Parse command-line options for the "-dir" option only. Return 0 if all
+ * went well or -1 for a syntax error.
+ */
+
+/* XXX this could fail if we have "-some-option-taking-an-argument -dir" */
+
+static int parse_dir_options(int ac, char **av)
+{
+ int i;
+ char *s;
+
+ for (i = 1; i < ac; i++) {
+ s = av[i];
+ if (*s == '-') {
+ s++;
+ if (strcmp(s, "dir") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-dir requires a parameter\n");
+ return -1;
+ }
+ services_dir = av[i];
+ } else if (strcmp(s, "log") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-log requires a parameter\n");
+ return -1;
+ }
+ log_filename = av[i];
+ } else if (strcmp(s, "version") == 0) {
+ fprintf(stdout, "Anope-%s %s -- %s\n", version_number,
+ version_flags, version_build);
+ exit(EXIT_SUCCESS);
+ }
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Parse command-line options. Return 0 if all went well, -1 for an error
+ * with an option, or 1 for -help.
+ */
+
+static int parse_options(int ac, char **av)
+{
+ int i;
+ char *s, *t;
+
+ for (i = 1; i < ac; i++) {
+ s = av[i];
+ if (*s == '-') {
+ s++;
+ if (strcmp(s, "remote") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-remote requires hostname[:port]\n");
+ return -1;
+ }
+ s = av[i];
+ t = strchr(s, ':');
+ if (t) {
+ int portnum;
+ *t++ = 0;
+ portnum = atoi(t);
+ if ((portnum > 0) && (portnum < 65535))
+ RemotePort = portnum;
+ else {
+ fprintf(stderr,
+ "-remote: Port numbers must be in the range 1..65535. Using default.\n");
+ return -1;
+ }
+ }
+ RemoteServer = s;
+ } else if (strcmp(s, "local") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr,
+ "-local requires hostname or [hostname]:[port]\n");
+ return -1;
+ }
+ s = av[i];
+ t = strchr(s, ':');
+ if (t) {
+ int portnum;
+ *t++ = 0;
+ portnum = atoi(t);
+ if ((portnum >= 0) && (portnum < 65535))
+ LocalPort = portnum;
+ else {
+ fprintf(stderr,
+ "-local: Port numbers must be in the range 1..65535 or 0. Using default.\n");
+ return -1;
+ }
+ }
+ LocalHost = s;
+ } else if (strcmp(s, "name") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-name requires a parameter\n");
+ return -1;
+ }
+ ServerName = av[i];
+ } else if (strcmp(s, "desc") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-desc requires a parameter\n");
+ return -1;
+ }
+ ServerDesc = av[i];
+ } else if (strcmp(s, "user") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-user requires a parameter\n");
+ return -1;
+ }
+ ServiceUser = av[i];
+ } else if (strcmp(s, "host") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-host requires a parameter\n");
+ return -1;
+ }
+ ServiceHost = av[i];
+ } else if (strcmp(s, "dir") == 0) {
+ /* Handled by parse_dir_options() */
+ i++; /* Skip parameter */
+ } else if (strcmp(s, "log") == 0) {
+ /* Handled by parse_dir_options(), too */
+ i++; /* Skip parameter */
+ } else if (strcmp(s, "update") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-update requires a parameter\n");
+ return -1;
+ }
+ s = av[i];
+ if (atoi(s) <= 0) {
+ fprintf(stderr,
+ "-update: number of seconds must be positive");
+ return -1;
+ } else
+ UpdateTimeout = atol(s);
+ } else if (strcmp(s, "expire") == 0) {
+ if (++i >= ac) {
+ fprintf(stderr, "-expire requires a parameter\n");
+ return -1;
+ }
+ s = av[i];
+ if (atoi(s) <= 0) {
+ fprintf(stderr,
+ "-expire: number of seconds must be positive\n");
+ return -1;
+ } else
+ ExpireTimeout = atol(s);
+ } else if (strcmp(s, "debug") == 0) {
+ debug++;
+ } else if (strcmp(s, "readonly") == 0) {
+ readonly = 1;
+ skeleton = 0;
+ } else if (strcmp(s, "skeleton") == 0) {
+ readonly = 0;
+ skeleton = 1;
+ } else if (strcmp(s, "nofork") == 0) {
+ nofork = 1;
+ } else if (strcmp(s, "logchan") == 0) {
+ if (!LogChannel) {
+ fprintf(stderr,
+ "-logchan: LogChannel must be defined in services.conf\n");
+ } else { /* LogChannel */
+
+ logchan = 1;
+ }
+ } else if (strcmp(s, "forceload") == 0) {
+ forceload = 1;
+ } else if (strcmp(s, "nothird") == 0) {
+ nothird = 1;
+ } else if (strcmp(s, "protocoldebug") == 0) {
+ protocoldebug = 1;
+ } else if (strcmp(s, "support") == 0) {
+ nofork = 1;
+ debug++;
+ nothird = 1;
+ } else if (!strcmp(s, "noexpire")) {
+ noexpire = 1;
+ } else if (!strcmp(s, "help")) {
+ fprintf(stdout, "Anope-%s %s -- %s\n", version_number,
+ version_flags, version_build);
+ fprintf(stdout,
+ "Anope IRC Services (http://www.anope.org)\n");
+ fprintf(stdout, "Usage ./services [options] ...\n");
+ fprintf(stdout,
+ "-remote -remote hostname[:port]\n");
+ fprintf(stdout, "-local -local hostname[:port]\n");
+ fprintf(stdout, "-name -name servername\n");
+ fprintf(stdout, "-desc -desc serverdesc\n");
+ fprintf(stdout, "-user -user serviceuser\n");
+ fprintf(stdout, "-host -host servicehost\n");
+ fprintf(stdout,
+ "-update -update updatetime(secs)\n");
+ fprintf(stdout,
+ "-expire -expire expiretime(secs)\n");
+ fprintf(stdout, "-debug -debug\n");
+ fprintf(stdout, "-nofork -nofork\n");
+ fprintf(stdout, "-logchan -logchan channelname\n");
+ fprintf(stdout, "-skeleton -skeleton\n");
+ fprintf(stdout, "-forceload -forceload\n");
+ fprintf(stdout, "-nothird -nothird\n");
+ fprintf(stdout, "-support -support\n");
+ fprintf(stdout, "-readonly -readonly\n");
+ fprintf(stdout, "-noexpire -noexpire\n");
+ fprintf(stdout, "-version -version\n");
+ fprintf(stdout, "-help -help\n");
+ fprintf(stdout, "-log -log logfilename\n");
+ fprintf(stdout,
+ "-dir -dir servicesdirectory\n\n");
+ fprintf(stdout,
+ "Further support is available from http://www.anope.org\n");
+ fprintf(stdout,
+ "Or visit US on IRC at irc.anope.org #anope\n");
+ exit(EXIT_SUCCESS);
+ } else {
+ fprintf(stderr, "Unknown option -%s\n", s);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "Non-option arguments not allowed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Remove our PID file. Done at exit. */
+
+static void remove_pidfile(void)
+{
+ remove(PIDFilename);
+}
+
+/*************************************************************************/
+
+/* Create our PID file and write the PID to it. */
+
+static void write_pidfile(void)
+{
+ FILE *pidfile;
+
+ pidfile = fopen(PIDFilename, "w");
+ if (pidfile) {
+ fprintf(pidfile, "%d\n", (int) getpid());
+ fclose(pidfile);
+ atexit(remove_pidfile);
+ } else {
+ log_perror("Warning: cannot write to PID file %s", PIDFilename);
+ }
+}
+
+/*************************************************************************/
+
+/* Overall initialization routines. Return 0 on success, -1 on failure. */
+
+int openlog_failed = 0, openlog_errno = 0;
+
+int init_primary(int ac, char **av)
+{
+ int started_from_term = isatty(0) && isatty(1) && isatty(2);
+
+ /* Set file creation mask and group ID. */
+#if defined(DEFUMASK) && HAVE_UMASK
+ umask(DEFUMASK);
+#endif
+ if (set_group() < 0)
+ return -1;
+
+ /* Parse command line for -dir and -version options. */
+ parse_dir_options(ac, av);
+
+ /* Chdir to Services data directory. */
+ if (chdir(services_dir) < 0) {
+ fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
+ return -1;
+ }
+
+ /* Open logfile, and complain if we didn't. */
+ if (open_log() < 0) {
+ openlog_errno = errno;
+ if (started_from_term) {
+ fprintf(stderr, "Warning: unable to open log file %s: %s\n",
+ log_filename, strerror(errno));
+ } else {
+ openlog_failed = 1;
+ }
+ }
+
+ /* Read configuration file; exit if there are problems. */
+ if (!read_config(0)) {
+ return -1;
+ }
+
+ /* Add IRCD Protocol Module; exit if there are errors */
+ if (protocol_module_init()) {
+ return -1;
+ }
+
+ /* Add Encryption Module; exit if there are errors */
+ if (encryption_module_init()) {
+ return -1;
+ }
+ return 0;
+}
+
+int init_secondary(int ac, char **av)
+{
+ int i;
+ int started_from_term = isatty(0) && isatty(1) && isatty(2);
+
+ /* Add Core MSG handles */
+ moduleAddMsgs();
+
+ /* Parse all remaining command-line options. */
+ parse_options(ac, av);
+
+ /* Parse the defcon mode string if needed */
+ if (DefConLevel) {
+ if (!defconParseModeString(DefConChanModes)) {
+ fprintf(stderr,
+ "services.conf: The given DefConChanModes mode string was incorrect (see log for exact errors)\n");
+ return -1;
+ }
+ }
+#ifndef _WIN32
+ if (!nofork) {
+ if ((i = fork()) < 0) {
+ perror("fork()");
+ return -1;
+ } else if (i != 0) {
+ exit(0);
+ }
+ if (started_from_term) {
+ close(0);
+ close(1);
+ close(2);
+ }
+ if (setpgid(0, 0) < 0) {
+ perror("setpgid()");
+ return -1;
+ }
+ }
+#else
+ /* Initialize winsocks -- codemastr */
+ {
+ WSADATA wsa;
+ if (WSAStartup(MAKEWORD(1, 1), &wsa)) {
+ alog("Failed to initialized WinSock library");
+ return -1;
+ }
+ }
+ if (!SupportedWindowsVersion()) {
+
+ char *winver = GetWindowsVersion();
+
+ alog("%s is not a supported version of Windows", winver);
+
+ free(winver);
+
+ return -1;
+
+ }
+ if (!nofork) {
+ alog("Launching Anope into the background");
+ FreeConsole();
+ }
+#endif
+
+ /* Write our PID to the PID file. */
+ write_pidfile();
+
+ /* Announce ourselves to the logfile. */
+ if (debug || readonly || skeleton) {
+ alog("Anope %s (ircd protocol: %s) starting up (options:%s%s%s)",
+ version_number, version_protocol,
+ debug ? " debug" : "", readonly ? " readonly" : "",
+ skeleton ? " skeleton" : "");
+ } else {
+ alog("Anope %s (ircd protocol: %s) starting up",
+ version_number, version_protocol);
+ }
+ start_time = time(NULL);
+
+
+
+ /* If in read-only mode, close the logfile again. */
+ if (readonly)
+ close_log();
+
+ /* Set signal handlers. Catch certain signals to let us do things or
+ * panic as necessary, and ignore all others.
+ */
+
+#ifndef _WIN32
+#if defined(NSIG)
+ for (i = 1; i <= NSIG - 1; i++) {
+#else
+ for (i = 1; i <= 31; i++) {
+#endif
+ signal(i, SIG_IGN);
+ }
+#else
+ /* work around to bug #527 */
+ signal(SIGILL, SIG_IGN);
+ signal(SIGBREAK, SIG_IGN);
+ signal(SIGABRT, SIG_IGN);
+#endif
+
+ signal(SIGINT, sighandler);
+ signal(SIGTERM, sighandler);
+#ifndef _WIN32
+ signal(SIGQUIT, sighandler);
+#endif
+ if (!DumpCore) {
+ signal(SIGSEGV, sighandler);
+#ifndef _WIN32
+ signal(SIGBUS, sighandler);
+ signal(SIGTRAP, sighandler);
+#endif
+ } else {
+ signal(SIGSEGV, SIG_DFL);
+#ifndef _WIN32
+ signal(SIGBUS, sighandler);
+ signal(SIGTRAP, sighandler);
+#endif
+ }
+#ifndef _WIN32
+ signal(SIGQUIT, sighandler);
+ signal(SIGHUP, sighandler);
+ signal(SIGUSR2, sighandler);
+#endif
+
+#ifdef SIGIOT
+ signal(SIGIOT, sighandler);
+#endif
+ signal(SIGFPE, sighandler);
+
+#ifndef _WIN32
+ signal(SIGUSR1, sighandler); /* This is our "out-of-memory" panic switch */
+#endif
+
+ /* Initialize multi-language support */
+ lang_init();
+ if (debug)
+ alog("debug: Loaded languages");
+
+
+ /* Initialize subservices */
+ ns_init();
+ cs_init();
+ ms_init();
+ bs_init();
+ os_init();
+ hostserv_init();
+ helpserv_init();
+
+#ifdef USE_RDB
+ if (!rdb_init()) {
+ if (UseRDB) {
+ UseRDB = 0;
+ alog("Error: Disabling UseRDB due to errors with SQL");
+ }
+ } else {
+ if (MysqlSecure && UseRDB) {
+ UseRDB = 0;
+ alog("Error: MySQL password are encrypted using method in MysqlSecure disabling UseRDB");
+ }
+ }
+#endif
+
+ /* load any custom modules */
+ modules_init();
+
+ /* Initialize random number generator */
+ rand_init();
+ add_entropy_userkeys();
+
+ /* Load up databases */
+#ifdef USE_RDB
+ if (UseRDB)
+ rdb_load_dbases();
+ /* Need a better way to handle this -dane */
+ if (!UseRDB) {
+#endif
+ if (!skeleton) {
+ load_ns_dbase();
+ if (debug)
+ alog("debug: Loaded %s database (1/%d)", s_NickServ,
+ (PreNickDBName ? 8 : 7));
+ if (s_HostServ) {
+ load_hs_dbase();
+ if (debug)
+ alog("debug: Loaded %s database (2/%d)", s_HostServ,
+ (PreNickDBName ? 8 : 7));
+ } else if (debug) {
+ alog("debug: HostServ database (2/%d) not loaded because HostServ is disabled", (PreNickDBName ? 8 : 7));
+ }
+ if (s_BotServ) {
+ load_bs_dbase();
+ if (debug)
+ alog("debug: Loaded %s database (3/%d)", s_BotServ,
+ (PreNickDBName ? 8 : 7));
+ } else if (debug) {
+ alog("debug: BotServ database (3/%d) not loaded because BotServ is disabled", (PreNickDBName ? 8 : 7));
+ }
+ load_cs_dbase();
+ if (debug)
+ alog("debug: Loaded %s database (4/%d)", s_ChanServ,
+ (PreNickDBName ? 8 : 7));
+ }
+ load_os_dbase();
+ if (debug)
+ alog("debug: Loaded %s database (5/%d)", s_OperServ,
+ (PreNickDBName ? 8 : 7));
+ load_news();
+ if (debug)
+ alog("debug: Loaded news database (6/%d)",
+ (PreNickDBName ? 8 : 7));
+ load_exceptions();
+ if (debug)
+ alog("debug: Loaded exception database (7/%d)",
+ (PreNickDBName ? 8 : 7));
+ if (PreNickDBName) {
+ load_ns_req_db();
+ if (debug)
+ alog("debug: Loaded PreNick database (8/8)");
+ }
+#ifdef USE_RDB
+ }
+#endif
+ alog("Databases loaded");
+
+ /* Save the databases back to file/mysql to reflect any changes */
+#ifdef USE_RDB
+ if (!UseRDB) { /* Only save if we are not using remote databases
+ * to avoid floods. As a side effects our nice
+ * FFF databases won't get overwritten if the
+ * mysql db is broken (empty etc.) */
+#endif
+ alog("Info: Reflecting database records.");
+ save_databases();
+#ifdef USE_RDB
+ } else {
+ alog("Info: Not reflecting database records.");
+ }
+#endif
+ send_event(EVENT_CONNECT, 1, EVENT_START);
+
+ /* Connect to the remote server */
+ servsock = conn(RemoteServer, RemotePort, LocalHost, LocalPort);
+ if (servsock < 0 && RemoteServer2) {
+ servsock = conn(RemoteServer2, RemotePort2, LocalHost, LocalPort);
+ if (servsock < 0 && RemoteServer3) {
+ servsock =
+ conn(RemoteServer3, RemotePort3, LocalHost, LocalPort);
+ if (servsock < 0) {
+ fatal_perror("Can't connect to server");
+ } else {
+ servernum = 3;
+ alog("Connected to Server %d (%s:%d)", servernum,
+ RemoteServer3, RemotePort3);
+ }
+ } else {
+ if (servsock < 0) {
+ fatal_perror("Can't connect to server");
+ }
+ servernum = 2;
+ alog("Connected to Server %d (%s:%d)", servernum,
+ RemoteServer2, RemotePort2);
+ }
+ } else {
+ if (servsock < 0) {
+ fatal_perror("Can't connect to server");
+ }
+ servernum = 1;
+ alog("Connected to Server %d (%s:%d)", servernum, RemoteServer,
+ RemotePort);
+ }
+
+ anope_cmd_connect(servernum);
+ send_event(EVENT_CONNECT, 1, EVENT_STOP);
+
+ sgets2(inbuf, sizeof(inbuf), servsock);
+ if (strnicmp(inbuf, "ERROR", 5) == 0) {
+ /* Close server socket first to stop wallops, since the other
+ * server doesn't want to listen to us anyway */
+ disconn(servsock);
+ servsock = -1;
+ fatal("Remote server returned: %s", inbuf);
+ }
+
+ /* Announce a logfile error if there was one */
+ if (openlog_failed) {
+ anope_cmd_global(NULL, "Warning: couldn't open logfile: %s",
+ strerror(openlog_errno));
+ }
+
+ /* Bring in our pseudo-clients */
+ introduce_user(NULL);
+
+ /* And hybrid needs Global joined in the logchan */
+ if (logchan && ircd->join2msg) {
+ /* XXX might desync */
+ anope_cmd_join(s_GlobalNoticer, LogChannel, time(NULL));
+ }
+
+ anope_cmd_eob();
+
+ /**
+ * Load our delayed modeles - modules that are planing on making clients need to wait till now
+ * where as modules wanting to modify our ircd connection messages need to load eariler :|
+ **/
+ modules_delayed_init();
+
+ /* Success! */
+ return 0;
+}
+
+/*************************************************************************/
diff --git a/src/ircd.c b/src/ircd.c
new file mode 100644
index 000000000..b6dda769c
--- /dev/null
+++ b/src/ircd.c
@@ -0,0 +1,1215 @@
+/* Main ircd functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "extern.h"
+
+IRCDProto ircdproto;
+IRCDModes ircd_modes;
+
+/**
+ * Globals we want from the protocol file
+ **/
+IRCDVar *ircd;
+IRCDCAPAB *ircdcap;
+char *version_protocol;
+CBModeInfo *cbmodeinfos;
+CUMode cumodes[128];
+char *flood_mode_char_set;
+char *flood_mode_char_remove;
+CBMode cbmodes[128];
+CMMode cmmodes[128];
+char csmodes[128];
+int UseTSMODE;
+
+/**
+ * Initiate a protocol struct ready for use
+ **/
+void initIrcdProto()
+{
+ ircdproto.ircd_set_mod_current_buffer = NULL;
+ ircdproto.ircd_set_umode = NULL;
+ ircdproto.ircd_cmd_svsnoop = NULL;
+ ircdproto.ircd_cmd_remove_akill = NULL;
+ ircdproto.ircd_cmd_topic = NULL;
+ ircdproto.ircd_cmd_vhost_off = NULL;
+ ircdproto.ircd_cmd_akill = NULL;
+ ircdproto.ircd_cmd_svskill = NULL;
+ ircdproto.ircd_cmd_svsmode = NULL;
+ ircdproto.ircd_cmd_372 = NULL;
+ ircdproto.ircd_cmd_372_error = NULL;
+ ircdproto.ircd_cmd_375 = NULL;
+ ircdproto.ircd_cmd_376 = NULL;
+ ircdproto.ircd_cmd_nick = NULL;
+ ircdproto.ircd_cmd_guest_nick = NULL;
+ ircdproto.ircd_cmd_mode = NULL;
+ ircdproto.ircd_cmd_bot_nick = NULL;
+ ircdproto.ircd_cmd_kick = NULL;
+ ircdproto.ircd_cmd_notice_ops = NULL;
+ ircdproto.ircd_cmd_notice = NULL;
+ ircdproto.ircd_cmd_notice2 = NULL;
+ ircdproto.ircd_cmd_privmsg = NULL;
+ ircdproto.ircd_cmd_privmsg2 = NULL;
+ ircdproto.ircd_cmd_serv_notice = NULL;
+ ircdproto.ircd_cmd_serv_privmsg = NULL;
+ ircdproto.ircd_cmd_bot_chan_mode = NULL;
+ ircdproto.ircd_cmd_351 = NULL;
+ ircdproto.ircd_cmd_quit = NULL;
+ ircdproto.ircd_cmd_pong = NULL;
+ ircdproto.ircd_cmd_join = NULL;
+ ircdproto.ircd_cmd_unsqline = NULL;
+ ircdproto.ircd_cmd_invite = NULL;
+ ircdproto.ircd_cmd_part = NULL;
+ ircdproto.ircd_cmd_391 = NULL;
+ ircdproto.ircd_cmd_250 = NULL;
+ ircdproto.ircd_cmd_307 = NULL;
+ ircdproto.ircd_cmd_311 = NULL;
+ ircdproto.ircd_cmd_312 = NULL;
+ ircdproto.ircd_cmd_317 = NULL;
+ ircdproto.ircd_cmd_219 = NULL;
+ ircdproto.ircd_cmd_401 = NULL;
+ ircdproto.ircd_cmd_318 = NULL;
+ ircdproto.ircd_cmd_242 = NULL;
+ ircdproto.ircd_cmd_243 = NULL;
+ ircdproto.ircd_cmd_211 = NULL;
+ ircdproto.ircd_cmd_global = NULL;
+ ircdproto.ircd_cmd_global_legacy = NULL;
+ ircdproto.ircd_cmd_sqline = NULL;
+ ircdproto.ircd_cmd_squit = NULL;
+ ircdproto.ircd_cmd_svso = NULL;
+ ircdproto.ircd_cmd_chg_nick = NULL;
+ ircdproto.ircd_cmd_svsnick = NULL;
+ ircdproto.ircd_cmd_vhost_on = NULL;
+ ircdproto.ircd_cmd_connect = NULL;
+ ircdproto.ircd_cmd_svshold = NULL;
+ ircdproto.ircd_cmd_release_svshold = NULL;
+ ircdproto.ircd_cmd_unsgline = NULL;
+ ircdproto.ircd_cmd_unszline = NULL;
+ ircdproto.ircd_cmd_szline = NULL;
+ ircdproto.ircd_cmd_sgline = NULL;
+ ircdproto.ircd_cmd_unban = NULL;
+ ircdproto.ircd_cmd_svsmode_chan = NULL;
+ ircdproto.ircd_cmd_svid_umode = NULL;
+ ircdproto.ircd_cmd_nc_change = NULL;
+ ircdproto.ircd_cmd_svid_umode2 = NULL;
+ ircdproto.ircd_cmd_svid_umode3 = NULL;
+ ircdproto.ircd_cmd_svsjoin = NULL;
+ ircdproto.ircd_cmd_svspart = NULL;
+ ircdproto.ircd_cmd_swhois = NULL;
+ ircdproto.ircd_cmd_eob = NULL;
+ ircdproto.ircd_flood_mode_check = NULL;
+ ircdproto.ircd_cmd_jupe = NULL;
+ ircdproto.ircd_valid_nick = NULL;
+ ircdproto.ircd_valid_chan = NULL;
+ ircdproto.ircd_cmd_ctcp = NULL;
+}
+
+/* Special function, returns 1 if executed, 0 if not */
+int anope_set_mod_current_buffer(int ac, char **av)
+{
+ if (ircdproto.ircd_set_mod_current_buffer) {
+ ircdproto.ircd_set_mod_current_buffer(ac, av);
+ return 1;
+ }
+
+ return 0;
+}
+
+void anope_set_umode(User * user, int ac, char **av)
+{
+ ircdproto.ircd_set_umode(user, ac, av);
+}
+
+void anope_cmd_svsnoop(char *server, int set)
+{
+ ircdproto.ircd_cmd_svsnoop(server, set);
+}
+
+void anope_cmd_remove_akill(char *user, char *host)
+{
+ ircdproto.ircd_cmd_remove_akill(user, host);
+}
+
+void anope_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ ircdproto.ircd_cmd_topic(whosets, chan, whosetit, topic, when);
+}
+
+void anope_cmd_vhost_off(User * u)
+{
+ ircdproto.ircd_cmd_vhost_off(u);
+}
+
+void anope_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ ircdproto.ircd_cmd_akill(user, host, who, when, expires, reason);
+}
+
+void anope_cmd_svskill(char *source, char *user, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_svskill(source, user, buf);
+}
+
+void anope_cmd_svsmode(User * u, int ac, char **av)
+{
+ ircdproto.ircd_cmd_svsmode(u, ac, av);
+}
+
+void anope_cmd_372(char *source, char *msg)
+{
+ ircdproto.ircd_cmd_372(source, msg);
+}
+
+void anope_cmd_372_error(char *source)
+{
+ ircdproto.ircd_cmd_372_error(source);
+}
+
+void anope_cmd_375(char *source)
+{
+ ircdproto.ircd_cmd_375(source);
+}
+
+void anope_cmd_376(char *source)
+{
+ ircdproto.ircd_cmd_376(source);
+}
+
+void anope_cmd_nick(char *nick, char *name, char *modes)
+{
+ ircdproto.ircd_cmd_nick(nick, name, modes);
+}
+
+void anope_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ ircdproto.ircd_cmd_guest_nick(nick, user, host, real, modes);
+}
+
+void anope_cmd_mode(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_mode(source, dest, buf);
+}
+
+void anope_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ ircdproto.ircd_cmd_bot_nick(nick, user, host, real, modes);
+}
+
+void anope_cmd_kick(char *source, char *chan, char *user, const char *fmt,
+ ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_kick(source, chan, user, buf);
+}
+
+void anope_cmd_notice_ops(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_notice_ops(source, dest, buf);
+}
+
+void anope_cmd_notice(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_notice(source, dest, buf);
+}
+
+void anope_cmd_notice2(char *source, char *dest, char *msg)
+{
+ ircdproto.ircd_cmd_notice2(source, dest, msg);
+}
+
+void anope_cmd_action(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ char actionbuf[BUFSIZE];
+ *buf = '\0';
+ *actionbuf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ } else {
+ return;
+ }
+ if (!buf) {
+ return;
+ }
+ snprintf(actionbuf, BUFSIZE - 1, "%cACTION %s %c", 1, buf, 1);
+ ircdproto.ircd_cmd_privmsg(source, dest, actionbuf);
+ }
+ void anope_cmd_privmsg(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_privmsg(source, dest, buf);
+}
+
+void anope_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ ircdproto.ircd_cmd_privmsg2(source, dest, msg);
+}
+
+void anope_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ ircdproto.ircd_cmd_serv_notice(source, dest, msg);
+}
+
+void anope_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ ircdproto.ircd_cmd_serv_privmsg(source, dest, msg);
+}
+
+void anope_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ ircdproto.ircd_cmd_bot_chan_mode(nick, chan);
+}
+
+void anope_cmd_351(char *source)
+{
+ ircdproto.ircd_cmd_351(source);
+}
+
+void anope_cmd_quit(char *source, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_quit(source, buf);
+}
+
+void anope_cmd_pong(char *servname, char *who)
+{
+ ircdproto.ircd_cmd_pong(servname, who);
+}
+
+void anope_cmd_join(char *user, char *channel, time_t chantime)
+{
+ ircdproto.ircd_cmd_join(user, channel, chantime);
+}
+
+void anope_cmd_unsqline(char *user)
+{
+ ircdproto.ircd_cmd_unsqline(user);
+}
+
+void anope_cmd_invite(char *source, char *chan, char *nick)
+{
+ ircdproto.ircd_cmd_invite(source, chan, nick);
+}
+
+void anope_cmd_part(char *nick, char *chan, const char *fmt, ...)
+{
+ if (fmt) {
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ ircdproto.ircd_cmd_part(nick, chan, buf);
+ } else {
+ ircdproto.ircd_cmd_part(nick, chan, NULL);
+ }
+}
+
+void anope_cmd_391(char *source, char *timestr)
+{
+ ircdproto.ircd_cmd_391(source, timestr);
+}
+
+void anope_cmd_250(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_250(buf);
+}
+
+void anope_cmd_307(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_307(buf);
+}
+
+void anope_cmd_311(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_311(buf);
+}
+
+void anope_cmd_312(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_312(buf);
+}
+
+void anope_cmd_317(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_317(buf);
+}
+
+void anope_cmd_219(char *source, char *letter)
+{
+ ircdproto.ircd_cmd_219(source, letter);
+}
+
+void anope_cmd_401(char *source, char *who)
+{
+ ircdproto.ircd_cmd_401(source, who);
+}
+
+void anope_cmd_318(char *source, char *who)
+{
+ ircdproto.ircd_cmd_318(source, who);
+}
+
+void anope_cmd_242(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_242(buf);
+}
+
+void anope_cmd_243(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_243(buf);
+}
+
+void anope_cmd_211(const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_211(buf);
+}
+
+void anope_cmd_global(char *source, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_global(source, buf);
+}
+
+void anope_cmd_global_legacy(char *source, char *fmt)
+{
+ ircdproto.ircd_cmd_global_legacy(source, fmt);
+}
+
+void anope_cmd_sqline(char *mask, char *reason)
+{
+ ircdproto.ircd_cmd_sqline(mask, reason);
+}
+
+void anope_cmd_squit(char *servname, char *message)
+{
+ ircdproto.ircd_cmd_squit(servname, message);
+}
+
+void anope_cmd_svso(char *source, char *nick, char *flag)
+{
+ ircdproto.ircd_cmd_svso(source, nick, flag);
+}
+
+void anope_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ ircdproto.ircd_cmd_chg_nick(oldnick, newnick);
+}
+
+void anope_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ ircdproto.ircd_cmd_svsnick(source, guest, when);
+}
+
+void anope_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ ircdproto.ircd_cmd_vhost_on(nick, vIdent, vhost);
+}
+
+void anope_cmd_connect(int servernum)
+{
+ ircdproto.ircd_cmd_connect(servernum);
+}
+
+void anope_cmd_svshold(char *nick)
+{
+ ircdproto.ircd_cmd_svshold(nick);
+}
+
+void anope_cmd_release_svshold(char *nick)
+{
+ ircdproto.ircd_cmd_release_svshold(nick);
+}
+
+void anope_cmd_unsgline(char *mask)
+{
+ ircdproto.ircd_cmd_unsgline(mask);
+}
+
+void anope_cmd_unszline(char *mask)
+{
+ ircdproto.ircd_cmd_unszline(mask);
+}
+
+void anope_cmd_szline(char *mask, char *reason, char *whom)
+{
+ ircdproto.ircd_cmd_szline(mask, reason, whom);
+}
+
+void anope_cmd_sgline(char *mask, char *reason)
+{
+ ircdproto.ircd_cmd_sgline(mask, reason);
+}
+
+void anope_cmd_unban(char *name, char *nick)
+{
+ ircdproto.ircd_cmd_unban(name, nick);
+}
+
+void anope_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ ircdproto.ircd_cmd_svsmode_chan(name, mode, nick);
+}
+
+void anope_cmd_svid_umode(char *nick, time_t ts)
+{
+ ircdproto.ircd_cmd_svid_umode(nick, ts);
+}
+
+void anope_cmd_nc_change(User * u)
+{
+ ircdproto.ircd_cmd_nc_change(u);
+}
+
+void anope_cmd_svid_umode2(User * u, char *ts)
+{
+ ircdproto.ircd_cmd_svid_umode2(u, ts);
+}
+
+void anope_cmd_svid_umode3(User * u, char *ts)
+{
+ ircdproto.ircd_cmd_svid_umode3(u, ts);
+}
+
+void anope_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ ircdproto.ircd_cmd_svsjoin(source, nick, chan, param);
+}
+
+void anope_cmd_svspart(char *source, char *nick, char *chan)
+{
+ ircdproto.ircd_cmd_svspart(source, nick, chan);
+}
+
+void anope_cmd_swhois(char *source, char *who, char *mask)
+{
+ ircdproto.ircd_cmd_swhois(source, who, mask);
+}
+
+void anope_cmd_eob()
+{
+ ircdproto.ircd_cmd_eob();
+}
+
+int anope_flood_mode_check(char *value)
+{
+ return ircdproto.ircd_flood_mode_check(value);
+}
+
+void anope_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ ircdproto.ircd_cmd_jupe(jserver, who, reason);
+}
+
+int anope_valid_nick(char *nick)
+{
+ return ircdproto.ircd_valid_nick(nick);
+}
+
+int anope_valid_chan(char *chan)
+{
+ return ircdproto.ircd_valid_chan(chan);
+}
+
+
+void anope_cmd_ctcp(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ ircdproto.ircd_cmd_ctcp(source, dest, buf);
+}
+
+
+
+/**
+ * Set routines for modules to set the prefered function for dealing with things.
+ **/
+
+void pmodule_set_mod_current_buffer(void (*func) (int ac, char **av))
+{
+ ircdproto.ircd_set_mod_current_buffer = func;
+}
+
+void pmodule_cmd_svsnoop(void (*func) (char *server, int set))
+{
+ ircdproto.ircd_cmd_svsnoop = func;
+}
+
+void pmodule_cmd_remove_akill(void (*func) (char *user, char *host))
+{
+ ircdproto.ircd_cmd_remove_akill = func;
+}
+
+void pmodule_cmd_topic(void (*func)
+ (char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when))
+{
+ ircdproto.ircd_cmd_topic = func;
+}
+
+void pmodule_cmd_vhost_off(void (*func) (User * u))
+{
+ ircdproto.ircd_cmd_vhost_off = func;
+}
+
+void pmodule_cmd_akill(void (*func)
+ (char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason))
+{
+ ircdproto.ircd_cmd_akill = func;
+}
+
+void
+pmodule_cmd_svskill(void (*func) (char *source, char *user, char *buf))
+{
+ ircdproto.ircd_cmd_svskill = func;
+}
+
+void pmodule_cmd_svsmode(void (*func) (User * u, int ac, char **av))
+{
+ ircdproto.ircd_cmd_svsmode = func;
+}
+
+void pmodule_cmd_372(void (*func) (char *source, char *msg))
+{
+ ircdproto.ircd_cmd_372 = func;
+}
+
+void pmodule_cmd_372_error(void (*func) (char *source))
+{
+ ircdproto.ircd_cmd_372_error = func;
+}
+
+void pmodule_cmd_375(void (*func) (char *source))
+{
+ ircdproto.ircd_cmd_375 = func;
+}
+
+void pmodule_cmd_376(void (*func) (char *source))
+{
+ ircdproto.ircd_cmd_376 = func;
+}
+
+void pmodule_cmd_nick(void (*func) (char *nick, char *name, char *modes))
+{
+ ircdproto.ircd_cmd_nick = func;
+}
+
+void pmodule_cmd_guest_nick(void (*func)
+ (char *nick, char *user, char *host,
+ char *real, char *modes))
+{
+ ircdproto.ircd_cmd_guest_nick = func;
+}
+
+void pmodule_cmd_mode(void (*func) (char *source, char *dest, char *buf))
+{
+ ircdproto.ircd_cmd_mode = func;
+}
+
+void pmodule_cmd_bot_nick(void (*func)
+ (char *nick, char *user, char *host, char *real,
+ char *modes))
+{
+ ircdproto.ircd_cmd_bot_nick = func;
+}
+
+void pmodule_cmd_kick(void (*func)
+ (char *source, char *chan, char *user, char *buf))
+{
+ ircdproto.ircd_cmd_kick = func;
+}
+
+void
+pmodule_cmd_notice_ops(void (*func) (char *source, char *dest, char *buf))
+{
+ ircdproto.ircd_cmd_notice_ops = func;
+}
+
+void pmodule_cmd_notice(void (*func) (char *source, char *dest, char *buf))
+{
+ ircdproto.ircd_cmd_notice = func;
+}
+
+void
+pmodule_cmd_notice2(void (*func) (char *source, char *dest, char *msg))
+{
+ ircdproto.ircd_cmd_notice2 = func;
+}
+
+void
+pmodule_cmd_privmsg(void (*func) (char *source, char *dest, char *buf))
+{
+ ircdproto.ircd_cmd_privmsg = func;
+}
+
+void
+pmodule_cmd_privmsg2(void (*func) (char *source, char *dest, char *msg))
+{
+ ircdproto.ircd_cmd_privmsg2 = func;
+}
+
+void
+pmodule_cmd_serv_notice(void (*func) (char *source, char *dest, char *msg))
+{
+ ircdproto.ircd_cmd_serv_notice = func;
+}
+
+void pmodule_cmd_serv_privmsg(void (*func)
+ (char *source, char *dest, char *msg))
+{
+ ircdproto.ircd_cmd_serv_privmsg = func;
+}
+
+void pmodule_cmd_bot_chan_mode(void (*func) (char *nick, char *chan))
+{
+ ircdproto.ircd_cmd_bot_chan_mode = func;
+}
+
+void pmodule_cmd_351(void (*func) (char *source))
+{
+ ircdproto.ircd_cmd_351 = func;
+}
+
+void pmodule_cmd_quit(void (*func) (char *source, char *buf))
+{
+ ircdproto.ircd_cmd_quit = func;
+}
+
+void pmodule_cmd_pong(void (*func) (char *servname, char *who))
+{
+ ircdproto.ircd_cmd_pong = func;
+}
+
+void
+pmodule_cmd_join(void (*func) (char *user, char *channel, time_t chantime))
+{
+ ircdproto.ircd_cmd_join = func;
+}
+
+void pmodule_cmd_unsqline(void (*func) (char *user))
+{
+ ircdproto.ircd_cmd_unsqline = func;
+}
+
+void
+pmodule_cmd_invite(void (*func) (char *source, char *chan, char *nick))
+{
+ ircdproto.ircd_cmd_invite = func;
+}
+
+void pmodule_cmd_part(void (*func) (char *nick, char *chan, char *buf))
+{
+ ircdproto.ircd_cmd_part = func;
+}
+
+void pmodule_cmd_391(void (*func) (char *source, char *timestr))
+{
+ ircdproto.ircd_cmd_391 = func;
+}
+
+void pmodule_cmd_250(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_250 = func;
+}
+
+void pmodule_cmd_307(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_307 = func;
+}
+
+void pmodule_cmd_311(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_311 = func;
+}
+
+void pmodule_cmd_312(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_312 = func;
+}
+
+void pmodule_cmd_317(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_317 = func;
+}
+
+void pmodule_cmd_219(void (*func) (char *source, char *letter))
+{
+ ircdproto.ircd_cmd_219 = func;
+}
+
+void pmodule_cmd_401(void (*func) (char *source, char *who))
+{
+ ircdproto.ircd_cmd_401 = func;
+}
+
+void pmodule_cmd_318(void (*func) (char *source, char *who))
+{
+ ircdproto.ircd_cmd_318 = func;
+}
+
+void pmodule_cmd_242(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_242 = func;
+}
+
+void pmodule_cmd_243(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_243 = func;
+}
+
+void pmodule_cmd_211(void (*func) (char *buf))
+{
+ ircdproto.ircd_cmd_211 = func;
+}
+
+void pmodule_cmd_global(void (*func) (char *source, char *buf))
+{
+ ircdproto.ircd_cmd_global = func;
+}
+
+void pmodule_cmd_global_legacy(void (*func) (char *source, char *fmt))
+{
+ ircdproto.ircd_cmd_global_legacy = func;
+}
+
+void pmodule_cmd_sqline(void (*func) (char *mask, char *reason))
+{
+ ircdproto.ircd_cmd_sqline = func;
+}
+
+void pmodule_cmd_squit(void (*func) (char *servname, char *message))
+{
+ ircdproto.ircd_cmd_squit = func;
+}
+
+void pmodule_cmd_svso(void (*func) (char *source, char *nick, char *flag))
+{
+ ircdproto.ircd_cmd_svso = func;
+}
+
+void pmodule_cmd_chg_nick(void (*func) (char *oldnick, char *newnick))
+{
+ ircdproto.ircd_cmd_chg_nick = func;
+}
+
+void
+pmodule_cmd_svsnick(void (*func) (char *source, char *guest, time_t when))
+{
+ ircdproto.ircd_cmd_svsnick = func;
+}
+
+void
+pmodule_cmd_vhost_on(void (*func) (char *nick, char *vIdent, char *vhost))
+{
+ ircdproto.ircd_cmd_vhost_on = func;
+}
+
+void pmodule_cmd_connect(void (*func) (int servernum))
+{
+ ircdproto.ircd_cmd_connect = func;
+}
+
+void pmodule_cmd_svshold(void (*func) (char *nick))
+{
+ ircdproto.ircd_cmd_svshold = func;
+}
+
+void pmodule_cmd_release_svshold(void (*func) (char *nick))
+{
+ ircdproto.ircd_cmd_release_svshold = func;
+}
+
+void pmodule_cmd_unsgline(void (*func) (char *mask))
+{
+ ircdproto.ircd_cmd_unsgline = func;
+}
+
+void pmodule_cmd_unszline(void (*func) (char *mask))
+{
+ ircdproto.ircd_cmd_unszline = func;
+}
+
+void
+pmodule_cmd_szline(void (*func) (char *mask, char *reason, char *whom))
+{
+ ircdproto.ircd_cmd_szline = func;
+}
+
+void pmodule_cmd_sgline(void (*func) (char *mask, char *reason))
+{
+ ircdproto.ircd_cmd_sgline = func;
+}
+
+void pmodule_cmd_unban(void (*func) (char *name, char *nick))
+{
+ ircdproto.ircd_cmd_unban = func;
+}
+
+void
+pmodule_cmd_svsmode_chan(void (*func) (char *name, char *mode, char *nick))
+{
+ ircdproto.ircd_cmd_svsmode_chan = func;
+}
+
+void pmodule_cmd_svid_umode(void (*func) (char *nick, time_t ts))
+{
+ ircdproto.ircd_cmd_svid_umode = func;
+}
+
+void pmodule_cmd_nc_change(void (*func) (User * u))
+{
+ ircdproto.ircd_cmd_nc_change = func;
+}
+
+void pmodule_cmd_svid_umode2(void (*func) (User * u, char *ts))
+{
+ ircdproto.ircd_cmd_svid_umode2 = func;
+}
+
+void pmodule_cmd_svid_umode3(void (*func) (User * u, char *ts))
+{
+ ircdproto.ircd_cmd_svid_umode3 = func;
+}
+
+void pmodule_cmd_ctcp(void (*func) (char *source, char *dest, char *buf))
+{
+ ircdproto.ircd_cmd_ctcp = func;
+}
+
+void pmodule_cmd_svsjoin(void (*func)
+ (char *source, char *nick, char *chan,
+ char *param))
+{
+ ircdproto.ircd_cmd_svsjoin = func;
+}
+
+void
+pmodule_cmd_svspart(void (*func) (char *source, char *nick, char *chan))
+{
+ ircdproto.ircd_cmd_svspart = func;
+}
+
+void pmodule_cmd_swhois(void (*func) (char *source, char *who, char *mask))
+{
+ ircdproto.ircd_cmd_swhois = func;
+}
+
+void pmodule_cmd_eob(void (*func) ())
+{
+ ircdproto.ircd_cmd_eob = func;
+}
+
+void
+pmodule_cmd_jupe(void (*func) (char *jserver, char *who, char *reason))
+{
+ ircdproto.ircd_cmd_jupe = func;
+}
+
+void pmodule_set_umode(void (*func) (User * user, int ac, char **av))
+{
+ ircdproto.ircd_set_umode = func;
+}
+
+void pmodule_valid_nick(int (*func) (char *nick))
+{
+ ircdproto.ircd_valid_nick = func;
+}
+
+void pmodule_valid_chan(int (*func) (char *chan))
+{
+ ircdproto.ircd_valid_chan = func;
+}
+
+void pmodule_flood_mode_check(int (*func) (char *value))
+{
+ ircdproto.ircd_flood_mode_check = func;
+}
+
+void pmodule_ircd_var(IRCDVar * ircdvar)
+{
+ ircd = ircdvar;
+}
+
+void pmodule_ircd_cap(IRCDCAPAB * cap)
+{
+ ircdcap = cap;
+}
+
+void pmodule_ircd_version(char *version)
+{
+ version_protocol = sstrdup(version);
+}
+
+void pmodule_ircd_cbmodeinfos(CBModeInfo * modeinfos)
+{
+ cbmodeinfos = modeinfos;
+}
+
+void pmodule_ircd_cumodes(CUMode modes[128])
+{
+ int i = 0;
+ for (i = 0; i < 128; i++) {
+ cumodes[i] = modes[i];
+ }
+}
+
+void pmodule_ircd_flood_mode_char_set(char *mode)
+{
+ flood_mode_char_set = sstrdup(mode);
+}
+
+void pmodule_ircd_flood_mode_char_remove(char *mode)
+{
+ flood_mode_char_remove = sstrdup(mode);
+}
+
+void pmodule_ircd_cbmodes(CBMode modes[128])
+{
+ int i = 0;
+ for (i = 0; i < 128; i++) {
+ cbmodes[i] = modes[i];
+ }
+}
+
+void pmodule_ircd_cmmodes(CMMode modes[128])
+{
+ int i = 0;
+ for (i = 0; i < 128; i++) {
+ cmmodes[i] = modes[i];
+ }
+}
+
+void pmodule_ircd_csmodes(char mode[128])
+{
+ int i = 0;
+ for (i = 0; i < 128; i++) {
+ csmodes[i] = mode[i];
+ }
+}
+
+void pmodule_ircd_useTSMode(int use)
+{
+ UseTSMODE = use;
+}
+
+/** mode stuff */
+
+void pmodule_invis_umode(int mode)
+{
+ ircd_modes.user_invis = mode;
+}
+
+void pmodule_oper_umode(int mode)
+{
+ ircd_modes.user_oper = mode;
+}
+
+void pmodule_invite_cmode(int mode)
+{
+ ircd_modes.chan_invite = mode;
+}
+
+void pmodule_secret_cmode(int mode)
+{
+ ircd_modes.chan_secret = mode;
+}
+
+void pmodule_private_cmode(int mode)
+{
+ ircd_modes.chan_private = mode;
+}
+
+void pmodule_key_mode(int mode)
+{
+ ircd_modes.chan_key = mode;
+}
+
+void pmodule_limit_mode(int mode)
+{
+ ircd_modes.chan_limit = mode;
+}
+
+int anope_get_invis_mode()
+{
+ return ircd_modes.user_invis;
+}
+
+int anope_get_oper_mode()
+{
+ return ircd_modes.user_oper;
+}
+
+int anope_get_invite_mode()
+{
+ return ircd_modes.chan_invite;
+}
+
+int anope_get_secret_mode()
+{
+ return ircd_modes.chan_secret;
+}
+
+int anope_get_private_mode()
+{
+ return ircd_modes.chan_private;
+}
+
+int anope_get_key_mode()
+{
+ return ircd_modes.chan_key;
+}
+
+int anope_get_limit_mode()
+{
+ return ircd_modes.chan_limit;
+}
diff --git a/src/language.c b/src/language.c
new file mode 100644
index 000000000..1c29b1ec9
--- /dev/null
+++ b/src/language.c
@@ -0,0 +1,309 @@
+/* Multi-language support.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+
+/*************************************************************************/
+
+/* The list of lists of messages. */
+char **langtexts[NUM_LANGS];
+
+/* The list of names of languages. */
+char *langnames[NUM_LANGS];
+
+/* Indexes of available languages: */
+int langlist[NUM_LANGS];
+
+/* Order in which languages should be displayed: (alphabetical) */
+static int langorder[NUM_LANGS] = {
+ LANG_EN_US, /* English (US) */
+ LANG_FR, /* French */
+ LANG_DE, /* German */
+ LANG_IT, /* Italian */
+ LANG_JA_JIS, /* Japanese (JIS encoding) */
+ LANG_JA_EUC, /* Japanese (EUC encoding) */
+ LANG_JA_SJIS, /* Japanese (SJIS encoding) */
+ LANG_PT, /* Portugese */
+ LANG_ES, /* Spanish */
+ LANG_TR, /* Turkish */
+ LANG_CAT, /* Catalan */
+ LANG_GR, /* Greek */
+ LANG_NL, /* Dutch */
+ LANG_RU, /* Russian */
+ LANG_HUN, /* Hungarian */
+ LANG_PL, /* Polish */
+};
+
+/*************************************************************************/
+
+/* Load a language file. */
+
+static int read_int32(int32 * ptr, FILE * f)
+{
+ int a = fgetc(f);
+ int b = fgetc(f);
+ int c = fgetc(f);
+ int d = fgetc(f);
+ if (a == EOF || b == EOF || c == EOF || d == EOF)
+ return -1;
+ *ptr = a << 24 | b << 16 | c << 8 | d;
+ return 0;
+}
+
+static void load_lang(int index, const char *filename)
+{
+ char buf[256];
+ FILE *f;
+ int32 num, i;
+
+ if (debug) {
+ alog("debug: Loading language %d from file `languages/%s'",
+ index, filename);
+ }
+ snprintf(buf, sizeof(buf), "languages/%s", filename);
+#ifndef _WIN32
+ if (!(f = fopen(buf, "r"))) {
+#else
+ if (!(f = fopen(buf, "rb"))) {
+#endif
+ log_perror("Failed to load language %d (%s)", index, filename);
+ return;
+ } else if (read_int32(&num, f) < 0) {
+ alog("Failed to read number of strings for language %d (%s)",
+ index, filename);
+ return;
+ } else if (num != NUM_STRINGS) {
+ alog("Warning: Bad number of strings (%d, wanted %d) "
+ "for language %d (%s)", num, NUM_STRINGS, index, filename);
+ }
+ langtexts[index] = scalloc(sizeof(char *), NUM_STRINGS);
+ if (num > NUM_STRINGS)
+ num = NUM_STRINGS;
+ for (i = 0; i < num; i++) {
+ int32 pos, len;
+ fseek(f, i * 8 + 4, SEEK_SET);
+ if (read_int32(&pos, f) < 0 || read_int32(&len, f) < 0) {
+ alog("Failed to read entry %d in language %d (%s) TOC",
+ i, index, filename);
+ while (--i >= 0) {
+ if (langtexts[index][i])
+ free(langtexts[index][i]);
+ }
+ free(langtexts[index]);
+ langtexts[index] = NULL;
+ return;
+ }
+ if (len == 0) {
+ langtexts[index][i] = NULL;
+ } else if (len >= 65536) {
+ alog("Entry %d in language %d (%s) is too long (over 64k)--"
+ "corrupt TOC?", i, index, filename);
+ while (--i >= 0) {
+ if (langtexts[index][i])
+ free(langtexts[index][i]);
+ }
+ free(langtexts[index]);
+ langtexts[index] = NULL;
+ return;
+ } else if (len < 0) {
+ alog("Entry %d in language %d (%s) has negative length--"
+ "corrupt TOC?", i, index, filename);
+ while (--i >= 0) {
+ if (langtexts[index][i])
+ free(langtexts[index][i]);
+ }
+ free(langtexts[index]);
+ langtexts[index] = NULL;
+ return;
+ } else {
+ langtexts[index][i] = scalloc(len + 1, 1);
+ fseek(f, pos, SEEK_SET);
+ if (fread(langtexts[index][i], 1, len, f) != len) {
+ alog("Failed to read string %d in language %d (%s)",
+ i, index, filename);
+ while (--i >= 0) {
+ if (langtexts[index][i])
+ free(langtexts[index][i]);
+ }
+ free(langtexts[index]);
+ langtexts[index] = NULL;
+ return;
+ }
+ langtexts[index][i][len] = 0;
+ }
+ }
+ fclose(f);
+}
+
+/*************************************************************************/
+
+/* Replace all %M's with "/msg " or "/" */
+void lang_sanitize()
+{
+ int i = 0, j = 0;
+ int len = 0;
+ char tmp[2000];
+ char *newstr = NULL;
+ for (i = 0; i < NUM_LANGS; i++) {
+ for (j = 0; j < NUM_STRINGS; j++) {
+ if (strstr(langtexts[i][j], "%R")) {
+ len = strlen(langtexts[i][j]);
+ strscpy(tmp, langtexts[i][j], sizeof(tmp));
+ if (UseStrictPrivMsg) {
+ strnrepl(tmp, sizeof(tmp), "%R", "/");
+ } else {
+ strnrepl(tmp, sizeof(tmp), "%R", "/msg ");
+ }
+ newstr = sstrdup(tmp);
+ free(langtexts[i][j]);
+ langtexts[i][j] = newstr;
+ }
+ }
+ }
+}
+
+
+/* Initialize list of lists. */
+
+void lang_init()
+{
+ int i, j, n = 0;
+
+ load_lang(LANG_CAT, "cat");
+ load_lang(LANG_DE, "de");
+ load_lang(LANG_EN_US, "en_us");
+ load_lang(LANG_ES, "es");
+ load_lang(LANG_FR, "fr");
+ load_lang(LANG_GR, "gr");
+ load_lang(LANG_PT, "pt");
+ load_lang(LANG_TR, "tr");
+ load_lang(LANG_IT, "it");
+ load_lang(LANG_NL, "nl");
+ load_lang(LANG_RU, "ru");
+ load_lang(LANG_HUN, "hun");
+ load_lang(LANG_PL, "pl");
+
+ for (i = 0; i < NUM_LANGS; i++) {
+ if (langtexts[langorder[i]] != NULL) {
+ langnames[langorder[i]] = langtexts[langorder[i]][LANG_NAME];
+ langlist[n++] = langorder[i];
+ for (j = 0; j < NUM_STRINGS; j++) {
+ if (!langtexts[langorder[i]][j]) {
+ langtexts[langorder[i]][j] =
+ langtexts[DEF_LANGUAGE][j];
+ }
+ if (!langtexts[langorder[i]][j]) {
+ langtexts[langorder[i]][j] = langtexts[LANG_EN_US][j];
+ }
+ }
+ }
+ }
+ while (n < NUM_LANGS)
+ langlist[n++] = -1;
+
+ /* Not what I intended to do, but these services are so archaïc
+ * that it's difficult to do more. */
+ if ((NSDefLanguage = langlist[NSDefLanguage]) < 0)
+ NSDefLanguage = DEF_LANGUAGE;
+
+ if (!langtexts[DEF_LANGUAGE])
+ fatal("Unable to load default language");
+ for (i = 0; i < NUM_LANGS; i++) {
+ if (!langtexts[i])
+ langtexts[i] = langtexts[DEF_LANGUAGE];
+ }
+ lang_sanitize();
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Format a string in a strftime()-like way, but heed the user's language
+ * setting for month and day names. The string stored in the buffer will
+ * always be null-terminated, even if the actual string was longer than the
+ * buffer size.
+ * Assumption: No month or day name has a length (including trailing null)
+ * greater than BUFSIZE.
+ */
+
+int strftime_lang(char *buf, int size, User * u, int format, struct tm *tm)
+{
+ int language = u && u->na ? u->na->nc->language : NSDefLanguage;
+ char tmpbuf[BUFSIZE], buf2[BUFSIZE];
+ char *s;
+ int i, ret;
+
+ if (!tm) {
+ return 0;
+ }
+
+ strscpy(tmpbuf, langtexts[language][format], sizeof(tmpbuf));
+ if ((s = langtexts[language][STRFTIME_DAYS_SHORT]) != NULL) {
+ for (i = 0; i < tm->tm_wday; i++)
+ s += strcspn(s, "\n") + 1;
+ i = strcspn(s, "\n");
+ strncpy(buf2, s, i);
+ buf2[i] = 0;
+ strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
+ }
+ if ((s = langtexts[language][STRFTIME_DAYS_LONG]) != NULL) {
+ for (i = 0; i < tm->tm_wday; i++)
+ s += strcspn(s, "\n") + 1;
+ i = strcspn(s, "\n");
+ strncpy(buf2, s, i);
+ buf2[i] = 0;
+ strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
+ }
+ if ((s = langtexts[language][STRFTIME_MONTHS_SHORT]) != NULL) {
+ for (i = 0; i < tm->tm_mon; i++)
+ s += strcspn(s, "\n") + 1;
+ i = strcspn(s, "\n");
+ strncpy(buf2, s, i);
+ buf2[i] = 0;
+ strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
+ }
+ if ((s = langtexts[language][STRFTIME_MONTHS_LONG]) != NULL) {
+ for (i = 0; i < tm->tm_mon; i++)
+ s += strcspn(s, "\n") + 1;
+ i = strcspn(s, "\n");
+ strncpy(buf2, s, i);
+ buf2[i] = 0;
+ strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
+ }
+ ret = strftime(buf, size, tmpbuf, tm);
+ if (ret == size)
+ buf[size - 1] = 0;
+ return ret;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Send a syntax-error message to the user. */
+
+void syntax_error(char *service, User * u, const char *command, int msgnum)
+{
+ const char *str;
+
+ if (!u) {
+ return;
+ }
+
+ str = getstring(u->na, msgnum);
+ notice_lang(service, u, SYNTAX_ERROR, str);
+ notice_lang(service, u, MORE_INFO, service, command);
+}
+
+/*************************************************************************/
diff --git a/src/list.c b/src/list.c
new file mode 100644
index 000000000..c59bf9f5e
--- /dev/null
+++ b/src/list.c
@@ -0,0 +1,196 @@
+/* Routines to handle `listnicks' and `listchans' invocations.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+/**
+ * List all register nicks
+ * @param ac Number of Arguments
+ * @param av Array if Arguments
+ * @return void
+ */
+void do_listnicks(int ac, char **av)
+{
+ int count = 0; /* Count only rather than display? */
+ int usage = 0; /* Display command usage? (>0 also indicates error) */
+ int i;
+
+ i = 1;
+ while (i < ac) {
+ if (av[i][0] == '-') {
+ switch (av[i][1]) {
+ case 'h':
+ usage = -1;
+ break;
+ case 'c':
+ if (i > 1)
+ usage = 1;
+ count = 1;
+ break;
+ case 'd':
+ if (av[i][2]) {
+ services_dir = av[i] + 2;
+ } else {
+ if (i >= ac - 1) {
+ usage = 1;
+ break;
+ }
+ ac--;
+ memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
+ services_dir = av[i];
+ }
+ default:
+ usage = 1;
+ break;
+ } /* switch */
+ ac--;
+ if (i < ac)
+ memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
+ } else {
+ if (count)
+ usage = 1;
+ i++;
+ }
+ }
+ if (usage) {
+ fprintf(stderr, "\
+\n\
+Usage: listnicks [-c] [-d data-dir] [nick [nick...]]\n\
+ -c: display only count of registered nicks\n\
+ (cannot be combined with nicks)\n\
+ nick: nickname(s) to display information for\n\
+\n\
+If no nicks are given, the entire nickname database is printed out in\n\
+compact format followed by the number of registered nicks (with -c, the\n\
+list is suppressed and only the count is printed). If one or more nicks\n\
+are given, detailed information about those nicks is displayed.\n\
+\n");
+ exit(usage > 0 ? 1 : 0);
+ }
+
+ if (chdir(services_dir) < 0) {
+ fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
+ ModuleRunTimeDirCleanUp();
+ exit(1);
+ }
+ if (!read_config(0)) {
+ ModuleRunTimeDirCleanUp();
+ exit(1);
+ }
+ load_ns_dbase();
+
+ lang_init();
+
+ if (ac > 1) {
+ for (i = 1; i < ac; i++)
+ listnicks(0, av[i]);
+ } else {
+ listnicks(count, NULL);
+ }
+ exit(0);
+}
+
+/*************************************************************************/
+
+/**
+ * List all register channels
+ * @param ac Number of Arguments
+ * @param av Array if Arguments
+ * @return void
+ */
+void do_listchans(int ac, char **av)
+{
+ int count = 0; /* Count only rather than display? */
+ int usage = 0; /* Display command usage? (>0 also indicates error) */
+ int i;
+
+ i = 1;
+ while (i < ac) {
+ if (av[i][0] == '-') {
+ switch (av[i][1]) {
+ case 'h':
+ usage = -1;
+ break;
+ case 'c':
+ if (i > 1)
+ usage = 1;
+ count = 1;
+ break;
+ case 'd':
+ if (av[i][2]) {
+ services_dir = av[i] + 2;
+ } else {
+ if (i >= ac - 1) {
+ usage = 1;
+ break;
+ }
+ ac--;
+ memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
+ services_dir = av[i];
+ }
+ default:
+ usage = 1;
+ break;
+ } /* switch */
+ ac--;
+ if (i < ac)
+ memmove(av + i, av + i + 1, sizeof(char *) * ac - i);
+ } else {
+ if (count)
+ usage = 1;
+ i++;
+ }
+ }
+ if (usage) {
+ fprintf(stderr, "\
+\n\
+Usage: listchans [-c] [-d data-dir] [channel [channel...]]\n\
+ -c: display only count of registered channels\n\
+ (cannot be combined with channels)\n\
+channel: channel(s) to display information for\n\
+\n\
+If no channels are given, the entire channel database is printed out in\n\
+compact format followed by the number of registered channels (with -c, the\n\
+list is suppressed and only the count is printed). If one or more channels\n\
+are given, detailed information about those channels is displayed.\n\
+\n");
+ exit(usage > 0 ? 1 : 0);
+ }
+
+ if (chdir(services_dir) < 0) {
+ fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
+ ModuleRunTimeDirCleanUp();
+ exit(1);
+ }
+ if (!read_config(0)) {
+ ModuleRunTimeDirCleanUp();
+ exit(1);
+ }
+ load_ns_dbase();
+ load_cs_dbase();
+
+ lang_init();
+
+ if (ac > 1) {
+ for (i = 1; i < ac; i++)
+ listchans(0, av[i]);
+ } else {
+ listchans(count, NULL);
+ }
+ exit(0);
+}
+
+/*************************************************************************/
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 000000000..a4f354993
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,336 @@
+/* Logging routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+static FILE *logfile;
+
+static int curday = 0;
+
+/*************************************************************************/
+
+static int get_logname(char *name, int count, struct tm *tm)
+{
+ char timestamp[32];
+ time_t t;
+
+
+ if (!tm) {
+ time(&t);
+ tm = localtime(&t);
+ }
+
+ /* fix bug 577 */
+ strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm);
+ snprintf(name, count, "logs/%s.%s", log_filename, timestamp);
+ curday = tm->tm_yday;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+static void remove_log(void)
+{
+ time_t t;
+ struct tm tm;
+
+ char name[PATH_MAX];
+
+ if (!KeepLogs)
+ return;
+
+ time(&t);
+ t -= (60 * 60 * 24 * KeepLogs);
+ tm = *localtime(&t);
+
+ /* removed if from here cause get_logchan is always 1 */
+ get_logname(name, sizeof(name), &tm);
+#ifndef _WIN32
+ unlink(name);
+#else
+ DeleteFile(name);
+#endif
+}
+
+/*************************************************************************/
+
+static void checkday(void)
+{
+ time_t t;
+ struct tm tm;
+
+ time(&t);
+ tm = *localtime(&t);
+
+ if (curday != tm.tm_yday) {
+ close_log();
+ remove_log();
+ open_log();
+ }
+}
+
+/*************************************************************************/
+
+/* Open the log file. Return -1 if the log file could not be opened, else
+ * return 0. */
+
+int open_log(void)
+{
+ char name[PATH_MAX];
+
+ if (logfile)
+ return 0;
+
+ /* if removed again.. get_logname is always 1 */
+ get_logname(name, sizeof(name), NULL);
+ logfile = fopen(name, "a");
+
+ if (logfile)
+ setbuf(logfile, NULL);
+ return logfile != NULL ? 0 : -1;
+}
+
+/*************************************************************************/
+
+/* Close the log file. */
+
+void close_log(void)
+{
+ if (!logfile)
+ return;
+ fclose(logfile);
+ logfile = NULL;
+}
+
+/*************************************************************************/
+
+/* added cause this is used over and over in the code */
+char *log_gettimestamp(void)
+{
+ time_t t;
+ struct tm tm;
+ static char tbuf[256];
+
+ time(&t);
+ tm = *localtime(&t);
+#if HAVE_GETTIMEOFDAY
+ if (debug) {
+ char *s;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S", &tm);
+ s = tbuf + strlen(tbuf);
+ s += snprintf(s, sizeof(tbuf) - (s - tbuf), ".%06d",
+ (int) tv.tv_usec);
+ strftime(s, sizeof(tbuf) - (s - tbuf) - 1, " %Y]", &tm);
+ } else {
+#endif
+ strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S %Y]", &tm);
+#if HAVE_GETTIMEOFDAY
+ }
+#endif
+ return tbuf;
+}
+
+/*************************************************************************/
+
+/* Log stuff to the log file with a datestamp. Note that errno is
+ * preserved by this routine and log_perror().
+ */
+
+void alog(const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int errno_save = errno;
+ char str[BUFSIZE];
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(str, sizeof(str), fmt, args);
+ va_end(args);
+
+ buf = log_gettimestamp();
+
+ if (logfile) {
+ fprintf(logfile, "%s %s\n", buf, str);
+ }
+ if (nofork) {
+ fprintf(stderr, "%s %s\n", buf, str);
+ }
+ if (LogChannel && logchan && !debug && findchan(LogChannel)) {
+ privmsg(s_GlobalNoticer, LogChannel, "%s", str);
+ }
+ errno = errno_save;
+}
+
+/*************************************************************************/
+
+/* Like alog(), but tack a ": " and a system error message (as returned by
+ * strerror()) onto the end.
+ */
+
+void log_perror(const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int errno_save = errno;
+ char str[BUFSIZE];
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(str, sizeof(str), fmt, args);
+ va_end(args);
+
+ buf = log_gettimestamp();
+
+ if (logfile) {
+ fprintf(logfile, "%s %s : %s\n", buf, str, strerror(errno_save));
+ }
+ if (nofork) {
+ fprintf(stderr, "%s %s : %s\n", buf, str, strerror(errno_save));
+ }
+ errno = errno_save;
+}
+
+/*************************************************************************/
+
+/* We've hit something we can't recover from. Let people know what
+ * happened, then go down.
+ */
+
+void fatal(const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ char buf2[4096];
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(buf2, sizeof(buf2), fmt, args);
+ va_end(args);
+
+ buf = log_gettimestamp();
+
+ if (logfile)
+ fprintf(logfile, "%s FATAL: %s\n", buf, buf2);
+ if (nofork)
+ fprintf(stderr, "%s FATAL: %s\n", buf, buf2);
+ if (servsock >= 0)
+ anope_cmd_global(NULL, "FATAL ERROR! %s", buf2);
+
+ /* one of the many places this needs to be called from */
+ ModuleRunTimeDirCleanUp();
+
+ exit(1);
+}
+
+/*************************************************************************/
+
+/* Same thing, but do it like perror(). */
+
+void fatal_perror(const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ char buf2[4096];
+ int errno_save = errno;
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(buf2, sizeof(buf2), fmt, args);
+ va_end(args);
+
+ buf = log_gettimestamp();
+
+ if (logfile)
+ fprintf(logfile, "%s FATAL: %s: %s\n", buf, buf2,
+ strerror(errno_save));
+ if (nofork)
+ fprintf(stderr, "%s FATAL: %s: %s\n", buf, buf2,
+ strerror(errno_save));
+ if (servsock >= 0)
+ anope_cmd_global(NULL, "FATAL ERROR! %s: %s", buf2,
+ strerror(errno_save));
+
+ /* one of the many places this needs to be called from */
+ ModuleRunTimeDirCleanUp();
+
+ exit(1);
+}
+
+/*************************************************************************/
+
+/* Same thing, but do it like perror().
+ * This is for socket errors. On *nix, it works just like fatal_perror,
+ * on Win32, it uses the socket error code and formatting functions.
+ */
+
+void fatal_sockerror(const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ char buf2[4096];
+ int errno_save = ano_sockgeterr();
+
+ if (!fmt) {
+ return;
+ }
+
+ checkday();
+
+ /* this will fix 581 */
+ va_start(args, fmt);
+ vsnprintf(buf2, sizeof(buf2), fmt, args);
+ va_end(args);
+
+ buf = log_gettimestamp();
+
+ if (logfile)
+ fprintf(logfile, "%s FATAL: %s: %s\n", buf, buf2,
+ ano_sockstrerror(errno_save));
+ if (stderr)
+ fprintf(stderr, "%s FATAL: %s: %s\n", buf, buf2,
+ ano_sockstrerror(errno_save));
+ if (servsock >= 0)
+ anope_cmd_global(NULL, "FATAL ERROR! %s: %s", buf2,
+ strerror(errno_save));
+
+ /* one of the many places this needs to be called from */
+ ModuleRunTimeDirCleanUp();
+
+ exit(1);
+}
diff --git a/src/mail.c b/src/mail.c
new file mode 100644
index 000000000..096191935
--- /dev/null
+++ b/src/mail.c
@@ -0,0 +1,285 @@
+/* Mail utility routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+
+/*************************************************************************/
+
+/**
+ * Begins to send a mail. Must be followed by a MailEnd call.
+ * Returns NULL if the call failed. Error messages are
+ * automatically sent to the user.
+ * @param u the User struct
+ * @param nr NickReqest Struct
+ * @param subject Subject of the email
+ * @param service Service to respond with
+ * @return MailInfo struct
+ */
+MailInfo *MailRegBegin(User * u, NickRequest * nr, char *subject,
+ char *service)
+{
+ int timeToWait = 0;
+ if (!u || !nr || !subject || !service) {
+ return NULL;
+ }
+
+ if (!UseMail) {
+ notice_lang(service, u, MAIL_DISABLED);
+ } else if ((time(NULL) - u->lastmail < MailDelay)) {
+ timeToWait = MailDelay - (time(NULL) - u->lastmail);
+ notice_lang(service, u, MAIL_DELAYED, timeToWait);
+ } else if (!nr->email) {
+ notice_lang(service, u, MAIL_INVALID, nr->nick);
+ } else {
+ MailInfo *mail;
+
+ mail = scalloc(sizeof(MailInfo), 1);
+ mail->sender = u;
+ mail->recipient = NULL;
+ mail->recip = nr;
+
+ if (!(mail->pipe = popen(SendMailPath, "w"))) {
+ free(mail);
+ notice_lang(service, u, MAIL_LATER);
+ return NULL;
+ }
+
+ fprintf(mail->pipe, "From: %s\n", SendFrom);
+ if (DontQuoteAddresses) {
+ fprintf(mail->pipe, "To: %s <%s>\n", nr->nick, nr->email);
+ } else {
+ fprintf(mail->pipe, "To: \"%s\" <%s>\n", nr->nick, nr->email);
+ }
+ fprintf(mail->pipe, "Subject: %s\n", subject);
+ return mail;
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * Begins to send a mail. Must be followed by a MailEnd call.
+ * Returns NULL if the call failed. Error messages are
+ * automatically sent to the user.
+ * @param u the User struct
+ * @param nc NickCore Struct
+ * @param subject Subject of the email
+ * @param service Service to respond with
+ * @return MailInfo struct
+ */
+MailInfo *MailBegin(User * u, NickCore * nc, char *subject, char *service)
+{
+ if (!u || !nc || !subject || !service) {
+ return NULL;
+ }
+
+ if (!UseMail) {
+ notice_lang(service, u, MAIL_DISABLED);
+ } else if (((time(NULL) - u->lastmail < MailDelay)
+ || (time(NULL) - nc->lastmail < MailDelay))
+ && !is_services_root(u)) {
+ notice_lang(service, u, MAIL_DELAYED, MailDelay);
+ } else if (!nc->email) {
+ notice_lang(service, u, MAIL_INVALID, nc->display);
+ } else {
+ MailInfo *mail;
+
+ mail = scalloc(sizeof(MailInfo), 1);
+ mail->sender = u;
+ mail->recipient = nc;
+ mail->recip = NULL;
+
+ if (!(mail->pipe = popen(SendMailPath, "w"))) {
+ free(mail);
+ notice_lang(service, u, MAIL_LATER);
+ return NULL;
+ }
+
+ fprintf(mail->pipe, "From: %s\n", SendFrom);
+ if (DontQuoteAddresses) {
+ fprintf(mail->pipe, "To: %s <%s>\n", nc->display, nc->email);
+ } else {
+ fprintf(mail->pipe, "To: \"%s\" <%s>\n", nc->display,
+ nc->email);
+ }
+ fprintf(mail->pipe, "Subject: %s\n", subject);
+
+ return mail;
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * new function to send memo mails
+ * @param nc NickCore Struct
+ * @return MailInfo struct
+ */
+MailInfo *MailMemoBegin(NickCore * nc)
+{
+
+ if (!nc)
+ return NULL;
+
+ if (!UseMail || !nc->email) {
+ return NULL;
+
+ } else {
+ MailInfo *mail;
+
+ mail = scalloc(sizeof(MailInfo), 1);
+ mail->sender = NULL;
+ mail->recipient = nc;
+ mail->recip = NULL;
+
+ if (!(mail->pipe = popen(SendMailPath, "w"))) {
+ free(mail);
+ return NULL;
+ }
+
+ fprintf(mail->pipe, "From: %s\n", SendFrom);
+ if (DontQuoteAddresses) {
+ fprintf(mail->pipe, "To: %s <%s>\n", nc->display, nc->email);
+ } else {
+ fprintf(mail->pipe, "To: \"%s\" <%s>\n", nc->display,
+ nc->email);
+ }
+ fprintf(mail->pipe, "Subject: %s\n",
+ getstring2(NULL, MEMO_MAIL_SUBJECT));
+ return mail;
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * Finish to send the mail. Cleanup everything.
+ * @param mail MailInfo Struct
+ * @return void
+ */
+void MailEnd(MailInfo * mail)
+{
+ /* - param checking modified because we don't
+ have an user sending this mail.
+ Certus, 02.04.2004 */
+
+ if (!mail || !mail->pipe) { /* removed sender check */
+ return;
+ }
+
+ if (!mail->recipient && !mail->recip) {
+ return;
+ }
+
+ pclose(mail->pipe);
+
+ if (mail->sender) /* added sender check */
+ mail->sender->lastmail = time(NULL);
+
+ if (mail->recipient)
+ mail->recipient->lastmail = time(NULL);
+ else
+ mail->recip->lastmail = time(NULL);
+
+
+ free(mail);
+}
+
+/*************************************************************************/
+
+/**
+ * Resets the MailDelay protection.
+ * @param u the User struct
+ * @param nc NickCore Struct
+ * @return void
+ */
+void MailReset(User * u, NickCore * nc)
+{
+ if (u)
+ u->lastmail = 0;
+ if (nc)
+ nc->lastmail = 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Checks whether we have a valid, common e-mail address.
+ * This is NOT entirely RFC compliant, and won't be so, because I said
+ * *common* cases. ;) It is very unlikely that e-mail addresses that
+ * are really being used will fail the check.
+ *
+ * FIXME: rewrite this a bit cleaner.
+ * @param email Email to Validate
+ * @return int
+ */
+int MailValidate(const char *email)
+{
+ int i, j, has_period = 0, len;
+ char copy[BUFSIZE], *domain;
+
+ static char specials[] =
+ { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '[', ']',
+ ' '
+ };
+
+ if (!email)
+ return 0;
+ strcpy(copy, email);
+
+ domain = strchr(copy, '@');
+ if (!domain)
+ return 0;
+ *domain = '\0';
+ domain++;
+
+ /* Don't accept NULL copy or domain. */
+ if (*copy == 0 || *domain == 0)
+ return 0;
+
+ /* Check for forbidden characters in the name */
+ for (i = 0; i < strlen(copy); i++) {
+
+ if (copy[i] <= 31 || copy[i] >= 127)
+ return 0;
+ for (j = 0; j < 13; j++)
+ if (copy[i] == specials[j])
+ return 0;
+ }
+
+ /* Check for forbidden characters in the domain, and if it seems to be valid. */
+ for (i = 0; i < (len = strlen(domain)); i++) {
+ if (domain[i] <= 31 || domain[i] >= 127)
+ return 0;
+ for (j = 0; j < 13; j++)
+ if (domain[i] == specials[j])
+ return 0;
+ if (domain[i] == '.') {
+ if (i == 0 || i == len - 1)
+ return 0;
+ has_period = 1;
+ }
+ }
+
+ if (!has_period)
+ return 0;
+
+ return 1;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 000000000..3cece40b3
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,752 @@
+/* Services -- main source file.
+ *
+ * (C) 2003-2008 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.
+ *
+ * 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 (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "timeout.h"
+#include "version.h"
+#include "datafiles.h"
+
+/******** Global variables! ********/
+
+/* Command-line options: (note that configuration variables are in config.c) */
+char *services_dir = SERVICES_DIR; /* -dir dirname */
+char *log_filename = LOG_FILENAME; /* -log filename */
+int debug = 0; /* -debug */
+int readonly = 0; /* -readonly */
+int logchan = 0; /* -logchan */
+int skeleton = 0; /* -skeleton */
+int nofork = 0; /* -nofork */
+int forceload = 0; /* -forceload */
+int nothird = 0; /* -nothrid */
+int noexpire = 0; /* -noexpire */
+int protocoldebug = 0; /* -protocoldebug */
+
+#ifdef _WIN32
+char *binary_dir; /* Used to store base path for win32 restart */
+#endif
+
+#ifdef USE_RDB
+int do_mysql = 0; /* use mysql ? */
+#endif
+
+/* Set to 1 if we are to quit */
+int quitting = 0;
+
+/* Set to 1 if we are to quit after saving databases */
+int delayed_quit = 0;
+
+/* Contains a message as to why services is terminating */
+char *quitmsg = NULL;
+
+/* Input buffer - global, so we can dump it if something goes wrong */
+char inbuf[BUFSIZE];
+
+/* Socket for talking to server */
+int servsock = -1;
+
+/* Should we update the databases now? */
+int save_data = 0;
+
+/* At what time were we started? */
+time_t start_time;
+
+/* Parameters and environment */
+char **my_av, **my_envp;
+
+/* Moved here from version.h */
+const char version_number[] = VERSION_STRING;
+const char version_number_dotted[] = VERSION_STRING_DOTTED;
+const char version_build[] =
+ "build #" BUILD ", compiled " __DATE__ " " __TIME__;
+/* the space is needed cause if you build with nothing it will complain */
+const char version_flags[] = " " VER_DEBUG VER_OS VER_MYSQL VER_MODULE;
+
+extern char *mod_current_buffer;
+
+/******** Local variables! ********/
+
+/* Set to 1 if we are waiting for input */
+static int waiting = 0;
+
+/* Set to 1 after we've set everything up */
+static int started = 0;
+
+/*************************************************************************/
+
+/* Run expiration routines */
+
+extern void expire_all(void)
+{
+ waiting = -30;
+ send_event(EVENT_DB_EXPIRE, 1, EVENT_START);
+ waiting = -3;
+ if (debug)
+ alog("debug: Running expire routines");
+ if (!skeleton) {
+ waiting = -21;
+ expire_nicks();
+ waiting = -22;
+ expire_chans();
+ waiting = -23;
+ expire_requests();
+ }
+ waiting = -25;
+ expire_akills();
+ if (ircd->sgline) {
+ waiting = -26;
+ expire_sglines();
+ }
+ if (ircd->sqline) {
+ waiting = -28;
+ expire_sqlines();
+ }
+ if (ircd->szline) {
+ waiting = -27;
+ expire_szlines();
+ }
+ waiting = -29;
+ expire_exceptions();
+ waiting = -31;
+ send_event(EVENT_DB_EXPIRE, 1, EVENT_STOP);
+}
+
+/*************************************************************************/
+
+void save_databases(void)
+{
+ waiting = -19;
+ send_event(EVENT_DB_SAVING, 1, EVENT_START);
+ waiting = -2;
+ if (debug)
+ alog("debug: Saving FFF databases");
+ waiting = -10;
+ backup_databases();
+ if (!skeleton) {
+ waiting = -11;
+ save_ns_dbase();
+ waiting = -12;
+ if (PreNickDBName) {
+ save_ns_req_dbase();
+ waiting = -13;
+ }
+ save_cs_dbase();
+ if (s_BotServ) {
+ waiting = -14;
+ save_bs_dbase();
+ }
+ if (s_HostServ) {
+ waiting = -15;
+ save_hs_dbase();
+ }
+ }
+ waiting = -16;
+ save_os_dbase();
+ waiting = -17;
+ save_news();
+ waiting = -18;
+ save_exceptions();
+
+#ifdef USE_RDB
+ if (do_mysql) {
+ if (debug)
+ alog("debug: Saving RDB databases");
+ waiting = -10;
+ if (!skeleton) {
+ waiting = -11;
+ save_ns_rdb_dbase();
+ /* We send these PONG's when we're not syncing to avoid timeouts.
+ * If we send them during the sync, we fuck something up there and
+ * break the syncing process, resulting in lost (literally lost)
+ * data. -GD
+ * This used is_sync(serv_uplink) to check for sync states. There's
+ * only a minor error with this: serv_uplink doesn't exist during
+ * the first save. So now we check for serv_uplink only; if it
+ * exists we're safe. -GD
+ */
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ waiting = -12;
+ save_cs_rdb_dbase();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ if (PreNickDBName) {
+ save_ns_req_rdb_dbase();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ waiting = -13;
+ }
+ if (s_BotServ) {
+ waiting = -14;
+ save_bs_rdb_dbase();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ }
+ if (s_HostServ) {
+ waiting = -15;
+ save_hs_rdb_dbase();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ }
+ waiting = -16;
+ save_os_rdb_dbase();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ waiting = -17;
+ save_rdb_news();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+ waiting = -18;
+ save_rdb_exceptions();
+ if (serv_uplink)
+ anope_cmd_pong(ServerName, ServerName);
+
+ } else {
+ alog("!WARNING! Both MySQL and SKELETON are enabled, however SKELETON mode overrides MySQL dumping so databases will NOT be saved to MySQL. Keep this in mind next time you start Anope with UseRDB!");
+ }
+ }
+#endif
+ waiting = -20;
+ send_event(EVENT_DB_SAVING, 1, EVENT_STOP);
+}
+
+/*************************************************************************/
+
+/* Restarts services */
+
+static void services_restart(void)
+{
+ alog("Restarting");
+ send_event(EVENT_RESTART, 1, EVENT_START);
+ if (!quitmsg)
+ quitmsg = "Restarting";
+ anope_cmd_squit(ServerName, quitmsg);
+ disconn(servsock);
+ close_log();
+ /* First don't unload protocol module, then do so */
+ modules_unload_all(true, false);
+ modules_unload_all(true, true);
+#ifdef _WIN32
+ /* This fixes bug #589 - change to binary directory for restart */
+ /* -- heinz */
+ if (binary_dir)
+ chdir(binary_dir);
+#endif
+ execve(SERVICES_BIN, my_av, my_envp);
+ if (!readonly) {
+ open_log();
+ log_perror("Restart failed");
+ close_log();
+ }
+}
+
+/*************************************************************************/
+/**
+ * Added to allow do_restart from operserv access to the static functions without making them
+ * fair game to every other function - not exactly ideal :|
+ **/
+void do_restart_services(void)
+{
+ if (!readonly) {
+ expire_all();
+ save_databases();
+ }
+ services_restart();
+ exit(1);
+}
+
+/*************************************************************************/
+
+/* Terminates services */
+
+static void services_shutdown(void)
+{
+ User *u, *next;
+
+ send_event(EVENT_SHUTDOWN, 1, EVENT_START);
+
+ if (!quitmsg)
+ quitmsg = "Terminating, reason unknown";
+ alog("%s", quitmsg);
+ if (started) {
+ anope_cmd_squit(ServerName, quitmsg);
+ Anope_Free(uplink);
+ Anope_Free(mod_current_buffer);
+ if (ircd->chanmodes) {
+ Anope_Free(ircd->chanmodes);
+ }
+ u = firstuser();
+ while (u) {
+ next = nextuser();
+ delete_user(u);
+ u = next;
+ }
+ }
+ send_event(EVENT_SHUTDOWN, 1, EVENT_STOP);
+ disconn(servsock);
+ /* First don't unload protocol module, then do so */
+ modules_unload_all(true, false);
+ modules_unload_all(true, true);
+ /* just in case they weren't all removed at least run once */
+ ModuleRunTimeDirCleanUp();
+}
+
+/*************************************************************************/
+
+/* If we get a weird signal, come here. */
+
+void sighandler(int signum)
+{
+ /* We set the quit message to something default, just to be sure it is
+ * always set when we need it. It seems some signals slip through to the
+ * QUIT code without having a valid quitmsg. -GD
+ */
+ quitmsg = sstrdup("Signal Received");
+ if (started) {
+#ifndef _WIN32
+ if (signum == SIGHUP) { /* SIGHUP = save databases and restart */
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGUSR2, SIG_IGN);
+ alog("Received SIGHUP, restarting.");
+
+ expire_all();
+ save_databases();
+
+ if (!quitmsg)
+ quitmsg = "Restarting on SIGHUP";
+
+#ifdef SERVICES_BIN
+ services_restart();
+ exit(1);
+#else
+ quitmsg =
+ "Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
+#endif
+ } else if (signum == SIGQUIT) {
+ /* had to move it to here to make win32 happy */
+ } else if (signum == SIGUSR2) {
+
+ alog("Received SIGUSR2: Saving Databases & Rehash Configuration");
+
+ expire_all();
+ save_databases();
+
+ if (!read_config(1)) {
+ sprintf(quitmsg,
+ "Error Reading Configuration File (Received SIGUSR2)");
+ quitting = 1;
+ }
+ send_event(EVENT_RELOAD, 1, EVENT_START);
+ return;
+
+ } else
+#endif
+ if (signum == SIGTERM) {
+ signal(SIGTERM, SIG_IGN);
+#ifndef _WIN32
+ signal(SIGHUP, SIG_IGN);
+#endif
+
+ alog("Received SIGTERM, exiting.");
+
+ expire_all();
+ save_databases();
+ quitmsg = "Shutting down on SIGTERM";
+ services_shutdown();
+ exit(0);
+ } else if (signum == SIGINT) {
+ if (nofork) {
+ signal(SIGINT, SIG_IGN);
+ alog("Received SIGINT, exiting.");
+ expire_all();
+ save_databases();
+ quitmsg = "Shutting down on SIGINT";
+ services_shutdown();
+ exit(0);
+ }
+ } else if (!waiting) {
+ alog("PANIC! buffer = %s", inbuf);
+ /* Cut off if this would make IRC command >510 characters. */
+ if (strlen(inbuf) > 448) {
+ inbuf[446] = '>';
+ inbuf[447] = '>';
+ inbuf[448] = 0;
+ }
+ wallops(NULL, "PANIC! buffer = %s\r\n", inbuf);
+ modules_unload_all(false, true);
+ } else if (waiting < 0) {
+ /* This is static on the off-chance we run low on stack */
+ static char buf[BUFSIZE];
+ switch (waiting) {
+ case -1:
+ snprintf(buf, sizeof(buf), "in timed_update");
+ break;
+ case -10:
+ snprintf(buf, sizeof(buf), "backing up databases");
+ break;
+ case -11:
+ snprintf(buf, sizeof(buf), "saving %s", NickDBName);
+ break;
+ case -12:
+ snprintf(buf, sizeof(buf), "saving %s", ChanDBName);
+ break;
+ case -13:
+ snprintf(buf, sizeof(buf), "saving %s", PreNickDBName);
+ break;
+ case -14:
+ snprintf(buf, sizeof(buf), "saving %s", BotDBName);
+ break;
+ case -15:
+ snprintf(buf, sizeof(buf), "saving %s", HostDBName);
+ break;
+ case -16:
+ snprintf(buf, sizeof(buf), "saving %s", OperDBName);
+ break;
+ case -17:
+ snprintf(buf, sizeof(buf), "saving %s", NewsDBName);
+ break;
+ case -18:
+ snprintf(buf, sizeof(buf), "saving %s", ExceptionDBName);
+ break;
+ case -19:
+ snprintf(buf, sizeof(buf), "Sending event %s %s",
+ EVENT_DB_SAVING, EVENT_START);
+ break;
+ case -20:
+ snprintf(buf, sizeof(buf), "Sending event %s %s",
+ EVENT_DB_SAVING, EVENT_STOP);
+ break;
+ case -21:
+ snprintf(buf, sizeof(buf), "expiring nicknames");
+ break;
+ case -22:
+ snprintf(buf, sizeof(buf), "expiring channels");
+ break;
+ case -25:
+ snprintf(buf, sizeof(buf), "expiring autokills");
+ break;
+ case -26:
+ snprintf(buf, sizeof(buf), "expiring SGLINEs");
+ break;
+ case -27:
+ snprintf(buf, sizeof(buf), "expiring SZLINEs");
+ break;
+ case -28:
+ snprintf(buf, sizeof(buf), "expiring SQLINEs");
+ break;
+ case -29:
+ snprintf(buf, sizeof(buf), "expiring Exceptions");
+ break;
+ case -30:
+ snprintf(buf, sizeof(buf), "Sending event %s %s",
+ EVENT_DB_EXPIRE, EVENT_START);
+ break;
+ case -31:
+ snprintf(buf, sizeof(buf), "Sending event %s %s",
+ EVENT_DB_EXPIRE, EVENT_STOP);
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "waiting=%d", waiting);
+ }
+ wallops(NULL, "PANIC! %s (%s)", buf, strsignal(signum));
+ alog("PANIC! %s (%s)", buf, strsignal(signum));
+ modules_unload_all(false, true);
+ }
+ }
+
+ if (
+#ifndef _WIN32
+ signum == SIGUSR1 ||
+#endif
+ !(quitmsg = calloc(BUFSIZE, 1))) {
+ quitmsg = "Out of memory!";
+ } else {
+#if HAVE_STRSIGNAL
+ snprintf(quitmsg, BUFSIZE, "Services terminating: %s",
+ strsignal(signum));
+#else
+ snprintf(quitmsg, BUFSIZE, "Services terminating on signal %d",
+ signum);
+#endif
+ }
+
+ if (signum == SIGSEGV) {
+ do_backtrace(1);
+ modules_unload_all(false, true); /* probably cant do this, but might as well try, we have nothing left to loose */
+ }
+ /* Should we send the signum here as well? -GD */
+ send_event(EVENT_SIGNAL, 1, quitmsg);
+
+ if (started) {
+ services_shutdown();
+ exit(0);
+ } else {
+ if (isatty(2)) {
+ fprintf(stderr, "%s\n", quitmsg);
+ } else {
+ alog("%s", quitmsg);
+ }
+ exit(1);
+ }
+}
+
+/*************************************************************************/
+
+/* Main routine. (What does it look like? :-) ) */
+
+int main(int ac, char **av, char **envp)
+{
+ volatile time_t last_update; /* When did we last update the databases? */
+ volatile time_t last_expire; /* When did we last expire nicks/channels? */
+ volatile time_t last_check; /* When did we last check timeouts? */
+ volatile time_t last_DefCon; /* When was DefCon last checked? */
+
+ int i;
+ char *progname;
+
+ my_av = av;
+ my_envp = envp;
+
+#ifndef _WIN32
+ /* If we're root, issue a warning now */
+ if ((getuid() == 0) && (getgid() == 0)) {
+ fprintf(stderr,
+ "WARNING: You are currently running Anope as the root superuser. Anope does not\n");
+ fprintf(stderr,
+ " require root privileges to run, and it is discouraged that you run Anope\n");
+ fprintf(stderr, " as the root superuser.\n");
+ }
+#else
+ /*
+ * We need to know which directory we're in for when restart is called.
+ * This only affects Windows as a full path is not specified in services_dir.
+ * This fixes bug #589.
+ * -- heinz
+ */
+ binary_dir = smalloc(MAX_PATH);
+ if (!getcwd(binary_dir, MAX_PATH)) {
+ fprintf(stderr, "error: getcwd() error\n");
+ return -1;
+ }
+#endif
+
+ /* General initialization first */
+ if ((i = init_primary(ac, av)) != 0)
+ return i;
+
+ /* Find program name. */
+ if ((progname = strrchr(av[0], '/')) != NULL)
+ progname++;
+ else
+ progname = av[0];
+
+#ifdef _WIN32
+ if (strcmp(progname, "listnicks.exe") == 0)
+#else
+ if (strcmp(progname, "listnicks") == 0)
+#endif
+ {
+ do_listnicks(ac, av);
+ modules_unload_all(1, 0);
+ modules_unload_all(1, 1);
+ ModuleRunTimeDirCleanUp();
+ return 0;
+ }
+#ifdef _WIN32
+ else if (strcmp(progname, "listchans.exe") == 0)
+#else
+ else if (strcmp(progname, "listchans") == 0)
+#endif
+ {
+ do_listchans(ac, av);
+ modules_unload_all(1, 0);
+ modules_unload_all(1, 1);
+ ModuleRunTimeDirCleanUp();
+ return 0;
+ }
+
+ /* Initialization stuff. */
+ if ((i = init_secondary(ac, av)) != 0)
+ return i;
+
+
+ /* We have a line left over from earlier, so process it first. */
+ process();
+
+ /* Set up timers. */
+ last_update = time(NULL);
+ last_expire = time(NULL);
+ last_check = time(NULL);
+ last_DefCon = time(NULL);
+
+ started = 1;
+
+ /*** Main loop. ***/
+
+ while (!quitting) {
+ time_t t = time(NULL);
+
+ if (debug >= 2)
+ alog("debug: Top of main loop");
+
+ if (!noexpire && !readonly
+ && (save_data || t - last_expire >= ExpireTimeout)) {
+ expire_all();
+ last_expire = t;
+ }
+
+ if (!readonly && (save_data || t - last_update >= UpdateTimeout)) {
+ if (delayed_quit)
+ anope_cmd_global(NULL,
+ "Updating databases on shutdown, please wait.");
+
+ save_databases();
+
+ if (save_data < 0)
+ break; /* out of main loop */
+
+ save_data = 0;
+ last_update = t;
+ }
+
+ if ((DefConTimeOut) && (t - last_DefCon >= dotime(DefConTimeOut))) {
+ resetDefCon(5);
+ last_DefCon = t;
+ }
+
+ if (delayed_quit)
+ break;
+
+ moduleCallBackRun();
+
+ waiting = -1;
+ if (t - last_check >= TimeoutCheck) {
+ check_timeouts();
+ last_check = t;
+ }
+
+ waiting = 1;
+ /* this is a nasty nasty typecast. we need to rewrite the
+ socket stuff -Certus */
+ i = (int) (long) sgets2(inbuf, sizeof(inbuf), servsock);
+ waiting = 0;
+ if ((i > 0) || (i < (-1))) {
+ process();
+ } else if (i == 0) {
+ int errno_save = errno;
+ quitmsg = scalloc(BUFSIZE, 1);
+ if (quitmsg) {
+ snprintf(quitmsg, BUFSIZE,
+ "Read error from server: %s (error num: %d)",
+ strerror(errno_save), errno_save);
+ } else {
+ quitmsg = "Read error from server";
+ }
+ quitting = 1;
+
+ /* Save the databases */
+ if (!readonly)
+ save_databases();
+ }
+ waiting = -4;
+ }
+
+
+ /* Check for restart instead of exit */
+ if (save_data == -2) {
+#ifdef SERVICES_BIN
+ alog("Restarting");
+ if (!quitmsg)
+ quitmsg = "Restarting";
+ anope_cmd_squit(ServerName, quitmsg);
+ disconn(servsock);
+ close_log();
+#ifdef _WIN32
+ /* This fixes bug #589 - change to binary directory for restart */
+ /* -- heinz */
+ if (binary_dir)
+ chdir(binary_dir);
+#endif
+ execve(SERVICES_BIN, av, envp);
+ if (!readonly) {
+ open_log();
+ log_perror("Restart failed");
+ close_log();
+ }
+ return 1;
+#else
+ quitmsg =
+ "Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
+#endif
+ }
+
+ /* Disconnect and exit */
+ services_shutdown();
+
+#ifdef _WIN32
+ if (binary_dir)
+ free(binary_dir);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+void do_backtrace(int show_segheader)
+{
+#ifndef _WIN32
+#ifdef HAVE_BACKTRACE
+ void *array[50];
+ size_t size;
+ char **strings;
+ int i;
+
+ if (show_segheader) {
+ alog("Backtrace: Segmentation fault detected");
+ alog("Backtrace: report the following lines");
+ }
+ alog("Backtrace: Anope version %s %s %s", version_number,
+ version_build, version_flags);
+ size = backtrace(array, 10);
+ strings = backtrace_symbols(array, size);
+ for (i = 0; i < size; i++) {
+ alog("Backtrace(%d): %s", i, strings[i]);
+ }
+ free(strings);
+ alog("Backtrace: complete");
+#else
+ alog("Backtrace: not available on this platform");
+#endif
+#else
+ char *winver;
+ winver = GetWindowsVersion();
+ alog("Backtrace: not available on Windows");
+ alog("Running %S", winver);
+ free(winver);
+#endif
+}
diff --git a/src/makefile.win32 b/src/makefile.win32
new file mode 100644
index 000000000..a6b90b708
--- /dev/null
+++ b/src/makefile.win32
@@ -0,0 +1,109 @@
+# Make file for Win32
+#
+# (C) 2003-2008 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.
+#
+# $Id$
+#
+
+# Source Makefile
+
+include ../Makefile.inc.win32
+
+###########################################################################
+
+OBJS = actions.obj base64.obj botserv.obj channels.obj chanserv.obj commands.obj compat.obj \
+ config.obj datafiles.obj encrypt.obj events.obj helpserv.obj hostserv.obj \
+ init.obj ircd.obj language.obj list.obj log.obj mail.obj main.obj memory.obj \
+ memoserv.obj messages.obj misc.obj modules.obj mod_version.obj news.obj nickserv.obj operserv.obj \
+ process.obj send.obj servers.obj sessions.obj slist.obj sockutil.obj \
+ timeout.obj users.obj $(RDB_O) $(MYSQL_O)
+
+SRCS = actions.c base64.c botserv.c channels.c chanserv.c commands.c compat.c \
+ config.c datafiles.c encrypt.c events.c helpserv.c hostserv.c init.c ircd.c \
+ language.c list.c log.c mail.c main.c memory.c memoserv.c messages.c misc.c \
+ modules.c mod_version.c news.c nickserv.c operserv.c process.c send.c servers.obj sessions.c \
+ slist.c sockutil.c timeout.c users.c $(RDB_C) $(MYSQL_C)
+
+###########################################################################
+
+.c.obj:
+ $(CC) $(CFLAGS) -c $<
+
+all: $(PROGRAM)
+
+$(PROGRAM): $(OBJS) win32.res
+ $(CC) $(OBJS) win32.res /link /out:$(PROGRAM) /implib:anope.lib $(LIBS) $(LFLAGS) $(MLIBS) $(ELIBS)
+
+spotless:
+ -@erase *.obj *.exe *.exp *.lib tools\*.exe *.res win32.rc *.manifest
+
+install:
+ -@copy anope.exe ..\anope.exe
+ -@mkdir ..\$(DATDEST)\bin
+ -@copy bin\* ..\$(DATDEST)\bin
+ -@copy anope.exe.manifest ..\anope.exe.manifest
+
+win32.res: win32.rc
+ $(RC) /l 0x409 $(RC_FLAGS) /fowin32.res win32.rc
+
+
+###########################################################################
+
+# Catch any changes in compilation options at the top of this file
+$(OBJS):
+
+actions.obj: actions.c ..\include\services.h
+base64.obj: base64.c ..\include\services.h
+botserv.obj: botserv.c ..\include\services.h ..\include\pseudo.h ..\include\language.h
+channels.obj: channels.c ..\include\services.h
+chanserv.obj: chanserv.c ..\include\services.h ..\include\pseudo.h
+commands.obj: commands.c ..\include\services.h ..\include\commands.h ..\include\language.h
+compat.obj: compat.c ..\include\services.h
+config.obj: config.c ..\include\services.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
+ircd.obj: ircd.c ..\include\services.h
+hostserv.obj: hostserv.c ..\include\services.h ..\include\pseudo.h
+language.obj: language.c ..\include\services.h ..\include\language.h
+list.obj: list.c ..\include\services.h
+log.obj: log.c ..\include\services.h ..\include\pseudo.h
+mail.obj: mail.c ..\include\services.h ..\include\language.h
+main.obj: main.c ..\include\services.h ..\include\timeout.h ..\include\version.h
+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
+mod_version.obj: mod_version.c ..\include\modules.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
+operserv.obj: operserv.c ..\include\services.h ..\include\pseudo.h
+process.obj: process.c ..\include\services.h ..\include\messages.h
+send.obj: send.c ..\include\services.h
+servers.obj: servers.c ..\include\services.h
+sessions.obj: sessions.c ..\include\services.h ..\include\pseudo.h
+slist.obj: slist.c ..\include\services.h ..\include\slist.h
+sockutil.obj: sockutil.c ..\include\services.h
+timeout.obj: timeout.c ..\include\services.h ..\include\timeout.h
+users.obj: users.c ..\include\services.h
+vsnprintf.obj: vsnprintf.c
+
+###########################################################################
+
+..\include\services.h: ..\include\sysconf.h ..\include\config.h ..\include\extern.h
+
+..\include\extern.h: ..\include\slist.h
+
+..\include\pseudo.h: ..\include\commands.h ..\include\language.h ..\include\timeout.h ..\include\encrypt.h ..\include\datafiles.h ..\include\slist.h
+
+###########################################################################
+
+FRC:
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 000000000..056a29a76
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,138 @@
+/* Memory management routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/* smalloc, scalloc, srealloc, sstrdup:
+ * Versions of the memory allocation functions which will cause the
+ * program to terminate with an "Out of memory" error if the memory
+ * cannot be allocated. (Hence, the return value from these functions
+ * is never NULL.)
+ */
+
+/*************************************************************************/
+
+/**
+ * malloc, replacement so we can trap for "out of memory"
+ * @param size to allocate
+ * @return void
+ */
+void *smalloc(long size)
+{
+ void *buf;
+
+ if (!size) {
+ size = 1;
+ }
+ buf = malloc(size);
+ if (!buf)
+#ifndef _WIN32
+ raise(SIGUSR1);
+#else
+ abort();
+#endif
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * calloc, replacement so we can trap for "out of memory"
+ * @param elsize to allocate
+ * @param els size of members
+ * @return void
+ */
+void *scalloc(long elsize, long els)
+{
+ void *buf;
+
+ if (!elsize || !els) {
+ elsize = els = 1;
+ }
+ buf = calloc(elsize, els);
+ if (!buf)
+#ifndef _WIN32
+ raise(SIGUSR1);
+#else
+ abort();
+#endif
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * realloc, replacement so we can trap for "out of memory"
+ * @param oldptr Old Pointer
+ * @param newsize Size of new pointer
+ * @return void
+ */
+void *srealloc(void *oldptr, long newsize)
+{
+ void *buf;
+
+ if (!newsize) {
+ newsize = 1;
+ }
+ buf = realloc(oldptr, newsize);
+ if (!buf)
+#ifndef _WIN32
+ raise(SIGUSR1);
+#else
+ abort();
+#endif
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * strdup, replacement so we can trap for "out of memory"
+ * @param oldptr Old Pointer
+ * @param newsize Size of new pointer
+ * @return void
+ */
+char *sstrdup(const char *src)
+{
+ char *ret = NULL;
+ if (src) {
+#ifdef __STRICT_ANSI__
+ if ((ret = (char *) malloc(strlen(src) + 1))) {;
+ strcpy(ret, src);
+ }
+#else
+ ret = strdup(src);
+#endif
+ if (!ret)
+#ifndef _WIN32
+ raise(SIGUSR1);
+#else
+ abort();
+#endif
+ } else {
+ alog("sstrdup() called with NULL-arg");
+ if (debug)
+ do_backtrace(0);
+ }
+
+ return ret;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* In the future: malloc() replacements that tell us if we're leaking and
+ * maybe do sanity checks too... */
+
+/*************************************************************************/
diff --git a/src/memoserv.c b/src/memoserv.c
new file mode 100644
index 000000000..c55f9633f
--- /dev/null
+++ b/src/memoserv.c
@@ -0,0 +1,445 @@
+/* MemoServ functions.
+*
+* (C) 2003-2008 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.
+*
+* $Id$
+*
+*/
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+/* *INDENT-OFF* */
+
+NickCore *nclists[1024];
+E void moduleAddMemoServCmds(void);
+static void new_memo_mail(NickCore *nc, Memo *m);
+E void rsend_notify(User *u, Memo *m, const char *chan);
+
+/*************************************************************************/
+
+void moduleAddMemoServCmds(void) {
+ modules_core_init(MemoServCoreNumber, MemoServCoreModules);
+}
+
+/*************************************************************************/
+/*************************************************************************/
+/* *INDENT-ON* */
+
+/**
+ * MemoServ initialization.
+ * @return void
+ */
+void ms_init(void)
+{
+ moduleAddMemoServCmds();
+}
+
+/*************************************************************************/
+
+/**
+ * memoserv: Main MemoServ routine.
+ * Note that the User structure passed to the do_* routines will
+ * always be valid (non-NULL) and will always have a valid
+ * NickInfo pointer in the `ni' field.
+ * @param u User Struct
+ * @param buf Buffer containing the privmsg
+ * @return void
+ */
+void memoserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_MemoServ, u->nick, "PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_MemoServ, u, SERVICE_OFFLINE, s_MemoServ);
+ } else {
+ if (!u->na && stricmp(cmd, "HELP") != 0)
+ notice_lang(s_MemoServ, u, NICK_NOT_REGISTERED_HELP,
+ s_NickServ);
+ else
+ mod_run_cmd(s_MemoServ, u, MEMOSERV, cmd);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * check_memos: See if the given user has any unread memos, and send a
+ * NOTICE to that user if so (and if the appropriate flag is
+ * set).
+ * @param u User Struct
+ * @return void
+ */
+void check_memos(User * u)
+{
+ NickCore *nc;
+ int i, newcnt = 0;
+
+ if (!u) {
+ if (debug) {
+ alog("debug: check_memos called with NULL values");
+ }
+ return;
+ }
+
+ if (!(nc = (u->na ? u->na->nc : NULL)) || !nick_recognized(u) ||
+ !(nc->flags & NI_MEMO_SIGNON)) {
+ return;
+ }
+
+ for (i = 0; i < nc->memos.memocount; i++) {
+ if (nc->memos.memos[i].flags & MF_UNREAD)
+ newcnt++;
+ }
+ if (newcnt > 0) {
+ notice_lang(s_MemoServ, u,
+ newcnt == 1 ? MEMO_HAVE_NEW_MEMO : MEMO_HAVE_NEW_MEMOS,
+ newcnt);
+ if (newcnt == 1 && (nc->memos.memos[i - 1].flags & MF_UNREAD)) {
+ notice_lang(s_MemoServ, u, MEMO_TYPE_READ_LAST, s_MemoServ);
+ } else if (newcnt == 1) {
+ for (i = 0; i < nc->memos.memocount; i++) {
+ if (nc->memos.memos[i].flags & MF_UNREAD)
+ break;
+ }
+ notice_lang(s_MemoServ, u, MEMO_TYPE_READ_NUM, s_MemoServ,
+ nc->memos.memos[i].number);
+ } else {
+ notice_lang(s_MemoServ, u, MEMO_TYPE_LIST_NEW, s_MemoServ);
+ }
+ }
+ if (nc->memos.memomax > 0 && nc->memos.memocount >= nc->memos.memomax) {
+ if (nc->memos.memocount > nc->memos.memomax)
+ notice_lang(s_MemoServ, u, MEMO_OVER_LIMIT, nc->memos.memomax);
+ else
+ notice_lang(s_MemoServ, u, MEMO_AT_LIMIT, nc->memos.memomax);
+ }
+}
+
+/*************************************************************************/
+/*********************** MemoServ private routines ***********************/
+/*************************************************************************/
+
+/**
+ * Return the MemoInfo corresponding to the given nick or channel name.
+ * @param name Name to check
+ * @param ischan - the result its a channel will be stored in here
+ * @param isforbid - the result if its forbidden will be stored in here
+ * @return `ischan' 1 if the name was a channel name, else 0.
+ * @return `isforbid' 1 if the name is forbidden, else 0.
+ */
+MemoInfo *getmemoinfo(const char *name, int *ischan, int *isforbid)
+{
+ if (*name == '#') {
+ ChannelInfo *ci;
+ if (ischan)
+ *ischan = 1;
+ ci = cs_findchan(name);
+ if (ci) {
+ if (!(ci->flags & CI_VERBOTEN)) {
+ *isforbid = 0;
+ return &ci->memos;
+ } else {
+ *isforbid = 1;
+ return NULL;
+ }
+ } else {
+ *isforbid = 0;
+ return NULL;
+ }
+ } else {
+ NickAlias *na;
+ if (ischan)
+ *ischan = 0;
+ na = findnick(name);
+ if (na) {
+ if (!(na->status & NS_VERBOTEN)) {
+ *isforbid = 0;
+ return &na->nc->memos;
+ } else {
+ *isforbid = 1;
+ return NULL;
+ }
+ } else {
+ *isforbid = 0;
+ return NULL;
+ }
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Split from do_send, this way we can easily send a memo from any point
+ * @param u User Struct
+ * @param name Target of the memo
+ * @param text Memo Text
+ * @param z type see info
+ * 0 - reply to user
+ * 1 - silent
+ * 2 - silent with no delay timer
+ * 3 - reply to user and request read receipt
+ * @return void
+ */
+void memo_send(User * u, char *name, char *text, int z)
+{
+ int ischan;
+ int isforbid;
+ Memo *m;
+ MemoInfo *mi;
+ time_t now = time(NULL);
+ char *source = u->na->nc->display;
+ int is_servoper = is_services_oper(u);
+
+ if (readonly) {
+ notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED);
+ } else if (checkDefCon(DEFCON_NO_NEW_MEMOS)) {
+ notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED);
+ return;
+ } else if (!text) {
+ if (z == 0)
+ syntax_error(s_MemoServ, u, "SEND", MEMO_SEND_SYNTAX);
+
+ if (z == 3)
+ syntax_error(s_MemoServ, u, "RSEND", MEMO_RSEND_SYNTAX);
+
+ } else if (!nick_recognized(u)) {
+ if (z == 0 || z == 3)
+ notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
+
+ } else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) {
+ if (z == 0 || z == 3) {
+ if (isforbid) {
+ notice_lang(s_MemoServ, u,
+ ischan ? CHAN_X_FORBIDDEN :
+ NICK_X_FORBIDDEN, name);
+ } else {
+ notice_lang(s_MemoServ, u,
+ ischan ? CHAN_X_NOT_REGISTERED :
+ NICK_X_NOT_REGISTERED, name);
+ }
+ }
+ } else if (z != 2 && MSSendDelay > 0 &&
+ u && u->lastmemosend + MSSendDelay > now && !is_servoper) {
+ u->lastmemosend = now;
+ if (z == 0)
+ notice_lang(s_MemoServ, u, MEMO_SEND_PLEASE_WAIT, MSSendDelay);
+
+ if (z == 3)
+ notice_lang(s_MemoServ, u, MEMO_RSEND_PLEASE_WAIT,
+ MSSendDelay);
+
+ } else if (mi->memomax == 0 && !is_servoper) {
+ if (z == 0 || z == 3)
+ notice_lang(s_MemoServ, u, MEMO_X_GETS_NO_MEMOS, name);
+
+ } else if (mi->memomax > 0 && mi->memocount >= mi->memomax
+ && !is_servoper) {
+ if (z == 0 || z == 3)
+ notice_lang(s_MemoServ, u, MEMO_X_HAS_TOO_MANY_MEMOS, name);
+
+ } else {
+ u->lastmemosend = now;
+ mi->memocount++;
+ mi->memos = srealloc(mi->memos, sizeof(Memo) * mi->memocount);
+ m = &mi->memos[mi->memocount - 1];
+ strscpy(m->sender, source, NICKMAX);
+ m->moduleData = NULL;
+ if (mi->memocount > 1) {
+ m->number = m[-1].number + 1;
+ if (m->number < 1) {
+ int i;
+ for (i = 0; i < mi->memocount; i++) {
+ mi->memos[i].number = i + 1;
+ }
+ }
+ } else {
+ m->number = 1;
+ }
+ m->time = time(NULL);
+ m->text = sstrdup(text);
+ m->flags = MF_UNREAD;
+ /* Set notify sent flag - DrStein */
+ if (z == 2) {
+ m->flags |= MF_NOTIFYS;
+ }
+ /* Set receipt request flag */
+ if (z == 3)
+ m->flags |= MF_RECEIPT;
+ if (z == 0 || z == 3)
+ notice_lang(s_MemoServ, u, MEMO_SENT, name);
+ if (!ischan) {
+ NickAlias *na;
+ NickCore *nc = (findnick(name))->nc;
+
+ if (MSNotifyAll) {
+ if ((nc->flags & NI_MEMO_RECEIVE)
+ && get_ignore(name) == NULL) {
+ int i;
+
+ for (i = 0; i < nc->aliases.count; i++) {
+ na = nc->aliases.list[i];
+ if (na->u && nick_identified(na->u))
+ notice_lang(s_MemoServ, na->u,
+ MEMO_NEW_MEMO_ARRIVED, source,
+ s_MemoServ, m->number);
+ }
+ } else {
+ if ((u = finduser(name)) && nick_identified(u)
+ && (nc->flags & NI_MEMO_RECEIVE))
+ notice_lang(s_MemoServ, u, MEMO_NEW_MEMO_ARRIVED,
+ source, s_MemoServ, m->number);
+ } /* if (flags & MEMO_RECEIVE) */
+ }
+ /* if (MSNotifyAll) */
+ /* let's get out the mail if set in the nickcore - certus */
+ if (nc->flags & NI_MEMO_MAIL)
+ new_memo_mail(nc, m);
+ } else {
+ struct c_userlist *cu, *next;
+ Channel *c;
+
+ if (MSNotifyAll && (c = findchan(name))) {
+ for (cu = c->users; cu; cu = next) {
+ next = cu->next;
+ if (check_access(cu->user, c->ci, CA_MEMO)) {
+ if (cu->user->na
+ && (cu->user->na->nc->flags & NI_MEMO_RECEIVE)
+ && get_ignore(cu->user->nick) == NULL) {
+ notice_lang(s_MemoServ, cu->user,
+ MEMO_NEW_X_MEMO_ARRIVED,
+ c->ci->name, s_MemoServ,
+ c->ci->name, m->number);
+ }
+ }
+ }
+ } /* MSNotifyAll */
+ } /* if (!ischan) */
+ } /* if command is valid */
+}
+
+/*************************************************************************/
+/**
+ * Delete a memo by number.
+ * @param mi Memoinfo struct
+ * @param num Memo number to delete
+ * @return int 1 if the memo was found, else 0.
+ */
+int delmemo(MemoInfo * mi, int num)
+{
+ int i;
+
+ for (i = 0; i < mi->memocount; i++) {
+ if (mi->memos[i].number == num)
+ break;
+ }
+ if (i < mi->memocount) {
+ moduleCleanStruct(&mi->memos[i].moduleData);
+ free(mi->memos[i].text); /* Deallocate memo text memory */
+ mi->memocount--; /* One less memo now */
+ if (i < mi->memocount) /* Move remaining memos down a slot */
+ memmove(mi->memos + i, mi->memos + i + 1,
+ sizeof(Memo) * (mi->memocount - i));
+ if (mi->memocount == 0) { /* If no more memos, free array */
+ free(mi->memos);
+ mi->memos = NULL;
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*************************************************************************/
+
+static void new_memo_mail(NickCore * nc, Memo * m)
+{
+ MailInfo *mail = NULL;
+
+ if (!nc || !m)
+ return;
+
+ mail = MailMemoBegin(nc);
+ if (!mail) {
+ return;
+ }
+ fprintf(mail->pipe, getstring2(NULL, MEMO_MAIL_TEXT1), nc->display);
+ fprintf(mail->pipe, "\n");
+ fprintf(mail->pipe, getstring2(NULL, MEMO_MAIL_TEXT2), m->sender,
+ m->number);
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, getstring2(NULL, MEMO_MAIL_TEXT3));
+ fprintf(mail->pipe, "\n\n");
+ fprintf(mail->pipe, "%s", m->text);
+ fprintf(mail->pipe, "\n");
+ MailEnd(mail);
+ return;
+}
+
+
+/*************************************************************************/
+/* Send receipt notification to sender. */
+
+void rsend_notify(User * u, Memo * m, const char *chan)
+{
+ NickAlias *na;
+ NickCore *nc;
+ char text[256];
+ const char *fmt;
+
+ /* Only send receipt if memos are allowed */
+ if ((!readonly) && (!checkDefCon(DEFCON_NO_NEW_MEMOS))) {
+
+ /* Get nick alias for sender */
+ na = findnick(m->sender);
+
+ if (!na) {
+ return;
+ }
+
+ /* Get nick core for sender */
+ nc = na->nc;
+
+ if (!nc) {
+ return;
+ }
+
+ /* Text of the memo varies if the recepient was a
+ nick or channel */
+ if (chan) {
+ fmt = getstring(na, MEMO_RSEND_CHAN_MEMO_TEXT);
+ sprintf(text, fmt, chan);
+ } else {
+ fmt = getstring(na, MEMO_RSEND_NICK_MEMO_TEXT);
+ sprintf(text, fmt);
+ }
+
+ /* Send notification */
+ memo_send(u, m->sender, text, 2);
+
+ /* Notify recepient of the memo that a notification has
+ been sent to the sender */
+ notice_lang(s_MemoServ, u, MEMO_RSEND_USER_NOTIFICATION,
+ nc->display);
+ }
+
+ /* Remove receipt flag from the original memo */
+ m->flags &= ~MF_RECEIPT;
+
+ return;
+}
diff --git a/src/messages.c b/src/messages.c
new file mode 100644
index 000000000..33dd54619
--- /dev/null
+++ b/src/messages.c
@@ -0,0 +1,415 @@
+/* Definitions of IRC message functions and list of messages.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "messages.h"
+#include "language.h"
+
+int servernum;
+
+/*************************************************************************/
+
+int m_nickcoll(char *user)
+{
+ if (!skeleton && !readonly)
+ introduce_user(user);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_away(char *source, char *msg)
+{
+ User *u;
+
+ u = finduser(source);
+
+ if (u && msg == 0) /* un-away */
+ check_memos(u);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_kill(char *nick, char *msg)
+{
+ BotInfo *bi;
+
+ /* Recover if someone kills us. */
+ /* use nickIsServices() to reduce the number of lines of code - TSL */
+ if (nickIsServices(nick, 0)) {
+ if (!readonly && !skeleton)
+ introduce_user(nick);
+ } else if (s_BotServ && (bi = findbot(nick))) {
+ if (!readonly && !skeleton) {
+ introduce_user(nick);
+ bot_rejoin_all(bi);
+ }
+ } else {
+ do_kill(nick, msg);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_time(char *source, int ac, char **av)
+{
+ time_t t;
+ struct tm *tm;
+ char buf[64];
+
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ time(&t);
+ tm = localtime(&t);
+ strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z", tm);
+ anope_cmd_391(source, buf);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_motd(char *source)
+{
+ FILE *f;
+ char buf[BUFSIZE];
+
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ f = fopen(MOTDFilename, "r");
+ if (f) {
+ anope_cmd_375(source);
+ while (fgets(buf, sizeof(buf), f)) {
+ buf[strlen(buf) - 1] = 0;
+ anope_cmd_372(source, buf);
+ }
+ fclose(f);
+ anope_cmd_376(source);
+ } else {
+ anope_cmd_372_error(source);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_privmsg(char *source, char *receiver, char *msg)
+{
+ char *s;
+ time_t starttime, stoptime; /* When processing started and finished */
+
+ BotInfo *bi;
+ ChannelInfo *ci;
+ User *u;
+
+ if (!source || !*source || !*receiver || !receiver || !msg) {
+ return MOD_CONT;
+ }
+
+ u = finduser(source);
+
+ if (!u) {
+ alog("%s: user record for %s not found", msg, source);
+ anope_cmd_notice(receiver, source,
+ getstring(NULL, USER_RECORD_NOT_FOUND));
+ return MOD_CONT;
+ }
+
+ if (*receiver == '#') {
+ if (s_BotServ && (ci = cs_findchan(receiver))) {
+ /* Some paranoia checks */
+ if (!(ci->flags & CI_VERBOTEN) && ci->c && ci->bi) {
+ botchanmsgs(u, ci, msg);
+ }
+ }
+ } else {
+ /* Check if we should ignore. Operators always get through. */
+ if (allow_ignore && !is_oper(u)) {
+ IgnoreData *ign = get_ignore(source);
+ if (ign) {
+ alog("Ignored message from %s: \"%s\"", source, inbuf);
+ return MOD_CONT;
+ }
+ }
+
+ /* If a server is specified (nick@server format), make sure it matches
+ * us, and strip it off. */
+ s = strchr(receiver, '@');
+ if (s) {
+ *s++ = 0;
+ if (stricmp(s, ServerName) != 0)
+ return MOD_CONT;
+ } else if (UseStrictPrivMsg) {
+ if (debug) {
+ alog("Ignored PRIVMSG without @ from %s", source);
+ }
+ notice_lang(receiver, u, INVALID_TARGET, receiver, receiver,
+ ServerName, receiver);
+ return MOD_CONT;
+ }
+
+ starttime = time(NULL);
+
+ if ((stricmp(receiver, s_OperServ) == 0)
+ || (s_OperServAlias
+ && (stricmp(receiver, s_OperServAlias) == 0))) {
+ if (!is_oper(u) && OSOpersOnly) {
+ notice_lang(s_OperServ, u, ACCESS_DENIED);
+ if (WallBadOS)
+ anope_cmd_global(s_OperServ,
+ "Denied access to %s from %s!%s@%s (non-oper)",
+ s_OperServ, u->nick, u->username,
+ u->host);
+ } else {
+ operserv(u, msg);
+ }
+ } else if ((stricmp(receiver, s_NickServ) == 0)
+ || (s_NickServAlias
+ && (stricmp(receiver, s_NickServAlias) == 0))) {
+ nickserv(u, msg);
+ } else if ((stricmp(receiver, s_ChanServ) == 0)
+ || (s_ChanServAlias
+ && (stricmp(receiver, s_ChanServAlias) == 0))) {
+ if (!is_oper(u) && CSOpersOnly)
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ else
+ chanserv(u, msg);
+ } else if ((stricmp(receiver, s_MemoServ) == 0)
+ || (s_MemoServAlias
+ && (stricmp(receiver, s_MemoServAlias) == 0))) {
+ memoserv(u, msg);
+ } else if (s_HostServ && ((stricmp(receiver, s_HostServ) == 0)
+ || (s_HostServAlias
+ &&
+ (stricmp(receiver, s_HostServAlias)
+ == 0)))) {
+ hostserv(u, msg);
+ } else if (s_HelpServ && ((stricmp(receiver, s_HelpServ) == 0)
+ || (s_HelpServAlias
+ &&
+ (stricmp(receiver, s_HelpServAlias)
+ == 0)))) {
+ helpserv(u, msg);
+ } else if (s_BotServ && ((stricmp(receiver, s_BotServ) == 0)
+ || (s_BotServAlias
+ && (stricmp(receiver, s_BotServAlias)
+ == 0)))) {
+ botserv(u, msg);
+ } else if (s_BotServ && (bi = findbot(receiver))) {
+ botmsgs(u, bi, msg);
+ }
+
+ /* Add to ignore list if the command took a significant amount of time. */
+ if (allow_ignore) {
+ stoptime = time(NULL);
+ if (stoptime > starttime && *source && !strchr(source, '.'))
+ add_ignore(source, stoptime - starttime);
+ }
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_stats(char *source, int ac, char **av)
+{
+ int i;
+ User *u;
+ NickCore *nc;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ switch (*av[0]) {
+ case 'l':
+ u = finduser(source);
+
+ if (u && is_oper(u)) {
+
+ if (servernum == 1) {
+ anope_cmd_211
+ ("%s Server SendBuf SentBytes SentMsgs RecvBuf "
+ "RecvBytes RecvMsgs ConnTime", source);
+ anope_cmd_211("%s %s %d %d %d %d %d %d %ld", source,
+ RemoteServer, write_buffer_len(),
+ total_written, -1, read_buffer_len(),
+ total_read, -1, time(NULL) - start_time);
+ } else if (servernum == 2) {
+ anope_cmd_211
+ ("%s Server SendBuf SentBytes SentMsgs RecvBuf "
+ "RecvBytes RecvMsgs ConnTime", source);
+ anope_cmd_211("%s %s %d %d %d %d %d %d %ld", source,
+ RemoteServer2, write_buffer_len(),
+ total_written, -1, read_buffer_len(),
+ total_read, -1, time(NULL) - start_time);
+ } else if (servernum == 3) {
+ anope_cmd_211
+ ("%s Server SendBuf SentBytes SentMsgs RecvBuf "
+ "RecvBytes RecvMsgs ConnTime", source);
+ anope_cmd_211("%s %s %d %d %d %d %d %d %ld", source,
+ RemoteServer3, write_buffer_len(),
+ total_written, -1, read_buffer_len(),
+ total_read, -1, time(NULL) - start_time);
+ }
+ }
+
+ anope_cmd_219(source, av[0]);
+ break;
+ case 'o':
+ case 'O':
+/* Check whether the user is an operator */
+ u = finduser(source);
+ if (u && !is_oper(u) && HideStatsO) {
+ anope_cmd_219(source, av[0]);
+ } else {
+ for (i = 0; i < RootNumber; i++)
+ anope_cmd_243("%s O * * %s Root 0", source,
+ ServicesRoots[i]);
+ for (i = 0; i < servadmins.count && (nc = servadmins.list[i]);
+ i++)
+ anope_cmd_243("%s O * * %s Admin 0", source, nc->display);
+ for (i = 0; i < servopers.count && (nc = servopers.list[i]);
+ i++)
+ anope_cmd_243("%s O * * %s Oper 0", source, nc->display);
+
+ anope_cmd_219(source, av[0]);
+ }
+
+ break;
+
+ case 'u':{
+ int uptime = time(NULL) - start_time;
+ anope_cmd_242("%s :Services up %d day%s, %02d:%02d:%02d",
+ source, uptime / 86400,
+ (uptime / 86400 == 1) ? "" : "s",
+ (uptime / 3600) % 24, (uptime / 60) % 60,
+ uptime % 60);
+ anope_cmd_250("%s :Current users: %d (%d ops); maximum %d",
+ source, usercnt, opcnt, maxusercnt);
+ anope_cmd_219(source, av[0]);
+ break;
+ } /* case 'u' */
+
+ default:
+ anope_cmd_219(source, av[0]);
+ break;
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+int m_version(char *source, int ac, char **av)
+{
+ if (source) {
+ anope_cmd_351(source);
+ }
+ return MOD_CONT;
+}
+
+
+/*************************************************************************/
+
+int m_whois(char *source, char *who)
+{
+ BotInfo *bi;
+ NickAlias *na;
+ const char *clientdesc;
+
+ if (source && who) {
+ if (stricmp(who, s_NickServ) == 0)
+ clientdesc = desc_NickServ;
+ else if (stricmp(who, s_ChanServ) == 0)
+ clientdesc = desc_ChanServ;
+ else if (stricmp(who, s_MemoServ) == 0)
+ clientdesc = desc_MemoServ;
+ else if (s_BotServ && stricmp(who, s_BotServ) == 0)
+ clientdesc = desc_BotServ;
+ else if (s_HostServ && stricmp(who, s_HostServ) == 0)
+ clientdesc = desc_HostServ;
+ else if (stricmp(who, s_HelpServ) == 0)
+ clientdesc = desc_HelpServ;
+ else if (stricmp(who, s_OperServ) == 0)
+ clientdesc = desc_OperServ;
+ else if (stricmp(who, s_GlobalNoticer) == 0)
+ clientdesc = desc_GlobalNoticer;
+ else if (s_DevNull && stricmp(who, s_DevNull) == 0)
+ clientdesc = desc_DevNull;
+ else if (s_BotServ && (bi = findbot(who))) {
+ /* Bots are handled separately */
+ anope_cmd_311("%s %s %s %s * :%s", source, bi->nick,
+ bi->user, bi->host, bi->real);
+ anope_cmd_307("%s %s :is a registered nick", source, bi->nick);
+ anope_cmd_312("%s %s %s :%s", source, bi->nick, ServerName,
+ ServerDesc);
+ anope_cmd_317("%s %s %ld %ld :seconds idle, signon time",
+ source, bi->nick, time(NULL) - bi->lastmsg,
+ start_time);
+ anope_cmd_318(source, bi->nick);
+ return MOD_CONT;
+ } else if (!(ircd->svshold && UseSVSHOLD) && (na = findnick(who))
+ && (na->status & NS_KILL_HELD)) {
+ /* We have a nick enforcer client here that we need to respond to.
+ * We can't just say it doesn't exist here, even tho it does for
+ * other servers :) -GD
+ */
+ anope_cmd_311("%s %s %s %s * :Services Enforcer", source,
+ na->nick, NSEnforcerUser, NSEnforcerHost);
+ anope_cmd_312("%s %s %s :%s", source, na->nick, ServerName,
+ ServerDesc);
+ anope_cmd_318(source, na->nick);
+ return MOD_CONT;
+ } else {
+ anope_cmd_401(source, who);
+ return MOD_CONT;
+ }
+ anope_cmd_311("%s %s %s %s * :%s", source, who,
+ ServiceUser, ServiceHost, clientdesc);
+ anope_cmd_312("%s %s %s :%s", source, who, ServerName, ServerDesc);
+ anope_cmd_317("%s %s %ld %ld :seconds idle, signon time", source,
+ who, time(NULL) - start_time, start_time);
+ anope_cmd_318(source, who);
+ }
+ return MOD_CONT;
+}
+
+/* NULL route messages */
+int anope_event_null(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/* *INDENT-OFF* */
+void moduleAddMsgs(void) {
+ Message *m;
+ m = createMessage("STATS", m_stats); addCoreMessage(IRCD,m);
+ m = createMessage("TIME", m_time); addCoreMessage(IRCD,m);
+ m = createMessage("VERSION", m_version); addCoreMessage(IRCD,m);
+}
+
+/*************************************************************************/
+
+Message *find_message(const char *name)
+{
+ Message *m;
+ m = findMessage(IRCD, name);
+ return m;
+}
+
+/*************************************************************************/
diff --git a/src/misc.c b/src/misc.c
new file mode 100644
index 000000000..68c470192
--- /dev/null
+++ b/src/misc.c
@@ -0,0 +1,1663 @@
+
+/* Miscellaneous routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "language.h"
+
+/* Cheaper than isspace() or isblank() */
+#define issp(c) ((c) == 32)
+
+struct arc4_stream {
+ u_int8_t i;
+ u_int8_t j;
+ u_int8_t s[256];
+} rs;
+
+/*************************************************************************/
+
+/**
+ * toupper: Like the ANSI functions, but make sure we return an
+ * int instead of a (signed) char.
+ * @param c Char
+ * @return int
+ */
+int toupper(char c)
+{
+ if (islower(c)) {
+ return (unsigned char) c - ('a' - 'A');
+ } else {
+ return (unsigned char) c;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * tolower: Like the ANSI functions, but make sure we return an
+ * int instead of a (signed) char.
+ * @param c Char
+ * @return int
+ */
+int tolower(char c)
+{
+ if (isupper(c)) {
+ return (unsigned char) c + ('a' - 'A');
+ } else {
+ return (unsigned char) c;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Simple function to convert binary data to hex.
+ * Taken from hybrid-ircd ( http://ircd-hybrid.com/ )
+ */
+void binary_to_hex(unsigned char *bin, char *hex, int length)
+{
+ static const char trans[] = "0123456789ABCDEF";
+ int i;
+
+ for (i = 0; i < length; i++) {
+ hex[i << 1] = trans[bin[i] >> 4];
+ hex[(i << 1) + 1] = trans[bin[i] & 0xf];
+ }
+
+ hex[i << 1] = '\0';
+}
+
+
+/*************************************************************************/
+
+/**
+ * strscpy: Copy at most len-1 characters from a string to a buffer, and
+ * add a null terminator after the last character copied.
+ * @param d Buffer to copy into
+ * @param s Data to copy int
+ * @param len Length of data
+ * @return updated buffer
+ */
+char *strscpy(char *d, const char *s, size_t len)
+{
+ char *d_orig = d;
+
+ if (!len) {
+ return d;
+ }
+ while (--len && (*d++ = *s++));
+ *d = '\0';
+ return d_orig;
+}
+
+/*************************************************************************/
+
+/**
+ * stristr: Search case-insensitively for string s2 within string s1,
+ * returning the first occurrence of s2 or NULL if s2 was not
+ * found.
+ * @param s1 String 1
+ * @param s2 String 2
+ * @return first occurrence of s2
+ */
+char *stristr(char *s1, char *s2)
+{
+ register char *s = s1, *d = s2;
+
+ while (*s1) {
+ if (tolower(*s1) == tolower(*d)) {
+ s1++;
+ d++;
+ if (*d == 0)
+ return s;
+ } else {
+ s = ++s1;
+ d = s2;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/**
+ * strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
+ * replacing if a replacement would cause the string to exceed
+ * `size' bytes (including the null terminator). Return the
+ * string.
+ * @param s String
+ * @param size size of s
+ * @param old character to replace
+ * @param new character to replace with
+ * @return updated s
+ */
+char *strnrepl(char *s, int32 size, const char *old, const char *new)
+{
+ char *ptr = s;
+ int32 left = strlen(s);
+ int32 avail = size - (left + 1);
+ int32 oldlen = strlen(old);
+ int32 newlen = strlen(new);
+ int32 diff = newlen - oldlen;
+
+ while (left >= oldlen) {
+ if (strncmp(ptr, old, oldlen) != 0) {
+ left--;
+ ptr++;
+ continue;
+ }
+ if (diff > avail)
+ break;
+ if (diff != 0)
+ memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
+ strncpy(ptr, new, newlen);
+ ptr += newlen;
+ left -= oldlen;
+ }
+ return s;
+}
+
+/*************************************************************************/
+
+/**
+ * merge_args: Take an argument count and argument vector and merge them
+ * into a single string in which each argument is separated by
+ * a space.
+ * @param int Number of Args
+ * @param argv Array
+ * @return string of the merged array
+ */
+char *merge_args(int argc, char **argv)
+{
+ int i;
+ static char s[4096];
+ char *t;
+
+ t = s;
+ for (i = 0; i < argc; i++)
+ t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
+ (i < argc - 1) ? " " : "");
+ return s;
+}
+
+/*************************************************************************/
+
+/**
+ * do_match_wild: Attempt to match a string to a pattern which might contain
+ * '*' or '?' wildcards. Return 1 if the string matches the
+ * pattern, 0 if not.
+ * @param pattern To be matched
+ * @param str String in which the pattern is to be matched
+ * @param docase Case In/Senstive
+ * @return 1 if the string matches the pattern, 0 if not.
+ */
+static int do_match_wild(const char *pattern, const char *str, int docase)
+{
+ char c;
+ const char *s;
+
+ if (!str || !*str || !pattern || !*pattern) {
+ return 0;
+ }
+
+ /* This WILL eventually terminate: either by *pattern == 0, or by a
+ * trailing '*'. */
+
+ for (;;) {
+ switch (c = *pattern++) {
+ case 0:
+ if (!*str)
+ return 1;
+ return 0;
+ case '?':
+ if (!*str)
+ return 0;
+ str++;
+ break;
+ case '*':
+ if (!*pattern)
+ return 1; /* trailing '*' matches everything else */
+ s = str;
+ while (*s) {
+ if ((docase ? (*s == *pattern)
+ : (tolower(*s) == tolower(*pattern)))
+ && do_match_wild(pattern, s, docase))
+ return 1;
+ s++;
+ }
+ break;
+ default:
+ if (docase ? (*str++ != c) : (tolower(*str++) != tolower(c)))
+ return 0;
+ break;
+ } /* switch */
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * match_wild: Case Senstive wild card search
+ * @param pattern To be matched
+ * @param str String in which the pattern is to be matched
+ * @return 1 if the string matches the pattern, 0 if not.
+ */
+int match_wild(const char *pattern, const char *str)
+{
+ return do_match_wild(pattern, str, 1);
+}
+
+/*************************************************************************/
+
+/**
+ * match_wild: Case Insenstive wild card search
+ * @param pattern To be matched
+ * @param str String in which the pattern is to be matched
+ * @return 1 if the string matches the pattern, 0 if not.
+ */
+int match_wild_nocase(const char *pattern, const char *str)
+{
+ return do_match_wild(pattern, str, 0);
+}
+
+/*************************************************************************/
+
+/**
+ * Process a string containing a number/range list in the form
+ * "n1[-n2][,n3[-n4]]...", calling a caller-specified routine for each
+ * number in the list. If the callback returns -1, stop immediately.
+ * Returns the sum of all nonnegative return values from the callback.
+ * If `count' is non-NULL, it will be set to the total number of times the
+ * callback was called.
+ *
+ * The callback should be of type range_callback_t, which is defined as:
+ * int (*range_callback_t)(User *u, int num, va_list args)
+ * @param numstr
+ * @param count_ret
+ * @param callback Call back function
+ * @param u User Struct
+ * @param ... various args
+ * @return int
+ */
+int process_numlist(const char *numstr, int *count_ret,
+ range_callback_t callback, User * u, ...)
+{
+ int n1, n2, i;
+ int res = 0, retval = 0, count = 0;
+ va_list args, preserve;
+
+ if (!numstr || !*numstr) {
+ return -1;
+ }
+
+ va_start(args, u);
+
+ /*
+ * This algorithm ignores invalid characters, ignores a dash
+ * when it precedes a comma, and ignores everything from the
+ * end of a valid number or range to the next comma or null.
+ */
+ for (;;) {
+ n1 = n2 = strtol(numstr, (char **) &numstr, 10);
+ numstr += strcspn(numstr, "0123456789,-");
+ if (*numstr == '-') {
+ numstr++;
+ numstr += strcspn(numstr, "0123456789,");
+ if (isdigit(*numstr)) {
+ n2 = strtol(numstr, (char **) &numstr, 10);
+ numstr += strcspn(numstr, "0123456789,-");
+ }
+ }
+ for (i = n1; i <= n2 && i >= 0; i++) {
+ VA_COPY(preserve, args);
+ res = callback(u, i, preserve);
+ va_end(preserve);
+ count++;
+ if (res < 0)
+ break;
+ retval += res;
+ if (count >= 32767) {
+ if (count_ret)
+ *count_ret = count;
+ return retval;
+ }
+ }
+ if (res < -1)
+ break;
+ numstr += strcspn(numstr, ",");
+ if (*numstr)
+ numstr++;
+ else
+ break;
+ }
+ if (count_ret)
+ *count_ret = count;
+
+ va_end(args);
+
+ return retval;
+}
+
+/*************************************************************************/
+
+/**
+ * dotime: Return the number of seconds corresponding to the given time
+ * string. If the given string does not represent a valid time,
+ * return -1.
+ *
+ * A time string is either a plain integer (representing a number
+ * of seconds), or an integer followed by one of these characters:
+ * "s" (seconds), "m" (minutes), "h" (hours), or "d" (days).
+ * @param s String to convert
+ * @return int
+ */
+int dotime(const char *s)
+{
+ int amount;
+
+ if (!s || !*s) {
+ return -1;
+ }
+
+ amount = strtol(s, (char **) &s, 10);
+ if (*s) {
+ switch (*s) {
+ case 's':
+ return amount;
+ case 'm':
+ return amount * 60;
+ case 'h':
+ return amount * 3600;
+ case 'd':
+ return amount * 86400;
+ default:
+ return -1;
+ }
+ } else {
+ return amount;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Expresses in a string the period of time represented by a given amount
+ * of seconds (with days/hours/minutes).
+ * @param na Nick Alias
+ * @param buf buffer to store result into
+ * @param bufsize Size of the buffer
+ * @param seconds time in seconds
+ * @return buffer
+ */
+char *duration(NickAlias * na, char *buf, int bufsize, time_t seconds)
+{
+ int days = 0, hours = 0, minutes = 0;
+ int need_comma = 0;
+
+ char buf2[64], *end;
+ char *comma = getstring(na, COMMA_SPACE);
+
+ /* We first calculate everything */
+ days = seconds / 86400;
+ seconds -= (days * 86400);
+ hours = seconds / 3600;
+ seconds -= (hours * 3600);
+ minutes = seconds / 60;
+
+ if (!days && !hours && !minutes) {
+ snprintf(buf, bufsize,
+ getstring(na,
+ (seconds <=
+ 1 ? DURATION_SECOND : DURATION_SECONDS)),
+ seconds);
+ } else {
+ end = buf;
+ if (days) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (days == 1 ? DURATION_DAY : DURATION_DAYS)),
+ days);
+ end += snprintf(end, bufsize - (end - buf), "%s", buf2);
+ need_comma = 1;
+ }
+ if (hours) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (hours ==
+ 1 ? DURATION_HOUR : DURATION_HOURS)),
+ hours);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ if (minutes) {
+ snprintf(buf2, sizeof(buf2),
+ getstring(na,
+ (minutes ==
+ 1 ? DURATION_MINUTE : DURATION_MINUTES)),
+ minutes);
+ end +=
+ snprintf(end, bufsize - (end - buf), "%s%s",
+ (need_comma ? comma : ""), buf2);
+ need_comma = 1;
+ }
+ }
+
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * Generates a human readable string of type "expires in ..."
+ * @param na Nick Alias
+ * @param buf buffer to store result into
+ * @param bufsize Size of the buffer
+ * @param seconds time in seconds
+ * @return buffer
+ */
+char *expire_left(NickAlias * na, char *buf, int len, time_t expires)
+{
+ time_t now = time(NULL);
+
+ if (!expires) {
+ strncpy(buf, getstring(na, NO_EXPIRE), len);
+ } else if (expires <= now) {
+ strncpy(buf, getstring(na, EXPIRES_SOON), len);
+ } else {
+ time_t diff = expires - now + 59;
+
+ if (diff >= 86400) {
+ int days = diff / 86400;
+ snprintf(buf, len,
+ getstring(na, (days == 1) ? EXPIRES_1D : EXPIRES_D),
+ days);
+ } else {
+ if (diff <= 3600) {
+ int minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(na,
+ (minutes ==
+ 1) ? EXPIRES_1M : EXPIRES_M), minutes);
+ } else {
+ int hours = diff / 3600, minutes;
+ diff -= (hours * 3600);
+ minutes = diff / 60;
+ snprintf(buf, len,
+ getstring(na,
+ ((hours == 1
+ && minutes ==
+ 1) ? EXPIRES_1H1M : ((hours == 1
+ && minutes !=
+ 1) ? EXPIRES_1HM
+ : ((hours != 1
+ && minutes ==
+ 1) ?
+ EXPIRES_H1M :
+ EXPIRES_HM)))),
+ hours, minutes);
+ }
+ }
+ }
+
+ return buf;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Validate the host
+ * shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
+ * hostname = shortname *( "." shortname )
+ * ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
+ * @param host = string to check
+ * @param type = format, 1 = ip4addr, 2 = hostname
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int doValidHost(const char *host, int type)
+{
+ int idx = 0;
+ int len = 0;
+ int sec_len = 0;
+ int dots = 1;
+ if (type != 1 && type != 2) {
+ return 0;
+ }
+ if (!host) {
+ return 0;
+ }
+
+ len = strlen(host);
+
+ if (len > HOSTMAX) {
+ return 0;
+ }
+
+ switch (type) {
+ case 1:
+ for (idx = 0; idx < len; idx++) {
+ if (isdigit(host[idx])) {
+ if (sec_len < 3) {
+ sec_len++;
+ } else {
+ return 0;
+ }
+ } else {
+ if (idx == 0) {
+ return 0;
+ } /* cant start with a non-digit */
+ if (host[idx] != '.') {
+ return 0;
+ } /* only . is a valid non-digit */
+ if (sec_len > 3) {
+ return 0;
+ } /* sections cant be more than 3 digits */
+ sec_len = 0;
+ dots++;
+ }
+ }
+ if (dots != 4) {
+ return 0;
+ }
+ break;
+ case 2:
+ dots = 0;
+ for (idx = 0; idx < len; idx++) {
+ if (!isalnum(host[idx])) {
+ if (idx == 0) {
+ return 0;
+ }
+ if ((host[idx] != '.') && (host[idx] != '-')) {
+ return 0;
+ }
+ if (host[idx] == '.') {
+ dots++;
+ }
+ }
+ }
+ if (host[len - 1] == '.') {
+ return 0;
+ }
+ /**
+ * Ultimate3 dosnt like a non-dotted hosts at all, nor does unreal,
+ * so just dont allow them.
+ **/
+ if (dots == 0) {
+ return 0;
+ }
+
+ break;
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Front end to doValidHost
+ * @param host = string to check
+ * @param type = format, 1 = ip4addr, 2 = hostname
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int isValidHost(const char *host, int type)
+{
+ int status = 0;
+ if (type == 3) {
+ if (!(status = doValidHost(host, 1))) {
+ status = doValidHost(host, 2);
+ }
+ } else {
+ status = doValidHost(host, type);
+ }
+ return status;
+}
+
+/*************************************************************************/
+
+/**
+ * Valid character check
+ * @param c Character to check
+ * @return 1 if a host is valid, 0 if it isnt.
+ */
+int isvalidchar(const char c)
+{
+ if (((c >= 'A') && (c <= 'Z')) ||
+ ((c >= 'a') && (c <= 'z')) ||
+ ((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
+ return 1;
+ else
+ return 0;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Get the token
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetToken(const char *str, const char dilim, int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the token only
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetOnlyToken(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if (str[idx] == dilim) {
+ if (counter == token_number) {
+ if (str[idx] == '\r')
+ substring = myStrSubString(str, start_pos, idx - 1);
+ else
+ substring = myStrSubString(str, start_pos, idx);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the Remaining tokens
+ * @param str String to search in
+ * @param dilim Character to search for
+ * @param token_number the token number
+ * @return token
+ */
+char *myStrGetTokenRemainder(const char *str, const char dilim,
+ int token_number)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ char *substring = NULL;
+ if (!str) {
+ return NULL;
+ }
+ len = strlen(str);
+
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ if (counter == token_number) {
+ substring = myStrSubString(str, start_pos, len);
+ counter++;
+ } else {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the string between point A and point B
+ * @param str String to search in
+ * @param start Point A
+ * @param end Point B
+ * @return the string in between
+ */
+char *myStrSubString(const char *src, int start, int end)
+{
+ char *substring = NULL;
+ int len, idx;
+ if (!src) {
+ return NULL;
+ }
+ len = strlen(src);
+ if (((start >= 0) && (end <= len)) && (end > start)) {
+ substring = (char *) malloc(sizeof(char) * ((end - start) + 1));
+ for (idx = 0; idx <= end - start; idx++) {
+ substring[idx] = src[start + idx];
+ }
+ substring[end - start] = '\0';
+ }
+ return substring;
+}
+
+/*************************************************************************/
+
+void protocol_debug(char *source, char *cmd, int argc, char **argv)
+{
+ int i;
+
+ if (protocoldebug) {
+ if (source)
+ alog("debug: Source %s", source);
+ if (cmd)
+ alog("debug: Token %s", cmd);
+ if (argc) {
+ for (i = 0; i < argc; i++) {
+ alog("debug: av[%d] = %s", i, argv[i]);
+ }
+ } else {
+ alog("debug: av[0] = NULL");
+ }
+ }
+ return;
+}
+
+/*************************************************************************/
+
+/**
+ * Clean up the buffer for extra spaces
+ * @param str to clean up
+ * @return void
+ */
+void doCleanBuffer(char *str)
+{
+ char *in, *out;
+ char ch;
+
+ if (!str) {
+ return;
+ }
+
+ in = str;
+ out = str;
+
+ while (issp(ch = *in++));
+ if (ch != '\0')
+ for (;;) {
+ *out++ = ch;
+ ch = *in++;
+ if (ch == '\0')
+ break;
+ if (!issp(ch))
+ continue;
+ while (issp(ch = *in++));
+ if (ch == '\0')
+ break;
+ *out++ = ' ';
+ }
+ *out = ch; /* == '\0' */
+}
+
+/*************************************************************************/
+
+/**
+ * Kill the user to enforce the sqline
+ * @param nick to kill
+ * @param killer whom is doing the killing
+ * @return void
+ */
+void EnforceQlinedNick(char *nick, char *killer)
+{
+ User *u2;
+
+ if ((u2 = finduser(nick))) {
+ alog("Killed Q-lined nick: %s!%s@%s", u2->nick, u2->username,
+ u2->host);
+ kill_user(killer, u2->nick,
+ "This nick is reserved for Services. Please use a non Q-Lined nick.");
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Is the given nick a network service
+ * @param nick to check
+ * @param int Check if botserv bots
+ * @return int
+ */
+int nickIsServices(char *tempnick, int bot)
+{
+ int found = 0;
+ char *s, *nick;
+
+ if (!tempnick) {
+ return found;
+ }
+
+ nick = sstrdup(tempnick);
+
+ s = strchr(nick, '@');
+ if (s) {
+ *s++ = 0;
+ if (stricmp(s, ServerName) != 0) {
+ free(nick);
+ return found;
+ }
+ }
+
+ if (s_NickServ && (stricmp(nick, s_NickServ) == 0))
+ found++;
+ else if (s_ChanServ && (stricmp(nick, s_ChanServ) == 0))
+ found++;
+ else if (s_HostServ && (stricmp(nick, s_HostServ) == 0))
+ found++;
+ else if (s_MemoServ && (stricmp(nick, s_MemoServ) == 0))
+ found++;
+ else if (s_BotServ && (stricmp(nick, s_BotServ) == 0))
+ found++;
+ else if (s_HelpServ && (stricmp(nick, s_HelpServ) == 0))
+ found++;
+ else if (s_OperServ && (stricmp(nick, s_OperServ) == 0))
+ found++;
+ else if (s_DevNull && (stricmp(nick, s_DevNull) == 0))
+ found++;
+ else if (s_GlobalNoticer && (stricmp(nick, s_GlobalNoticer) == 0))
+ found++;
+ else if (s_NickServAlias && (stricmp(nick, s_NickServAlias) == 0))
+ found++;
+ else if (s_ChanServAlias && (stricmp(nick, s_ChanServAlias) == 0))
+ found++;
+ else if (s_MemoServAlias && (stricmp(nick, s_MemoServAlias) == 0))
+ found++;
+ else if (s_BotServAlias && (stricmp(nick, s_BotServAlias) == 0))
+ found++;
+ else if (s_HelpServAlias && (stricmp(nick, s_HelpServAlias) == 0))
+ found++;
+ else if (s_OperServAlias && (stricmp(nick, s_OperServAlias) == 0))
+ found++;
+ else if (s_DevNullAlias && (stricmp(nick, s_DevNullAlias) == 0))
+ found++;
+ else if (s_HostServAlias && (stricmp(nick, s_HostServAlias) == 0))
+ found++;
+ else if (s_GlobalNoticerAlias
+ && (stricmp(nick, s_GlobalNoticerAlias) == 0))
+ found++;
+ else if (s_BotServ && bot) {
+ BotInfo *bi;
+ int i;
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ if (stricmp(nick, bi->nick) == 0) {
+ found++;
+ continue;
+ }
+ }
+ }
+ }
+
+ /* Somehow, something tells me we should free this :) -GD */
+ free(nick);
+
+ return found;
+}
+
+/*************************************************************************/
+
+/**
+ * arc4 init
+ * @return void
+ */
+static void arc4_init(void)
+{
+ int n;
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+/*************************************************************************/
+
+/**
+ * arc4 addrandom
+ * @param data
+ * @param dalen Data Length
+ * @return void
+ */
+static void arc4_addrandom(void *dat, int datlen)
+{
+ int n;
+ u_int8_t si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + ((unsigned char *) dat)[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * random init
+ * @return void
+ */
+void rand_init(void)
+{
+ int n;
+#ifndef _WIN32
+ int fd;
+#endif
+ struct {
+#ifdef USE_MYSQL
+ int sqlrand;
+#endif
+#ifndef _WIN32
+ struct timeval nowt; /* time */
+ char rnd[32]; /* /dev/urandom */
+#else
+ MEMORYSTATUS mstat; /* memory status */
+ struct _timeb nowt; /* time */
+#endif
+ } rdat;
+
+ arc4_init();
+
+ /* Grab "random" MYSQL data */
+#ifdef USE_MYSQL
+ rdat.sqlrand = mysql_rand();
+#endif
+
+ /* Grab OS specific "random" data */
+#ifndef _WIN32
+ /* unix/bsd: time */
+ gettimeofday(&rdat.nowt, NULL);
+ /* unix/bsd: /dev/urandom */
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd) {
+ n = read(fd, &rdat.rnd, sizeof(rdat.rnd));
+ close(fd);
+ }
+#else
+ /* win32: time */
+ _ftime(&rdat.nowt);
+ /* win32: memory status */
+ GlobalMemoryStatus(&rdat.mstat);
+#endif
+
+ arc4_addrandom(&rdat, sizeof(rdat));
+}
+
+/*************************************************************************/
+
+/**
+ * Setup the random numbers
+ * @return void
+ */
+void add_entropy_userkeys(void)
+{
+ arc4_addrandom(&UserKey1, sizeof(UserKey1));
+ arc4_addrandom(&UserKey2, sizeof(UserKey2));
+ arc4_addrandom(&UserKey3, sizeof(UserKey3));
+ /* UserKey3 is also used in mysql_rand() */
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 8 byte deep
+ * @return char
+ */
+unsigned char getrandom8(void)
+{
+ unsigned char si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 16 byte deep
+ * @return char
+ */
+u_int16_t getrandom16(void)
+{
+ u_int16_t val;
+
+ val = getrandom8() << 8;
+ val |= getrandom8();
+ return val;
+}
+
+/*************************************************************************/
+
+/**
+ * Get the random numbers 32 byte deep
+ * @return char
+ */
+u_int32_t getrandom32(void)
+{
+ u_int32_t val;
+
+ val = getrandom8() << 24;
+ val |= getrandom8() << 16;
+ val |= getrandom8() << 8;
+ val |= getrandom8();
+ return val;
+}
+
+/*************************************************************************/
+
+/**
+ * Determine if we need to send the TOKEN
+ * @param token1
+ * @param token2
+ * @return token to send
+ */
+char *send_token(char *token1, char *token2)
+{
+ if (UseTokens && ircd->token && ircdcap->token) {
+ return token2;
+ } else {
+ return token1;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Number of tokens in a string
+ * @param str String
+ * @param dilim Dilimiter
+ * @return number of tokens
+ */
+int myNumToken(const char *str, const char dilim)
+{
+ int len, idx, counter = 0, start_pos = 0;
+ if (!str) {
+ return 0;
+ }
+ len = strlen(str);
+ for (idx = 0; idx <= len; idx++) {
+ if ((str[idx] == dilim) || (idx == len)) {
+ start_pos = idx + 1;
+ counter++;
+ }
+ }
+ return counter;
+}
+
+/*************************************************************************/
+
+/**
+ * Resolve a host to an IP
+ * @param host to convert
+ * @return ip address
+ */
+char *host_resolve(char *host)
+{
+ struct hostent *hentp = NULL;
+ uint32 ip = INADDR_NONE;
+ char ipbuf[16];
+ char *ipreturn;
+ struct in_addr addr;
+
+ ipreturn = NULL;
+
+ hentp = gethostbyname(host);
+
+ if (hentp) {
+ memcpy(&ip, hentp->h_addr, sizeof(hentp->h_length));
+ addr.s_addr = ip;
+ ntoa(addr, ipbuf, sizeof(ipbuf));
+ ipreturn = sstrdup(ipbuf);
+ if (debug) {
+ alog("debug: resolved %s to %s", host, ipbuf);
+ }
+ return ipreturn;
+ } else {
+ return ipreturn;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Change an unsigned string to a signed string, overwriting the original
+ * string.
+ * @param input string
+ * @return output string, same as input string.
+ */
+
+char *str_signed(unsigned char *str)
+{
+ char *nstr;
+
+ nstr = (char *) str;
+ while (*str) {
+ *nstr = (char) *str;
+ str++;
+ nstr++;
+ }
+
+ return nstr;
+}
+
+/**
+ * Strip the mode prefix from the given string.
+ * Useful for using the modes stored in things like ircd->ownerset etc..
+ **/
+
+char *stripModePrefix(const char *str)
+{
+ if (str && ((*str == '+') || (*str == '-'))) {
+ return sstrdup(str + 1);
+ }
+ return NULL;
+}
+
+/* Equivalent to inet_ntoa */
+
+void ntoa(struct in_addr addr, char *ipaddr, int len)
+{
+ unsigned char *bytes = (unsigned char *) &addr.s_addr;
+ snprintf(ipaddr, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2],
+ bytes[3]);
+}
+
+/**
+ * Build a string list from a given source string.
+ * This is usually used for parsing out values from the config file, but could
+ * be used for other things.
+ * NOTE: this function uses strtok(), be aware it will break any buffer you think you have in there ;)
+ **/
+char **buildStringList(char *src, int *number)
+{
+ char *s;
+ int i = 0;
+ char **list = NULL;
+
+ if (src) {
+ s = strtok(src, " ");
+ do {
+ if (s) {
+ i++;
+ list = realloc(list, sizeof(char *) * i);
+ list[i - 1] = sstrdup(s);
+ }
+ } while ((s = strtok(NULL, " ")));
+ }
+ *number = i; /* always zero it, even if we have no setters */
+ return list;
+}
+
+/*
+* strlcat and strlcpy were ripped from openssh 2.5.1p2
+* They had the following Copyright info:
+*
+*
+* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz, dlen;
+
+ while (n-- != 0 && *d != '\0')
+ d++;
+
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return (dlen + strlen(s));
+
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+
+ s++;
+ }
+
+ *d = '\0';
+ return dlen + (s - src); /* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ }
+ while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++);
+ }
+
+ return s - src - 1; /* count does not include NUL */
+}
+#endif
+
+
+
+
+#ifdef _WIN32
+char *GetWindowsVersion(void)
+{
+ OSVERSIONINFOEX osvi;
+ BOOL bOsVersionInfoEx;
+ char buf[BUFSIZE];
+ char *extra;
+ char *cputype;
+ SYSTEM_INFO si;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
+ return sstrdup("");
+ }
+ }
+ GetSystemInfo(&si);
+
+ /* Determine CPU type 32 or 64 */
+ if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) {
+ cputype = sstrdup(" 64-bit");
+ } else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) {
+ cputype = sstrdup(" 32-bit");
+ } else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) {
+ cputype = sstrdup(" Itanium 64-bit");
+ } else {
+ cputype = sstrdup(" ");
+ }
+
+ switch (osvi.dwPlatformId) {
+ /* test for the Windows NT product family. */
+ case VER_PLATFORM_WIN32_NT:
+ /* Windows Vista or Windows Server 2008 */
+ if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
+ if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Enterprise Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+ extra = sstrdup("Home Premium/Basic");
+ } else {
+ extra = sstrdup(" ");
+ }
+ if (osvi.wProductType & VER_NT_WORKSTATION) {
+ snprintf(buf, sizeof(buf), "Microsoft Windows Vista %s%s",
+ cputype, extra);
+ } else {
+ snprintf(buf, sizeof(buf), "Microsoft Windows Server 2008 %s%s",
+ cputype, extra);
+ }
+ free(extra);
+ }
+ /* Windows 2003 or Windows XP Pro 64 */
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Enterprise Edition");
+ } else if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) {
+ extra = sstrdup("Compute Cluster Edition");
+ } else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
+ extra = sstrdup("Web Edition");
+ } else {
+ extra = sstrdup("Standard Edition");
+ }
+ if ( osvi.wProductType & VER_NT_WORKSTATION && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+ snprintf(buf, sizeof(buf), "Windows XP Professional x64 Edition %s",
+ extra);
+ } else {
+ snprintf(buf, sizeof(buf),
+ "Microsoft Windows Server 2003 Family %s%s", cputype, extra);
+ }
+ free(extra);
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+ if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) {
+ extra = sstrdup("Embedded");
+ } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+ extra = sstrdup("Home Edition");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows XP %s", extra);
+ free(extra);
+ }
+ if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+ if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+ extra = sstrdup("Datacenter Server");
+ } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Advanced Server");
+ } else {
+ extra = sstrdup("Server");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 2000 %s", extra);
+ free(extra);
+ }
+ if (osvi.dwMajorVersion <= 4) {
+ if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+ extra = sstrdup("Server 4.0, Enterprise Edition");
+ } else {
+ extra = sstrdup("Server 4.0");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows NT %s", extra);
+ free(extra);
+ }
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+ if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
+ extra = sstrdup("OSR2");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 95 %s", extra);
+ free(extra);
+ }
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+ if (osvi.szCSDVersion[1] == 'A') {
+ extra = sstrdup("SE");
+ } else {
+ extra = sstrdup(" ");
+ }
+ snprintf(buf, sizeof(buf), "Microsoft Windows 98 %s", extra);
+ free(extra);
+ }
+ if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
+ snprintf(buf, sizeof(buf),
+ "Microsoft Windows Millennium Edition");
+ }
+ }
+ free(cputype);
+ return sstrdup(buf);
+}
+
+int SupportedWindowsVersion(void)
+{
+ OSVERSIONINFOEX osvi;
+ BOOL bOsVersionInfoEx;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
+ return 0;
+ }
+ }
+
+ switch (osvi.dwPlatformId) {
+ /* test for the Windows NT product family. */
+ case VER_PLATFORM_WIN32_NT:
+ /* win nt4 */
+ if (osvi.dwMajorVersion <= 4) {
+ return 0;
+ }
+ /* the rest */
+ return 1;
+ /* win95 win98 winME */
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return 0;
+ }
+ return 0;
+}
+
+#endif
+
+
+/*************************************************************************/
+/* This 2 functions were originally found in Bahamut */
+
+/**
+ * Turn a cidr value into a netmask
+ * @param cidr CIDR value
+ * @return Netmask value
+ */
+uint32 cidr_to_netmask(uint16 cidr)
+{
+ if (cidr == 0)
+ return 0;
+
+ return (0xFFFFFFFF - (1 << (32 - cidr)) + 1);
+}
+
+/**
+ * Turn a netmask into a cidr value
+ * @param mask Netmask
+ * @return CIDR value
+ */
+uint16 netmask_to_cidr(uint32 mask)
+{
+ int tmp = 0;
+
+ while (!(mask & (1 << tmp)) && (tmp < 32))
+ tmp++;
+
+ return (32 - tmp);
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is some sort of wildcard
+ * @param str String to check
+ * @return 1 for wildcard, 0 for anything else
+ */
+int str_is_wildcard(const char *str)
+{
+ while (*str) {
+ if ((*str == '*') || (*str == '?'))
+ return 1;
+ str++;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if the given string is a pure wildcard
+ * @param str String to check
+ * @return 1 for pure wildcard, 0 for anything else
+ */
+int str_is_pure_wildcard(const char *str)
+{
+ while (*str) {
+ if (*str != '*')
+ return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is an IP, and return the IP.
+ * @param str String to check
+ * @return The IP, if one found. 0 if none.
+ */
+uint32 str_is_ip(char *str)
+{
+ int i;
+ int octets[4] = { -1, -1, -1, -1 };
+ char *s = str;
+ uint32 ip;
+
+ for (i = 0; i < 4; i++) {
+ octets[i] = strtol(s, &s, 10);
+ /* Bail out if the octet is invalid or wrongly terminated */
+ if ((octets[i] < 0) || (octets[i] > 255)
+ || ((i < 3) && (*s != '.')))
+ return 0;
+ if (i < 3)
+ s++;
+ }
+
+ /* Fill the IP - the dirty way */
+ ip = octets[3];
+ ip += octets[2] * 256;
+ ip += octets[1] * 65536;
+ ip += octets[0] * 16777216;
+
+ return ip;
+}
+
+/*************************************************************************/
+
+/**
+ * Check if the given string is an IP or CIDR mask, and fill the given
+ * ip/cidr params if so.
+ * @param str String to check
+ * @param ip The ipmask to fill when a CIDR is found
+ * @param mask The CIDR mask to fill when a CIDR is found
+ * @param host Displayed host
+ * @return 1 for IP/CIDR, 0 for anything else
+ */
+int str_is_cidr(char *str, uint32 * ip, uint32 * mask, char **host)
+{
+ int i;
+ int octets[4] = { -1, -1, -1, -1 };
+ char *s = str;
+ char buf[512];
+ uint16 cidr;
+
+ for (i = 0; i < 4; i++) {
+ octets[i] = strtol(s, &s, 10);
+ /* Bail out if the octet is invalid or wrongly terminated */
+ if ((octets[i] < 0) || (octets[i] > 255)
+ || ((i < 3) && (*s != '.')))
+ return 0;
+ if (i < 3)
+ s++;
+ }
+
+ /* Fill the IP - the dirty way */
+ *ip = octets[3];
+ *ip += octets[2] * 256;
+ *ip += octets[1] * 65536;
+ *ip += octets[0] * 16777216;
+
+ if (*s == '/') {
+ s++;
+ /* There's a CIDR mask here! */
+ cidr = strtol(s, &s, 10);
+ /* Bail out if the CIDR is invalid or the string isn't done yet */
+ if ((cidr > 32) || (*s))
+ return 0;
+ } else {
+ /* No CIDR mask here - use 32 so the whole ip will be matched */
+ cidr = 32;
+ }
+
+ *mask = cidr_to_netmask(cidr);
+ /* Apply the mask to avoid 255.255.255.255/8 bans */
+ *ip &= *mask;
+
+ /* Refill the octets to fill the host */
+ octets[0] = (*ip & 0xFF000000) / 16777216;
+ octets[1] = (*ip & 0x00FF0000) / 65536;
+ octets[2] = (*ip & 0x0000FF00) / 256;
+ octets[3] = (*ip & 0x000000FF);
+
+ if (cidr == 32)
+ snprintf(buf, 512, "%d.%d.%d.%d", octets[0], octets[1], octets[2],
+ octets[3]);
+ else
+ snprintf(buf, 512, "%d.%d.%d.%d/%d", octets[0], octets[1],
+ octets[2], octets[3], cidr);
+
+ *host = sstrdup(buf);
+
+ return 1;
+}
+
+/* EOF */
diff --git a/src/mod_version.c b/src/mod_version.c
new file mode 100644
index 000000000..e314b8b42
--- /dev/null
+++ b/src/mod_version.c
@@ -0,0 +1,36 @@
+#include "version.h"
+
+#ifndef _WIN32
+#define E extern
+#define I extern
+#else
+#ifndef MODULE_COMPILE
+#define E extern __declspec(dllexport)
+#define I extern __declspec(dllimport)
+#else
+#define E extern __declspec(dllimport)
+#define I extern __declspec(dllexport)
+#endif
+#endif
+
+E int getAnopeBuildVersion();
+E int getAnopeMajorVersion();
+E int getAnopeMinorVersion();
+E int getAnopePatchVersion();
+
+int getAnopeBuildVersion() {
+ return VERSION_BUILD;
+}
+
+int getAnopeMajorVersion() {
+ return VERSION_MAJOR;
+}
+
+int getAnopeMinorVersion() {
+ return VERSION_MINOR;
+}
+
+int getAnopePatchVersion() {
+ return VERSION_PATCH;
+}
+
diff --git a/src/modules.c b/src/modules.c
new file mode 100644
index 000000000..99974d2ef
--- /dev/null
+++ b/src/modules.c
@@ -0,0 +1,2874 @@
+
+/* Modular support
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+#include "modules.h"
+#include "language.h"
+#include "version.h"
+
+#if defined(USE_MODULES) && !defined(_WIN32)
+#include <dlfcn.h>
+/* Define these for systems without them */
+#ifndef RTLD_NOW
+#define RTLD_NOW 0
+#endif
+#ifndef RTLD_LAZY
+#define RTLD_LAZY RTLD_NOW
+#endif
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+#ifndef RTLD_LOCAL
+#define RTLD_LOCAL 0
+#endif
+#endif
+
+#ifdef _WIN32
+const char *ano_moderr(void);
+#endif
+
+/**
+ * Declare all the list's we want to use here
+ **/
+CommandHash *HOSTSERV[MAX_CMD_HASH];
+CommandHash *BOTSERV[MAX_CMD_HASH];
+CommandHash *MEMOSERV[MAX_CMD_HASH];
+CommandHash *NICKSERV[MAX_CMD_HASH];
+CommandHash *CHANSERV[MAX_CMD_HASH];
+CommandHash *HELPSERV[MAX_CMD_HASH];
+CommandHash *OPERSERV[MAX_CMD_HASH];
+MessageHash *IRCD[MAX_CMD_HASH];
+ModuleHash *MODULE_HASH[MAX_CMD_HASH];
+
+Module *mod_current_module;
+char *mod_current_module_name = NULL;
+char *mod_current_buffer = NULL;
+User *mod_current_user;
+ModuleCallBack *moduleCallBackHead = NULL;
+ModuleQueue *mod_operation_queue = NULL;
+
+int displayCommand(Command * c);
+int displayCommandFromHash(CommandHash * cmdTable[], char *name);
+int displayMessageFromHash(char *name);
+int displayMessage(Message * m);
+char *ModuleGetErrStr(int status);
+
+char *ModuleGetErrStr(int status)
+{
+ const char *module_err_str[] = {
+ "Module, Okay - No Error", /* MOD_ERR_OK */
+ "Module Error, Allocating memory", /* MOD_ERR_MEMORY */
+ "Module Error, Not enough parameters", /* MOD_ERR_PARAMS */
+ "Module Error, Already loaded", /* MOD_ERR_EXISTS */
+ "Module Error, File does not exist", /* MOD_ERR_NOEXIST */
+ "Module Error, No User", /* MOD_ERR_NOUSER */
+ "Module Error, Error during load time or module returned MOD_STOP", /* MOD_ERR_NOLOAD */
+ "Module Error, Unable to unload", /* MOD_ERR_NOUNLOAD */
+ "Module Error, Incorrect syntax", /* MOD_ERR_SYNTAX */
+ "Module Error, Unable to delete", /* MOD_ERR_NODELETE */
+ "Module Error, Unknown Error occuried", /* MOD_ERR_UNKOWN */
+ "Module Error, File I/O Error", /* MOD_ERR_FILE_IO */
+ "Module Error, No Service found for request", /* MOD_ERR_NOSERVICE */
+ "Module Error, No module name for request" /* MOD_ERR_NO_MOD_NAME */
+ };
+ return (char *) module_err_str[status];
+}
+
+/**
+ * Automaticaly load modules at startup.
+ * This will load modules at startup before the IRCD link is attempted, this
+ * allows admins to have a module relating to ircd support load
+ */
+void modules_init(void)
+{
+#ifdef USE_MODULES
+ int idx;
+ int ret;
+ Module *m;
+
+ if(nothird) {
+ return;
+ }
+
+ for (idx = 0; idx < ModulesNumber; idx++) {
+ m = findModule(ModulesAutoload[idx]);
+ if (!m) {
+ m = createModule(ModulesAutoload[idx]);
+ mod_current_module = m;
+ mod_current_user = NULL;
+ alog("trying to load [%s]", mod_current_module->name);
+ ret = loadModule(mod_current_module, NULL);
+ alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
+ if (ret != MOD_ERR_OK)
+ destroyModule(m);
+ mod_current_module = NULL;
+ mod_current_user = NULL;
+ }
+ }
+#endif
+}
+
+/**
+ * Load up a list of core modules from the conf.
+ * @param number The number of modules to load
+ * @param list The list of modules to load
+ **/
+void modules_core_init(int number, char **list)
+{
+ int idx;
+ Module *m;
+ int status = 0;
+ for (idx = 0; idx < number; idx++) {
+ m = findModule(list[idx]);
+ if (!m) {
+ m = createModule(list[idx]);
+ mod_current_module = m;
+ mod_current_user = NULL;
+ status = loadModule(mod_current_module, NULL);
+ if (debug || status) {
+ alog("debug: trying to load core module [%s]",
+ mod_current_module->name);
+ alog("debug: status: [%d][%s]", status, ModuleGetErrStr(status));
+ if (status != MOD_ERR_OK)
+ destroyModule(mod_current_module);
+ }
+ mod_current_module = NULL;
+ mod_current_user = NULL;
+ }
+ }
+}
+/**
+ *
+ **/
+int encryption_module_init(void) {
+ int ret = 0;
+ Module *m;
+
+ m = createModule(EncModule);
+ mod_current_module = m;
+ mod_current_user = NULL;
+ alog("Loading Encryption Module: [%s]", mod_current_module->name);
+ ret = loadModule(mod_current_module, NULL);
+ moduleSetType(ENCRYPTION);
+ alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
+ mod_current_module = NULL;
+ if (ret != MOD_ERR_OK) {
+ destroyModule(m);
+ }
+ return ret;
+}
+
+/**
+ * Load the ircd protocol module up
+ **/
+int protocol_module_init(void)
+{
+ int ret = 0;
+ Module *m;
+
+ m = createModule(IRCDModule);
+ mod_current_module = m;
+ mod_current_user = NULL;
+ alog("Loading IRCD Protocol Module: [%s]", mod_current_module->name);
+ ret = loadModule(mod_current_module, NULL);
+ moduleSetType(PROTOCOL);
+ alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
+ mod_current_module = NULL;
+
+ if (ret == MOD_ERR_OK) {
+ /* This is really NOT the correct place to do config checks, but
+ * as we only have the ircd struct filled here, we have to over
+ * here. -GD
+ */
+ if (UseTokens && !(ircd->token)) {
+ alog("Anope does not support TOKENS for this ircd setting; unsetting UseToken");
+ UseTokens = 0;
+ }
+
+ if (UseTS6 && !(ircd->ts6)) {
+ alog("Chosen IRCd does not support TS6, unsetting UseTS6");
+ UseTS6 = 0;
+ }
+
+ /* We can assume the ircd supports TS6 here */
+ if (UseTS6 && !Numeric) {
+ alog("UseTS6 requires the setting of Numeric to be enabled.");
+ ret = -1;
+ }
+ } else {
+ destroyModule(m);
+ }
+
+ return ret;
+}
+
+/**
+ * Automaticaly load modules at startup, delayed.
+ * This function waits until the IRCD link has been made, and then attempts
+ * to load the specified modules.
+ */
+void modules_delayed_init(void)
+{
+#ifdef USE_MODULES
+ int idx;
+ int ret;
+ Module *m;
+
+ if(nothird) {
+ return;
+ }
+
+ for (idx = 0; idx < ModulesDelayedNumber; idx++) {
+ m = findModule(ModulesDelayedAutoload[idx]);
+ if (!m) {
+ m = createModule(ModulesDelayedAutoload[idx]);
+ mod_current_module = m;
+ mod_current_user = NULL;
+ alog("trying to load [%s]", mod_current_module->name);
+ ret = loadModule(mod_current_module, NULL);
+ alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
+ mod_current_module = NULL;
+ mod_current_user = NULL;
+ if (ret != MOD_ERR_OK)
+ destroyModule(m);
+ }
+ }
+#endif
+}
+
+/**
+ * Unload ALL loaded modules, no matter what kind of module it is.
+ * Do NEVER EVER, and i mean NEVER (and if that isn't clear enough
+ * yet, i mean: NEVER AT ALL) call this unless we're shutting down,
+ * or we'll fuck up Anope badly (protocol handling won't work for
+ * example). If anyone calls this function without a justified need
+ * for it, i reserve the right to break their legs in a painful way.
+ * And if that isn't enough discouragement, you'll wake up with your
+ * both legs broken tomorrow ;) -GD
+ */
+void modules_unload_all(boolean fini, boolean unload_proto)
+{
+#ifdef USE_MODULES
+ int idx;
+ ModuleHash *mh, *next;
+ void (*func) (void);
+
+ for (idx = 0; idx < MAX_CMD_HASH; idx++) {
+ mh = MODULE_HASH[idx];
+ while (mh) {
+ next = mh->next;
+ if (unload_proto || (mh->m->type != PROTOCOL)) {
+ mod_current_module = mh->m;
+ if(fini) {
+ func = (void (*)(void))ano_modsym(mh->m->handle, "AnopeFini");
+ if (func) {
+ mod_current_module_name = mh->m->name;
+ func(); /* exec AnopeFini */
+ mod_current_module_name = NULL;
+ }
+
+ if (prepForUnload(mh->m) != MOD_ERR_OK) {
+ mh = next;
+ continue;
+ }
+
+ if ((ano_modclose(mh->m->handle)) != 0)
+ alog(ano_moderr());
+ else
+ delModule(mh->m);
+ } else {
+ delModule(mh->m);
+ }
+ }
+ mh = next;
+ }
+ }
+#endif
+}
+
+/**
+ * Create a new module, setting up the default values as needed.
+ * @param filename the filename of the new module
+ * @return a newly created module struct
+ */
+Module *createModule(char *filename)
+{
+ Module *m;
+ int i = 0;
+ if (!filename) {
+ return NULL;
+ }
+ if ((m = malloc(sizeof(Module))) == NULL) {
+ fatal("Out of memory!");
+ }
+
+ m->name = sstrdup(filename); /* Our Name */
+ m->handle = NULL; /* Handle */
+ m->version = NULL;
+ m->author = NULL;
+ m->nickHelp = NULL;
+ m->chanHelp = NULL;
+ m->memoHelp = NULL;
+ m->botHelp = NULL;
+ m->operHelp = NULL;
+ m->hostHelp = NULL;
+ m->helpHelp = NULL;
+
+ m->type = THIRD;
+ for (i = 0; i < NUM_LANGS; i++) {
+ m->lang[i].argc = 0;
+ }
+ return m; /* return a nice new module */
+}
+
+/**
+ * Destory the module.
+ * free up all memory used by our module struct.
+ * @param m the module to free
+ * @return MOD_ERR_OK on success, anything else on fail
+ */
+int destroyModule(Module * m)
+{
+ int i = 0;
+ if (!m) {
+ return MOD_ERR_PARAMS;
+ }
+
+ mod_current_module = m;
+ for (i = 0; i < NUM_LANGS; i++) {
+ moduleDeleteLanguage(i);
+ }
+
+ if (m->name) {
+ free(m->name);
+ }
+ if (m->filename) {
+ remove(m->filename);
+ free(m->filename);
+ }
+ m->handle = NULL;
+ if (m->author) {
+ free(m->author);
+ }
+ if (m->version) {
+ free(m->version);
+ }
+
+ /* No need to free our cmd/msg list, as they will always be empty by the module is destroyed */
+ free(m);
+ return MOD_ERR_OK;
+}
+
+/**
+ * Add the module to the list of currently loaded modules.
+ * @param m the currently loaded module
+ * @return MOD_ERR_OK on success, anything else on fail
+ */
+int addModule(Module * m)
+{
+ int index = 0;
+ ModuleHash *current = NULL;
+ ModuleHash *newHash = NULL;
+ ModuleHash *lastHash = NULL;
+
+ index = CMD_HASH(m->name);
+
+ for (current = MODULE_HASH[index]; current; current = current->next) {
+ if (stricmp(m->name, current->name) == 0)
+ return MOD_ERR_EXISTS;
+ lastHash = current;
+ }
+
+ if ((newHash = malloc(sizeof(ModuleHash))) == NULL) {
+ fatal("Out of memory");
+ }
+ m->time = time(NULL);
+ newHash->next = NULL;
+ newHash->name = sstrdup(m->name);
+ newHash->m = m;
+
+ if (lastHash == NULL)
+ MODULE_HASH[index] = newHash;
+ else
+ lastHash->next = newHash;
+ return MOD_ERR_OK;
+}
+
+/**
+ * Remove the module from the list of loaded modules.
+ * @param m module to remove
+ * @return MOD_ERR_OK on success anything else on fail
+ */
+int delModule(Module * m)
+{
+ int index = 0;
+ ModuleHash *current = NULL;
+ ModuleHash *lastHash = NULL;
+
+ if (!m) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(m->name);
+
+ for (current = MODULE_HASH[index]; current; current = current->next) {
+ if (stricmp(m->name, current->name) == 0) {
+ if (!lastHash) {
+ MODULE_HASH[index] = current->next;
+ } else {
+ lastHash->next = current->next;
+ }
+ destroyModule(current->m);
+ free(current->name);
+ free(current);
+ return MOD_ERR_OK;
+ }
+ lastHash = current;
+ }
+ return MOD_ERR_NOEXIST;
+}
+
+/**
+ * Search the list of loaded modules for the given name.
+ * @param name the name of the module to find
+ * @return a pointer to the module found, or NULL
+ */
+Module *findModule(char *name)
+{
+ int idx;
+ ModuleHash *current = NULL;
+ if (!name) {
+ return NULL;
+ }
+ idx = CMD_HASH(name);
+
+ for (current = MODULE_HASH[idx]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ return current->m;
+ }
+ }
+ return NULL;
+
+}
+
+/**
+ * Search all loaded modules looking for a protocol module.
+ * @return 1 if one is found.
+ **/
+int protocolModuleLoaded()
+{
+ int idx = 0;
+ ModuleHash *current = NULL;
+
+ for (idx = 0; idx != MAX_CMD_HASH; idx++) {
+ for (current = MODULE_HASH[idx]; current; current = current->next) {
+ if (current->m->type == PROTOCOL) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Search all loaded modules looking for an encryption module.
+ * @ return 1 if one is loaded
+ **/
+int encryptionModuleLoaded()
+{
+ int idx = 0;
+ ModuleHash *current = NULL;
+
+ for (idx = 0; idx != MAX_CMD_HASH; idx++) {
+ for (current = MODULE_HASH[idx]; current; current = current->next) {
+ if (current->m->type == ENCRYPTION) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Copy the module from the modules folder to the runtime folder.
+ * This will prevent module updates while the modules is loaded from
+ * triggering a segfault, as the actaul file in use will be in the
+ * runtime folder.
+ * @param name the name of the module to copy
+ * @param output the destination to copy the module to
+ * @return MOD_ERR_OK on success
+ */
+int moduleCopyFile(char *name, char *output)
+{
+#ifdef USE_MODULES
+ int ch;
+ FILE *source, *target;
+ int srcfp;
+ char input[4096];
+ int len;
+
+ strncpy(input, MODULE_PATH, 4095); /* Get full path with module extension */
+ len = strlen(input);
+ strncat(input, name, 4095 - len);
+ len = strlen(output);
+ strncat(input, MODULE_EXT, 4095 - len);
+
+#ifndef _WIN32
+ if ((srcfp = mkstemp(output)) == -1)
+ return MOD_ERR_FILE_IO;
+#else
+ if (!mktemp(output))
+ return MOD_ERR_FILE_IO;
+#endif
+
+ if (debug)
+ alog("Runtime module location: %s", output);
+
+ /* Linux/UNIX should ignore the b param, why do we still have seperate
+ * calls for it here? -GD
+ */
+#ifndef _WIN32
+ if ((source = fopen(input, "r")) == NULL) {
+#else
+ if ((source = fopen(input, "rb")) == NULL) {
+#endif
+ return MOD_ERR_NOEXIST;
+ }
+#ifndef _WIN32
+ if ((target = fdopen(srcfp, "w")) == NULL) {
+#else
+ if ((target = fopen(output, "wb")) == NULL) {
+#endif
+ return MOD_ERR_FILE_IO;
+ }
+ while ((ch = fgetc(source)) != EOF) {
+ fputc(ch, target);
+ }
+ fclose(source);
+ if (fclose(target) != 0) {
+ return MOD_ERR_FILE_IO;
+ }
+#endif
+ return MOD_ERR_OK;
+}
+
+/**
+ * Loads a given module.
+ * @param m the module to load
+ * @param u the user who loaded it, NULL for auto-load
+ * @return MOD_ERR_OK on success, anything else on fail
+ */
+int loadModule(Module * m, User * u)
+{
+#ifdef USE_MODULES
+ char buf[4096];
+ int len;
+ const char *err;
+ int (*func) (int, char **);
+ int (*version)();
+ int ret = 0;
+ char *argv[1];
+ int argc = 0;
+
+ Module *m2;
+ if (!m || !m->name) {
+ return MOD_ERR_PARAMS;
+ }
+ if (m->handle) {
+ return MOD_ERR_EXISTS;
+ }
+ if ((m2 = findModule(m->name)) != NULL) {
+ return MOD_ERR_EXISTS;
+ }
+
+ /* Generate the filename for the temporary copy of the module */
+ strncpy(buf, MODULE_PATH, 4095); /* Get full path with module extension */
+ len = strlen(buf);
+#ifndef _WIN32
+ strncat(buf, "runtime/", 4095 - len);
+#else
+ strncat(buf, "runtime\\", 4095 - len);
+#endif
+ len = strlen(buf);
+ strncat(buf, m->name, 4095 - len);
+ len = strlen(buf);
+ strncat(buf, MODULE_EXT, 4095 - len);
+ len = strlen(buf);
+ strncat(buf, ".", 4095 - len);
+ len = strlen(buf);
+ strncat(buf, "XXXXXX", 4095 - len);
+ buf[4095] = '\0';
+ /* Don't skip return value checking! -GD */
+ if ((ret = moduleCopyFile(m->name, buf)) != MOD_ERR_OK) {
+ m->filename = sstrdup(buf);
+ return ret;
+ }
+
+ m->filename = sstrdup(buf);
+ ano_modclearerr();
+ m->handle = ano_modopen(m->filename);
+ if ( m->handle == NULL && (err = ano_moderr()) != NULL) {
+ alog(err);
+ return MOD_ERR_NOLOAD;
+ }
+ ano_modclearerr();
+ func = (int (*)(int, char **))ano_modsym(m->handle, "AnopeInit");
+ if ( func == NULL && (err = ano_moderr()) != NULL) {
+ ano_modclose(m->handle); /* If no AnopeInit - it isnt an Anope Module, close it */
+ return MOD_ERR_NOLOAD;
+ }
+ if (func) {
+ version = (int (*)())ano_modsym(m->handle,"getAnopeBuildVersion");
+ if (version) {
+ if (version() >= VERSION_BUILD ) {
+ if(debug) {
+ alog("Module %s compiled against current or newer anope revision %d, this is %d",m->name,version(),VERSION_BUILD);
+ }
+ } else {
+ alog("Module %s is compiled against an old version of anope (%d) current is %d", m->name, version(), VERSION_BUILD);
+ alog("Rebuild module %s against the current version to resolve this error", m->name);
+ ano_modclose(m->handle);
+ ano_modclearerr();
+ return MOD_ERR_NOLOAD;
+ }
+ } else {
+ ano_modclose(m->handle);
+ ano_modclearerr();
+ alog("Module %s is compiled against an older version of anope (unknown)", m->name);
+ alog("Rebuild module %s against the current version to resolve this error", m->name);
+ return MOD_ERR_NOLOAD;
+ }
+ /* TODO */
+ mod_current_module_name = m->name;
+ /* argv[0] is the user if there was one, or NULL if not */
+ if (u) {
+ argv[0] = sstrdup(u->nick);
+ } else {
+ argv[0] = NULL;
+ }
+ argc++;
+
+ ret = func(argc, argv); /* exec AnopeInit */
+ if (u) {
+ free(argv[0]);
+ }
+ if (m->type == PROTOCOL && protocolModuleLoaded()) {
+ alog("You cannot load two protocol modules");
+ ret = MOD_STOP;
+ } else if (m->type == ENCRYPTION && encryptionModuleLoaded()) {
+ alog("You cannot load two encryption modules");
+ ret = MOD_STOP;
+ }
+ if (ret == MOD_STOP) {
+ alog("%s requested unload...", m->name);
+ unloadModule(m, NULL);
+ mod_current_module_name = NULL;
+ return MOD_ERR_NOLOAD;
+ }
+
+ mod_current_module_name = NULL;
+ }
+
+ if (u) {
+ anope_cmd_global(s_OperServ, "%s loaded module %s", u->nick,
+ m->name);
+ notice_lang(s_OperServ, u, OPER_MODULE_LOADED, m->name);
+ }
+ addModule(m);
+ return MOD_ERR_OK;
+
+#else
+ return MOD_ERR_NOLOAD;
+#endif
+}
+
+/**
+ * Unload the given module.
+ * @param m the module to unload
+ * @param u the user who unloaded it
+ * @return MOD_ERR_OK on success, anything else on fail
+ */
+int unloadModule(Module * m, User * u)
+{
+#ifdef USE_MODULES
+ void (*func) (void);
+
+ if (!m || !m->handle) {
+ if (u) {
+ notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
+ }
+ return MOD_ERR_PARAMS;
+ }
+
+ if (m->type == PROTOCOL) {
+ if (u) {
+ notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD);
+ }
+ return MOD_ERR_NOUNLOAD;
+ } else if(m->type == ENCRYPTION) {
+ if (u) {
+ notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD);
+ }
+ return MOD_ERR_NOUNLOAD;
+ }
+
+ func = (void (*)(void))ano_modsym(m->handle, "AnopeFini");
+ if (func) {
+ mod_current_module_name = m->name;
+ func(); /* exec AnopeFini */
+ mod_current_module_name = NULL;
+ }
+
+ if (prepForUnload(m) != MOD_ERR_OK) {
+ return MOD_ERR_UNKNOWN;
+ }
+
+ if ((ano_modclose(m->handle)) != 0) {
+ alog(ano_moderr());
+ if (u) {
+ notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
+ }
+ return MOD_ERR_NOUNLOAD;
+ } else {
+ if (u) {
+ anope_cmd_global(s_OperServ, "%s unloaded module %s", u->nick,
+ m->name);
+ notice_lang(s_OperServ, u, OPER_MODULE_UNLOADED, m->name);
+ }
+ delModule(m);
+ return MOD_ERR_OK;
+ }
+#else
+ return MOD_ERR_NOUNLOAD;
+#endif
+}
+
+/**
+ * Module setType()
+ * Lets the module set a type, CORE,PROTOCOL,3RD etc..
+ **/
+void moduleSetType(MODType type)
+{
+ if ((mod_current_module_name) && (!mod_current_module)) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+ mod_current_module->type = type;
+}
+
+/**
+ * Prepare a module to be unloaded.
+ * Remove all commands and messages this module is providing, and delete
+ * any callbacks which are still pending.
+ * @param m the module to prepare for unload
+ * @return MOD_ERR_OK on success
+ */
+int prepForUnload(Module * m)
+{
+ int idx;
+ CommandHash *current = NULL;
+ MessageHash *mcurrent = NULL;
+ EvtMessageHash *ecurrent = NULL;
+ EvtHookHash *ehcurrent = NULL;
+
+ Command *c;
+ Message *msg;
+ EvtMessage *eMsg;
+ EvtHook *eHook;
+ int status = 0;
+
+ if (!m) {
+ return MOD_ERR_PARAMS;
+ }
+
+ /* Kill any active callbacks this module has */
+ moduleCallBackPrepForUnload(m->name);
+
+ /* Remove any stored data this module has */
+ moduleDelAllDataMod(m);
+
+ /**
+ * ok, im going to walk every hash looking for commands we own, now, not exactly elegant or efficiant :)
+ **/
+ for (idx = 0; idx < MAX_CMD_HASH; idx++) {
+ for (current = HS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(HOSTSERV, c->name);
+ }
+ }
+ }
+
+ for (current = BS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(BOTSERV, c->name);
+ }
+ }
+ }
+
+ for (current = MS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(MEMOSERV, c->name);
+ }
+ }
+ }
+
+ for (current = NS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(NICKSERV, c->name);
+ }
+ }
+ }
+
+ for (current = CS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(CHANSERV, c->name);
+ }
+ }
+ }
+
+ for (current = HE_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(HELPSERV, c->name);
+ }
+ }
+ }
+
+ for (current = OS_cmdTable[idx]; current; current = current->next) {
+ for (c = current->c; c; c = c->next) {
+ if ((c->mod_name) && (stricmp(c->mod_name, m->name) == 0)) {
+ moduleDelCommand(OPERSERV, c->name);
+ }
+ }
+ }
+
+ for (mcurrent = IRCD[idx]; mcurrent; mcurrent = mcurrent->next) {
+ for (msg = mcurrent->m; msg; msg = msg->next) {
+ if ((msg->mod_name)
+ && (stricmp(msg->mod_name, m->name) == 0)) {
+ moduleDelMessage(msg->name);
+ }
+ }
+ }
+
+ for (ecurrent = EVENT[idx]; ecurrent; ecurrent = ecurrent->next) {
+ for (eMsg = ecurrent->evm; eMsg; eMsg = eMsg->next) {
+ if ((eMsg->mod_name)
+ && (stricmp(eMsg->mod_name, m->name) == 0)) {
+ status = delEventHandler(EVENT, eMsg, m->name);
+ }
+ }
+ }
+ for (ehcurrent = EVENTHOOKS[idx]; ehcurrent;
+ ehcurrent = ehcurrent->next) {
+ for (eHook = ehcurrent->evh; eHook; eHook = eHook->next) {
+ if ((eHook->mod_name)
+ && (stricmp(eHook->mod_name, m->name) == 0)) {
+ status = delEventHook(EVENTHOOKS, eHook, m->name);
+ }
+ }
+ }
+
+ }
+ return MOD_ERR_OK;
+}
+
+/*******************************************************************************
+ * Command Functions
+ *******************************************************************************/
+/**
+ * Create a Command struct ready for use in anope.
+ * @param name the name of the command
+ * @param func pointer to the function to execute when command is given
+ * @param has_priv pointer to function to check user priv's
+ * @param help_all help file index for all users
+ * @param help_reg help file index for all regustered users
+ * @param help_oper help file index for all opers
+ * @param help_admin help file index for all admins
+ * @param help_root help file indenx for all services roots
+ * @return a "ready to use" Command struct will be returned
+ */
+Command *createCommand(const char *name, int (*func) (User * u),
+ int (*has_priv) (User * u), int help_all,
+ int help_reg, int help_oper, int help_admin,
+ int help_root)
+{
+ Command *c;
+ if (!name || !*name) {
+ return NULL;
+ }
+
+ if ((c = malloc(sizeof(Command))) == NULL) {
+ fatal("Out of memory!");
+ }
+ c->name = sstrdup(name);
+ c->routine = func;
+ c->has_priv = has_priv;
+ c->helpmsg_all = help_all;
+ c->helpmsg_reg = help_reg;
+ c->helpmsg_oper = help_oper;
+ c->helpmsg_admin = help_admin;
+ c->helpmsg_root = help_root;
+ c->help_param1 = NULL;
+ c->help_param2 = NULL;
+ c->help_param3 = NULL;
+ c->help_param4 = NULL;
+ c->next = NULL;
+ c->mod_name = NULL;
+ c->service = NULL;
+ c->all_help = NULL;
+ c->regular_help = NULL;
+ c->oper_help = NULL;
+ c->admin_help = NULL;
+ c->root_help = NULL;
+ return c;
+}
+
+/**
+ * Destroy a command struct freeing any memory.
+ * @param c Command to destroy
+ * @return MOD_ERR_OK on success, anything else on fail
+ */
+int destroyCommand(Command * c)
+{
+ if (!c) {
+ return MOD_ERR_PARAMS;
+ }
+ if (c->core == 1) {
+ return MOD_ERR_UNKNOWN;
+ }
+ if (c->name) {
+ free(c->name);
+ }
+ c->routine = NULL;
+ c->has_priv = NULL;
+ c->helpmsg_all = -1;
+ c->helpmsg_reg = -1;
+ c->helpmsg_oper = -1;
+ c->helpmsg_admin = -1;
+ c->helpmsg_root = -1;
+ if (c->help_param1) {
+ free(c->help_param1);
+ }
+ if (c->help_param2) {
+ free(c->help_param2);
+ }
+ if (c->help_param3) {
+ free(c->help_param3);
+ }
+ if (c->help_param4) {
+ free(c->help_param4);
+ }
+ if (c->mod_name) {
+ free(c->mod_name);
+ }
+ if (c->service) {
+ free(c->service);
+ }
+ c->next = NULL;
+ free(c);
+ return MOD_ERR_OK;
+}
+
+/**
+ * Add a CORE command ot the given command hash
+ * @param cmdTable the command table to add the command to
+ * @param c the command to add
+ * @return MOD_ERR_OK on success
+ */
+int addCoreCommand(CommandHash * cmdTable[], Command * c)
+{
+ if (!cmdTable || !c) {
+ return MOD_ERR_PARAMS;
+ }
+ c->core = 1;
+ c->next = NULL;
+ return addCommand(cmdTable, c, 0);
+}
+
+/**
+ * Add a module provided command to the given service.
+ * e.g. moduleAddCommand(NICKSERV,c,MOD_HEAD);
+ * @param cmdTable the services to add the command to
+ * @param c the command to add
+ * @param pos the position to add to, MOD_HEAD, MOD_TAIL, MOD_UNIQUE
+ * @see createCommand
+ * @return MOD_ERR_OK on successfully adding the command
+ */
+int moduleAddCommand(CommandHash * cmdTable[], Command * c, int pos)
+{
+ int status;
+
+ if (!cmdTable || !c) {
+ return MOD_ERR_PARAMS;
+ }
+ /* ok, this appears to be a module adding a command 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 */
+ c->core = 0;
+ if (!c->mod_name) {
+ c->mod_name = sstrdup(mod_current_module->name);
+ }
+
+
+ if (cmdTable == HOSTSERV) {
+ if (s_HostServ) {
+ c->service = sstrdup(s_HostServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == BOTSERV) {
+ if (s_BotServ) {
+ c->service = sstrdup(s_BotServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == MEMOSERV) {
+ if (s_MemoServ) {
+ c->service = sstrdup(s_MemoServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == CHANSERV) {
+ if (s_ChanServ) {
+ c->service = sstrdup(s_ChanServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == NICKSERV) {
+ if (s_NickServ) {
+ c->service = sstrdup(s_NickServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == HELPSERV) {
+ if (s_HelpServ) {
+ c->service = sstrdup(s_HelpServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else if (cmdTable == OPERSERV) {
+ if (s_OperServ) {
+ c->service = sstrdup(s_OperServ);
+ } else {
+ return MOD_ERR_NOSERVICE;
+ }
+ } else
+ c->service = sstrdup("Unknown");
+
+ if (debug >= 2)
+ displayCommandFromHash(cmdTable, c->name);
+ status = addCommand(cmdTable, c, pos);
+ if (debug >= 2)
+ displayCommandFromHash(cmdTable, c->name);
+ if (status != MOD_ERR_OK) {
+ alog("ERROR! [%d]", status);
+ }
+ return status;
+}
+
+/**
+ * Delete a command from the service given.
+ * @param cmdTable the cmdTable for the services to remove the command from
+ * @param name the name of the command to delete from the service
+ * @return returns MOD_ERR_OK on success
+ */
+int moduleDelCommand(CommandHash * cmdTable[], char *name)
+{
+ Command *c = NULL;
+ Command *cmd = NULL;
+ int status = 0;
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ }
+
+ c = findCommand(cmdTable, name);
+ if (!c) {
+ return MOD_ERR_NOEXIST;
+ }
+
+
+ for (cmd = c; cmd; cmd = cmd->next) {
+ if (cmd->mod_name
+ && stricmp(cmd->mod_name, mod_current_module->name) == 0) {
+ if (debug >= 2) {
+ displayCommandFromHash(cmdTable, name);
+ }
+ status = delCommand(cmdTable, cmd, mod_current_module->name);
+ if (debug >= 2) {
+ displayCommandFromHash(cmdTable, name);
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * Output the command stack into the log files.
+ * This will print the call-stack for a given command into the log files, very useful for debugging.
+ * @param cmdTable the command table to read from
+ * @param name the name of the command to print
+ * @return 0 is returned, it has no relevence yet :)
+ */
+int displayCommandFromHash(CommandHash * cmdTable[], char *name)
+{
+ CommandHash *current = NULL;
+ int index = 0;
+ index = CMD_HASH(name);
+ if (debug > 1) {
+ alog("debug: trying to display command %s", name);
+ }
+ for (current = cmdTable[index]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ displayCommand(current->c);
+ }
+ }
+ if (debug > 1) {
+ alog("debug: done displaying command %s", name);
+ }
+ return 0;
+}
+
+/**
+ * Output the command stack into the log files.
+ * This will print the call-stack for a given command into the log files, very useful for debugging.
+ * @param c the command struct to print
+ * @return 0 is returned, it has no relevence yet :)
+ */
+
+int displayCommand(Command * c)
+{
+ Command *cmd = NULL;
+ int i = 0;
+ alog("Displaying command list for %s", c->name);
+ for (cmd = c; cmd; cmd = cmd->next) {
+ alog("%d: 0x%p", ++i, (void *) cmd);
+ }
+ 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 displayMessageFromHash(char *name)
+{
+ MessageHash *current = NULL;
+ int index = 0;
+ index = CMD_HASH(name);
+ if (debug > 1) {
+ alog("debug: trying to display message %s", name);
+ }
+ for (current = IRCD[index]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ displayMessage(current->m);
+ }
+ }
+ if (debug > 1) {
+ alog("debug: done displaying message %s", name);
+ }
+ 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 displayMessage(Message * m)
+{
+ Message *msg = NULL;
+ int i = 0;
+ alog("Displaying message list for %s", m->name);
+ for (msg = m; msg; msg = msg->next) {
+ alog("%d: 0x%p", ++i, (void *) msg);
+ }
+ alog("end");
+ return 0;
+}
+
+
+/**
+ * Add a command to a command table.
+ * only add if were unique, pos = 0;
+ * if we want it at the "head" of that command, pos = 1
+ * at the tail, pos = 2
+ * @param cmdTable the table to add the command to
+ * @param c the command to add
+ * @param pos the position in the cmd call stack to add the command
+ * @return MOD_ERR_OK will be returned on success.
+ */
+int addCommand(CommandHash * cmdTable[], Command * c, int pos)
+{
+ /* We can assume both param's have been checked by this point.. */
+ int index = 0;
+ CommandHash *current = NULL;
+ CommandHash *newHash = NULL;
+ CommandHash *lastHash = NULL;
+ Command *tail = NULL;
+
+ if (!cmdTable || !c || (pos < 0 || pos > 2)) {
+ return MOD_ERR_PARAMS;
+ }
+
+ if (mod_current_module_name && !c->mod_name)
+ return MOD_ERR_NO_MOD_NAME;
+
+ index = CMD_HASH(c->name);
+
+ for (current = cmdTable[index]; current; current = current->next) {
+ if ((c->service) && (current->c) && (current->c->service)
+ && (!strcmp(c->service, current->c->service) == 0)) {
+ continue;
+ }
+ if ((stricmp(c->name, current->name) == 0)) { /* the cmd exist's we are a addHead */
+ if (pos == 1) {
+ c->next = current->c;
+ current->c = c;
+ if (debug)
+ alog("debug: existing cmd: (0x%p), new cmd (0x%p)",
+ (void *) c->next, (void *) c);
+ return MOD_ERR_OK;
+ } else if (pos == 2) {
+
+ tail = current->c;
+ while (tail->next)
+ tail = tail->next;
+ if (debug)
+ alog("debug: existing cmd: (0x%p), new cmd (0x%p)",
+ (void *) tail, (void *) c);
+ tail->next = c;
+ c->next = NULL;
+
+ return MOD_ERR_OK;
+ } else
+ return MOD_ERR_EXISTS;
+ }
+ lastHash = current;
+ }
+
+ if ((newHash = malloc(sizeof(CommandHash))) == NULL) {
+ fatal("Out of memory");
+ }
+ newHash->next = NULL;
+ newHash->name = sstrdup(c->name);
+ newHash->c = c;
+
+ if (lastHash == NULL)
+ cmdTable[index] = newHash;
+ else
+ lastHash->next = newHash;
+
+ return MOD_ERR_OK;
+}
+
+/**
+ * Remove a command from the command hash.
+ * @param cmdTable the command table to remove the command from
+ * @param c the command to remove
+ * @param mod_name the name of the module who owns the command
+ * @return MOD_ERR_OK will be returned on success
+ */
+int delCommand(CommandHash * cmdTable[], Command * c, char *mod_name)
+{
+ int index = 0;
+ CommandHash *current = NULL;
+ CommandHash *lastHash = NULL;
+ Command *tail = NULL, *last = NULL;
+
+ if (!c || !cmdTable) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(c->name);
+ for (current = cmdTable[index]; current; current = current->next) {
+ if (stricmp(c->name, current->name) == 0) {
+ if (!lastHash) {
+ tail = current->c;
+ 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->c = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ cmdTable[index] = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ } else {
+ tail = current->c;
+ 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->c = 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;
+}
+
+/**
+ * Search the command table gieven for a command.
+ * @param cmdTable the name of the command table to search
+ * @param name the name of the command to look for
+ * @return returns a pointer to the found command struct, or NULL
+ */
+Command *findCommand(CommandHash * cmdTable[], const char *name)
+{
+ int idx;
+ CommandHash *current = NULL;
+ if (!cmdTable || !name) {
+ return NULL;
+ }
+
+ idx = CMD_HASH(name);
+
+ for (current = cmdTable[idx]; current; current = current->next) {
+ if (stricmp(name, current->name) == 0) {
+ return current->c;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ * 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
+ **/
+Message *createMessage(const char *name,
+ int (*func) (char *source, int ac, char **av))
+{
+ Message *m = NULL;
+ if (!name || !func) {
+ return NULL;
+ }
+ if ((m = malloc(sizeof(Message))) == NULL) {
+ fatal("Out of memory!");
+ }
+ m->name = sstrdup(name);
+ m->func = func;
+ m->mod_name = NULL;
+ m->next = NULL;
+ return m;
+}
+
+/**
+ * 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
+ **/
+Message *findMessage(MessageHash * msgTable[], const char *name)
+{
+ int idx;
+ MessageHash *current = NULL;
+ if (!msgTable || !name) {
+ return NULL;
+ }
+ idx = CMD_HASH(name);
+
+ for (current = msgTable[idx]; current; current = current->next) {
+ if (UseTokens) {
+ if (ircd->tokencaseless) {
+ if (stricmp(name, current->name) == 0) {
+ return current->m;
+ }
+ } else {
+ if (strcmp(name, current->name) == 0) {
+ return current->m;
+ }
+ }
+ } else {
+ if (stricmp(name, current->name) == 0) {
+ return current->m;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * 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
+ * @param pos the position we want to add the message to, E.G. MOD_HEAD, MOD_TAIL, MOD_UNIQUE
+ * @return MOD_ERR_OK on a successful add.
+ **/
+
+int addMessage(MessageHash * msgTable[], Message * m, int pos)
+{
+ /* We can assume both param's have been checked by this point.. */
+ int index = 0;
+ MessageHash *current = NULL;
+ MessageHash *newHash = NULL;
+ MessageHash *lastHash = NULL;
+ Message *tail = NULL;
+ int match = 0;
+
+ if (!msgTable || !m || (pos < 0 || pos > 2)) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(m->name);
+
+ for (current = msgTable[index]; current; current = current->next) {
+ if ((UseTokens) && (!ircd->tokencaseless)) {
+ match = strcmp(m->name, current->name);
+ } else {
+ match = stricmp(m->name, current->name);
+ }
+ if (match == 0) { /* the msg exist's we are a addHead */
+ if (pos == 1) {
+ m->next = current->m;
+ current->m = m;
+ if (debug)
+ alog("debug: existing msg: (0x%p), new msg (0x%p)",
+ (void *) m->next, (void *) m);
+ return MOD_ERR_OK;
+ } else if (pos == 2) {
+ tail = current->m;
+ while (tail->next)
+ tail = tail->next;
+ if (debug)
+ alog("debug: existing msg: (0x%p), new msg (0x%p)",
+ (void *) tail, (void *) m);
+ tail->next = m;
+ m->next = NULL;
+ return MOD_ERR_OK;
+ } else
+ return MOD_ERR_EXISTS;
+ }
+ lastHash = current;
+ }
+
+ if ((newHash = malloc(sizeof(MessageHash))) == NULL) {
+ fatal("Out of memory");
+ }
+ newHash->next = NULL;
+ newHash->name = sstrdup(m->name);
+ newHash->m = m;
+
+ if (lastHash == NULL)
+ msgTable[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 addCoreMessage(MessageHash * msgTable[], Message * m)
+{
+ if (!msgTable || !m) {
+ return MOD_ERR_PARAMS;
+ }
+ m->core = 1;
+ return addMessage(msgTable, m, 0);
+}
+
+/**
+ * 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 moduleAddMessage(Message * m, int pos)
+{
+ int status;
+
+ if (!m) {
+ 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 */
+ m->core = 0;
+ if (!m->mod_name) {
+ m->mod_name = sstrdup(mod_current_module->name);
+ }
+
+ status = addMessage(IRCD, m, pos);
+ if (debug) {
+ displayMessageFromHash(m->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 moduleDelMessage(char *name)
+{
+ Message *m;
+ int status;
+
+ if (!mod_current_module) {
+ return MOD_ERR_UNKNOWN;
+ }
+ m = findMessage(IRCD, name);
+ if (!m) {
+ return MOD_ERR_NOEXIST;
+ }
+
+ status = delMessage(IRCD, m, mod_current_module->name);
+ if (debug) {
+ displayMessageFromHash(m->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 delMessage(MessageHash * msgTable[], Message * m, char *mod_name)
+{
+ int index = 0;
+ MessageHash *current = NULL;
+ MessageHash *lastHash = NULL;
+ Message *tail = NULL, *last = NULL;
+
+ if (!m || !msgTable) {
+ return MOD_ERR_PARAMS;
+ }
+
+ index = CMD_HASH(m->name);
+
+ for (current = msgTable[index]; current; current = current->next) {
+ if (stricmp(m->name, current->name) == 0) {
+ if (!lastHash) {
+ tail = current->m;
+ 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->m = tail->next;
+ }
+ return MOD_ERR_OK;
+ }
+ last = tail;
+ tail = tail->next;
+ }
+ } else {
+ msgTable[index] = current->next;
+ free(current->name);
+ return MOD_ERR_OK;
+ }
+ } else {
+ tail = current->m;
+ 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->m = 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 destroyMessage(Message * m)
+{
+ if (!m) {
+ return MOD_ERR_PARAMS;
+ }
+ if (m->name) {
+ free(m->name);
+ }
+ m->func = NULL;
+ if (m->mod_name) {
+ free(m->mod_name);
+ }
+ m->next = NULL;
+ return MOD_ERR_OK;
+}
+
+/**
+ * Add the modules version info.
+ * @param version the version of the current module
+ **/
+void moduleAddVersion(const char *version)
+{
+ if (mod_current_module && version) {
+ mod_current_module->version = sstrdup(version);
+ }
+}
+
+/**
+ * Add the modules author info
+ * @param author the author of the module
+ **/
+void moduleAddAuthor(const char *author)
+{
+ if (mod_current_module && author) {
+ mod_current_module->author = sstrdup(author);
+ }
+}
+
+/*******************************************************************************
+ * Module Callback Functions
+ *******************************************************************************/
+ /**
+ * Adds a timed callback for the current module.
+ * This allows modules to request that anope executes one of there functions at a time in the future, without an event to trigger it
+ * @param name the name of the callback, this is used for refrence mostly, but is needed it you want to delete this particular callback later on
+ * @param when when should the function be executed, this is a time in the future, seconds since 00:00:00 1970-01-01 UTC
+ * @param func the function to be executed when the callback is ran, its format MUST be int func(int argc, char **argv);
+ * @param argc the argument count for the argv paramter
+ * @param atgv a argument list to be passed to the called function.
+ * @return MOD_ERR_OK on success, anything else on fail.
+ * @see moduleDelCallBack
+ **/
+int moduleAddCallback(char *name, time_t when,
+ int (*func) (int argc, char *argv[]), int argc,
+ char **argv)
+{
+ ModuleCallBack *new, *tmp, *prev;
+ int i;
+ new = malloc(sizeof(ModuleCallBack));
+ if (!new)
+ return MOD_ERR_MEMORY;
+
+ if (name)
+ new->name = sstrdup(name);
+ else
+ new->name = NULL;
+ new->when = when;
+ if (mod_current_module_name) {
+ new->owner_name = sstrdup(mod_current_module_name);
+ } else {
+ new->owner_name = NULL;
+ }
+ new->func = func;
+ new->argc = argc;
+ new->argv = malloc(sizeof(char *) * argc);
+ for (i = 0; i < argc; i++) {
+ new->argv[i] = sstrdup(argv[i]);
+ }
+ new->next = NULL;
+
+ if (moduleCallBackHead == NULL) {
+ moduleCallBackHead = new;
+ } else { /* find place in list */
+ tmp = moduleCallBackHead;
+ prev = tmp;
+ if (new->when < tmp->when) {
+ new->next = tmp;
+ moduleCallBackHead = new;
+ } else {
+ while (tmp && new->when >= tmp->when) {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ prev->next = new;
+ new->next = tmp;
+ }
+ }
+ if (debug)
+ alog("debug: added module CallBack: [%s] due to execute at %ld",
+ new->name ? new->name : "?", (long int) new->when);
+ return MOD_ERR_OK;
+}
+
+/**
+ * Execute a stored call back
+ **/
+void moduleCallBackRun(void)
+{
+ ModuleCallBack *tmp;
+
+ while ((tmp = moduleCallBackHead) && (tmp->when <= time(NULL))) {
+ if (debug)
+ alog("debug: executing callback: %s", tmp->name ? tmp->name : "<unknown>");
+ if (tmp->func) {
+ mod_current_module_name = tmp->owner_name;
+ tmp->func(tmp->argc, tmp->argv);
+ mod_current_module = NULL;
+ moduleCallBackDeleteEntry(NULL);
+ }
+ }
+}
+
+/**
+ * Removes a entry from the modules callback list
+ * @param prev a pointer to the previous entry in the list, NULL for the head
+ **/
+void moduleCallBackDeleteEntry(ModuleCallBack * prev)
+{
+ ModuleCallBack *tmp = NULL;
+ int i;
+ if (prev == NULL) {
+ tmp = moduleCallBackHead;
+ moduleCallBackHead = tmp->next;
+ } else {
+ tmp = prev->next;
+ prev->next = tmp->next;
+ }
+ if (tmp->name)
+ free(tmp->name);
+ if (tmp->owner_name)
+ free(tmp->owner_name);
+ tmp->func = NULL;
+ for (i = 0; i < tmp->argc; i++) {
+ free(tmp->argv[i]);
+ }
+ tmp->argc = 0;
+ tmp->next = NULL;
+ free(tmp);
+}
+
+/**
+ * Search the module callback list for a given module
+ * @param mod_name the name of the module were looking for
+ * @param found have we found it?
+ * @return a pointer to the ModuleCallBack struct or NULL - dont forget to check the found paramter!
+ **/
+ModuleCallBack *moduleCallBackFindEntry(char *mod_name, boolean * found)
+{
+ ModuleCallBack *prev = NULL, *current = NULL;
+ *found = false;
+ current = moduleCallBackHead;
+ while (current != NULL) {
+ if (current->owner_name
+ && (strcmp(mod_name, current->owner_name) == 0)) {
+ *found = true;
+ break;
+ } else {
+ prev = current;
+ current = current->next;
+ }
+ }
+ if (current == moduleCallBackHead) {
+ return NULL;
+ } else {
+ return prev;
+ }
+}
+
+/**
+ * Allow module coders to delete a callback by name.
+ * @param name the name of the callback they wish to delete
+ **/
+void moduleDelCallback(char *name)
+{
+ ModuleCallBack *current = NULL;
+ ModuleCallBack *prev = NULL, *tmp = NULL;
+ int del = 0;
+ if (!mod_current_module_name) {
+ return;
+ }
+ if (!name) {
+ return;
+ }
+ current = moduleCallBackHead;
+ while (current) {
+ if ((current->owner_name) && (current->name)) {
+ if ((strcmp(mod_current_module_name, current->owner_name) == 0)
+ && (strcmp(current->name, name) == 0)) {
+ if (debug) {
+ alog("debug: removing CallBack %s for module %s", name,
+ mod_current_module_name);
+ }
+ tmp = current->next; /* get a pointer to the next record, as once we delete this record, we'll lose it :) */
+ moduleCallBackDeleteEntry(prev); /* delete this record */
+ del = 1; /* set the record deleted flag */
+ }
+ }
+ if (del == 1) { /* if a record was deleted */
+ current = tmp; /* use the value we stored in temp */
+ tmp = NULL; /* clear it for next time */
+ del = 0; /* reset the flag */
+ } else {
+ prev = current; /* just carry on as normal */
+ current = current->next;
+ }
+ }
+}
+
+/**
+ * Remove all outstanding module callbacks for the given module.
+ * When a module is unloaded, any callbacks it had outstanding must be removed, else when they attempt to execute the func pointer will no longer be valid, and we'll seg.
+ * @param mod_name the name of the module we are preping for unload
+ **/
+void moduleCallBackPrepForUnload(char *mod_name)
+{
+ boolean found = false;
+ ModuleCallBack *tmp = NULL;
+
+ tmp = moduleCallBackFindEntry(mod_name, &found);
+ while (found) {
+ if (debug) {
+ alog("debug: removing CallBack for module %s", mod_name);
+ }
+ moduleCallBackDeleteEntry(tmp);
+ tmp = moduleCallBackFindEntry(mod_name, &found);
+ }
+}
+
+/**
+ * Return a copy of the complete last buffer.
+ * This is needed for modules who cant trust the strtok() buffer, as we dont know who will have already messed about with it.
+ * @reutrn a pointer to a copy of the last buffer - DONT mess with this, copy if first if you must do things to it.
+ **/
+char *moduleGetLastBuffer(void)
+{
+ char *tmp = NULL;
+ if (mod_current_buffer) {
+ tmp = strchr(mod_current_buffer, ' ');
+ if (tmp) {
+ tmp++;
+ }
+ }
+ return tmp;
+}
+
+/*******************************************************************************
+ * Module HELP Functions
+ *******************************************************************************/
+ /**
+ * Add help for Root admins.
+ * @param c the Command to add help for
+ * @param func the function to run when this help is asked for
+ **/
+int moduleAddRootHelp(Command * c, int (*func) (User * u))
+{
+ if (c) {
+ c->root_help = func;
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+ /**
+ * Add help for Admins.
+ * @param c the Command to add help for
+ * @param func the function to run when this help is asked for
+ **/
+int moduleAddAdminHelp(Command * c, int (*func) (User * u))
+{
+ if (c) {
+ c->admin_help = func;
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+ /**
+ * Add help for opers..
+ * @param c the Command to add help for
+ * @param func the function to run when this help is asked for
+ **/
+int moduleAddOperHelp(Command * c, int (*func) (User * u))
+{
+ if (c) {
+ c->oper_help = func;
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Add help for registered users
+ * @param c the Command to add help for
+ * @param func the function to run when this help is asked for
+ **/
+int moduleAddRegHelp(Command * c, int (*func) (User * u))
+{
+ if (c) {
+ c->regular_help = func;
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Add help for all users
+ * @param c the Command to add help for
+ * @param func the function to run when this help is asked for
+ **/
+int moduleAddHelp(Command * c, int (*func) (User * u))
+{
+ if (c) {
+ c->all_help = func;
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Add output to nickserv help.
+ * when doing a /msg nickserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetNickHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->nickHelp = func;
+ }
+}
+
+/**
+ * Add output to chanserv help.
+ * when doing a /msg chanserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetChanHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->chanHelp = func;
+ }
+}
+
+/**
+ * Add output to memoserv help.
+ * when doing a /msg memoserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetMemoHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->memoHelp = func;
+ }
+}
+
+/**
+ * Add output to botserv help.
+ * when doing a /msg botserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetBotHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->botHelp = func;
+ }
+}
+
+/**
+ * Add output to operserv help.
+ * when doing a /msg operserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetOperHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->operHelp = func;
+ }
+}
+
+/**
+ * Add output to hostserv help.
+ * when doing a /msg hostserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetHostHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->hostHelp = func;
+ }
+}
+
+/**
+ * Add output to helpserv help.
+ * when doing a /msg helpserv help, your function will be called to allow it to send out a notice() with the code you wish to dispaly
+ * @param func a pointer to the function which will display the code
+ **/
+void moduleSetHelpHelp(void (*func) (User * u))
+{
+ if (mod_current_module) {
+ mod_current_module->helpHelp = func;
+ }
+}
+
+/**
+ * Display any extra module help for the given service.
+ * @param services which services is help being dispalyed for?
+ * @param u which user is requesting the help
+ **/
+void moduleDisplayHelp(int service, User * u)
+{
+#ifdef USE_MODULES
+ int idx;
+ ModuleHash *current = NULL;
+ Module *calling_module = mod_current_module;
+ char *calling_module_name = mod_current_module_name;
+
+ for (idx = 0; idx != MAX_CMD_HASH; idx++) {
+ for (current = MODULE_HASH[idx]; current; current = current->next) {
+ mod_current_module_name = current->name;
+ mod_current_module = current->m;
+
+ if ((service == 1) && current->m->nickHelp) {
+ current->m->nickHelp(u);
+ } else if ((service == 2) && current->m->chanHelp) {
+ current->m->chanHelp(u);
+ } else if ((service == 3) && current->m->memoHelp) {
+ current->m->memoHelp(u);
+ } else if ((service == 4) && current->m->botHelp) {
+ current->m->botHelp(u);
+ } else if ((service == 5) && current->m->operHelp) {
+ current->m->operHelp(u);
+ } else if ((service == 6) && current->m->hostHelp) {
+ current->m->hostHelp(u);
+ } else if ((service == 7) && current->m->helpHelp) {
+ current->m->helpHelp(u);
+ }
+ }
+ }
+
+ mod_current_module = calling_module;
+ mod_current_module_name = calling_module_name;
+#endif
+}
+
+/**
+ * Output module data information into the log file.
+ * This is a vwey "debug only" function to dump the whole contents
+ * of a moduleData struct into the log files.
+ * @param md The module data for the struct to be used
+ * @return 0 is always returned;
+ **/
+int moduleDataDebug(ModuleData ** md)
+{
+ ModuleData *current = NULL;
+ alog("Dumping module data....");
+ for (current = *md; current; current = current->next) {
+ alog("Module: [%s]", current->moduleName);
+ alog(" Key [%s]\tValue [%s]", current->key, current->value);
+ }
+ alog("End of module data dump");
+ return 0;
+}
+
+/**
+ * Add module data to a struct.
+ * This allows module coders to add data to an existing struct
+ * @param md The module data for the struct to be used
+ * @param key The Key for the key/value pair
+ * @param value The value for the key/value pair, this is what will be stored for you
+ * @return MOD_ERR_OK will be returned on success
+ **/
+int moduleAddData(ModuleData ** md, char *key, char *value)
+{
+ ModuleData *newData = NULL;
+
+ if (mod_current_module_name == NULL) {
+ alog("moduleAddData() called with mod_current_module_name being NULL");
+ if (debug)
+ do_backtrace(0);
+ }
+
+ if (!key || !value) {
+ alog("A module (%s) tried to use ModuleAddData() with one or more NULL arguments... returning", mod_current_module_name);
+ return MOD_ERR_PARAMS;
+ }
+
+ moduleDelData(md, key); /* Remove any existing module data for this module with the same key */
+
+ newData = malloc(sizeof(ModuleData));
+ if (!newData) {
+ return MOD_ERR_MEMORY;
+ }
+
+ newData->moduleName = sstrdup(mod_current_module_name);
+ newData->key = sstrdup(key);
+ newData->value = sstrdup(value);
+ newData->next = *md;
+ *md = newData;
+
+ if (debug) {
+ moduleDataDebug(md);
+ }
+ return MOD_ERR_OK;
+}
+
+/**
+ * Returns the value from a key/value pair set.
+ * This allows module coders to retrive any data they have previuosly stored in any given struct
+ * @param md The module data for the struct to be used
+ * @param key The key to find the data for
+ * @return the value paired to the given key will be returned, or NULL
+ **/
+char *moduleGetData(ModuleData ** md, char *key)
+{
+ /* See comment in moduleAddData... -GD */
+ char *mod_name = sstrdup(mod_current_module_name);
+ ModuleData *current = *md;
+
+ if (mod_current_module_name == NULL) {
+ alog("moduleGetData() called with mod_current_module_name being NULL");
+ if (debug)
+ do_backtrace(0);
+ }
+
+ if (debug) {
+ alog("debug: moduleGetData %p : key %s", (void *) md, key);
+ alog("debug: Current Module %s", mod_name);
+ }
+
+ while (current) {
+ if ((stricmp(current->moduleName, mod_name) == 0)
+ && (stricmp(current->key, key) == 0)) {
+ free(mod_name);
+ return sstrdup(current->value);
+ }
+ current = current->next;
+ }
+ free(mod_name);
+ return NULL;
+}
+
+/**
+ * Delete the key/value pair indicated by "key" for the current module.
+ * This allows module coders to remove a previously stored key/value pair.
+ * @param md The module data for the struct to be used
+ * @param key The key to delete the key/value pair for
+ **/
+void moduleDelData(ModuleData ** md, char *key)
+{
+ /* See comment in moduleAddData... -GD */
+ char *mod_name = sstrdup(mod_current_module_name);
+ ModuleData *current = *md;
+ ModuleData *prev = NULL;
+ ModuleData *next = NULL;
+
+ if (mod_current_module_name == NULL) {
+ alog("moduleDelData() called with mod_current_module_name being NULL");
+ if (debug)
+ do_backtrace(0);
+ }
+
+ if (key) {
+ while (current) {
+ next = current->next;
+ if ((stricmp(current->moduleName, mod_name) == 0)
+ && (stricmp(current->key, key) == 0)) {
+ if (prev) {
+ prev->next = current->next;
+ } else {
+ *md = current->next;
+ }
+ free(current->moduleName);
+ free(current->key);
+ free(current->value);
+ current->next = NULL;
+ free(current);
+ } else {
+ prev = current;
+ }
+ current = next;
+ }
+ }
+ free(mod_name);
+}
+
+/**
+ * This will remove all data for a particular module from existing structs.
+ * Its primary use is modulePrepForUnload() however, based on past expericance with module coders wanting to
+ * do just about anything and everything, its safe to use from inside the module.
+ * @param md The module data for the struct to be used
+ **/
+void moduleDelAllData(ModuleData ** md)
+{
+ /* See comment in moduleAddData... -GD */
+ char *mod_name = sstrdup(mod_current_module_name);
+ ModuleData *current = *md;
+ ModuleData *prev = NULL;
+ ModuleData *next = NULL;
+
+ if (mod_current_module_name == NULL) {
+ alog("moduleDelAllData() called with mod_current_module_name being NULL");
+ if (debug)
+ do_backtrace(0);
+ }
+
+ while (current) {
+ next = current->next;
+ if ((stricmp(current->moduleName, mod_name) == 0)) {
+ if (prev) {
+ prev->next = current->next;
+ } else {
+ *md = current->next;
+ }
+ free(current->moduleName);
+ free(current->key);
+ free(current->value);
+ current->next = NULL;
+ free(current);
+ } else {
+ prev = current;
+ }
+ current = next;
+ }
+ free(mod_name);
+}
+
+/**
+ * This will delete all module data used in any struct by module m.
+ * @param m The module to clear all data for
+ **/
+void moduleDelAllDataMod(Module * m)
+{
+ boolean freeme = false;
+ int i, j;
+ User *user;
+ NickAlias *na;
+ NickCore *nc;
+ ChannelInfo *ci;
+
+ if (!mod_current_module_name) {
+ mod_current_module_name = sstrdup(m->name);
+ freeme = true;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ /* Remove the users */
+ for (user = userlist[i]; user; user = user->next) {
+ moduleDelAllData(&user->moduleData);
+ }
+ /* Remove the nick Cores */
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ moduleDelAllData(&nc->moduleData);
+ /* Remove any memo data for this nick core */
+ for (j = 0; j < nc->memos.memocount; j++) {
+ moduleCleanStruct(&nc->memos.memos[j].moduleData);
+ }
+ }
+ /* Remove the nick Aliases */
+ for (na = nalists[i]; na; na = na->next) {
+ moduleDelAllData(&na->moduleData);
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ /* Remove any chan info data */
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ moduleDelAllData(&ci->moduleData);
+ /* Remove any memo data for this nick core */
+ for (j = 0; j < ci->memos.memocount; j++) {
+ moduleCleanStruct(&ci->memos.memos[j].moduleData);
+ }
+ }
+ }
+
+ if (freeme) {
+ free(mod_current_module_name);
+ mod_current_module_name = NULL;
+ }
+}
+
+/**
+ * Remove any data from any module used in the given struct.
+ * Useful for cleaning up when a User leave's the net, a NickCore is deleted, etc...
+ * @param moduleData the moduleData struct to "clean"
+ **/
+void moduleCleanStruct(ModuleData ** moduleData)
+{
+ ModuleData *current = *moduleData;
+ ModuleData *next = NULL;
+
+ while (current) {
+ next = current->next;
+ free(current->moduleName);
+ free(current->key);
+ free(current->value);
+ current->next = NULL;
+ free(current);
+ current = next;
+ }
+ *moduleData = NULL;
+}
+
+/**
+ * Check the current version of anope against a given version number
+ * Specifiying -1 for minor,patch or build
+ * @param major The major version of anope, the first part of the verison number
+ * @param minor The minor version of anope, the second part of the version number
+ * @param patch The patch version of anope, the third part of the version number
+ * @param build The build revision of anope from SVN
+ * @return True if the version newer than the version specified.
+ **/
+boolean moduleMinVersion(int major, int minor, int patch, int build)
+{
+ boolean ret = false;
+ if (VERSION_MAJOR > major) { /* Def. new */
+ ret = true;
+ } else if (VERSION_MAJOR == major) { /* Might be newer */
+ if (minor == -1) {
+ return true;
+ } /* They dont care about minor */
+ if (VERSION_MINOR > minor) { /* Def. newer */
+ ret = true;
+ } else if (VERSION_MINOR == minor) { /* Might be newer */
+ if (patch == -1) {
+ return true;
+ } /* They dont care about patch */
+ if (VERSION_PATCH > patch) {
+ ret = true;
+ } else if (VERSION_PATCH == patch) {
+ if (build == -1) {
+ return true;
+ } /* They dont care about build */
+ if (VERSION_BUILD >= build) {
+ ret = true;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+#ifdef _WIN32
+const char *ano_moderr(void)
+{
+ static char errbuf[513];
+ DWORD err = GetLastError();
+ if (err == 0)
+ return NULL;
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, errbuf, 512,
+ NULL);
+ return errbuf;
+}
+#endif
+
+/**
+ * Allow ircd protocol files to update the protect level info tables.
+ **/
+void updateProtectDetails(char *level_info_protect_word,
+ char *level_info_protectme_word,
+ char *fant_protect_add, char *fant_protect_del,
+ char *level_protect_word, char *protect_set_mode,
+ char *protect_unset_mode)
+{
+ int i = 0;
+ CSModeUtil ptr;
+ LevelInfo l_ptr;
+
+ ptr = csmodeutils[i];
+ while (ptr.name) {
+ if (strcmp(ptr.name, "PROTECT") == 0) {
+ csmodeutils[i].bsname = sstrdup(fant_protect_add);
+ csmodeutils[i].mode = sstrdup(protect_set_mode);
+ } else if (strcmp(ptr.name, "DEPROTECT") == 0) {
+ csmodeutils[i].bsname = sstrdup(fant_protect_del);
+ csmodeutils[i].mode = sstrdup(protect_unset_mode);
+ }
+ ptr = csmodeutils[++i];
+ }
+
+ i = 0;
+ l_ptr = levelinfo[i];
+ while (l_ptr.what != -1) {
+ if (l_ptr.what == CA_PROTECT) {
+ levelinfo[i].name = sstrdup(level_info_protect_word);
+ } else if (l_ptr.what == CA_PROTECTME) {
+ levelinfo[i].name = sstrdup(level_info_protectme_word);
+ } else if (l_ptr.what == CA_AUTOPROTECT) {
+ levelinfo[i].name = sstrdup(level_protect_word);
+ }
+ l_ptr = levelinfo[++i];
+ }
+}
+
+/**
+ * Deal with modules who want to lookup config directives!
+ * @param h The Directive to lookup in the config file
+ * @return 1 on success, 0 on error
+ **/
+int moduleGetConfigDirective(Directive * d)
+{
+ FILE *config;
+ char *dir = NULL;
+ char buf[1024];
+ char *directive;
+ int linenum = 0;
+ int ac = 0;
+ char *av[MAXPARAMS];
+ char *str = NULL;
+ char *s = NULL;
+ char *t = NULL;
+ int retval = 1;
+
+ config = fopen(SERVICES_CONF, "r");
+ if (!config) {
+ alog("Can't open %s", SERVICES_CONF);
+ return 0;
+ }
+ while (fgets(buf, sizeof(buf), config)) {
+ linenum++;
+ if (*buf == '#' || *buf == '\r' || *buf == '\n') {
+ continue;
+ }
+ dir = myStrGetOnlyToken(buf, '\t', 0);
+ if (dir) {
+ str = myStrGetTokenRemainder(buf, '\t', 1);
+ } else {
+ dir = myStrGetOnlyToken(buf, ' ', 0);
+ if (dir || (dir = myStrGetOnlyToken(buf, '\n', 0))) {
+ str = myStrGetTokenRemainder(buf, ' ', 1);
+ } else {
+ continue;
+ }
+ }
+ if (dir) {
+ directive = normalizeBuffer(dir);
+ } else {
+ continue;
+ }
+
+ if (stricmp(directive, d->name) == 0) {
+ if (str) {
+ s = str;
+ while (isspace(*s))
+ s++;
+ while (*s) {
+ if (ac >= MAXPARAMS) {
+ alog("module error: too many config. params");
+ break;
+ }
+ t = s;
+ if (*s == '"') {
+ t++;
+ s++;
+ while (*s && *s != '"') {
+ if (*s == '\\' && s[1] != 0)
+ s++;
+ s++;
+ }
+ if (!*s)
+ alog("module error: Warning: unterminated double-quoted string");
+ else
+ *s++ = 0;
+ } else {
+ s += strcspn(s, " \t\r\n");
+ if (*s)
+ *s++ = 0;
+ }
+ av[ac++] = t;
+ while (isspace(*s))
+ s++;
+ }
+ }
+ retval = parse_directive(d, directive, ac, av, linenum, 0, s);
+ }
+ if (directive) {
+ free(directive);
+ }
+ }
+ if (dir)
+ free(dir);
+ if (str)
+ free(str);
+ fclose(config);
+ return retval;
+}
+
+/**
+ * Allow a module to add a set of language strings to anope
+ * @param langNumber the language number for the strings
+ * @param ac The language count for the strings
+ * @param av The language sring list.
+ **/
+void moduleInsertLanguage(int langNumber, int ac, char **av)
+{
+ int i;
+
+ if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+
+ if (debug)
+ alog("debug: %s Adding %d texts for language %d", mod_current_module->name, ac, langNumber);
+
+ if (mod_current_module->lang[langNumber].argc > 0) {
+ moduleDeleteLanguage(langNumber);
+ }
+
+ mod_current_module->lang[langNumber].argc = ac;
+ mod_current_module->lang[langNumber].argv =
+ malloc(sizeof(char *) * ac);
+ for (i = 0; i < ac; i++) {
+ mod_current_module->lang[langNumber].argv[i] = sstrdup(av[i]);
+ }
+}
+
+/**
+ * Send a notice to the user in the correct language, or english.
+ * @param source Who sends the notice
+ * @param u The user to send the message to
+ * @param number The message number
+ * @param ... The argument list
+ **/
+void moduleNoticeLang(char *source, User * u, int number, ...)
+{
+ va_list va;
+ char buffer[4096], outbuf[4096];
+ char *fmt = NULL;
+ int lang = NSDefLanguage;
+ char *s, *t, *buf;
+
+ if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+
+ /* Find the users lang, and use it if we can */
+ if (u && u->na && u->na->nc) {
+ lang = u->na->nc->language;
+ }
+
+ /* If the users lang isnt supported, drop back to English */
+ if (mod_current_module->lang[lang].argc == 0) {
+ lang = LANG_EN_US;
+ }
+
+ /* If the requested lang string exists for the language */
+ if (mod_current_module->lang[lang].argc > number) {
+ fmt = mod_current_module->lang[lang].argv[number];
+
+ buf = sstrdup(fmt);
+ va_start(va, number);
+ vsnprintf(buffer, 4095, buf, va);
+ va_end(va);
+ s = buffer;
+ while (*s) {
+ t = s;
+ s += strcspn(s, "\n");
+ if (*s)
+ *s++ = '\0';
+ strscpy(outbuf, t, sizeof(outbuf));
+ notice_user(source, u, "%s", outbuf);
+ }
+ free(buf);
+ } else {
+ alog("%s: INVALID language string call, language: [%d], String [%d]", mod_current_module->name, lang, number);
+ }
+}
+
+/**
+ * Get the text of the given lanugage string in the corrent language, or
+ * in english.
+ * @param u The user to send the message to
+ * @param number The message number
+ **/
+char *moduleGetLangString(User * u, int number)
+{
+ int lang = NSDefLanguage;
+
+ if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name)))
+ mod_current_module = findModule(mod_current_module_name);
+
+ /* Find the users lang, and use it if we can */
+ if (u && u->na && u->na->nc)
+ lang = u->na->nc->language;
+
+ /* If the users lang isnt supported, drop back to English */
+ if (mod_current_module->lang[lang].argc == 0)
+ lang = LANG_EN_US;
+
+ /* If the requested lang string exists for the language */
+ if (mod_current_module->lang[lang].argc > number) {
+ return mod_current_module->lang[lang].argv[number];
+ /* Return an empty string otherwise, because we might be used without
+ * the return value being checked. If we would return NULL, bad things
+ * would happen!
+ */
+ } else {
+ alog("%s: INVALID language string call, language: [%d], String [%d]", mod_current_module->name, lang, number);
+ return "";
+ }
+}
+
+/**
+ * Delete a language from a module
+ * @param langNumber the language Number to delete
+ **/
+void moduleDeleteLanguage(int langNumber)
+{
+ int idx = 0;
+ if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
+ mod_current_module = findModule(mod_current_module_name);
+ }
+ for (idx = 0; idx > mod_current_module->lang[langNumber].argc; idx++) {
+ free(mod_current_module->lang[langNumber].argv[idx]);
+ }
+ mod_current_module->lang[langNumber].argc = 0;
+}
+
+/**
+ * Enqueue a module operation (load/unload/reload)
+ * @param m Module to perform the operation on
+ * @param op Operation to perform on the module
+ * @param u User who requested the operation
+ **/
+void queueModuleOperation(Module *m, ModuleOperation op, User *u)
+{
+ ModuleQueue *qm;
+
+ qm = scalloc(1, sizeof(ModuleQueue));
+ qm->m = m;
+ qm->op = op;
+ qm->u = u;
+ qm->next = mod_operation_queue;
+ mod_operation_queue = qm;
+}
+
+/**
+ * Enqueue a module to load
+ * @param name Name of the module to load
+ * @param u User who requested the load
+ * @return 1 on success, 0 on error
+ **/
+int queueModuleLoad(char *name, User *u)
+{
+ Module *m;
+
+ if (!name || !u)
+ return 0;
+
+ if (findModule(name))
+ return 0;
+ m = createModule(name);
+ queueModuleOperation(m, MOD_OP_LOAD, u);
+
+ return 1;
+}
+
+/**
+ * Enqueue a module to unload
+ * @param name Name of the module to unload
+ * @param u User who requested the unload
+ * @return 1 on success, 0 on error
+ **/
+int queueModuleUnload(char *name, User *u)
+{
+ Module *m;
+
+ if (!name || !u)
+ return 0;
+
+ m = findModule(name);
+ if (!m)
+ return 0;
+ queueModuleOperation(m, MOD_OP_UNLOAD, u);
+
+ return 1;
+}
+
+/**
+ * Execute all queued module operations
+ **/
+void handleModuleOperationQueue(void)
+{
+ ModuleQueue *next;
+ int status;
+
+ if (!mod_operation_queue)
+ return;
+
+ while (mod_operation_queue) {
+ next = mod_operation_queue->next;
+
+ mod_current_module = mod_operation_queue->m;
+ mod_current_user = mod_operation_queue->u;
+
+ if (mod_operation_queue->op == MOD_OP_LOAD) {
+ alog("Trying to load module [%s]", mod_operation_queue->m->name);
+ status = loadModule(mod_operation_queue->m, mod_operation_queue->u);
+ alog("Module loading status: %d (%s)", status, ModuleGetErrStr(status));
+ if (status != MOD_ERR_OK) {
+ if(mod_current_user) {
+ notice_lang(s_OperServ, mod_current_user, OPER_MODULE_LOAD_FAIL,mod_operation_queue->m->name);
+ }
+ destroyModule(mod_operation_queue->m);
+ }
+ } else if (mod_operation_queue->op == MOD_OP_UNLOAD) {
+ alog("Trying to unload module [%s]", mod_operation_queue->m->name);
+ status = unloadModule(mod_operation_queue->m, mod_operation_queue->u);
+ alog("Module unloading status: %d (%s)", status, ModuleGetErrStr(status));
+ }
+
+ /* Remove the ModuleQueue from memory */
+ free(mod_operation_queue);
+
+ mod_operation_queue = next;
+ }
+
+ mod_current_module = NULL;
+ mod_current_user = NULL;
+}
+
+void ModuleRunTimeDirCleanUp(void)
+{
+#ifndef _WIN32
+ DIR *dirp;
+ struct dirent *dp;
+#else
+ BOOL fFinished;
+ HANDLE hList;
+ TCHAR szDir[MAX_PATH + 1];
+ TCHAR szSubDir[MAX_PATH + 1];
+ WIN32_FIND_DATA FileData;
+ char buffer[_MAX_PATH];
+#endif
+ char dirbuf[BUFSIZE];
+ char filebuf[BUFSIZE];
+
+
+#ifndef _WIN32
+ snprintf(dirbuf, BUFSIZE, "%s/modules/runtime", services_dir);
+#else
+ snprintf(dirbuf, BUFSIZE, "\\%s", "modules/runtime");
+#endif
+
+ if (debug) {
+ alog("debug: Cleaning out Module run time directory (%s) - this may take a moment please wait", dirbuf);
+ }
+
+#ifndef _WIN32
+ if ((dirp = opendir(dirbuf)) == NULL) {
+ if (debug) {
+ alog("debug: cannot open directory (%s)", dirbuf);
+ }
+ return;
+ }
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_ino == 0) {
+ continue;
+ }
+ if (!stricmp(dp->d_name, ".") || !stricmp(dp->d_name, "..")) {
+ continue;
+ }
+ snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, dp->d_name);
+ unlink(filebuf);
+ }
+ closedir(dirp);
+#else
+ /* Get the current working directory: */
+ if (_getcwd(buffer, _MAX_PATH) == NULL) {
+ if (debug) {
+ alog("debug: Unable to set Current working directory");
+ }
+ }
+ snprintf(szDir, sizeof(szDir), "%s\\%s\\*", buffer, dirbuf);
+
+ hList = FindFirstFile(szDir, &FileData);
+ if (hList != INVALID_HANDLE_VALUE) {
+ fFinished = FALSE;
+ while (!fFinished) {
+ if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, FileData.cFileName);
+ DeleteFile(filebuf);
+ }
+ if (!FindNextFile(hList, &FileData)) {
+ if (GetLastError() == ERROR_NO_MORE_FILES) {
+ fFinished = TRUE;
+ }
+ }
+ }
+ } else {
+ if (debug) {
+ alog("debug: Invalid File Handle. GetLastError reports %d\n", GetLastError());
+ }
+ }
+ FindClose(hList);
+#endif
+ if (debug) {
+ alog("debug: Module run time directory has been cleaned out");
+ }
+}
+
+/* EOF */
diff --git a/src/modules/Makefile b/src/modules/Makefile
new file mode 100644
index 000000000..cafbe451c
--- /dev/null
+++ b/src/modules/Makefile
@@ -0,0 +1,48 @@
+include ./Makefile.inc
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: modules subs
+
+modules: $(OBJECTS) $(SO_FILES)
+
+install:
+ $(CP) ./*.so $(MODULE_PATH)
+ @for i in $(SUBS); do \
+ echo "make install in $$i..."; \
+ (cd $$i; $(MAKE) $(MAKEARGS) install);done
+
+distclean: spotless
+
+.c.o:
+ $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../${INCLUDEDIR} -c $<
+
+.o.s:
+ $(CC) ${SHARED} ../mod_version.o $< -o $*.so ${PROFILE}
+ @$(TOUCH) $*.s
+
+subs:
+ @for i in $(SUBS); do \
+ echo "make all in $$i..."; \
+ (cd $$i; $(MAKE) $(MAKEARGS) all); done
+
+subs_clean:
+ @for i in $(SUBS); do \
+ echo "cleaning in $$i..."; \
+ (cd $$i; $(MAKE) $(MAKEARGS) clean); done
+
+clean: subs_clean
+ rm -f *.o *.s *.so *.c~ core
+
+spotless:
+ rm -f *.o *.s *.so *.c~ core *.so Makefile.inc
+
diff --git a/src/modules/Makefile.sub b/src/modules/Makefile.sub
new file mode 100644
index 000000000..7697249bf
--- /dev/null
+++ b/src/modules/Makefile.sub
@@ -0,0 +1,28 @@
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: module
+
+module: $(OBJECTS) so
+
+distclean: spotless
+
+.c.o:
+ $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../ -I../../${INCLUDEDIR} -c $<
+
+so:
+ $(CC) ${SHARED} ../../mod_version.o $(OBJECTS) -o ../$(TARGET).so ${PROFILE}
+
+clean:
+ rm -f *.o *.so *.c~ core
+
+spotless:
+ rm -f *~ *.o *.so *.c~ core
diff --git a/src/modules/README b/src/modules/README
new file mode 100644
index 000000000..6aee0ac47
--- /dev/null
+++ b/src/modules/README
@@ -0,0 +1 @@
+Please read the "MODULES" file located on the "docs" directory.
diff --git a/src/modules/bs_fantasy_unban.c b/src/modules/bs_fantasy_unban.c
new file mode 100644
index 000000000..a17e06551
--- /dev/null
+++ b/src/modules/bs_fantasy_unban.c
@@ -0,0 +1,82 @@
+/* BotServ core fantasy functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+int do_fantasy(int argc, char **argv);
+
+/**
+ * Create the hook, and tell anope about it.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hook;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(CORE);
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_fantasy);
+ moduleAddEventHook(hook);
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+
+}
+
+/**
+ * Handle unban fantasy command.
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_fantasy(int argc, char **argv)
+{
+ User *u;
+ ChannelInfo *ci;
+ char *target = NULL;
+
+ if (argc < 3)
+ return MOD_CONT;
+
+ if (stricmp(argv[0], "unban") == 0) {
+ u = finduser(argv[1]);
+ ci = cs_findchan(argv[2]);
+ if (!u || !ci || !check_access(u, ci, CA_UNBAN))
+ return MOD_CONT;
+
+ if (argc >= 4)
+ target = myStrGetToken(argv[3], ' ', 0);
+ if (!target)
+ common_unban(ci, u->nick);
+ else
+ common_unban(ci, target);
+
+ /* free target if needed (#852) */
+ Anope_Free(target);
+ }
+
+ return MOD_CONT;
+}
diff --git a/src/modules/configure b/src/modules/configure
new file mode 100755
index 000000000..cf2158d66
--- /dev/null
+++ b/src/modules/configure
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+echo2 () {
+ $ECHO2 "$*$ECHO2SUF" # these are defined later
+}
+
+ECHO2SUF=''
+if [ "`echo -n a ; echo -n b`" = "ab" ] ; then
+ ECHO2='echo -n'
+elif [ "`echo 'a\c' ; echo 'b\c'`" = "ab" ] ; then
+ ECHO2='echo' ; ECHO2SUF='\c'
+elif [ "`printf 'a' 2>&1 ; printf 'b' 2>&1`" = "ab" ] ; then
+ ECHO2='printf "%s"'
+else
+ # oh well...
+ ECHO2='echo'
+fi
+export ECHO2 ECHO2SUF
+
+
+echo2 "SRCS=" > ./Makefile.inc
+FIRST=1
+for oldfile in *.c
+do
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$oldfile >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $oldfile >> ./Makefile.inc
+ fi
+ FIRST=0
+done
+echo "" >> ./Makefile.inc
+
+echo2 "SUBS=" >> ./Makefile.inc
+FIRST=1
+for dir in *
+do
+ if [ -d $dir ] ; then
+ if [ -f $dir/configure ] ; then
+ cd $dir
+ ./configure
+ cd ..
+ fi
+ if [ -f $dir/Makefile ] ; then
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$dir >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $dir >> ./Makefile.inc
+ fi
+ FIRST=0
+ fi
+ fi
+done
+
+exit 0
+
diff --git a/src/modules/cs_appendtopic.c b/src/modules/cs_appendtopic.c
new file mode 100644
index 000000000..7e0d27bb4
--- /dev/null
+++ b/src/modules/cs_appendtopic.c
@@ -0,0 +1,247 @@
+/* cs_appendtopic.c - Add text to a channels topic
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Based on the original module by SGR <Alex_SGR@ntlworld.com>
+ * Included in the Anope module pack since Anope 1.7.9
+ * Anope Coder: GeniusDex <geniusdex@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send bug reports to the Anope Coder instead of the module
+ * author, because any changes since the inclusion into anope
+ * are not supported by the original author.
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define AUTHOR "SGR"
+#define VERSION "$Id$"
+
+ /* ------------------------------------------------------------
+ * Name: cs_appendtopic
+ * Author: SGR <Alex_SGR@ntlworld.com>
+ * Date: 31/08/2003
+ * ------------------------------------------------------------
+ *
+ * This module has no configurable options. For information on
+ * this module, load it and refer to /ChanServ APPENDTOPIC HELP
+ *
+ * Thanks to dengel, Rob and Certus for all there support.
+ * Especially Rob, who always manages to show me where I have
+ * not allocated any memory. Even if it takes a few weeks of
+ * pestering to get him to look at it.
+ *
+ * ------------------------------------------------------------
+ */
+
+/* ---------------------------------------------------------------------- */
+/* DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING */
+/* ---------------------------------------------------------------------- */
+
+#define LNG_NUM_STRINGS 3
+
+#define LNG_CHAN_HELP 0
+#define LNG_CHAN_HELP_APPENDTOPIC 1
+#define LNG_APPENDTOPIC_SYNTAX 2
+
+int my_cs_appendtopic(User * u);
+void my_cs_help(User * u);
+int my_cs_help_appendtopic(User * u);
+void my_add_languages(void);
+
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ int status;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ c = createCommand("APPENDTOPIC", my_cs_appendtopic, NULL, -1, -1, -1,
+ -1, -1);
+ if ((status = moduleAddCommand(CHANSERV, c, MOD_HEAD))) {
+ alog("[cs_appendtopic] Unable to create APPENDTOPIC command: %d",
+ status);
+ return MOD_STOP;
+ }
+ moduleAddHelp(c, my_cs_help_appendtopic);
+ moduleSetChanHelp(my_cs_help);
+
+ my_add_languages();
+
+ alog("[cs_appendtopic] Loaded successfully");
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ alog("[cs_appendtopic] Unloaded successfully");
+}
+
+void my_cs_help(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP);
+}
+
+int my_cs_help_appendtopic(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, LNG_APPENDTOPIC_SYNTAX);
+ notice(s_ChanServ, u->nick, " ");
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP_APPENDTOPIC);
+ return MOD_STOP;
+}
+
+int my_cs_appendtopic(User * u)
+{
+ char *cur_buffer;
+ char *chan;
+ char *newtopic;
+ char topic[1024];
+ Channel *c;
+ ChannelInfo *ci;
+
+ cur_buffer = moduleGetLastBuffer();
+ chan = myStrGetToken(cur_buffer, ' ', 0);
+ newtopic = myStrGetTokenRemainder(cur_buffer, ' ', 1);
+
+ if (!chan || !newtopic) {
+ moduleNoticeLang(s_ChanServ, u, LNG_APPENDTOPIC_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (!is_services_admin(u) && !check_access(u, ci, CA_TOPIC)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ if (ci->last_topic) {
+ snprintf(topic, sizeof(topic), "%s %s", ci->last_topic,
+ newtopic);
+ free(ci->last_topic);
+ } else {
+ strscpy(topic, newtopic, sizeof(topic));
+ }
+
+ ci->last_topic = *topic ? sstrdup(topic) : NULL;
+ strscpy(ci->last_topic_setter, u->nick, NICKMAX);
+ ci->last_topic_time = time(NULL);
+
+ if (c->topic)
+ free(c->topic);
+ c->topic = *topic ? sstrdup(topic) : NULL;
+ strscpy(c->topic_setter, u->nick, NICKMAX);
+ if (ircd->topictsbackward)
+ c->topic_time = c->topic_time - 1;
+ else
+ c->topic_time = ci->last_topic_time;
+
+ if (is_services_admin(u) && !check_access(u, ci, CA_TOPIC))
+ alog("%s: %s!%s@%s changed topic of %s as services admin.",
+ s_ChanServ, u->nick, u->username, u->host, c->name);
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_join(s_ChanServ, c->name, c->creation_time);
+ anope_cmd_mode(NULL, c->name, "+o %s", s_ChanServ);
+ }
+ }
+ anope_cmd_topic(whosends(ci), c->name, u->nick, topic, c->topic_time);
+ if (ircd->join2set) {
+ if (whosends(ci) == s_ChanServ) {
+ anope_cmd_part(s_ChanServ, c->name, NULL);
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+void my_add_languages(void)
+{
+ /* English (US) */
+ char *langtable_en_us[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Add text to a channels topic",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "This command allows users to append text to a currently set\n"
+ "channel topic. When TOPICLOCK is on, the topic is updated and\n"
+ "the new, updated topic is locked.",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Syntax: APPENDTOPIC channel text\n"
+ };
+
+ /* Dutch (NL) */
+ char *langtable_nl[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Voeg tekst aan een kanaal onderwerp toe",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "Dit command stelt gebruikers in staat om text toe te voegen\n"
+ "achter het huidige onderwerp van een kanaal. Als TOPICLOCK aan\n"
+ "staat, zal het onderwerp worden bijgewerkt en zal het nieuwe,\n"
+ "bijgewerkte topic worden geforceerd.",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Gebruik: APPENDTOPIC kanaal tekst\n"
+ };
+
+ /* German (DE) */
+ char *langtable_de[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Fügt einen Text zu einem Channel-Topic hinzu.",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "Dieser Befehl erlaubt Benutzern, einen Text zu dem vorhandenen Channel-Topic\n"
+ "hinzuzufügen. Wenn TOPICLOCK gesetzt ist, wird das Topic aktualisiert\n"
+ "und das neue, aktualisierte Topic wird gesperrt.",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Syntax: APPENDTOPIC Channel Text\n"
+ };
+
+ /* Portuguese (PT) */
+ char *langtable_pt[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Adiciona texto ao tópico de um canal",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "Este comando permite aos usuários anexar texto a um tópico de canal\n"
+ "já definido. Quando TOPICLOCK está ativado, o tópico é atualizado e\n"
+ "o novo tópico é travado.",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Sintaxe: APPENDTOPIC canal texto\n"
+ };
+
+ /* Russian (RU) */
+ char *langtable_ru[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Äîáàâëÿåò òåêñò ê òîïèêó êàíàëà",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "Äàííàÿ êîìàíäà ïîçâîëÿåò äîáàâèòü òåêñò ê òîïèêó, êîòîðûé óñòàíîâëåí íà óêàçàííîì\n"
+ "êàíàëå. Åñëè àêòèâèðîâàí ðåæèì TOPICLOCK, òîïèê áóäåò îáíîâëåí è çàáëîêèðîâàí.\n"
+ "Ïðèìå÷àíèå: òåêñò áóäåò ÄÎÁÀÂËÅÍ ê òîïèêó, òî åñòü ñòàðûé òîïèê óäàëåí ÍÅ ÁÓÄÅÒ.\n",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Ñèíòàêñèñ: APPENDTOPIC #êàíàë òåêñò\n"
+ };
+
+ /* Italian (IT) */
+ char *langtable_it[] = {
+ /* LNG_CHAN_HELP */
+ " APPENDTOPIC Aggiunge del testo al topic di un canale",
+ /* LNG_CHAN_HELP_APPENDTOPIC */
+ "Questo comando permette agli utenti di aggiungere del testo ad un topic di un canale\n"
+ "già impostato. Se TOPICLOCK è attivato, il topic viene aggiornato e il nuovo topic\n"
+ "viene bloccato.",
+ /* LNG_APPENDTOPIC_SYNTAX */
+ "Sintassi: APPENDTOPIC canale testo\n"
+ };
+
+ moduleInsertLanguage(LANG_EN_US, LNG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_NL, LNG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_DE, LNG_NUM_STRINGS, langtable_de);
+ moduleInsertLanguage(LANG_PT, LNG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LNG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LNG_NUM_STRINGS, langtable_it);
+}
+
+/* EOF */
diff --git a/src/modules/cs_enforce.c b/src/modules/cs_enforce.c
new file mode 100644
index 000000000..a9beec419
--- /dev/null
+++ b/src/modules/cs_enforce.c
@@ -0,0 +1,479 @@
+/* cs_enforce - Add a /cs ENFORCE command to enforce various set
+ * options and channelmodes on a channel.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Included in the Anope module pack since Anope 1.7.9
+ * Anope Coder: GeniusDex <geniusdex@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send any bug reports to the Anope Coder, as he will be able
+ * to deal with it best.
+ */
+
+#include "module.h"
+
+#define AUTHOR "Anope"
+#define VERSION "$Id$"
+
+int my_cs_enforce(User * u);
+void my_cs_help(User * u);
+int my_cs_help_enforce(User * u);
+void my_add_languages(void);
+
+#define LNG_NUM_STRINGS 6
+
+#define LNG_CHAN_HELP 0
+#define LNG_ENFORCE_SYNTAX 1
+#define LNG_CHAN_HELP_ENFORCE 2
+#define LNG_CHAN_HELP_ENFORCE_R_ENABLED 3
+#define LNG_CHAN_HELP_ENFORCE_R_DISABLED 4
+#define LNG_CHAN_RESPONSE 5
+
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ int status;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ c = createCommand("ENFORCE", my_cs_enforce, NULL, -1, -1, -1, -1, -1);
+ if ((status = moduleAddCommand(CHANSERV, c, MOD_HEAD))) {
+ alog("[cs_enforce] Unable to create ENFORCE command: %d", status);
+ return MOD_STOP;
+ }
+
+ moduleAddHelp(c, my_cs_help_enforce);
+ moduleSetChanHelp(my_cs_help);
+
+ my_add_languages();
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ /* Nothing to clean up */
+}
+
+/* Enforcing functions */
+void do_enforce_secureops(Channel * c)
+{
+ struct c_userlist *user;
+ struct c_userlist *next;
+ ChannelInfo *ci;
+ uint32 flags;
+
+ if (!(ci = c->ci))
+ return;
+
+ if (debug)
+ alog("debug: cs_enforce: Enforcing SECUREOPS on %s", c->name);
+
+ /* Dirty hack to allow chan_set_correct_modes to work ok.
+ * We pretend like SECUREOPS is on so it doesn't ignore that
+ * part of the code. This way we can enforce SECUREOPS even
+ * if it's off.
+ */
+ flags = ci->flags;
+ ci->flags |= CI_SECUREOPS;
+
+ user = c->users;
+ do {
+ next = user->next;
+ chan_set_correct_modes(user->user, c, 0);
+ user = next;
+ } while (user);
+
+ ci->flags = flags;
+}
+
+void do_enforce_restricted(Channel * c)
+{
+ struct c_userlist *user;
+ struct c_userlist *next;
+ ChannelInfo *ci;
+ int16 old_nojoin_level;
+ char mask[BUFSIZE];
+ char *reason;
+ char *av[3];
+ User *u;
+
+ if (!(ci = c->ci))
+ return;
+
+ if (debug)
+ alog("debug: cs_enforce: Enforcing RESTRICTED on %s", c->name);
+
+ old_nojoin_level = ci->levels[CA_NOJOIN];
+ if (ci->levels[CA_NOJOIN] < 0)
+ ci->levels[CA_NOJOIN] = 0;
+
+ user = c->users;
+ do {
+ next = user->next;
+ u = user->user;
+ if (check_access(u, c->ci, CA_NOJOIN)) {
+ get_idealban(ci, u, mask, sizeof(mask));
+ reason = getstring(u->na, CHAN_NOT_ALLOWED_TO_JOIN);
+ anope_cmd_mode(whosends(ci), ci->name, "+b %s %lu", mask,
+ time(NULL));
+ anope_cmd_kick(whosends(ci), ci->name, u->nick, "%s", reason);
+ av[0] = ci->name;
+ av[1] = u->nick;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ user = next;
+ } while (user);
+
+ ci->levels[CA_NOJOIN] = old_nojoin_level;
+}
+
+void do_enforce_cmode_R(Channel * c)
+{
+ struct c_userlist *user;
+ struct c_userlist *next;
+ ChannelInfo *ci;
+ char mask[BUFSIZE];
+ char *reason;
+ char *av[3];
+ User *u;
+ CBMode *cbm;
+
+ if (!(ci = c->ci))
+ return;
+
+ if (debug)
+ alog("debug: cs_enforce: Enforcing mode +R on %s", c->name);
+
+ user = c->users;
+ do {
+ next = user->next;
+ u = user->user;
+ if (!nick_identified(u)) {
+ get_idealban(ci, u, mask, sizeof(mask));
+ reason = getstring(u->na, CHAN_NOT_ALLOWED_TO_JOIN);
+ if (((cbm = &cbmodes['R'])->flag == 0)
+ || !(c->mode & cbm->flag))
+ anope_cmd_mode(whosends(ci), ci->name, "+b %s %lu", mask,
+ time(NULL));
+ anope_cmd_kick(whosends(ci), ci->name, u->nick, "%s", reason);
+ av[0] = ci->name;
+ av[1] = u->nick;
+ av[2] = reason;
+ do_kick(s_ChanServ, 3, av);
+ }
+ user = next;
+ } while (user);
+}
+
+/* Enforcing Group Functions */
+void do_enforce_set(Channel * c)
+{
+ ChannelInfo *ci;
+
+ if (!(ci = c->ci))
+ return;
+
+ if (ci->flags & CI_SECUREOPS)
+ do_enforce_secureops(c);
+ if (ci->flags & CI_RESTRICTED)
+ do_enforce_restricted(c);
+}
+
+void do_enforce_modes(Channel * c)
+{
+ CBMode *cbm;
+
+ if (((cbm = &cbmodes['R'])->flag != 0) && (c->mode & cbm->flag))
+ do_enforce_cmode_R(c);
+}
+
+/* End of enforcing functions */
+
+int my_cs_enforce(User * u)
+{
+ char *cur_buffer;
+ char *chan=NULL;
+ char *what=NULL;
+ Channel *c;
+ ChannelInfo *ci;
+
+ cur_buffer = moduleGetLastBuffer();
+ chan = myStrGetToken(cur_buffer, ' ', 0);
+
+ if (!chan) {
+ moduleNoticeLang(s_ChanServ, u, LNG_ENFORCE_SYNTAX);
+ } else if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, ci->name);
+ } else if (!is_services_admin(u) && !check_access(u, ci, CA_AKICK)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ what = myStrGetToken(cur_buffer, ' ', 1);
+ if (!what || (stricmp(what, "SET") == 0)) {
+ do_enforce_set(c);
+ moduleNoticeLang(s_ChanServ,u,LNG_CHAN_RESPONSE,what);
+ } else if (stricmp(what, "MODES") == 0) {
+ do_enforce_modes(c);
+ moduleNoticeLang(s_ChanServ,u,LNG_CHAN_RESPONSE,what);
+ } else if (stricmp(what, "SECUREOPS") == 0) {
+ do_enforce_secureops(c);
+ moduleNoticeLang(s_ChanServ,u,LNG_CHAN_RESPONSE,what);
+ } else if (stricmp(what, "RESTRICTED") == 0) {
+ do_enforce_restricted(c);
+ moduleNoticeLang(s_ChanServ,u,LNG_CHAN_RESPONSE,what);
+ } else if (stricmp(what, "+R") == 0) {
+ do_enforce_cmode_R(c);
+ moduleNoticeLang(s_ChanServ,u,LNG_CHAN_RESPONSE,what);
+ } else {
+ moduleNoticeLang(s_ChanServ, u, LNG_ENFORCE_SYNTAX);
+ }
+ }
+
+ if(chan) free(chan);
+ if(what) free(what);
+
+ return MOD_CONT;
+}
+
+/* Language and response stuff */
+void my_cs_help(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP);
+}
+
+int my_cs_help_enforce(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, LNG_ENFORCE_SYNTAX);
+ notice(s_ChanServ, u->nick, " ");
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP_ENFORCE);
+ notice(s_ChanServ, u->nick, " ");
+ if (cbmodes['R'].flag != 0)
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP_ENFORCE_R_ENABLED);
+ else
+ moduleNoticeLang(s_ChanServ, u, LNG_CHAN_HELP_ENFORCE_R_DISABLED);
+
+ return MOD_STOP;
+}
+
+void my_add_languages(void)
+{
+ /* English (US) */
+ char *langtable_en_us[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Enforce various channel modes and set options",
+ /* LNG_ENFORCE_SYNTAX */
+ "Syntax: \002ENFORCE \037channel\037 [\037what\037]\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Enforce various channel modes and set options. The \037channel\037\n"
+ "option indicates what channel to enforce the modes and options\n"
+ "on. The \037what\037 option indicates what modes and options to\n"
+ "enforce, and can be any of SET, SECUREOPS, RESTRICTED, MODES,\n"
+ "or +R. When left out, it defaults to SET.\n"
+ " \n"
+ "If \037what\037 is SET, it will enforce SECUREOPS and RESTRICTED\n"
+ "on the users currently in the channel, if they are set. Give\n"
+ "SECUREOPS to enforce the SECUREOPS option, even if it is not\n"
+ "enabled. Use RESTRICTED to enfore the RESTRICTED option, also\n"
+ "if it's not enabled.",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "If \037what\037 is MODES, it will enforce channelmode +R if it is\n"
+ "set. If +R is specified for \037what\037, the +R channelmode will\n"
+ "also be enforced, but even if it is not set. If it is not set,\n"
+ "users will be banned to ensure they don't just rejoin.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "If \037what\037 is MODES, nothing will be enforced, since it would\n"
+ "enforce modes that the current ircd does not support. If +R is\n"
+ "specified for \037what\037, an equalivant of channelmode +R on\n"
+ "other ircds will be enforced. All users that are in the channel\n"
+ "but have not identified for their nickname will be kicked and\n"
+ "banned from the channel.",
+ /* LNG_CHAN_RESPONSE */
+ "Enforced %s"
+ };
+
+ /* Dutch (NL) */
+ char *langtable_nl[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Forceer enkele kanaalmodes en set-opties",
+ /* LNG_ENFORCE_SYNTAX */
+ "Syntax: \002ENFORCE \037kanaal\037 [\037wat\037]\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Forceer enkele kannalmodes en set-opties. De \037kanaal\037 optie\n"
+ "geeft aan op welk kanaal de modes en opties geforceerd moeten\n"
+ "worden. De \037wat\037 optie geeft aan welke modes en opties\n"
+ "geforceerd moeten worden; dit kan SET, SECUREOPS, RESTRICTED,\n"
+ "MODES, of +R zijn. Indien weggelaten is dit standaard SET.\n"
+ " \n"
+ "Als er voor \037wat\037 SET wordt ingevuld, zullen SECUREOPS en\n"
+ "RESTRICTED geforceerd worden op de gebruikers in het kanaal,\n"
+ "maar alleen als die opties aangezet zijn voor het kanaal. Als\n"
+ "SECUREOPS of RESTRICTED wordt gegeven voor \037wat\037 zal die optie\n"
+ "altijd geforceerd worden, ook als die niet is aangezet.",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "Als er voor \037wat\037 MODES wordt ingevuld, zal kanaalmode +R worden\n"
+ "geforceerd, als die op het kanaal aan staat. Als +R wordt ingevuld,\n"
+ "zal kanaalmode +R worden geforceerd, maar ook als die niet aan"
+ "staat voor het kanaal. Als +R niet aan staat, zullen alle ook\n"
+ "gebanned worden om te zorgen dat ze niet opnieuw het kanaal binnen\n"
+ "kunnen komen.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "Als er voor \037wat\037 MODES wordt ingevuld, zal er niks gebeuren.\n"
+ "Normaal gesproken wordt er een kanaalmode geforceerd die op deze\n"
+ "server niet ondersteund wordt. Als +R wordt ingevuld voor \037wat\037\n"
+ "zullen alle gebruikers die in het kanaal zitten maar zich niet\n"
+ "hebben geidentificeerd voor hun nick uit het kanaal gekicked en\n"
+ "verbannen worden.",
+ /* LNG_CHAN_RESPONSE */
+ "Enforced %s"
+ };
+
+ /* German (DE) */
+ char *langtable_de[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Erzwingt verschieden Modes und SET Optionen",
+ /* LNG_ENFORCE_SYNTAX */
+ "Syntax: \002ENFORCE \037Channel\037 [\037was\037]\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Erzwingt verschieden Modes und SET Optionen. Die \037Channel\037\n"
+ "Option zeigt dir den Channel an, indem Modes und Optionen\n"
+ "zu erzwingen sind. Die \037was\037 Option zeigt dir welche Modes\n"
+ "und Optionen zu erzwingen sind. Die können nur SET, SECUREOPS,\n"
+ "RESTRICTED, MODES oder +R sein.Default ist SET.\n"
+ " \n"
+ "Wenn \037was\037 SET ist, wird SECUREOPS und RESTRICTED\n"
+ "auf die User die z.Z.in Channel sind erzwungen, wenn sie AN sind.\n"
+ "Benutze SECUREOPS oder RESTRICTED , um die Optionen einzeln\n"
+ "zu erzwingen, also wenn sie nicht eingeschaltet sind.",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "Wenn \037was\037 MODES ist, wird das ChannelMode +R erzwungen\n"
+ "falls an. Wenn \037was\037 +R ist, wird +R erzwungen aber eben\n"
+ "wenn noch nicht als Channel-Mode ist. Wenn +R noch nicht als\n"
+ "Channel-Mode war werden alle User aus den Channel gebannt um\n"
+ "sicher zu sein das sie nicht rejoinen.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "Wenn \037was\037 MODES ist, wird nichts erzwungen weil es MODES seine\n"
+ "können die dein IRCD nicht unterstützt. Wenn \037was\037 +R ist\n"
+ "oder ein Modes was auf ein anderen IRCD gleich +R ist, wird es\n"
+ "erzwungen. Alle User die nicht für deren Nicknamen identifiziert\n"
+ "sind werden aus den Channel gekickt und gebannt.",
+ /* LNG_CHAN_RESPONSE */
+ "Erzwungen %s"
+ };
+
+ /* Portuguese (PT) */
+ char *langtable_pt[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Verifica o cumprimento de vários modos de canal e opções ajustadas",
+ /* LNG_ENFORCE_SYNTAX */
+ "Sintaxe: \002ENFORCE \037canal\037 [\037opção\037]\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Verifica o cumprimento de vários modos de canal e opções ajustadas.\n"
+ "O campo \037canal\037 indica qual canal deve ter os modos e opções verificadas\n"
+ "O campo \037opção\037 indica quais modos e opções devem ser verificadas,\n"
+ "e pode ser: SET, SECUREOPS, RESTRICTED, MODES ou +R\n"
+ "Quando deixado em branco, o padrão é SET.\n"
+ " \n"
+ "Se \037opção\037 for SET, serão verificadas as opções SECUREOPS e RESTRICTED\n"
+ "para usuários que estiverem no canal, caso elas estejam ativadas. Use\n"
+ "SECUREOPS para verificar a opção SECUREOPS, mesmo que ela não esteja ativada\n"
+ "Use RESTRICTED para verificar a opção RESTRICTED, mesmo que ela não esteja\n"
+ "ativada.",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "Se \037opção\037 for MODES, será verificado o modo de canal +R caso ele\n"
+ "esteja ativado. Se +R for especificado para \037opção\037, o modo de canal\n"
+ "+R também será verificado, mesmo que ele não esteja ativado. Se ele não\n"
+ "estiver ativado, os usuários serão banidos para evitar que reentrem no canal.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "Se \037opção\037 for MODES, nada será verificado, visto que isto poderia\n"
+ "verificar modos que o IRCd atual não suporta. Se +R for especificado\n"
+ "para \037opção\037, um equivalente ao modo de canal +R em outros IRCds\n"
+ "será verificado. Todos os usuários que estão no canal, mas não estejam\n"
+ "identificados para seus nicks serão kickados e banidos do canal.",
+ /* LNG_CHAN_RESPONSE */
+ "Verificado %s"
+ };
+
+ /* Russian (RU) */
+ char *langtable_ru[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Ïåðåïðîâåðêà è óñòàíîâêà ðàçëè÷íûõ ðåæèìîâ è îïöèé êàíàëà",
+ /* LNG_ENFORCE_SYNTAX */
+ "Ñèíòàêñèñ: \002ENFORCE \037#êàíàë\037 \037ïàðàìåòð\037\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Ïåðåïðîâåðêà è óñòàíîâêà ðàçëè÷íûõ ðåæèìîâ è îïöèé êàíàëà.\n"
+ "\037Ïàðàìåòð\037 óêàçûâàåò êàêèå îïöèè èëè ðåæèìû êàíàëà äîëæíû áûòü\n"
+ "ïåðåïðîâåðåíû.  êà÷åñòâå ïàðàìåòðà ìîãóò áûòü óêàçàíû: SET, SECUREOPS,\n"
+ "RESTRICTED, MODES, èëè +R. Åñëè ïàðàìåòð íå óêàçàí, ïî-óìîë÷àíèþ áóäåò SET.\n"
+ " \n"
+ "Åñëè â êà÷åñòâå \037ïàðàìåòðà\037 óêàçàíî SET, áóäóò ïåðåïðîâåðåíû îïöèè\n"
+ "SECUREOPS è RESTRICTED îòíîñèòåëüíî ïîëüçîâàòåëåé íà óêàçàííîì êàíàëå\n"
+ "(ïðè óñëîâèè, ÷òî îïöèè âêëþ÷åíû). Îòäåëüíî óêàçàííûé ïàðàìåòð SECUREOPS\n"
+ "ïðèìåíèò îïöèþ SECUREOPS (äàæå åñëè îíà \037ÍÅ\037 óñòàíîâëåíà). Ïàðàìåòð\n"
+ "RESTRICTED ïðèìåíèò îïöèþ RESTRICTED (äàæå åñëè îíà \037ÍÅ\037 óñòàíîâëåíà)",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "Åñëè â êà÷åñòâå \037ïàðàìåòðà\037 óêàçàíî MODES, áóäåò ïåðåïðîâåðåí ðåæèì +R\n"
+ "(åñëè îí óñòàíîâëåí). Îòäåëüíî óêàçàííûé ïàðàìåòð \037+R\037 ïðèìåíèò\n"
+ "êàíàëüíûé ðåæèì +R, äàæå åñëè îí íå óñòàíîâëåí, è çàáàíèò âñåõ ïîëüçîâàòåëåé,\n"
+ "êîòîðûå íå èäåíòèôèöèðîâàëèñü ê ñâîåìó íèêó èëè íå èìåþò çàðåãèñòðèðîâàííîãî íèêà.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "Åñëè â êà÷åñòâå \037ïàðàìåòðà\037 óêàçàíî MODES, ïåðåïðîâåðêà îñóùåñòâëåíà\n"
+ "ÍÅ ÁÓÄÅÒ, òàê êàê òåêóùèé IRCD íå ïîääåðæèâàåò íåîáõîäèìûå ðåæèìû.\n"
+ "Îòäåëüíî óêàçàííûé ïàðàìåòð \037+R\037 ïðèìåíèò êàíàëüíûé ðåæèì, ýêâèâàëåíòíûé\n"
+ "ðåæèìó +R è çàáàíèò âñåõ ïîëüçîâàòåëåé, êîòîðûå íå èäåíòèôèöèðîâàëèñü ê ñâîåìó\n"
+ "íèêó èëè íå èìåþò çàðåãèñòðèðîâàííîãî íèêà.",
+ /* LNG_CHAN_RESPONSE */
+ "Ïåðåïðîâåðåíî: %s"
+ };
+
+ /* Italian (IT) */
+ char *langtable_it[] = {
+ /* LNG_CHAN_HELP */
+ " ENFORCE Forza diversi modi di canale ed opzioni SET",
+ /* LNG_ENFORCE_SYNTAX */
+ "Sintassi: \002ENFORCE \037canale\037 [\037cosa\037]\002",
+ /* LNG_CHAN_HELP_ENFORCE */
+ "Forza diversi modi di canale ed opzioni SET. Il parametro \037canale\037\n"
+ "indica il canale sul quale forzare i modi e le opzioni. Il parametro\n"
+ "\037cosa\037 indica i modi e le opzioni da forzare, e possono essere\n"
+ "qualsiasi delle opzioni SET, SECUREOPS, RESTRICTED, MODES, o +R.\n"
+ "Se non specificato, viene sottointeso SET.\n"
+ " \n"
+ "Se \037cosa\037 è SET, forzerà SECUREOPS e RESTRICTED sugli utenti\n"
+ "attualmente nel canale, se sono impostati. Specifica SECUREOPS per\n"
+ "forzare l'opzione SECUREOPS, anche se non è attivata. Specifica\n"
+ "RESTRICTED per forzare l'opzione RESTRICTED, anche se non è\n"
+ "attivata.",
+ /* LNG_CHAN_HELP_ENFORCE_R_ENABLED */
+ "Se \037cosa\037 è MODES, forzerà il modo del canale +R se è impostato.\n"
+ "Se +R è specificato per \037cosa\037, il modo del canale +R verrà\n"
+ "forzato, anche se non è impostato. Se non è impostato, gli utenti\n"
+ "verranno bannati per assicurare che non rientrino semplicemente.",
+ /* LNG_CHAN_HELP_ENFORCE_R_DISABLED */
+ "Se \037cosa\037 è MODES, niente verrà forzato, siccome forzerebbe\n"
+ "dei modi che l'ircd in uso non supporterebbe. Se +R è specificato\n"
+ "per \037cosa\037, un modo equivalente a +R sui altri ircd verrà\n"
+ "forzato. Tutti gli utenti presenti nel canale ma non identificati\n"
+ "per il loro nickname verranno bannati ed espulsi dal canale.\n",
+ /* LNG_CHAN_RESPONSE */
+ "Forzato %s"
+ };
+
+ moduleInsertLanguage(LANG_EN_US, LNG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_NL, LNG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_DE, LNG_NUM_STRINGS, langtable_de);
+ moduleInsertLanguage(LANG_PT, LNG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LNG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LNG_NUM_STRINGS, langtable_it);
+}
+
+/* EOF */
diff --git a/src/modules/cs_tban.c b/src/modules/cs_tban.c
new file mode 100644
index 000000000..9558c92fd
--- /dev/null
+++ b/src/modules/cs_tban.c
@@ -0,0 +1,253 @@
+/* cs_tban.c - Bans the user for a given length of time
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Based on the original module by Rob <rob@anope.org>
+ * Included in the Anope module pack since Anope 1.7.8
+ * Anope Coder: Rob <rob@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send bug reports to the Anope Coder instead of the module
+ * author, because any changes since the inclusion into anope
+ * are not supported by the original author.
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define AUTHOR "Rob"
+#define VERSION "$Id$"
+
+void myHelp(User * u);
+void myFullHelpSyntax(User * u);
+int myFullHelp(User * u);
+void mySendResponse(User * u, char *channel, char *mask, char *time);
+
+int do_tban(User * u);
+void addBan(Channel * c, time_t timeout, char *banmask);
+int delBan(int argc, char **argv);
+int canBanUser(Channel * c, User * u, User * u2);
+
+void mAddLanguages(void);
+
+#define LANG_NUM_STRINGS 4
+#define TBAN_HELP 0
+#define TBAN_SYNTAX 1
+#define TBAN_HELP_DETAIL 2
+#define TBAN_RESPONSE 3
+
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ int status = 0;
+
+ moduleSetChanHelp(myHelp);
+ c = createCommand("TBAN", do_tban, NULL, -1, -1, -1, -1, -1);
+ moduleAddHelp(c, myFullHelp);
+ status = moduleAddCommand(CHANSERV, c, MOD_HEAD);
+
+ mAddLanguages();
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ if (status != MOD_ERR_OK) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ /* module is unloading */
+}
+
+void myHelp(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, TBAN_HELP);
+}
+
+void myFullHelpSyntax(User * u)
+{
+ moduleNoticeLang(s_ChanServ, u, TBAN_SYNTAX);
+}
+
+int myFullHelp(User * u)
+{
+ myFullHelpSyntax(u);
+ notice(s_ChanServ, u->nick, "");
+ moduleNoticeLang(s_ChanServ, u, TBAN_HELP_DETAIL);
+ return MOD_CONT;
+}
+
+void mySendResponse(User * u, char *channel, char *mask, char *time)
+{
+ moduleNoticeLang(s_ChanServ, u, TBAN_RESPONSE, mask, channel, time);
+}
+
+int do_tban(User * u)
+{
+ char mask[BUFSIZE];
+ Channel *c;
+ User *u2 = NULL;
+
+ char *buffer = moduleGetLastBuffer();
+ char *chan;
+ char *nick;
+ char *time;
+
+ chan = myStrGetToken(buffer, ' ', 0);
+ nick = myStrGetToken(buffer, ' ', 1);
+ time = myStrGetToken(buffer, ' ', 2);
+
+ if (time && chan && nick) {
+
+ if (!(c = findchan(chan))) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_IN_USE, chan);
+ } else if (!(u2 = finduser(nick))) {
+ notice_lang(s_ChanServ, u, NICK_X_NOT_IN_USE, nick);
+ } else {
+ if (canBanUser(c, u, u2)) {
+ get_idealban(c->ci, u2, mask, sizeof(mask));
+ addBan(c, dotime(time), mask);
+ mySendResponse(u, chan, mask, time);
+ }
+ }
+ } else {
+ myFullHelpSyntax(u);
+ }
+ if (time)
+ free(time);
+ if (nick)
+ free(nick);
+ if (chan)
+ free(chan);
+
+ return MOD_CONT;
+}
+
+void addBan(Channel * c, time_t timeout, char *banmask)
+{
+ char *av[3];
+ char *cb[2];
+
+ cb[0] = c->name;
+ cb[1] = banmask;
+
+ av[0] = sstrdup("+b");
+ av[1] = banmask;
+
+ anope_cmd_mode(whosends(c->ci), c->name, "+b %s", av[1]);
+ chan_set_modes(s_ChanServ, c, 2, av, 1);
+
+ free(av[0]);
+ moduleAddCallback("tban", time(NULL) + timeout, delBan, 2, cb);
+}
+
+int delBan(int argc, char **argv)
+{
+ char *av[3];
+ Channel *c;
+
+ av[0] = sstrdup("-b");
+ av[1] = argv[1];
+
+ if ((c = findchan(argv[0])) && c->ci) {
+ anope_cmd_mode(whosends(c->ci), c->name, "-b %s", av[1]);
+ chan_set_modes(s_ChanServ, c, 2, av, 1);
+ }
+
+ free(av[0]);
+
+ return MOD_CONT;
+}
+
+int canBanUser(Channel * c, User * u, User * u2)
+{
+ ChannelInfo *ci;
+ int ok = 0;
+ if (!(ci = c->ci)) {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, c->name);
+ } else if (ci->flags & CI_VERBOTEN) {
+ notice_lang(s_ChanServ, u, CHAN_X_FORBIDDEN, c->name);
+ } else if (!check_access(u, ci, CA_BAN)) {
+ notice_lang(s_ChanServ, u, ACCESS_DENIED);
+ } else if (ircd->except && is_excepted(ci, u2)) {
+ notice_lang(s_ChanServ, u, CHAN_EXCEPTED, u2->nick, ci->name);
+ } else if (ircd->protectedumode && is_protected(u2)) {
+ notice_lang(s_ChanServ, u, PERMISSION_DENIED);
+ } else {
+ ok = 1;
+ }
+
+ return ok;
+}
+
+
+void mAddLanguages(void)
+{
+ char *langtable_en_us[] = {
+ " TBAN Bans the user for a given length of time",
+ "Syntax: TBAN channel nick time",
+ "Bans the given user from a channel for a specified length of\n"
+ "time. If the ban is removed before by hand, it will NOT be replaced.",
+ "%s banned from %s, will auto-expire in %s"
+ };
+
+ char *langtable_nl[] = {
+ " TBAN Verban een gebruiker voor een bepaalde tijd",
+ "Syntax: TBAN kanaal nick tijd",
+ "Verbant de gegeven gebruiken van het gegeven kanaal voor de\n"
+ "gegeven tijdsduur. Als de verbanning eerder wordt verwijderd,\n"
+ "zal deze NIET worden vervangen.",
+ "%s verbannen van %s, zal verlopen in %s"
+ };
+
+ char *langtable_de[] = {
+ " TBAN Bant ein User für eine bestimmte Zeit aus ein Channel",
+ "Syntax: TBAN Channel Nickname Zeit",
+ "Bant ein User für eine bestimmte Zeit aus ein Channel\n"
+ "Wenn der Ban manuell entfernt wird, wird es NICHT ersetzt.",
+ "%s gebannt von %s, wird auto-auslaufen in %s"
+ };
+
+ char *langtable_pt[] = {
+ " TBAN Bane o usuário por um determinado período de tempo",
+ "Sintaxe: TBAN canal nick tempo",
+ "Bane de um canal o usuário especificado por um determinado período de\n"
+ "tempo. Se o ban for removido manualmente antes do tempo, ele não será recolocado.",
+ "%s foi banido do %s, irá auto-expirar em %s"
+ };
+
+ char *langtable_ru[] = {
+ " TBAN Áàíèò ïîëüçîâàòåëÿ íà óêàçàííûé ïðîìåæóòîê âðåìåíè",
+ "Ñèíòàêñèñ: TBAN #êàíàë íèê âðåìÿ",
+ "Áàíèò ïîëüçîâàòåëÿ íà óêàçàííûé ïðîìåæóòîê âðåìåíè â ñåêóíäàõ\n"
+ "Ïðèìå÷àíèå: óäàëåííûé âðó÷íóþ (äî ñâîåãî èñòå÷åíèÿ) áàí ÍÅ ÁÓÄÅÒ\n"
+ "ïåðåóñòàíîâëåí ñåðâèñàìè àâòîìàòè÷åñêè!",
+ "Óñòàíîâëåííûé áàí %s íà êàíàëå %s èñòå÷åò ÷åðåç %s ñåêóíä"
+ };
+
+ char *langtable_it[] = {
+ " TBAN Banna l'utente per un periodo di tempo specificato",
+ "Sintassi: TBAN canale nick tempo",
+ "Banna l'utente specificato da un canale per un periodo di tempo\n"
+ "specificato. Se il ban viene rimosso a mano prima della scadenza, NON verrà rimpiazzato.",
+ "%s bannato da %s, scadrà automaticamente tra %s"
+ };
+
+ moduleInsertLanguage(LANG_EN_US, LANG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_NL, LANG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_DE, LANG_NUM_STRINGS, langtable_de);
+ moduleInsertLanguage(LANG_PT, LANG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LANG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LANG_NUM_STRINGS, langtable_it);
+
+}
+
+
+/* EOF */
diff --git a/src/modules/demos/catserv/Makefile b/src/modules/demos/catserv/Makefile
new file mode 100644
index 000000000..5b2f4efa3
--- /dev/null
+++ b/src/modules/demos/catserv/Makefile
@@ -0,0 +1,9 @@
+SRCS= ircd_catserv.c \
+ catserv_messages.c \
+ meow.c \
+ purr.c
+
+TARGET=ircd_catserv
+
+include ../Makefile.sub
+
diff --git a/src/modules/demos/catserv/README b/src/modules/demos/catserv/README
new file mode 100644
index 000000000..c3d3f7084
--- /dev/null
+++ b/src/modules/demos/catserv/README
@@ -0,0 +1,4 @@
+This is an EXAMPLE module, it serves no real purpose.
+
+This module was broken down into multiple files to demonstrate how multiple files can be used.
+
diff --git a/src/modules/demos/catserv/catserv_extern.h b/src/modules/demos/catserv/catserv_extern.h
new file mode 100644
index 000000000..02c21addb
--- /dev/null
+++ b/src/modules/demos/catserv/catserv_extern.h
@@ -0,0 +1,11 @@
+#ifndef CATSERV_DEFS_H
+#define CATSERV_DEFS_H
+
+#ifdef _WIN32
+extern __declspec(dllexport) char *s_CatServ;
+#else
+E char *s_CatServ;
+#endif
+
+#endif
+
diff --git a/src/modules/demos/catserv/catserv_messages.c b/src/modules/demos/catserv/catserv_messages.c
new file mode 100644
index 000000000..e11235b4e
--- /dev/null
+++ b/src/modules/demos/catserv/catserv_messages.c
@@ -0,0 +1,14 @@
+#include "catserv_messages.h"
+#include "module.h"
+#include "meow.h"
+#include "purr.h"
+
+void addMessageList(void)
+{
+ Command *c;
+ c = createCommand("meow", do_meow, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(Catserv_cmdTable, c, MOD_UNIQUE);
+ c = createCommand("purr", do_purr, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(Catserv_cmdTable, c, MOD_UNIQUE);
+}
+
diff --git a/src/modules/demos/catserv/catserv_messages.h b/src/modules/demos/catserv/catserv_messages.h
new file mode 100644
index 000000000..bb3f82dd0
--- /dev/null
+++ b/src/modules/demos/catserv/catserv_messages.h
@@ -0,0 +1,10 @@
+#ifndef CATSERV_MESSAGES_H
+#define CATSERV_MESSAGES_H
+
+#include "module.h"
+
+CommandHash *Catserv_cmdTable[MAX_CMD_HASH];
+void addMessageList(void);
+
+#endif
+
diff --git a/src/modules/demos/catserv/ircd_catserv.c b/src/modules/demos/catserv/ircd_catserv.c
new file mode 100644
index 000000000..ae34d6161
--- /dev/null
+++ b/src/modules/demos/catserv/ircd_catserv.c
@@ -0,0 +1,112 @@
+/**
+ * Simple module to load up a client called CatServ and process commands for it
+ * This module is an example, and has no useful purpose!
+ *
+ * Please visit http://modules.anope.org for useful modules!
+ *
+ **/
+
+#include "module.h"
+#include "catserv_messages.h"
+
+#define AUTHOR "Anope"
+#define VERSION "$Id$"
+
+int my_privmsg(char *source, int ac, char **av);
+
+void addClient(char *nick, char *realname);
+void delClient(void);
+void catserv(User * u, char *buf);
+
+char *s_CatServ = "CatServ";
+
+int AnopeInit(int argc, char **argv)
+{
+ Message *msg = NULL;
+ int status;
+#ifdef IRC_UNREAL32
+ if (UseTokens) {
+ msg = createMessage("!", my_privmsg);
+ } else {
+ msg = createMessage("PRIVMSG", my_privmsg);
+ }
+#else
+ msg = createMessage("PRIVMSG", my_privmsg);
+#endif
+ status = moduleAddMessage(msg, MOD_HEAD);
+ if (status == MOD_ERR_OK) {
+ addClient(s_CatServ, "meow!");
+ addMessageList();
+ }
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ alog("ircd_catserv.so: loaded, message status [%d]", status);
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ delClient();
+}
+
+int my_privmsg(char *source, int ac, char **av)
+{
+ User *u;
+ char *s;
+
+ /* First, some basic checks */
+ if (ac != 2)
+ return MOD_CONT; /* bleh */
+ if (!(u = finduser(source))) {
+ return MOD_CONT;
+ } /* non-user source */
+ if (*av[0] == '#') {
+ return MOD_CONT;
+ }
+ /* Channel message */
+ /* we should prolly honour the ignore list here, but i cba for this... */
+ s = strchr(av[0], '@');
+ if (s) {
+ *s++ = 0;
+ if (stricmp(s, ServerName) != 0)
+ return MOD_CONT;
+ }
+ if ((stricmp(av[0], s_CatServ)) == 0) { /* its for US! */
+ catserv(u, av[1]);
+ return MOD_STOP;
+ } else { /* ok it isnt us, let the old code have it */
+ return MOD_CONT;
+ }
+}
+
+void addClient(char *nick, char *realname)
+{
+ anope_cmd_bot_nick(nick, "catserv", "meow.meow.land", realname, "+");
+}
+
+void delClient(void)
+{
+ anope_cmd_quit(s_CatServ, "QUIT :Module Unloaded!");
+}
+
+/*****************************************************************************/
+/* Main CatServ routine. */
+void catserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, "")))
+ s = "\1";
+ notice(s_CatServ, u->nick, "\1PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_CatServ, u, SERVICE_OFFLINE, s_CatServ);
+ } else {
+ mod_run_cmd(s_CatServ, u, Catserv_cmdTable, cmd);
+ }
+}
+
diff --git a/src/modules/demos/catserv/makefile.win32 b/src/modules/demos/catserv/makefile.win32
new file mode 100644
index 000000000..638704440
--- /dev/null
+++ b/src/modules/demos/catserv/makefile.win32
@@ -0,0 +1,4 @@
+SRCS=ircd_catserv.c purr.c catserv_messages.c meow.c
+TARGET=ircd_catserv.dll
+
+include ..\Makefile.sub.win32
diff --git a/src/modules/demos/catserv/meow.c b/src/modules/demos/catserv/meow.c
new file mode 100644
index 000000000..9279eec0b
--- /dev/null
+++ b/src/modules/demos/catserv/meow.c
@@ -0,0 +1,9 @@
+#include "meow.h"
+
+#include "catserv_extern.h"
+
+int do_meow(User * u) {
+ notice(s_CatServ, u->nick, "MEOW!");
+ return MOD_STOP;
+}
+
diff --git a/src/modules/demos/catserv/meow.h b/src/modules/demos/catserv/meow.h
new file mode 100644
index 000000000..0f28673a0
--- /dev/null
+++ b/src/modules/demos/catserv/meow.h
@@ -0,0 +1,9 @@
+#ifndef CATSERV_MEOW_H
+#define CATSERV_MEOW_H
+
+#include "module.h"
+
+int do_meow(User * u);
+
+#endif
+
diff --git a/src/modules/demos/catserv/purr.c b/src/modules/demos/catserv/purr.c
new file mode 100644
index 000000000..5a39dc26e
--- /dev/null
+++ b/src/modules/demos/catserv/purr.c
@@ -0,0 +1,8 @@
+#include "purr.h"
+#include "catserv_extern.h"
+
+int do_purr(User * u)
+{
+ notice(s_CatServ, u->nick, "PURR!");
+ return MOD_STOP;
+}
diff --git a/src/modules/demos/catserv/purr.h b/src/modules/demos/catserv/purr.h
new file mode 100644
index 000000000..a92e421f6
--- /dev/null
+++ b/src/modules/demos/catserv/purr.h
@@ -0,0 +1,9 @@
+#ifndef CATSERV_PURR_H
+#define CATSERV_PURR_H
+
+#include "module.h"
+
+int do_purr(User * u);
+
+#endif
+
diff --git a/src/modules/demos/events.c b/src/modules/demos/events.c
new file mode 100644
index 000000000..dad0fd0e6
--- /dev/null
+++ b/src/modules/demos/events.c
@@ -0,0 +1,82 @@
+/**
+ * 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 "$Id$"
+
+int my_nick(char *source, int ac, char **av);
+int my_save(int argc, char **argv);
+int do_moo(int argc, char **argv);
+
+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);
+
+
+ hook = createEventHook(EVENT_BOT_FANTASY, do_moo);
+ 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(int argc, char **argv)
+{
+ if(argc>=1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ alog("Saving the databases! has started");
+ } else {
+ alog("Saving the databases is complete");
+ }
+ }
+ return MOD_CONT;
+}
+
+/**
+ * command to be called when a EVENT_BOT_FANTASY event is recived.
+ * @param argc The paramater count for this event.
+ * @param argv[0] The cmd used.
+ * @param argv[1] The nick of the command user.
+ * @param argv[2] The channel name the command was used in.
+ * @param argv[3] The rest of the text after the command.
+ * @return MOD_CONT or MOD_STOP
+ **/
+int do_moo(int argc, char **argv) {
+ ChannelInfo *ci;
+ if(argc>=3) { /* We need at least 3 arguments */
+ if(stricmp(argv[0],"moo")==0) { /* is it meant for us? */
+ if((ci = cs_findchan(argv[2]))) { /* channel should always exist */
+ anope_cmd_privmsg(ci->bi->nick, ci->name, "%cACTION moo's at %s %c",1,argv[1],1);
+ return MOD_STOP; /* We've dealt with it, dont let others */
+ }
+ }
+ }
+ return MOD_CONT; /* guess it wasnt for us, pass it on */
+}
+
diff --git a/src/modules/demos/hs_conf.c b/src/modules/demos/hs_conf.c
new file mode 100644
index 000000000..45b4bb330
--- /dev/null
+++ b/src/modules/demos/hs_conf.c
@@ -0,0 +1,74 @@
+#include "module.h"
+
+#define AUTHOR "Anope"
+#define VERSION "1"
+
+/**
+ * Default setting to be used if no confing value is found
+ **/
+#define DEFAULT_SETTING "moo"
+
+int mShowSetting(User *u);
+int mReadConfig(int argc, char **argv);
+
+char *setting;
+
+int AnopeInit(int argc, char **argv) {
+ Command *c;
+ EvtHook *hook;
+ int status = 0;
+
+ setting = NULL;
+
+ mReadConfig(0,NULL);
+
+ c = createCommand("SHOW",mShowSetting,NULL,-1,-1,-1,-1,-1);
+ status = moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ hook = createEventHook(EVENT_RELOAD, mReadConfig);
+ status = moduleAddEventHook(hook);
+
+ if(status!=MOD_ERR_OK) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+/**
+ * free the globals when we close
+ **/
+void AnopeFini(void) {
+ if(setting)
+ free(setting);
+}
+
+/**
+ * Simple function to show the user the current config setting
+ **/
+int mShowSetting(User *u) {
+ notice(s_HostServ,u->nick,"Setting in use is [%s]",setting);
+ return MOD_CONT;
+}
+
+/**
+ * Load the config setting up, this will be called whenever
+ * the EVENT_RELOAD event is recived.
+ **/
+int mReadConfig(int argc, char **argv) {
+ char *tmp=NULL;
+ Directive d[] = {{"HSConfigSetting", {{PARAM_STRING, PARAM_RELOAD, &tmp}}}};
+ moduleGetConfigDirective(d);
+
+ if(setting) {
+ free(setting);
+ }
+ if(tmp) {
+ setting = tmp;
+ } else {
+ setting = sstrdup(DEFAULT_SETTING);
+ }
+ return MOD_CONT;
+}
+
+
+/* EOF */
diff --git a/src/modules/demos/hs_moo.c b/src/modules/demos/hs_moo.c
new file mode 100644
index 000000000..b65e83bb6
--- /dev/null
+++ b/src/modules/demos/hs_moo.c
@@ -0,0 +1,119 @@
+/**
+ * This is an EXAMPLE module, which adds the "moo" command to HostServ
+ *
+ * This command does NOT do anything useful at all!
+ *
+ * Please visit http://modules.anope.org for useful modules!
+ *
+ **/
+#include "module.h"
+
+#define AUTHOR "Anope" /* Set the Author for a modinfo reply */
+#define VERSION "$Id$" /* Set the version for a modinfo reply */
+
+int hs_moo_show(User * u); /* Function to use when a /hs moo command is recived */
+int test(int argc, char **argv);
+void myHostServHelp(User *u); /* Function to display out help in a /hs help response */
+int myHostServMooHelp(User *u); /* Function to display help to _everyone_ when a /hs help moo is called*/
+int myHostServMooRegHelp(User *u); /* Function to display extra help to regular-users when a /hs help moo is called*/
+int myHostServMooOperHelp(User *u); /* Function to display extra help to opers when a /hs help moo is called*/
+int myHostServMooAdminHelp(User *u); /* Function to display extra help to admins when a /hs help moo is called*/
+int myHostServMooRootHelp(User *u); /* Function to display extra help to roors when a /hs help moo is called*/
+
+int AnopeInit(int argc, char **argv) /* This will be executed when the module is loaded */
+{
+ Command *c; /* Pointer to a Command */
+ int status = 0; /* the status of our new command */
+ c = createCommand("moo", hs_moo_show, NULL, -1, -1, -1, -1, -1); /* Create a new command "moo" pointing to hs_moo */
+
+ moduleAddHelp(c,myHostServMooHelp); /* add help for all users to this command */
+ moduleAddRegHelp(c,myHostServMooRegHelp); /* add extra regular-user only help to this command */
+ moduleAddOperHelp(c,myHostServMooOperHelp); /* add extra oper only help to this command */
+ moduleAddAdminHelp(c,myHostServMooAdminHelp); /* add extra admin only help to this command */
+ moduleAddRootHelp(c,myHostServMooRootHelp); /* add extra root only help to this command */
+
+ moduleSetHostHelp(myHostServHelp); /* add us to the .hs help list */
+
+ status = moduleAddCommand(HOSTSERV, c, MOD_HEAD); /* Add the command to the HOSTSERV cmd table */
+
+ /* Check if we have any argv's */
+ if(argc>0) {
+ /* we do, the first will be the nick of the person modload'ing us */
+ /* or NULL if we were auto-loaded */
+ if(argv[0]) {
+ alog("hs_moo was modloaded by: [%s]",argv[0]);
+ } else {
+ alog("hs_moo was automatically loaded by anope");
+ }
+ }
+ alog("hs_moo.so: Add Command 'moo' Status: %d",status); /* Log the command being added */
+
+ moduleAddCallback("test",time(NULL)+dotime("15s"),test,0,NULL); /* set a call-back function to exec in 3 mins time */
+ moduleDelCallback("test");
+ moduleAddAuthor(AUTHOR); /* tell Anope about the author */
+ moduleAddVersion(VERSION); /* Tell Anope about the verison */
+
+ if(status!=MOD_ERR_OK) {
+ return MOD_STOP;
+ }
+ return MOD_CONT;
+}
+
+int hs_moo_show(User * u)
+{
+ notice(s_HostServ, u->nick, "MOO! - This command was loaded via a module!"); /* Just notice the user */
+ return MOD_STOP; /* MOD_STOP means we will NOT pass control back to other */
+} /* modules waiting to handle the /hs moo command! */
+
+int test(int argc, char **argv) {
+ alog("CallBack from hs_moo with %d paramaters",argc);
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ /* module is unloading */
+}
+
+/***************************************************************************************************************************************/
+/* The code below here shows various ways of dealing with the module help system */
+/***************************************************************************************************************************************/
+
+void myHostServHelp(User *u) {
+ notice(s_HostServ,u->nick, " MOO Moo's at the user!"); /* this will appear in the help list */
+}
+
+int myHostServMooHelp(User *u) {
+ notice(s_HostServ,u->nick,"Syntax: Moo"); /* this will be sent to everyone who does /msg hostserv help moo */
+ notice(s_HostServ,u->nick,"This command is an example provided");
+ notice(s_HostServ,u->nick,"by the Anope development team.");
+ return MOD_CONT; /* allow any other module's with help for /hs moo to run */
+}
+
+int myHostServMooRootHelp(User *u) { /* this will only be sent to ROOTS ONLY who /msg hostserv moo */
+ myHostServMooAdminHelp(u); /* this line lets us show roots the ADMIN help as well as the root help */
+ notice(s_HostServ,u->nick,"Only roots will see this part of the help");
+ return MOD_CONT;
+}
+
+int myHostServMooAdminHelp(User *u) { /* this will only be sent to ADMINS ONLY who /msg hostserv moo */
+ myHostServMooOperHelp(u); /* this line lets us show admins the OPER help as well as the admin help */
+ notice(s_HostServ,u->nick,"Only admins will see this part of the help");
+ notice(s_HostServ,u->nick,"why not visit us on www.anope.org ?");
+ return MOD_CONT;
+}
+
+int myHostServMooOperHelp(User *u) { /* this will only be sent to OPERS ONLY who /msg hostserv moo */
+ notice(s_HostServ,u->nick,"Only opers will see this part of the help");
+ notice(s_HostServ,u->nick,"for more help/support with modules");
+ notice(s_HostServ,u->nick,"visit us on irc.anope.org #anope! :)");
+ return MOD_CONT;
+}
+
+int myHostServMooRegHelp(User *u) { /* this will only be sent to REGULAR USERS ONLY who /msg hostserv moo */
+ notice(s_HostServ,u->nick,"Only non-opers will see this part of the help");
+ notice(s_HostServ,u->nick,"as we've left it hidden from opers");
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/modules/dummy/Makefile b/src/modules/dummy/Makefile
new file mode 100644
index 000000000..ec93af36d
--- /dev/null
+++ b/src/modules/dummy/Makefile
@@ -0,0 +1,6 @@
+all: DUMMY
+
+DUMMY:
+clean:
+distclean:
+install:
diff --git a/src/modules/hs_request.c b/src/modules/hs_request.c
new file mode 100644
index 000000000..dde94070c
--- /dev/null
+++ b/src/modules/hs_request.c
@@ -0,0 +1,986 @@
+/* hs_request.c - Add request and activate functionality to HostServ,
+ * along with adding +req as optional param to HostServ list.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Based on the original module by Rob <rob@anope.org>
+ * Included in the Anope module pack since Anope 1.7.11
+ * Anope Coder: GeniusDex <geniusdex@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send bug reports to the Anope Coder instead of the module
+ * author, because any changes since the inclusion into anope
+ * are not supported by the original author.
+ */
+
+#include "module.h"
+
+#define AUTHOR "Rob"
+#define VERSION "$Id$"
+
+/* Configuration variables */
+int HSRequestMemoUser = 0;
+int HSRequestMemoOper = 0;
+int HSRequestMemoSetters = 0;
+char *HSRequestDBName = NULL;
+
+#define HSREQ_DEFAULT_DBNAME "hs_request.db"
+
+/* Language defines */
+#define LNG_NUM_STRINGS 21
+
+#define LNG_REQUEST_SYNTAX 0
+#define LNG_REQUESTED 1
+#define LNG_REQUEST_WAIT 2
+#define LNG_REQUEST_MEMO 3
+#define LNG_ACTIVATE_SYNTAX 4
+#define LNG_ACTIVATED 5
+#define LNG_ACTIVATE_MEMO 6
+#define LNG_REJECT_SYNTAX 7
+#define LNG_REJECTED 8
+#define LNG_REJECT_MEMO 9
+#define LNG_REJECT_MEMO_REASON 10
+#define LNG_NO_REQUEST 11
+#define LNG_HELP 12
+#define LNG_HELP_SETTER 13
+#define LNG_HELP_REQUEST 14
+#define LNG_HELP_ACTIVATE 15
+#define LNG_HELP_ACTIVATE_MEMO 16
+#define LNG_HELP_REJECT 17
+#define LNG_HELP_REJECT_MEMO 18
+#define LNG_WAITING_SYNTAX 19
+#define LNG_HELP_WAITING 20
+
+int hs_do_request(User * u);
+int hs_do_activate(User * u);
+int hs_do_reject(User * u);
+int hs_do_list_out(User * u);
+
+int hs_help_request(User * u);
+int hs_help_activate(User * u);
+int hs_help_reject(User * u);
+int hs_help_waiting(User * u);
+void hs_help(User * u);
+
+void my_add_host_request(char *nick, char *vIdent, char *vhost,
+ char *creator, int32 tmp_time);
+int my_isvalidchar(const char c);
+void my_memo_lang(User * u, char *name, int z, int number, ...);
+void req_send_memos(User * u, char *vHost);
+void show_list(User * u);
+int hs_do_waiting(User * u);
+int ns_do_drop(User * u);
+
+void hsreq_save_db(void);
+void hsreq_load_db(void);
+int hsreqevt_db_saving(int argc, char **argv);
+int hsreqevt_db_backup(int argc, char **argv);
+
+void my_load_config(void);
+void my_add_languages(void);
+
+HostCore *hs_request_head;
+
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ EvtHook *hook;
+
+ c = createCommand("request", hs_do_request, nick_identified, -1, -1,
+ -1, -1, -1);
+ moduleAddHelp(c, hs_help_request);
+ moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ c = createCommand("activate", hs_do_activate, is_host_setter, -1, -1,
+ -1, -1, -1);
+ moduleAddHelp(c, hs_help_activate);
+ moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ c = createCommand("reject", hs_do_reject, is_host_setter, -1, -1, -1,
+ -1, -1);
+ moduleAddHelp(c, hs_help_reject);
+ moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ c = createCommand("waiting", hs_do_waiting, is_host_setter, -1, -1, -1,
+ -1, -1);
+ moduleAddHelp(c, hs_help_waiting);
+ moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ c = createCommand("list", hs_do_list_out, is_services_oper, -1, -1, -1,
+ -1, -1);
+ moduleAddCommand(HOSTSERV, c, MOD_HEAD);
+
+ c = createCommand("drop", ns_do_drop, NULL, -1, -1, -1, -1, -1);
+ moduleAddCommand(NICKSERV, c, MOD_HEAD);
+
+ hook = createEventHook(EVENT_DB_SAVING, hsreqevt_db_saving);
+ moduleAddEventHook(hook);
+
+ hook = createEventHook(EVENT_DB_BACKUP, hsreqevt_db_backup);
+ moduleAddEventHook(hook);
+
+ moduleSetHostHelp(hs_help);
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ my_load_config();
+ my_add_languages();
+ hs_request_head = NULL;
+
+ if (debug)
+ alog("[hs_request] Loading database...");
+ hsreq_load_db();
+ alog("hs_request loaded");
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ if (debug)
+ alog("[hs_request] Saving database...");
+ hsreq_save_db();
+
+ /* Clean up all open host requests */
+ while (hs_request_head)
+ hs_request_head = deleteHostCore(hs_request_head, NULL);
+
+ free(HSRequestDBName);
+ alog("hs_request un-loaded");
+}
+
+int hs_do_request(User * u)
+{
+ char *cur_buffer;
+ char *nick;
+ char *rawhostmask;
+ char hostmask[HOSTMAX];
+ NickAlias *na;
+ int32 tmp_time;
+ char *s;
+ char *vIdent = NULL;
+ time_t now = time(NULL);
+
+ cur_buffer = moduleGetLastBuffer();
+ nick = u->nick;
+ rawhostmask = myStrGetToken(cur_buffer, ' ', 0);
+
+ if (!nick || !rawhostmask) {
+ if (rawhostmask)
+ free(rawhostmask);
+ moduleNoticeLang(s_HostServ, u, LNG_REQUEST_SYNTAX);
+ return MOD_CONT;
+ }
+
+ vIdent = myStrGetOnlyToken(rawhostmask, '@', 0); /* Get the first substring, @ as delimiter */
+ if (vIdent) {
+ rawhostmask = myStrGetTokenRemainder(rawhostmask, '@', 1); /* get the remaining string */
+ if (!rawhostmask) {
+ moduleNoticeLang(s_HostServ, u, LNG_REQUEST_SYNTAX);
+ free(vIdent);
+ return MOD_CONT;
+ }
+ if (strlen(vIdent) > USERMAX - 1) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENTTOOLONG, USERMAX);
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ } else {
+ for (s = vIdent; *s; s++) {
+ if (!my_isvalidchar(*s)) {
+ notice_lang(s_HostServ, u, HOST_SET_IDENT_ERROR);
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ }
+ }
+ }
+ if (!ircd->vident) {
+ notice_lang(s_HostServ, u, HOST_NO_VIDENT);
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ }
+ }
+ if (strlen(rawhostmask) < HOSTMAX - 1) {
+ snprintf(hostmask, HOSTMAX, "%s", rawhostmask);
+ } else {
+ notice_lang(s_HostServ, u, HOST_SET_TOOLONG, HOSTMAX);
+ if (vIdent)
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ }
+
+ if (!isValidHost(hostmask, 3)) {
+ notice_lang(s_HostServ, u, HOST_SET_ERROR);
+ if (vIdent)
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ }
+
+ tmp_time = time(NULL);
+ if ((na = findnick(nick))) {
+ if (HSRequestMemoOper || HSRequestMemoSetters) {
+ if (MSSendDelay > 0 && u
+ && u->lastmemosend + MSSendDelay > now) {
+ moduleNoticeLang(s_HostServ, u, LNG_REQUEST_WAIT,
+ MSSendDelay);
+ u->lastmemosend = now;
+ if (vIdent)
+ free(vIdent);
+ free(rawhostmask);
+ return MOD_CONT;
+ }
+ }
+ my_add_host_request(nick, vIdent, hostmask, u->nick, tmp_time);
+
+ moduleNoticeLang(s_HostServ, u, LNG_REQUESTED);
+ req_send_memos(u, hostmask);
+ alog("New vHost Requested by %s", nick);
+ } else {
+ notice_lang(s_HostServ, u, HOST_NOREG, nick);
+ }
+
+ if (vIdent)
+ free(vIdent);
+ free(rawhostmask);
+
+ return MOD_CONT;
+}
+
+void my_memo_lang(User * u, char *name, int z, int number, ...)
+{
+ va_list va;
+ char buffer[4096], outbuf[4096];
+ char *fmt = NULL;
+ int lang = LANG_EN_US;
+ char *s, *t, *buf;
+ User *u2;
+
+ if ((mod_current_module_name)
+ && (!mod_current_module
+ || strcmp(mod_current_module_name, mod_current_module->name)))
+ mod_current_module = findModule(mod_current_module_name);
+
+ u2 = finduser(name);
+ /* Find the users lang, and use it if we cant */
+ if (u2 && u2->na && u2->na->nc)
+ lang = u2->na->nc->language;
+
+ /* If the users lang isnt supported, drop back to enlgish */
+ if (mod_current_module->lang[lang].argc == 0)
+ lang = LANG_EN_US;
+
+ /* If the requested lang string exists for the language */
+ if (mod_current_module->lang[lang].argc > number) {
+ fmt = mod_current_module->lang[lang].argv[number];
+
+ buf = sstrdup(fmt);
+ s = buf;
+ while (*s) {
+ t = s;
+ s += strcspn(s, "\n");
+ if (*s)
+ *s++ = '\0';
+ strscpy(outbuf, t, sizeof(outbuf));
+
+ va_start(va, number);
+ vsnprintf(buffer, 4095, outbuf, va);
+ va_end(va);
+ memo_send(u, name, buffer, z);
+ }
+ free(buf);
+ } else {
+ alog("%s: INVALID language string call, language: [%d], String [%d]", mod_current_module->name, lang, number);
+ }
+}
+
+
+void req_send_memos(User * u, char *vHost)
+{
+ int i;
+ int z = 2;
+
+ if (checkDefCon(DEFCON_NO_NEW_MEMOS))
+ return;
+
+ if (HSRequestMemoOper == 1) {
+ for (i = 0; i < servopers.count; i++) {
+ my_memo_lang(u, (((NickCore *) servopers.list[i])->display), z,
+ LNG_REQUEST_MEMO, vHost);
+ }
+ for (i = 0; i < servadmins.count; i++) {
+ my_memo_lang(u, (((NickCore *) servadmins.list[i])->display),
+ z, LNG_REQUEST_MEMO, vHost);
+ }
+ for (i = 0; i < RootNumber; i++) {
+ my_memo_lang(u, ServicesRoots[i], z, LNG_REQUEST_MEMO, vHost);
+ }
+ }
+ if (HSRequestMemoSetters == 1) {
+ for (i = 0; i < HostNumber; i++) {
+ my_memo_lang(u, HostSetters[i], z, LNG_REQUEST_MEMO, vHost);
+ }
+ }
+}
+
+int ns_do_drop(User * u)
+{
+ HostCore *tmp;
+ boolean found = false;
+ NickAlias *na;
+
+ na = findnick(u->nick);
+ tmp = findHostCore(hs_request_head, u->nick, &found);
+
+ if (found && na)
+ hs_request_head = deleteHostCore(hs_request_head, tmp);
+
+ return MOD_CONT;
+}
+
+int hs_do_reject(User * u)
+{
+ char *cur_buffer;
+ char *nick;
+ char *reason;
+ HostCore *tmp, *hc;
+ boolean found = false;
+
+ cur_buffer = moduleGetLastBuffer();
+ nick = myStrGetToken(cur_buffer, ' ', 0);
+ reason = myStrGetTokenRemainder(cur_buffer, ' ', 1);
+
+ if (!nick) {
+ moduleNoticeLang(s_HostServ, u, LNG_REJECT_SYNTAX);
+ if (reason)
+ free(reason);
+ return MOD_CONT;
+ }
+
+ tmp = findHostCore(hs_request_head, nick, &found);
+ if (found) {
+ if (!tmp)
+ hc = hs_request_head;
+ else
+ hc = tmp->next;
+
+ if (HSRequestMemoUser) {
+ if (reason)
+ my_memo_lang(u, hc->nick, 2, LNG_REJECT_MEMO_REASON,
+ reason);
+ else
+ my_memo_lang(u, hc->nick, 2, LNG_REJECT_MEMO);
+ }
+
+ hs_request_head = deleteHostCore(hs_request_head, tmp);
+ moduleNoticeLang(s_HostServ, u, LNG_REJECTED, nick);
+ alog("Host Request for %s rejected by %s (%s)", nick, u->nick,
+ reason ? reason : "");
+ } else {
+ moduleNoticeLang(s_HostServ, u, LNG_NO_REQUEST, nick);
+ }
+
+ free(nick);
+ if (reason)
+ free(reason);
+
+ return MOD_CONT;
+}
+
+int hs_do_activate(User * u)
+{
+ char *cur_buffer;
+ char *nick;
+ NickAlias *na;
+ HostCore *tmp, *hc;
+ boolean found = false;
+
+ cur_buffer = moduleGetLastBuffer();
+ nick = myStrGetToken(cur_buffer, ' ', 0);
+
+ if (!nick) {
+ moduleNoticeLang(s_HostServ, u, LNG_ACTIVATE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if ((na = findnick(nick))) {
+ tmp = findHostCore(hs_request_head, nick, &found);
+ if (found) {
+ if (!tmp)
+ hc = hs_request_head;
+ else
+ hc = tmp->next;
+
+ addHostCore(hc->nick, hc->vIdent, hc->vHost, u->nick,
+ time(NULL));
+
+ if (HSRequestMemoUser)
+ my_memo_lang(u, hc->nick, 2, LNG_ACTIVATE_MEMO);
+
+ hs_request_head = deleteHostCore(hs_request_head, tmp);
+ moduleNoticeLang(s_HostServ, u, LNG_ACTIVATED, nick);
+ alog("Host Request for %s activated by %s", nick, u->nick);
+ } else {
+ moduleNoticeLang(s_HostServ, u, LNG_NO_REQUEST, nick);
+ }
+ } else {
+ notice_lang(s_HostServ, u, NICK_X_NOT_REGISTERED, nick);
+ }
+
+ free(nick);
+ return MOD_CONT;
+}
+
+
+void my_add_host_request(char *nick, char *vIdent, char *vhost,
+ char *creator, int32 tmp_time)
+{
+ HostCore *tmp;
+ boolean found = false;
+
+ if (!hs_request_head) {
+ hs_request_head =
+ createHostCorelist(hs_request_head, nick, vIdent, vhost,
+ creator, tmp_time);
+ } else {
+ tmp = findHostCore(hs_request_head, nick, &found);
+ if (!found) {
+ hs_request_head =
+ insertHostCore(hs_request_head, tmp, nick, vIdent, vhost,
+ creator, tmp_time);
+ } else {
+ hs_request_head = deleteHostCore(hs_request_head, tmp); /* delete the old entry */
+ my_add_host_request(nick, vIdent, vhost, creator, tmp_time); /* recursive call to add new entry */
+ }
+ }
+}
+
+int my_isvalidchar(const char c)
+{
+ if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))
+ || ((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
+ return 1;
+ else
+ return 0;
+}
+
+int hs_do_list_out(User * u)
+{
+ char *key;
+
+ key = moduleGetLastBuffer();
+ if (!key)
+ return MOD_CONT;
+
+ if (stricmp(key, "+req") != 0)
+ return MOD_CONT;
+
+ show_list(u);
+
+ return MOD_CONT;
+}
+
+int hs_do_waiting(User * u)
+{
+ show_list(u);
+
+ return MOD_CONT;
+}
+
+void show_list(User * u)
+{
+ struct tm *tm;
+ char buf[BUFSIZE];
+ int counter = 1;
+ int from = 0, to = 0;
+ int display_counter = 0;
+ HostCore *current;
+
+ current = hs_request_head;
+ while (current) {
+ if ((((counter >= from) && (counter <= to))
+ || ((from == 0) && (to == 0)))
+ && (display_counter < NSListMax)) {
+ display_counter++;
+ tm = localtime(&current->time);
+ strftime(buf, sizeof(buf),
+ getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
+ if (current->vIdent)
+ notice_lang(s_HostServ, u, HOST_IDENT_ENTRY, counter,
+ current->nick, current->vIdent, current->vHost,
+ current->creator, buf);
+ else
+ notice_lang(s_HostServ, u, HOST_ENTRY, counter,
+ current->nick, current->vHost,
+ current->creator, buf);
+ }
+ counter++;
+ current = current->next;
+ }
+ notice_lang(s_HostServ, u, HOST_LIST_FOOTER, display_counter);
+}
+
+int hs_help_request(User * u)
+{
+ moduleNoticeLang(s_HostServ, u, LNG_REQUEST_SYNTAX);
+ notice(s_HostServ, u->nick, " ");
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_REQUEST);
+
+ return MOD_CONT;
+}
+
+int hs_help_activate(User * u)
+{
+ if (is_host_setter(u)) {
+ moduleNoticeLang(s_HostServ, u, LNG_ACTIVATE_SYNTAX);
+ notice(s_HostServ, u->nick, " ");
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_ACTIVATE);
+ if (HSRequestMemoUser)
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_ACTIVATE_MEMO);
+ } else {
+ notice_lang(s_HostServ, u, NO_HELP_AVAILABLE, "ACTIVATE");
+ }
+
+ return MOD_CONT;
+}
+
+int hs_help_reject(User * u)
+{
+ if (is_host_setter(u)) {
+ moduleNoticeLang(s_HostServ, u, LNG_REJECT_SYNTAX);
+ notice(s_HostServ, u->nick, " ");
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_REJECT);
+ if (HSRequestMemoUser)
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_REJECT_MEMO);
+ } else {
+ notice_lang(s_HostServ, u, NO_HELP_AVAILABLE, "REJECT");
+ }
+
+ return MOD_CONT;
+}
+
+int hs_help_waiting(User * u)
+{
+ if (is_host_setter(u)) {
+ moduleNoticeLang(s_HostServ, u, LNG_WAITING_SYNTAX);
+ notice(s_HostServ, u->nick, " ");
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_WAITING);
+ } else {
+ notice_lang(s_HostServ, u, NO_HELP_AVAILABLE, "WAITING");
+ }
+
+ return MOD_CONT;
+}
+
+void hs_help(User * u)
+{
+ moduleNoticeLang(s_HostServ, u, LNG_HELP);
+ if (is_host_setter(u))
+ moduleNoticeLang(s_HostServ, u, LNG_HELP_SETTER);
+}
+void hsreq_load_db(void)
+{
+ FILE *fp;
+ char *filename;
+ char readbuf[1024];
+ char *nick, *vident, *vhost, *creator, *tmp;
+ int32 tmp_time;
+ char *buf;
+
+ if (HSRequestDBName)
+ filename = HSRequestDBName;
+ else
+ filename = HSREQ_DEFAULT_DBNAME;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ alog("[hs_request] Unable to open database ('%s') for reading",
+ filename);
+ return;
+ }
+
+ while (fgets(readbuf, 1024, fp)) {
+ buf = normalizeBuffer(readbuf);
+ if (buf || *buf) {
+ nick = myStrGetToken(buf, ':', 0);
+ vident = myStrGetToken(buf, ':', 1);
+ vhost = myStrGetToken(buf, ':', 2);
+ tmp = myStrGetToken(buf, ':', 3);
+ if (tmp) {
+ tmp_time = strtol(tmp, (char **) NULL, 16);
+ free(tmp);
+ } else {
+ tmp_time = 0;
+ }
+ creator = myStrGetToken(buf, ':', 4);
+ if (!nick || !vident || !vhost || !creator) {
+ alog("[hs_request] Error while reading database, skipping record");
+ continue;
+ }
+ if (stricmp(vident, "(null)") == 0) {
+ free(vident);
+ vident = NULL;
+ }
+ my_add_host_request(nick, vident, vhost, creator, tmp_time);
+ free(nick);
+ free(vhost);
+ free(creator);
+ if (vident)
+ free(vident);
+ }
+ free(buf);
+ }
+
+ fclose(fp);
+
+ if (debug)
+ alog("[hs_request] Succesfully loaded database");
+}
+
+void hsreq_save_db(void)
+{
+ FILE *fp;
+ char *filename;
+ char *vident;
+ HostCore *current;
+
+ if (HSRequestDBName)
+ filename = HSRequestDBName;
+ else
+ filename = HSREQ_DEFAULT_DBNAME;
+
+ fp = fopen(filename, "w");
+ if (!fp) {
+ alog("[hs_request] Unable to open database ('%s') for writing",
+ filename);
+ return;
+ }
+
+ current = hs_request_head;
+ while (current) {
+ vident = (current->vIdent ? current->vIdent : "(null)");
+ fprintf(fp, "%s:%s:%s:%X:%s\n", current->nick, vident,
+ current->vHost, (uint32) current->time, current->creator);
+ current = current->next;
+ }
+
+ fclose(fp);
+
+ if (debug)
+ alog("[hs_request] Succesfully saved database");
+}
+
+int hsreqevt_db_saving(int argc, char **argv)
+{
+ if ((argc >= 1) && (stricmp(argv[0], EVENT_START) == 0))
+ hsreq_save_db();
+
+ return MOD_CONT;
+}
+
+int hsreqevt_db_backup(int argc, char **argv)
+{
+ if ((argc >= 1) && (stricmp(argv[0], EVENT_START) == 0)) {
+ if (HSRequestDBName)
+ ModuleDatabaseBackup(HSRequestDBName);
+ else
+ ModuleDatabaseBackup(HSREQ_DEFAULT_DBNAME);
+ }
+
+ return MOD_CONT;
+}
+
+void my_load_config(void)
+{
+ int i;
+ char *tmp = NULL;
+
+ Directive confvalues[][1] = {
+ {{"HSRequestMemoUser",
+ {{PARAM_SET, PARAM_RELOAD, &HSRequestMemoUser}}}},
+ {{"HSRequestMemoOper",
+ {{PARAM_SET, PARAM_RELOAD, &HSRequestMemoOper}}}},
+ {{"HSRequestMemoSetters",
+ {{PARAM_SET, PARAM_RELOAD, &HSRequestMemoSetters}}}},
+ {{"HSRequestDBName", {{PARAM_STRING, PARAM_RELOAD, &tmp}}}}
+ };
+
+ for (i = 0; i < 4; i++)
+ moduleGetConfigDirective(confvalues[i]);
+
+ if (tmp) {
+ if (HSRequestDBName)
+ free(HSRequestDBName);
+ HSRequestDBName = sstrdup(tmp);
+ } else {
+ HSRequestDBName = sstrdup(HSREQ_DEFAULT_DBNAME);
+ }
+
+ if (debug)
+ alog("debug: [hs_request] Set config vars: MemoUser=%d MemoOper=%d MemoSetters=%d DBName='%s'", HSRequestMemoUser, HSRequestMemoOper, HSRequestMemoSetters, HSRequestDBName);
+}
+
+void my_add_languages(void)
+{
+ char *langtable_en_us[] = {
+ /* LNG_REQUEST_SYNTAX */
+ "Syntax: \002REQUEST \037vhost\037\002",
+ /* LNG_REQUESTED */
+ "Your vHost has been requested",
+ /* LNG_REQUEST_WAIT */
+ "Please wait %d seconds before requesting a new vHost",
+ /* LNG_REQUEST_MEMO */
+ "[auto memo] vHost \002%s\002 has been requested.",
+ /* LNG_ACTIVATE_SYNTAX */
+ "Syntax: \002ACTIVATE \037nick\037\002",
+ /* LNG_ACTIVATED */
+ "vHost for %s has been activated",
+ /* LNG_ACTIVATE_MEMO */
+ "[auto memo] Your requested vHost has been approved.",
+ /* LNG_REJECT_SYNTAX */
+ "Syntax: \002REJECT \037nick\037\002",
+ /* LNG_REJECTED */
+ "vHost for %s has been rejected",
+ /* LNG_REJECT_MEMO */
+ "[auto memo] Your requested vHost has been rejected.",
+ /* LNG_REJECT_MEMO_REASON */
+ "[auto memo] Your requested vHost has been rejected. Reason: %s",
+ /* LNG_NO_REQUEST */
+ "No request for nick %s found.",
+ /* LNG_HELP */
+ " REQUEST Request a vHost for your nick",
+ /* LNG_HELP_SETTER */
+ " ACTIVATE Approve the requested vHost of a user\n"
+ " REJECT Reject the requested vHost of a user\n"
+ " WAITING Convenience command for LIST +req",
+ /* LNG_HELP_REQUEST */
+ "Request the given vHost to be actived for your nick by the\n"
+ "network administrators. Please be patient while your request\n"
+ "is being considered.",
+ /* LNG_HELP_ACTIVATE */
+ "Activate the requested vHost for the given nick.",
+ /* LNG_HELP_ACTIVATE_MEMO */
+ "A memo informing the user will also be sent.",
+ /* LNG_HELP_REJECT */
+ "Reject the requested vHost for the given nick.",
+ /* LNG_HELP_REJECT_MEMO */
+ "A memo informing the user will also be sent.",
+ /* LNG_WAITING_SYNTAX */
+ "Syntax: \002WAITING\002",
+ /* LNG_HELP_WAITING */
+ "This command is provided for convenience. It is essentially\n"
+ "the same as performing a LIST +req ."
+ };
+
+ char *langtable_nl[] = {
+ /* LNG_REQUEST_SYNTAX */
+ "Gebruik: \002REQUEST \037vhost\037\002",
+ /* LNG_REQUESTED */
+ "Je vHost is aangevraagd",
+ /* LNG_REQUEST_WAIT */
+ "Wacht %d seconden voor je een nieuwe vHost aanvraagt",
+ /* LNG_REQUEST_MEMO */
+ "[auto memo] vHost \002%s\002 is aangevraagd.",
+ /* LNG_ACTIVATE_SYNTAX */
+ "Gebruik: \002ACTIVATE \037nick\037\002",
+ /* LNG_ACTIVATED */
+ "vHost voor %s is geactiveerd",
+ /* LNG_ACTIVATE_MEMO */
+ "[auto memo] Je aangevraagde vHost is geaccepteerd.",
+ /* LNG_REJECT_SYNTAX */
+ "Gebruik: \002REJECT \037nick\037\002",
+ /* LNG_REJECTED */
+ "vHost voor %s is afgekeurd",
+ /* LNG_REJECT_MEMO */
+ "[auto memo] Je aangevraagde vHost is afgekeurd.",
+ /* LNG_REJECT_MEMO_REASON */
+ "[auto memo] Je aangevraagde vHost is afgekeurd. Reden: %s",
+ /* LNG_NO_REQUEST */
+ "Geen aanvraag voor nick %s gevonden.",
+ /* LNG_HELP */
+ " REQUEST Vraag een vHost aan voor je nick",
+ /* LNG_HELP_SETTER */
+ " ACTIVATE Activeer de aangevraagde vHost voor een gebruiker\n"
+ " REJECT Keur de aangevraagde vHost voor een gebruiker af\n"
+ " WAITING Snelkoppeling naar LIST +req",
+ /* LNG_HELP_REQUEST */
+ "Verzoek de gegeven vHost te activeren voor jouw nick bij de\n"
+ "netwerk beheerders. Het kan even duren voordat je aanvraag\n"
+ "afgehandeld wordt.",
+ /* LNG_HELP_ACTIVATE */
+ "Activeer de aangevraagde vHost voor de gegeven nick.",
+ /* LNG_HELP_ACTIVATE_MEMO */
+ "Een memo die de gebruiker op de hoogste stelt zal ook worden verstuurd.",
+ /* LNG_HELP_REJECT */
+ "Keur de aangevraagde vHost voor de gegeven nick af.",
+ /* LNG_HELP_REJECT_MEMO */
+ "Een memo die de gebruiker op de hoogste stelt zal ook worden verstuurd.",
+ /* LNG_WAITING_SYNTAX */
+ "Gebruik: \002WAITING\002",
+ /* LNG_HELP_WAITING */
+ "Dit commando is beschikbaar als handigheid. Het is simpelweg\n"
+ "hetzelfde als LIST +req ."
+ };
+
+ char *langtable_pt[] = {
+ /* LNG_REQUEST_SYNTAX */
+ "Sintaxe: \002REQUEST \037vhost\037\002",
+ /* LNG_REQUESTED */
+ "Seu pedido de vHost foi encaminhado",
+ /* LNG_REQUEST_WAIT */
+ "Por favor, espere %d segundos antes de fazer um novo pedido de vHost",
+ /* LNG_REQUEST_MEMO */
+ "[Auto Memo] O vHost \002%s\002 foi solicitado.",
+ /* LNG_ACTIVATE_SYNTAX */
+ "Sintaxe: \002ACTIVATE \037nick\037\002",
+ /* LNG_ACTIVATED */
+ "O vHost para %s foi ativado",
+ /* LNG_ACTIVATE_MEMO */
+ "[Auto Memo] Seu pedido de vHost foi aprovado.",
+ /* LNG_REJECT_SYNTAX */
+ "Sintaxe: \002REJECT \037nick\037\002",
+ /* LNG_REJECTED */
+ "O vHost de %s foi recusado",
+ /* LNG_REJECT_MEMO */
+ "[Auto Memo] Seu pedido de vHost foi recusado.",
+ /* LNG_REJECT_MEMO_REASON */
+ "[Auto Memo] Seu pedido de vHost foi recusado. Motivo: %s",
+ /* LNG_NO_REQUEST */
+ "Nenhum pedido encontrado para o nick %s.",
+ /* LNG_HELP */
+ " REQUEST Request a vHost for your nick",
+ /* LNG_HELP_SETTER */
+ " ACTIVATE Aprova o pedido de vHost de um usuário\n"
+ " REJECT Recusa o pedido de vHost de um usuário\n"
+ " WAITING Comando para LISTAR +req",
+ /* LNG_HELP_REQUEST */
+ "Solicita a ativação do vHost fornecido em seu nick pelos\n"
+ "administradores da rede. Por favor, tenha paciência\n"
+ "enquanto seu pedido é analisado.",
+ /* LNG_HELP_ACTIVATE */
+ "Ativa o vHost solicitado para o nick fornecido.",
+ /* LNG_HELP_ACTIVATE_MEMO */
+ "Um memo informando o usuário também será enviado.",
+ /* LNG_HELP_REJECT */
+ "Recusa o pedido de vHost para o nick fornecido.",
+ /* LNG_HELP_REJECT_MEMO */
+ "Um memo informando o usuário também será enviado.",
+ /* LNG_WAITING_SYNTAX */
+ "Sintaxe: \002WAITING\002",
+ /* LNG_HELP_WAITING */
+ "Este comando é usado por conveniência. É essencialmente\n"
+ "o mesmo que fazer um LIST +req"
+ };
+
+ char *langtable_ru[] = {
+ /* LNG_REQUEST_SYNTAX */
+ "Ñèíòàêñèñ: \002REQUEST \037vHost\037\002",
+ /* LNG_REQUESTED */
+ "Âàø çàïðîñ íà vHost îòïðàâëåí.",
+ /* LNG_REQUEST_WAIT */
+ "Ïîæàëóéñòà, ïîäîæäèòå %d ñåêóíä, ïðåæäå ÷åì çàïðàøèâàòü íîâûé vHost",
+ /* LNG_REQUEST_MEMO */
+ "[àâòî-ñîîáùåíèå] Áûë çàïðîøåí vHost \002%s\002",
+ /* LNG_ACTIVATE_SYNTAX */
+ "Ñèíòàêñèñ: \002ACTIVATE \037íèê\037\002",
+ /* LNG_ACTIVATED */
+ "vHost äëÿ %s óñïåøíî àêòèâèðîâàí",
+ /* LNG_ACTIVATE_MEMO */
+ "[àâòî-ñîîáùåíèå] Çàïðàøèâàåìûé âàìè vHost óòâåðæäåí è àêòèâèðîâàí.",
+ /* LNG_REJECT_SYNTAX */
+ "Ñèíòàêñèñ: \002REJECT \037íèê\037\002",
+ /* LNG_REJECTED */
+ "vHost äëÿ %s îòêëîíåí.",
+ /* LNG_REJECT_MEMO */
+ "[àâòî-ñîîáùåíèå] Çàïðàøèâàåìûé âàìè vHost îòêëîíåí.",
+ /* LNG_REJECT_MEMO_REASON */
+ "[àâòî-ñîîáùåíèå] Çàïðàøèâàåìûé âàìè vHost îòêëîíåí. Ïðè÷èíà: %s",
+ /* LNG_NO_REQUEST */
+ "Çàïðîñ íà vHost äëÿ íèêà %s íå íàéäåí.",
+ /* LNG_HELP */
+ " REQUEST Çàïðîñ íà vHost äëÿ âàøåãî òåêóùåãî íèêà",
+ /* LNG_HELP_SETTER */
+ " ACTIVATE Óòâåðäèòü çàïðàøèâàåìûé ïîëüçîâàòåëåì vHost\n"
+ " REJECT Îòêëîíèòü çàïðàøèâàåìûé ïîëüçîâàòåëåì vHost\n"
+ " WAITING Ñïèñîê çàïðîñîâ îæèäàþùèõ îáðàáîòêè (àíàëîã LIST +req)",
+ /* LNG_HELP_REQUEST */
+ "Îòïðàâëÿåò çàïðîñ íà àêòèâàöèþ vHost, êîòîðûé áóäåò ðàññìîòðåí îäíèì èç\n"
+ "àäìèíèñòðàòîðîâ ñåòè. Ïðîñüáà ïðîÿâèòü òåðïåíèå, ïîêà çàïðîñ\n"
+ "ðàññìàòðèâàåòñÿ àäìèíèñòðàöèåé.",
+ /* LNG_HELP_ACTIVATE */
+ "Óòâåðäèòü çàïðàøèâàåìûé vHost äëÿ óêàçàííîãî íèêà.",
+ /* LNG_HELP_ACTIVATE_MEMO */
+ "Ïîëüçîâàòåëþ áóäåò ïîñëàíî àâòî-óâåäîìëåíèå îá àêòèâàöèè åãî çàïðîñà.",
+ /* LNG_HELP_REJECT */
+ "Îòêëîíèòü çàïðàøèâàåìûé vHost äëÿ óêàçàííîãî íèêà.",
+ /* LNG_HELP_REJECT_MEMO */
+ "Ïîëüçîâàòåëþ áóäåò ïîñëàíî àâòî-óâåäîìëåíèå îá îòêëîíåíèè åãî çàïðîñà.",
+ /* LNG_WAITING_SYNTAX */
+ "Ñèíòàêñèñ: \002WAITING\002",
+ /* LNG_HELP_WAITING */
+ "Äàííàÿ êîìàíäà ñîçäàíà äëÿ óäîáñòâà èñïîëüçîâàíèÿ è âûâîäèò ñïèñîê çàïðîñîâ,\n"
+ "îæèäàþùèõ îáðàáîòêè. Àíàëîãè÷íàÿ êîìàíäà: LIST +req ."
+ };
+
+ char *langtable_it[] = {
+ /* LNG_REQUEST_SYNTAX */
+ "Sintassi: \002REQUEST \037vhost\037\002",
+ /* LNG_REQUESTED */
+ "Il tuo vHost è stato richiesto",
+ /* LNG_REQUEST_WAIT */
+ "Prego attendere %d secondi prima di richiedere un nuovo vHost",
+ /* LNG_REQUEST_MEMO */
+ "[auto memo] è stato richiesto il vHost \002%s\002.",
+ /* LNG_ACTIVATE_SYNTAX */
+ "Sintassi: \002ACTIVATE \037nick\037\002",
+ /* LNG_ACTIVATED */
+ "Il vHost per %s è stato attivato",
+ /* LNG_ACTIVATE_MEMO */
+ "[auto memo] Il vHost da te richiesto è stato approvato.",
+ /* LNG_REJECT_SYNTAX */
+ "Sintassi: \002REJECT \037nick\037\002",
+ /* LNG_REJECTED */
+ "Il vHost per %s è stato rifiutato",
+ /* LNG_REJECT_MEMO */
+ "[auto memo] Il vHost da te richiesto è stato rifiutato.",
+ /* LNG_REJECT_MEMO_REASON */
+ "[auto memo] Il vHost da te richiesto è stato rifiutato. Motivo: %s",
+ /* LNG_NO_REQUEST */
+ "Nessuna richiesta trovata per il nick %s.",
+ /* LNG_HELP */
+ " REQUEST Richiede un vHost per il tuo nick",
+ /* LNG_HELP_SETTER */
+ " ACTIVATE Approva il vHost richiesto di un utente\n"
+ " REJECT Rifiuta il vHost richiesto di un utente\n"
+ " WAITING Comando per LIST +req",
+ /* LNG_HELP_REQUEST */
+ "Richiede l'attivazione del vHost specificato per il tuo nick da parte\n"
+ "degli amministratori di rete. Sei pregato di pazientare finchè la tua\n"
+ "richiesta viene elaborata.",
+ /* LNG_HELP_ACTIVATE */
+ "Attiva il vHost richiesto per il nick specificato.",
+ /* LNG_HELP_ACTIVATE_MEMO */
+ "Viene inviato un memo per informare l'utente.",
+ /* LNG_HELP_REJECT */
+ "Rifiuta il vHost richiesto per il nick specificato.",
+ /* LNG_HELP_REJECT_MEMO */
+ "Viene inviato un memo per informare l'utente.",
+ /* LNG_WAITING_SYNTAX */
+ "Sintassi: \002WAITING\002",
+ /* LNG_HELP_WAITING */
+ "Questo comando è per comodità. Praticamente è la stessa cosa che\n"
+ "eseguire un LIST +req ."
+ };
+ moduleInsertLanguage(LANG_EN_US, LNG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_NL, LNG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_PT, LNG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LNG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LNG_NUM_STRINGS, langtable_it);
+}
+
+/* EOF */
diff --git a/src/modules/makefile.inc.win32 b/src/modules/makefile.inc.win32
new file mode 100644
index 000000000..f6a646329
--- /dev/null
+++ b/src/modules/makefile.inc.win32
@@ -0,0 +1,2 @@
+SRCS=cs_appendtopic.c cs_enforce.c cs_tban.c ns_maxemail.c hs_request.c os_info.c bs_fantasy_unban.c
+SUBS=test
diff --git a/src/modules/makefile.sub.win32 b/src/modules/makefile.sub.win32
new file mode 100644
index 000000000..4a811622e
--- /dev/null
+++ b/src/modules/makefile.sub.win32
@@ -0,0 +1,19 @@
+include ../../../Makefile.inc.win32
+
+OBJECTS= $(SRCS:.c=.obj)
+CFLAGS=/nologo /LD /MD /D MODULE_COMPILE $(CFLAGS) /I"../../../include" /I "../"
+LFLAGS=/nologo ../../anope.lib wsock32.lib $(LIBS) $(LFLAGS) $(MYSQL_LIB_PATH) /export:AnopeInit /export:AnopeFini /OUT:$(TARGET)
+
+all:
+ $(CC) $(SRCS) $(CFLAGS) ..\..\mod_version.c /link $(LFLAGS)
+
+distclean: clean spotless
+
+clean:
+ -@del *.obj
+
+spotless: clean
+ -@del *.dll *.lib *.exp *.manifest
+
+install:
+ -@copy *.dll ..\..\..\$(DATDEST)\modules
diff --git a/src/modules/makefile.win32 b/src/modules/makefile.win32
new file mode 100644
index 000000000..038ff25ba
--- /dev/null
+++ b/src/modules/makefile.win32
@@ -0,0 +1,41 @@
+include ../../Makefile.inc.win32
+include ./Makefile.inc.win32
+
+OBJECTS= $(SRCS:.c=.dll)
+CFLAGS=/LD /MD /D MODULE_COMPILE $(CFLAGS) /I"../../include"
+LFLAGS=/link ../anope.lib wsock32.lib $(LIBS) $(LFLAGS) $(MYSQL_LIB_PATH) /export:AnopeInit /export:AnopeFini
+
+all: $(OBJECTS) subs
+
+distclean: clean spotless
+
+.c.dll:
+ $(CC) $(CFLAGS) $(IRCTYPE) $< ..\mod_version.c $(LFLAGS)
+
+subs:
+ @for %i in ( $(SUBS) ); do \
+ @if exist %i; @cd %i && $(MAKE) $(MAKEARGS) && cd ..
+
+clean: subs-clean
+ -@del *.obj
+
+subs-clean:
+ @for %i in ( $(SUBS) ); do \
+ @if exist %i; @cd %i && $(MAKE) $(MAKEARGS) clean && cd ..
+
+spotless: clean subs-spotless
+ -@del *.dll *.lib *.exp *.manifest
+
+subs-spotless:
+ @for %i in ( $(SUBS) ); do \
+ @if exist %i; @cd %i && $(MAKE) $(MAKEARGS) spotless && cd ..
+
+install:
+ -@mkdir ..\..\$(DATDEST)\modules
+ -@mkdir ..\..\$(DATDEST)\modules\runtime
+ -@copy *.dll ..\..\$(DATDEST)\modules
+
+subs-install: install
+ @for %i in ( $(SUBS) ); do \
+ @if exist %i; @cd %i && $(MAKE) $(MAKEARGS) install && cd ..
+
diff --git a/src/modules/ns_maxemail.c b/src/modules/ns_maxemail.c
new file mode 100644
index 000000000..04747ff5a
--- /dev/null
+++ b/src/modules/ns_maxemail.c
@@ -0,0 +1,228 @@
+/* ns_maxemail.c - Limit the amount of times an email address
+ * can be used for a NickServ account.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Included in the Anope module pack since Anope 1.7.9
+ * Anope Coder: GeniusDex <geniusdex@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send any bug reports to the Anope Coder, as he will be able
+ * to deal with it best.
+ */
+
+#include "module.h"
+
+#define AUTHOR "Anope"
+#define VERSION "$Id$"
+
+void my_load_config(void);
+void my_add_languages(void);
+int my_ns_register(User * u);
+int my_ns_set(User * u);
+int my_event_reload(int argc, char **argv);
+
+int NSEmailMax = 0;
+
+#define LNG_NUM_STRINGS 2
+#define LNG_NSEMAILMAX_REACHED 0
+#define LNG_NSEMAILMAX_REACHED_ONE 1
+
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ EvtHook *evt;
+ int status;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ c = createCommand("REGISTER", my_ns_register, NULL, -1, -1, -1, -1,
+ -1);
+ if ((status = moduleAddCommand(NICKSERV, c, MOD_HEAD))) {
+ alog("[ns_maxemail] Unable to create REGISTER command: %d",
+ status);
+ return MOD_STOP;
+ }
+
+ c = createCommand("SET", my_ns_set, NULL, -1, -1, -1, -1, -1);
+ if ((status = moduleAddCommand(NICKSERV, c, MOD_HEAD))) {
+ alog("[ns_maxemail] Unable to create SET command: %d", status);
+ return MOD_STOP;
+ }
+
+ evt = createEventHook(EVENT_RELOAD, my_event_reload);
+ if ((status = moduleAddEventHook(evt))) {
+ alog("[ns_maxemail] Unable to hook to EVENT_RELOAD: %d", status);
+ return MOD_STOP;
+ }
+
+ my_load_config();
+ my_add_languages();
+
+ return MOD_CONT;
+}
+
+void AnopeFini(void)
+{
+ /* Nothing to do while unloading */
+}
+
+int count_email_in_use(char *email, User * u)
+{
+ NickCore *nc;
+ int i;
+ int count = 0;
+
+ if (!email)
+ return 0;
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ if (!(u->na && u->na->nc && (u->na->nc == nc)) && nc->email && (stricmp(nc->email, email) == 0))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+int check_email_limit_reached(char *email, User * u)
+{
+ if ((NSEmailMax < 1) || !email || is_services_admin(u))
+ return MOD_CONT;
+
+ if (count_email_in_use(email, u) < NSEmailMax)
+ return MOD_CONT;
+
+ if (NSEmailMax == 1)
+ moduleNoticeLang(s_NickServ, u, LNG_NSEMAILMAX_REACHED_ONE);
+ else
+ moduleNoticeLang(s_NickServ, u, LNG_NSEMAILMAX_REACHED,
+ NSEmailMax);
+
+ return MOD_STOP;
+}
+
+int my_ns_register(User * u)
+{
+ char *cur_buffer;
+ char *email;
+ int ret;
+
+ cur_buffer = moduleGetLastBuffer();
+ email = myStrGetToken(cur_buffer, ' ', 1);
+ if (!email)
+ return MOD_CONT;
+
+ ret = check_email_limit_reached(email, u);
+ free(email);
+
+ return ret;
+}
+
+int my_ns_set(User * u)
+{
+ char *cur_buffer;
+ char *set;
+ char *email;
+ int ret;
+
+ cur_buffer = moduleGetLastBuffer();
+ set = myStrGetToken(cur_buffer, ' ', 0);
+
+ if (!set)
+ return MOD_CONT;
+
+ if (stricmp(set, "email") != 0) {
+ free(set);
+ return MOD_CONT;
+ }
+
+ free(set);
+ email = myStrGetToken(cur_buffer, ' ', 1);
+ if (!email)
+ return MOD_CONT;
+
+ ret = check_email_limit_reached(email, u);
+ free(email);
+
+ return ret;
+}
+
+int my_event_reload(int argc, char **argv)
+{
+ if ((argc > 0) && (stricmp(argv[0], EVENT_START) == 0))
+ my_load_config();
+
+ return MOD_CONT;
+}
+
+void my_load_config(void)
+{
+ Directive confvalues[] = {
+ {"NSEmailMax", {{PARAM_INT, PARAM_RELOAD, &NSEmailMax}}}
+ };
+
+ moduleGetConfigDirective(confvalues);
+
+ if (debug)
+ alog("debug: [ns_maxemail] NSEmailMax set to %d", NSEmailMax);
+}
+
+void my_add_languages(void)
+{
+ char *langtable_en_us[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "The given email address has reached it's usage limit of %d users.",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "The given email address has reached it's usage limit of 1 user."
+ };
+
+ char *langtable_nl[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "Het gegeven email adres heeft de limiet van %d gebruikers bereikt.",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "Het gegeven email adres heeft de limiet van 1 gebruiker bereikt."
+ };
+
+ char *langtable_de[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "Die angegebene eMail hat die limit Begrenzung von %d User erreicht.",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "Die angegebene eMail hat die limit Begrenzung von 1 User erreicht."
+ };
+
+ char *langtable_pt[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "O endereço de email fornecido alcançou seu limite de uso de %d usuários.",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "O endereço de email fornecido alcançou seu limite de uso de 1 usuário."
+ };
+
+ char *langtable_ru[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "Óêàçàííûé âàìè email-àäðåñ èñïîëüçóåòñÿ ìàêñèìàëüíî äîïóñòèìîå êîë-âî ðàç: %d",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "Óêàçàííûé âàìè email-àäðåñ óæå êåì-òî èñïîëüçóåòñÿ."
+ };
+
+ char *langtable_it[] = {
+ /* LNG_NSEMAILMAX_REACHED */
+ "L'indirizzo email specificato ha raggiunto il suo limite d'utilizzo di %d utenti.",
+ /* LNG_NSEMAILMAX_REACHED_ONE */
+ "L'indirizzo email specificato ha raggiunto il suo limite d'utilizzo di 1 utente."
+ };
+
+ moduleInsertLanguage(LANG_EN_US, LNG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_NL, LNG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_DE, LNG_NUM_STRINGS, langtable_de);
+ moduleInsertLanguage(LANG_PT, LNG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LNG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LNG_NUM_STRINGS, langtable_it);
+}
+
+/* EOF */
diff --git a/src/modules/ns_noop_convert.c b/src/modules/ns_noop_convert.c
new file mode 100644
index 000000000..2858bef1e
--- /dev/null
+++ b/src/modules/ns_noop_convert.c
@@ -0,0 +1,173 @@
+/* ns_noop.c - Allows users to optionaly set autoop to off
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Based on the original module by Rob <rob@anope.org>
+ * Included in the Anope module pack since Anope 1.7.9
+ * Anope Coder: DrStein <drstein@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send bug reports to the Anope Coder instead of the module
+ * author, because any changes since the inclusion into anope
+ * are not supported by the original author.
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define AUTHOR "Rob"
+#define VERSION "$Id$"
+
+/* The name of the default database to save info to */
+#define DEFAULT_DB_NAME "autoop.db"
+
+/* Multi-language stuff */
+#define LANG_NUM_STRINGS 8
+
+#define AUTOOP_SYNTAX 0
+#define AUTOOP_STATUS_ON 1
+#define AUTOOP_STATUS_OFF 2
+#define AUTOOP_NO_NICK 3
+#define AUTOOP_ON 4
+#define AUTOOP_OFF 5
+#define AUTOOP_DESC 6
+#define AUTOOP_HELP 7
+
+/*************************************************************************/
+
+User *currentUser;
+int m_isIRCop = 0;
+
+char *NSAutoOPDBName;
+
+int myNickServAutoOpHelp(User * u);
+void myNickServHelp(User * u);
+
+int noop(User * u);
+int mEventJoin(int argc, char **argv);
+int setAutoOp(User * u);
+int UnsetAutoOp(User * u);
+
+int mLoadData(void);
+int mSaveData(int argc, char **argv);
+int mLoadConfig(int argc, char **argv);
+
+void m_AddLanguages(void);
+
+/*************************************************************************/
+
+/**
+ * AnopeInit is called when the module is loaded
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ NSAutoOPDBName = NULL;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ if (mLoadConfig(0, NULL))
+ return MOD_STOP;
+
+ mLoadData();
+
+ alog("ns_noop_convert: Your auto-op database has been converted and this module will now");
+ alog("ns_noop_convert: unload itself. You can now remove this module from your config");
+
+ return MOD_STOP;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+ if (NSAutoOPDBName)
+ free(NSAutoOPDBName);
+}
+
+/*************************************************************************/
+
+/**
+ * Load data from the db file, and populate the autoop setting
+ * @return 0 for success
+ **/
+int mLoadData(void)
+{
+ int ret = 0;
+ int len = 0;
+
+ char *name = NULL;
+
+ NickAlias *na = NULL;
+ FILE *in;
+
+ /* will _never_ be this big thanks to the 512 limit of a message */
+ char buffer[2000];
+ if ((in = fopen(NSAutoOPDBName, "r")) == NULL) {
+ alog("ns_noop: WARNING: Can not open database file! (it might not exist, this is not fatal)");
+ ret = 1;
+ } else {
+ while (fgets(buffer, 1500, in)) {
+ name = myStrGetToken(buffer, ' ', 0);
+ if (name) {
+ len = strlen(name);
+ /* Take the \n from the end of the line */
+ name[len - 1] = '\0';
+ if ((na = findnick(name))) {
+ na->nc->flags |= NI_AUTOOP;
+ }
+ free(name);
+ }
+ }
+ }
+ return ret;
+}
+
+/*************************************************************************/
+
+/**
+ * Load the configuration directives from Services configuration file.
+ * @return 0 for success
+ **/
+int mLoadConfig(int argc, char **argv)
+{
+ char *tmp = NULL;
+
+ Directive d[] = {
+ {"NSAutoOPDBName", {{PARAM_STRING, PARAM_RELOAD, &tmp}}},
+ };
+
+ moduleGetConfigDirective(d);
+
+ if (NSAutoOPDBName)
+ free(NSAutoOPDBName);
+
+ if (tmp) {
+ NSAutoOPDBName = tmp;
+ } else {
+ NSAutoOPDBName = sstrdup(DEFAULT_DB_NAME);
+ alog("ns_noop: NSAutoOPDBName is not defined in Services configuration file, using default %s", NSAutoOPDBName);
+ }
+
+ if (!NSAutoOPDBName) {
+ alog("ns_noop: FATAL: Can't read required configuration directives!");
+ return MOD_STOP;
+ } else {
+ alog("ns_noop: Directive NSAutoOPDBName loaded (%s)...",
+ NSAutoOPDBName);
+ }
+
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+/* EOF */
diff --git a/src/modules/os_ignore_db.c b/src/modules/os_ignore_db.c
new file mode 100644
index 000000000..474959068
--- /dev/null
+++ b/src/modules/os_ignore_db.c
@@ -0,0 +1,545 @@
+/* os_ignore_db.c - Provides a database backend for OS IGNORE.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Included in the Anope module pack since Anope 1.7.23
+ * Anope Coder: Viper <viper@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ */
+/* ------------------------------------------------------------------------------- */
+
+#include "module.h"
+
+#define AUTHOR "Viper"
+#define VERSION "$Id$"
+
+/* Default database name */
+#define DefIgnoreDB "os_ignore.db"
+#define IGNOREDBVERSION 1
+
+/* Database seperators */
+#define SEPARATOR '^' /* End of a key, seperates keys from values */
+#define BLOCKEND '\n' /* End of a block, e.g. a whole ignore */
+#define VALUEEND '\000' /* End of a value */
+#define SUBSTART '\010' /* Beginning of a new subblock, closed by a BLOCKEND */
+
+/* Database reading return values */
+#define DB_READ_SUCCESS 0
+#define DB_READ_ERROR 1
+#define DB_EOF_ERROR 2
+#define DB_VERSION_ERROR 3
+#define DB_READ_BLOCKEND 4
+#define DB_READ_SUBSTART 5
+
+#define DB_WRITE_SUCCESS 0
+#define DB_WRITE_ERROR 1
+#define DB_WRITE_NOVAL 2
+
+/* Database Key, Value max length */
+#define MAXKEYLEN 128
+#define MAXVALLEN 1024
+
+/* Structs */
+typedef struct db_file_ DBFile;
+
+struct db_file_ {
+ FILE *fptr; /* Pointer to the opened file */
+ int db_version; /* The db version of the datafiles (only needed for reading) */
+ int core_db_version; /* The current db version of this anope source */
+ char service[256]; /* StatServ/etc. */
+ char filename[256]; /* Filename of the database */
+ char temp_name[262]; /* Temp filename of the database */
+};
+
+
+/* Variables */
+char *IgnoreDB;
+
+/* Functions */
+int new_open_db_read(DBFile *dbptr, char **key, char **value);
+int new_open_db_write(DBFile *dbptr);
+void new_close_db(FILE *fptr, char **key, char **value);
+int new_read_db_entry(char **key, char **value, FILE * fptr);
+int new_write_db_entry(const char *key, DBFile *dbptr, const char *fmt, ...);
+int new_write_db_endofblock(DBFile *dbptr);
+void fill_db_ptr(DBFile *dbptr, int version, int core_version, char service[256], char filename[256]);
+
+int save_ignoredb(int argc, char **argv);
+int backup_ignoredb(int argc, char **argv);
+void load_ignore_db(void);
+void save_ignore_db(void);
+void load_config(void);
+int reload_config(int argc, char **argv);
+
+/* ------------------------------------------------------------------------------- */
+
+/**
+ * AnopeInit is called when the module is loaded
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv) {
+ EvtHook *hook;
+ IgnoreDB = NULL;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ hook = createEventHook(EVENT_RELOAD, reload_config);
+ if (moduleAddEventHook(hook) != MOD_ERR_OK) {
+ alog("[\002os_ignore_db\002] Can't hook to EVENT_RELOAD event");
+ return MOD_STOP;
+ }
+
+ hook = createEventHook(EVENT_DB_SAVING, save_ignoredb);
+ if (moduleAddEventHook(hook) != MOD_ERR_OK) {
+ alog("[\002os_ignore_db\002] Can't hook to EVENT_DB_SAVING event");
+ return MOD_STOP;
+ }
+
+ hook = createEventHook(EVENT_DB_BACKUP, backup_ignoredb);
+ if (moduleAddEventHook(hook) != MOD_ERR_OK) {
+ alog("[\002os_ignore_db\002] Can't hook to EVENT_DB_BACKUP event");
+ return MOD_STOP;
+ }
+
+ load_config();
+ /* Load the ignore database and re-add them to anopes ignorelist. */
+ load_ignore_db();
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void) {
+ /* Save the ignore database before bailing out.. */
+ save_ignore_db();
+
+ if (IgnoreDB)
+ free(IgnoreDB);
+}
+
+/* ------------------------------------------------------------------------------- */
+
+void load_config(void) {
+ int i;
+
+ Directive confvalues[][1] = {
+ {{"OSIgnoreDBName", {{PARAM_STRING, PARAM_RELOAD, &IgnoreDB}}}},
+ };
+
+ if (IgnoreDB)
+ free(IgnoreDB);
+ IgnoreDB = NULL;
+
+ for (i = 0; i < 1; i++)
+ moduleGetConfigDirective(confvalues[i]);
+
+ if (!IgnoreDB)
+ IgnoreDB = sstrdup(DefIgnoreDB);
+
+ if (debug)
+ alog("[os_ignore_db] debug: Set config vars: OSIgnoreDBName='%s'", IgnoreDB);
+}
+
+/**
+ * Upon /os reload call the routines for reloading the configuration directives
+ **/
+int reload_config(int argc, char **argv) {
+ if (argc >= 1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ load_config();
+ }
+ }
+ return MOD_CONT;
+}
+
+/**
+ * When anope saves her databases, we do the same.
+ **/
+int save_ignoredb(int argc, char **argv) {
+ if ((argc >= 1) && (!stricmp(argv[0], EVENT_STOP)))
+ save_ignore_db();
+
+ return MOD_CONT;
+}
+
+
+/**
+ * When anope backs her databases up, we do the same.
+ **/
+int backup_ignoredb(int argc, char **argv) {
+ if ((argc >= 1) && (!stricmp(argv[0], EVENT_STOP))) {
+ if (debug)
+ alog("[os_ignore_db] debug: Backing up %s database...", IgnoreDB);
+ ModuleDatabaseBackup(IgnoreDB);
+ }
+ return MOD_CONT;
+}
+
+/* ------------------------------------------------------------------------------- */
+
+/**************************************************************************
+ * DataBase Handling
+ **************************************************************************/
+
+void load_ignore_db(void) {
+ DBFile *dbptr = scalloc(1, sizeof(DBFile));
+ char *key, *value, *mask = NULL;
+ int retval = 0;
+ time_t expiry_time;
+ IgnoreData *ign;
+
+ expiry_time = time(NULL);
+ fill_db_ptr(dbptr, 0, IGNOREDBVERSION, s_OperServ, IgnoreDB);
+
+ /* let's remove existing temp files here, because we only load dbs on startup */
+ remove(dbptr->temp_name);
+
+ /* Open the db, fill the rest of dbptr and allocate memory for key and value */
+ if (new_open_db_read(dbptr, &key, &value)) {
+ free(dbptr);
+ return; /* Bang, an error occurred */
+ }
+
+ while (1) {
+ /* read a new entry and fill key and value with it -Certus */
+ retval = new_read_db_entry(&key, &value, dbptr->fptr);
+
+ if (retval == DB_READ_ERROR) {
+ new_close_db(dbptr->fptr, &key, &value);
+ free(dbptr);
+ return;
+
+ } else if (retval == DB_EOF_ERROR) {
+ new_close_db(dbptr->fptr, &key, &value);
+ free(dbptr);
+ return;
+ } else if (retval == DB_READ_BLOCKEND) { /* DB_READ_BLOCKEND */
+ /* Check if we have everything to add the ignore..
+ * We shouldn't bother with already expired ignores either.. */
+ if (mask && (expiry_time > time(NULL) || expiry_time == 0)) {
+ /* We should check for double entries.. */
+ for (ign = ignore; ign; ign = ign->next)
+ if (!stricmp(ign->mask, mask))
+ break;
+
+ if (!ign) {
+ /* Create a fresh entry.. */
+ ign = scalloc(sizeof(*ign), 1);
+ ign->mask = sstrdup(mask);
+ ign->time = expiry_time;
+ ign->prev = NULL;
+ ign->next = ignore;
+ if (ignore)
+ ignore->prev = ign;
+ ignore = ign;
+ if (debug)
+ alog("[os_ignore_db] debug: Added new ignore entry for %s", mask);
+ } else {
+ /* Update time on existing entry.
+ * The longest expiry time survives.. */
+ if (expiry_time == 0 || ign->time == 0)
+ ign->time = 0;
+ else if (expiry_time > ign->time)
+ ign->time = expiry_time;
+ }
+ }
+
+ if (mask) free(mask);
+ mask = NULL;
+ expiry_time = time(NULL);
+ } else { /* DB_READ_SUCCESS */
+ if (!*key || !*value)
+ continue;
+
+ /* mask */
+ if (!stricmp(key, "m")) {
+ if (mask)
+ free(mask);
+ mask = sstrdup(value);
+
+ /* expiry time */
+ } else if (!stricmp(key, "t")) {
+ expiry_time = atoi(value);
+
+ } else if (!stricmp(key, "IGNORE_DB_VERSION")) {
+ if ((int)atoi(value) != IGNOREDBVERSION) {
+ alog("[\002os_ignore_db\002] Database version does not match any database versions supported by this module.");
+ alog("[\002os_ignore_db\002] Continuing with clean database...");
+ break;
+ }
+ }
+ } /* else */
+ } /* while */
+
+ free(dbptr);
+}
+
+
+void save_ignore_db(void) {
+ DBFile *dbptr = scalloc(1, sizeof(DBFile));
+ time_t now;
+ IgnoreData *ign, *next;
+
+ now = time(NULL);
+ fill_db_ptr(dbptr, 0, IGNOREDBVERSION, s_OperServ, IgnoreDB);
+
+ /* time to backup the old db */
+ rename(IgnoreDB, dbptr->temp_name);
+
+ if (new_open_db_write(dbptr)) {
+ rename(dbptr->temp_name, IgnoreDB);
+ free(dbptr);
+ return; /* Bang, an error occurred */
+ }
+
+ /* Store the version of the DB in the DB as well...
+ * This will make stuff a lot easier if the database scheme needs to modified. */
+ new_write_db_entry("IGNORE_DB_VERSION", dbptr, "%d", IGNOREDBVERSION);
+ new_write_db_endofblock(dbptr);
+
+ /* Go over the entire ignorelist, check whether each entry is still valid
+ * and write it to the database if it is.*/
+ for (ign = ignore; ign; ign = next) {
+ next = ign->next;
+
+ if (ign->time != 0 && ign->time <= now) {
+ if (debug)
+ alog("[os_ignore_db] debug: Expiring ignore entry %s", ign->mask);
+ if (ign->prev)
+ ign->prev->next = ign->next;
+ else if (ignore == ign)
+ ignore = ign->next;
+ if (ign->next)
+ ign->next->prev = ign->prev;
+ free(ign->mask);
+ free(ign);
+ ign = NULL;
+ } else {
+ new_write_db_entry("m", dbptr, "%s", ign->mask);
+ new_write_db_entry("t", dbptr, "%d", ign->time);
+ new_write_db_endofblock(dbptr);
+ }
+ }
+
+ if (dbptr) {
+ new_close_db(dbptr->fptr, NULL, NULL); /* close file */
+ remove(dbptr->temp_name); /* saved successfully, no need to keep the old one */
+ free(dbptr); /* free the db struct */
+ }
+}
+
+
+/* ------------------------------------------------------------------------------- */
+
+/**************************************************************************
+ * Generic DataBase Functions (Borrowed this from Trystan :-) )
+ **************************************************************************/
+
+
+int new_open_db_read(DBFile *dbptr, char **key, char **value) {
+ *key = malloc(MAXKEYLEN);
+ *value = malloc(MAXVALLEN);
+
+ if (!(dbptr->fptr = fopen(dbptr->filename, "rb"))) {
+ if (debug) {
+ alog("debug: Can't read %s database %s : errno(%d)", dbptr->service,
+ dbptr->filename, errno);
+ }
+ free(*key);
+ *key = NULL;
+ free(*value);
+ *value = NULL;
+ return DB_READ_ERROR;
+ }
+ dbptr->db_version = fgetc(dbptr->fptr) << 24 | fgetc(dbptr->fptr) << 16
+ | fgetc(dbptr->fptr) << 8 | fgetc(dbptr->fptr);
+
+ if (ferror(dbptr->fptr)) {
+ if (debug) {
+ alog("debug: Error reading version number on %s", dbptr->filename);
+ }
+ free(*key);
+ *key = NULL;
+ free(*value);
+ *value = NULL;
+ return DB_READ_ERROR;
+ } else if (feof(dbptr->fptr)) {
+ if (debug) {
+ alog("debug: Error reading version number on %s: End of file detected",
+ dbptr->filename);
+ }
+ free(*key);
+ *key = NULL;
+ free(*value);
+ *value = NULL;
+ return DB_EOF_ERROR;
+ } else if (dbptr->db_version < 1) {
+ if (debug) {
+ alog("debug: Invalid version number (%d) on %s", dbptr->db_version, dbptr->filename);
+ }
+ free(*key);
+ *key = NULL;
+ free(*value);
+ *value = NULL;
+ return DB_VERSION_ERROR;
+ }
+ return DB_READ_SUCCESS;
+}
+
+
+int new_open_db_write(DBFile *dbptr) {
+ if (!(dbptr->fptr = fopen(dbptr->filename, "wb"))) {
+ if (debug) {
+ alog("debug: %s Can't open %s database for writing", dbptr->service, dbptr->filename);
+ }
+ return DB_WRITE_ERROR;
+ }
+
+ if (fputc(dbptr->core_db_version >> 24 & 0xFF, dbptr->fptr) < 0 ||
+ fputc(dbptr->core_db_version >> 16 & 0xFF, dbptr->fptr) < 0 ||
+ fputc(dbptr->core_db_version >> 8 & 0xFF, dbptr->fptr) < 0 ||
+ fputc(dbptr->core_db_version & 0xFF, dbptr->fptr) < 0) {
+ if (debug) {
+ alog("debug: Error writing version number on %s", dbptr->filename);
+ }
+ return DB_WRITE_ERROR;
+ }
+ return DB_WRITE_SUCCESS;
+}
+
+
+void new_close_db(FILE *fptr, char **key, char **value) {
+ if (key && *key) {
+ free(*key);
+ *key = NULL;
+ }
+ if (value && *value) {
+ free(*value);
+ *value = NULL;
+ }
+
+ if (fptr) {
+ fclose(fptr);
+ }
+}
+
+
+int new_read_db_entry(char **key, char **value, FILE *fptr) {
+ char *string = *key;
+ int character;
+ int i = 0;
+
+ **key = '\0';
+ **value = '\0';
+
+ while (1) {
+ if ((character = fgetc(fptr)) == EOF) { /* a problem occurred reading the file */
+ if (ferror(fptr)) {
+ return DB_READ_ERROR; /* error! */
+ }
+ return DB_EOF_ERROR; /* end of file */
+ } else if (character == BLOCKEND) { /* END OF BLOCK */
+ return DB_READ_BLOCKEND;
+ } else if (character == VALUEEND) { /* END OF VALUE */
+ string[i] = '\0'; /* end of value */
+ return DB_READ_SUCCESS;
+ } else if (character == SEPARATOR) { /* END OF KEY */
+ string[i] = '\0'; /* end of key */
+ string = *value; /* beginning of value */
+ i = 0; /* start with the first character of our value */
+ } else {
+ if ((i == (MAXKEYLEN - 1)) && (string == *key)) { /* max key length reached, continuing with value */
+ string[i] = '\0'; /* end of key */
+ string = *value; /* beginning of value */
+ i = 0; /* start with the first character of our value */
+ } else if ((i == (MAXVALLEN - 1)) && (string == *value)) { /* max value length reached, returning */
+ string[i] = '\0';
+ return DB_READ_SUCCESS;
+ } else {
+ string[i] = character; /* read string (key or value) */
+ i++;
+ }
+ }
+ }
+}
+
+
+int new_write_db_entry(const char *key, DBFile *dbptr, const char *fmt, ...) {
+ char string[MAXKEYLEN + MAXVALLEN + 2], value[MAXVALLEN]; /* safety byte :P */
+ va_list ap;
+ unsigned int length;
+
+ if (!dbptr) {
+ return DB_WRITE_ERROR;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(value, MAXVALLEN, fmt, ap);
+ va_end(ap);
+
+ if (!stricmp(value, "(null)")) {
+ return DB_WRITE_NOVAL;
+ }
+ snprintf(string, MAXKEYLEN + MAXVALLEN + 1, "%s%c%s", key, SEPARATOR, value);
+ length = strlen(string);
+ string[length] = VALUEEND;
+ length++;
+
+ if (fwrite(string, 1, length, dbptr->fptr) < length) {
+ if (debug) {
+ alog("debug: Error writing to %s", dbptr->filename);
+ }
+ new_close_db(dbptr->fptr, NULL, NULL);
+ if (debug) {
+ alog("debug: Restoring backup.");
+ }
+ remove(dbptr->filename);
+ rename(dbptr->temp_name, dbptr->filename);
+ free(dbptr);
+ dbptr = NULL;
+ return DB_WRITE_ERROR;
+ }
+ return DB_WRITE_SUCCESS;
+}
+
+
+int new_write_db_endofblock(DBFile *dbptr) {
+ if (!dbptr) {
+ return DB_WRITE_ERROR;
+ }
+ if (fputc(BLOCKEND, dbptr->fptr) == EOF) {
+ if (debug) {
+ alog("debug: Error writing to %s", dbptr->filename);
+ }
+ new_close_db(dbptr->fptr, NULL, NULL);
+ return DB_WRITE_ERROR;
+ }
+ return DB_WRITE_SUCCESS;
+}
+
+
+
+void fill_db_ptr(DBFile *dbptr, int version, int core_version,
+ char service[256], char filename[256]) {
+ dbptr->db_version = version;
+ dbptr->core_db_version = core_version;
+ if (!service)
+ strcpy(dbptr->service, service);
+ else
+ strcpy(dbptr->service, "");
+
+ strcpy(dbptr->filename, filename);
+ snprintf(dbptr->temp_name, 261, "%s.temp", filename);
+ return;
+}
+
+/* EOF */
diff --git a/src/modules/os_info.c b/src/modules/os_info.c
new file mode 100644
index 000000000..0343f957e
--- /dev/null
+++ b/src/modules/os_info.c
@@ -0,0 +1,780 @@
+/* os_info.c - Adds oper information lines to nicks/channels
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Based on the original module by Rob <rob@anope.org>
+ * Included in the Anope module pack since Anope 1.7.9
+ * Anope Coder: DrStein <drstein@anope.org>
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Send bug reports to the Anope Coder instead of the module
+ * author, because any changes since the inclusion into anope
+ * are not supported by the original author.
+ *
+ */
+/*************************************************************************/
+
+#include "module.h"
+
+#define AUTHOR "Rob"
+#define VERSION "$Id$"
+
+/* Default database name */
+#define DEFAULT_DB_NAME "os_info.db"
+
+/* Multi-language stuff */
+#define LANG_NUM_STRINGS 10
+
+#define OINFO_SYNTAX 0
+#define OINFO_ADD_SUCCESS 1
+#define OINFO_DEL_SUCCESS 2
+#define OCINFO_SYNTAX 3
+#define OCINFO_ADD_SUCCESS 4
+#define OCINFO_DEL_SUCCESS 5
+#define OINFO_HELP 6
+#define OCINFO_HELP 7
+#define OINFO_HELP_CMD 8
+#define OCINFO_HELP_CMD 9
+
+/*************************************************************************/
+
+char *OSInfoDBName = NULL;
+
+int myAddNickInfo(User * u);
+int myAddChanInfo(User * u);
+int myNickInfo(User * u);
+int myChanInfo(User * u);
+
+int mNickHelp(User * u);
+int mChanHelp(User * u);
+void mMainChanHelp(User * u);
+void mMainNickHelp(User * u);
+void m_AddLanguages(void);
+
+int mLoadData(void);
+int mSaveData(int argc, char **argv);
+int mBackupData(int argc, char **argv);
+int mLoadConfig();
+int mEventReload(int argc, char **argv);
+
+/*************************************************************************/
+
+/**
+ * AnopeInit is called when the module is loaded
+ * @param argc Argument count
+ * @param argv Argument list
+ * @return MOD_CONT to allow the module, MOD_STOP to stop it
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ Command *c;
+ EvtHook *hook = NULL;
+
+ int status;
+
+ moduleAddAuthor(AUTHOR);
+ moduleAddVersion(VERSION);
+ moduleSetType(SUPPORTED);
+
+ alog("os_info: Loading configuration directives...");
+ if (mLoadConfig()) {
+ return MOD_STOP;
+ }
+
+ c = createCommand("oInfo", myAddNickInfo, is_oper, -1, -1, -1, -1, -1);
+ moduleAddHelp(c, mNickHelp);
+ status = moduleAddCommand(NICKSERV, c, MOD_HEAD);
+
+ c = createCommand("Info", myNickInfo, NULL, -1, -1, -1, -1, -1);
+ status = moduleAddCommand(NICKSERV, c, MOD_TAIL);
+
+ c = createCommand("oInfo", myAddChanInfo, is_oper, -1, -1, -1, -1, -1);
+ moduleAddHelp(c, mChanHelp);
+ status = moduleAddCommand(CHANSERV, c, MOD_HEAD);
+
+ c = createCommand("Info", myChanInfo, NULL, -1, -1, -1, -1, -1);
+ status = moduleAddCommand(CHANSERV, c, MOD_TAIL);
+
+ hook = createEventHook(EVENT_DB_SAVING, mSaveData);
+ status = moduleAddEventHook(hook);
+
+ hook = createEventHook(EVENT_DB_BACKUP, mBackupData);
+ status = moduleAddEventHook(hook);
+
+ hook = createEventHook(EVENT_RELOAD, mEventReload);
+ status = moduleAddEventHook(hook);
+
+ moduleSetNickHelp(mMainNickHelp);
+ moduleSetChanHelp(mMainChanHelp);
+
+ mLoadData();
+ m_AddLanguages();
+
+ return MOD_CONT;
+}
+
+/**
+ * Unload the module
+ **/
+void AnopeFini(void)
+{
+ char *av[1];
+
+ av[0] = sstrdup(EVENT_START);
+ mSaveData(1, av);
+ free(av[0]);
+
+ if (OSInfoDBName)
+ free(OSInfoDBName);
+}
+
+/*************************************************************************/
+
+/**
+ * Provide the user interface to add/remove/update oper information
+ * about a nick.
+ * We are going to assume that anyone who gets this far is an oper;
+ * the createCommand should have handled this checking for us and its
+ * tedious / a waste to do it twice.
+ * @param u The user who executed this command
+ * @return MOD_CONT if we want to process other commands in this command
+ * stack, MOD_STOP if we dont
+ **/
+int myAddNickInfo(User * u)
+{
+ char *text = NULL;
+ char *cmd = NULL;
+ char *nick = NULL;
+ char *info = NULL;
+ NickAlias *na = NULL;
+
+ /* Get the last buffer anope recived */
+ text = moduleGetLastBuffer();
+ if (text) {
+ cmd = myStrGetToken(text, ' ', 0);
+ nick = myStrGetToken(text, ' ', 1);
+ info = myStrGetTokenRemainder(text, ' ', 2);
+ if (cmd && nick) {
+ if (strcasecmp(cmd, "ADD") == 0) {
+ /* Syntax error, again! */
+ if (info) {
+ /* ok we've found the user */
+ if ((na = findnick(nick))) {
+ /* Add the module data to the user */
+ moduleAddData(&na->nc->moduleData, "info", info);
+ moduleNoticeLang(s_NickServ, u,
+ OINFO_ADD_SUCCESS, nick);
+ /* NickCore not found! */
+ } else {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED,
+ nick);
+ }
+ free(info);
+ }
+ } else if (strcasecmp(cmd, "DEL") == 0) {
+ /* ok we've found the user */
+ if ((na = findnick(nick))) {
+ moduleDelData(&na->nc->moduleData, "info");
+ moduleNoticeLang(s_NickServ, u,
+ OINFO_DEL_SUCCESS, nick);
+ /* NickCore not found! */
+ } else {
+ notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED,
+ nick);
+ }
+ /* another syntax error! */
+ } else {
+ moduleNoticeLang(s_NickServ, u, OINFO_SYNTAX);
+ }
+ free(cmd);
+ free(nick);
+ /* Syntax error */
+ } else if (cmd) {
+ moduleNoticeLang(s_NickServ, u, OINFO_SYNTAX);
+ free(cmd);
+ /* Syntax error */
+ } else {
+ moduleNoticeLang(s_NickServ, u, OINFO_SYNTAX);
+ }
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Provide the user interface to add/remove/update oper information
+ * about a channel.
+ * We are going to assume that anyone who gets this far is an oper;
+ * the createCommand should have handled this checking for us and
+ * its tedious / a waste to do it twice.
+ * @param u The user who executed this command
+ * @return MOD_CONT if we want to process other commands in this command
+ * stack, MOD_STOP if we dont
+ **/
+int myAddChanInfo(User * u)
+{
+ char *text = NULL;
+ char *cmd = NULL;
+ char *chan = NULL;
+ char *info = NULL;
+ ChannelInfo *ci = NULL;
+
+ /* Get the last buffer anope recived */
+ text = moduleGetLastBuffer();
+ if (text) {
+ cmd = myStrGetToken(text, ' ', 0);
+ chan = myStrGetToken(text, ' ', 1);
+ info = myStrGetTokenRemainder(text, ' ', 2);
+ if (cmd && chan) {
+ if (strcasecmp(cmd, "ADD") == 0) {
+ if (info) {
+ if ((ci = cs_findchan(chan))) {
+ /* Add the module data to the channel */
+ moduleAddData(&ci->moduleData, "info", info);
+ moduleNoticeLang(s_ChanServ, u,
+ OCINFO_ADD_SUCCESS, chan);
+ /* ChanInfo */
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED,
+ chan);
+ }
+ free(info);
+ }
+ } else if (strcasecmp(cmd, "DEL") == 0) {
+ if ((ci = cs_findchan(chan))) {
+ /* Del the module data from the channel */
+ moduleDelData(&ci->moduleData, "info");
+ moduleNoticeLang(s_ChanServ, u,
+ OCINFO_DEL_SUCCESS, chan);
+ /* ChanInfo */
+ } else {
+ notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED,
+ chan);
+ }
+ /* another syntax error! */
+ } else {
+ moduleNoticeLang(s_ChanServ, u, OCINFO_SYNTAX);
+ }
+ free(cmd);
+ free(chan);
+ /* Syntax error */
+ } else if (cmd) {
+ moduleNoticeLang(s_ChanServ, u, OCINFO_SYNTAX);
+ free(cmd);
+ /* Syntax error */
+ } else {
+ moduleNoticeLang(s_ChanServ, u, OCINFO_SYNTAX);
+ }
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+/**
+ * Called after a user does a /msg nickserv info [nick]
+ * @param u The user who requested info
+ * @return MOD_CONT to continue processing commands or MOD_STOP to stop
+ **/
+int myNickInfo(User * u)
+{
+ char *text = NULL;
+ char *nick = NULL;
+ char *info = NULL;
+ NickAlias *na = NULL;
+
+ /* Only show our goodies to opers */
+ if (is_oper(u)) {
+ /* Get the last buffer anope recived */
+ text = moduleGetLastBuffer();
+ if (text) {
+ nick = myStrGetToken(text, ' ', 0);
+ if (nick) {
+ /* ok we've found the user */
+ if ((na = findnick(nick))) {
+ /* If we have any info on this user */
+ if ((info = moduleGetData(&na->nc->moduleData, "info"))) {
+ notice_user(s_NickServ, u, " OperInfo: %s", info);
+ free(info);
+ }
+ /* NickCore not found! */
+ } else {
+ /* we dont care! */
+ }
+ free(nick);
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+/**
+ * Called after a user does a /msg chanserv info chan
+ * @param u The user who requested info
+ * @return MOD_CONT to continue processing commands or MOD_STOP to stop
+ **/
+int myChanInfo(User * u)
+{
+ char *text = NULL;
+ char *chan = NULL;
+ char *info = NULL;
+ ChannelInfo *ci = NULL;
+
+ /* Only show our goodies to opers */
+ if (is_oper(u)) {
+ /* Get the last buffer anope recived */
+ text = moduleGetLastBuffer();
+ if (text) {
+ chan = myStrGetToken(text, ' ', 0);
+ if (chan) {
+ if ((ci = cs_findchan(chan))) {
+ /* If we have any info on this channel */
+ if ((info = moduleGetData(&ci->moduleData, "info"))) {
+ notice_user(s_ChanServ, u, " OperInfo: %s", info);
+ free(info);
+ }
+ }
+ free(chan);
+ }
+ }
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+/**
+ * Load data from the db file, and populate our OperInfo lines
+ * @return 0 for success
+ **/
+int mLoadData(void)
+{
+ int ret = 0;
+ FILE *in;
+
+ char *type = NULL;
+ char *name = NULL;
+ char *info = NULL;
+ int len = 0;
+
+ ChannelInfo *ci = NULL;
+ NickAlias *na = NULL;
+
+ /* will _never_ be this big thanks to the 512 limit of a message */
+ char buffer[2000];
+ if ((in = fopen(OSInfoDBName, "r")) == NULL) {
+ alog("os_info: WARNING: can not open the database file! (it might not exist, this is not fatal)");
+ ret = 1;
+ } else {
+ while (fgets(buffer, 1500, in)) {
+ type = myStrGetToken(buffer, ' ', 0);
+ name = myStrGetToken(buffer, ' ', 1);
+ info = myStrGetTokenRemainder(buffer, ' ', 2);
+ if (type) {
+ if (name) {
+ if (info) {
+ len = strlen(info);
+ /* Take the \n from the end of the line */
+ info[len - 1] = '\0';
+ if (stricmp(type, "C") == 0) {
+ if ((ci = cs_findchan(name))) {
+ moduleAddData(&ci->moduleData, "info",
+ info);
+ }
+ } else if (stricmp(type, "N") == 0) {
+ if ((na = findnick(name))) {
+ moduleAddData(&na->nc->moduleData, "info",
+ info);
+ }
+ }
+ free(info);
+ }
+ free(name);
+ }
+ free(type);
+ }
+ }
+ }
+ return ret;
+}
+
+/**
+ * Save all our data to our db file
+ * First walk through the nick CORE list, and any nick core which has
+ * oper info attached to it, write to the file.
+ * Next do the same again for ChannelInfos
+ * @return 0 for success
+ **/
+int mSaveData(int argc, char **argv)
+{
+ ChannelInfo *ci = NULL;
+ NickCore *nc = NULL;
+ int i = 0;
+ int ret = 0;
+ FILE *out;
+ char *info = NULL;
+
+ if (argc >= 1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ if ((out = fopen(OSInfoDBName, "w")) == NULL) {
+ alog("os_info: ERROR: can not open the database file!");
+ anope_cmd_global(s_OperServ,
+ "os_info: ERROR: can not open the database file!");
+ ret = 1;
+ } else {
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ /* If we have any info on this user */
+ if ((info = moduleGetData(&nc->moduleData, "info"))) {
+ fprintf(out, "N %s %s\n", nc->display, info);
+ free(info);
+ }
+ }
+ }
+
+
+ for (i = 0; i < 256; i++) {
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ /* If we have any info on this channel */
+ if ((info = moduleGetData(&ci->moduleData, "info"))) {
+ fprintf(out, "C %s %s\n", ci->name, info);
+ free(info);
+ }
+ }
+ }
+ fclose(out);
+ }
+ } else {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Backup our databases using the commands provided by Anope
+ * @return MOD_CONT
+ **/
+int mBackupData(int argc, char **argv)
+{
+ ModuleDatabaseBackup(OSInfoDBName);
+
+ return MOD_CONT;
+}
+
+/**
+ * Load the configuration directives from Services configuration file.
+ * @return 0 for success
+ **/
+int mLoadConfig(void)
+{
+ char *tmp = NULL;
+
+ Directive directivas[] = {
+ {"OSInfoDBName", {{PARAM_STRING, PARAM_RELOAD, &tmp}}},
+ };
+
+ Directive *d = &directivas[0];
+ moduleGetConfigDirective(d);
+
+ if (OSInfoDBName)
+ free(OSInfoDBName);
+
+ if (tmp) {
+ OSInfoDBName = tmp;
+ } else {
+ OSInfoDBName = sstrdup(DEFAULT_DB_NAME);
+ alog("os_info: OSInfoDBName is not defined in Services configuration file, using default %s", OSInfoDBName);
+ }
+
+ alog("os_info: Directive OSInfoDBName loaded (%s)...", OSInfoDBName);
+
+ return 0;
+}
+
+/**
+ * Manage the RELOAD EVENT
+ * @return MOD_CONT
+ **/
+int mEventReload(int argc, char **argv)
+{
+ int ret = 0;
+ if (argc >= 1) {
+ if (!stricmp(argv[0], EVENT_START)) {
+ alog("os_info: Reloading configuration directives...");
+ ret = mLoadConfig();
+ } else {
+ /* Nothing for now */
+ }
+ }
+
+ if (ret)
+ alog("os_info.c: ERROR: An error has occured while reloading the configuration file");
+
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+/**
+ * manages the multilanguage stuff
+ **/
+void m_AddLanguages(void)
+{
+ char *langtable_en_us[] = {
+ /* OINFO_SYNTAX */
+ "Syntax: OINFO [ADD|DEL] nick <info>",
+ /* OINFO_ADD_SUCCESS */
+ "OperInfo line has been added to nick %s",
+ /* OINFO_DEL_SUCCESS */
+ "OperInfo line has been removed from nick %s",
+ /* OCINFO_SYNTAX */
+ "Syntax: OINFO [ADD|DEL] chan <info>",
+ /* OCINFO_ADD_SUCCESS */
+ "OperInfo line has been added to channel %s",
+ /* OCINFO_DEL_SUCCESS */
+ "OperInfo line has been removed from channel %s",
+ /* OINFO_HELP */
+ "Syntax: OINFO [ADD|DEL] nick <info>\n"
+ "Add or Delete Oper information for the given nick\n"
+ "This will show up when any oper /ns info nick's the user.\n"
+ "and can be used for 'tagging' users etc....",
+ /* OCINFO_HELP */
+ "Syntax: OINFO [ADD|DEL] chan <info>\n"
+ "Add or Delete Oper information for the given channel\n"
+ "This will show up when any oper /cs info's the channel.\n"
+ "and can be used for 'tagging' channels etc....",
+ /* OINFO_HELP_CMD */
+ " OINFO Add / Del an OperInfo line to a nick",
+ /* OCINFO_HELP_CMD */
+ " OINFO Add / Del an OperInfo line to a channel"
+ };
+
+ char *langtable_es[] = {
+ /* OINFO_SYNTAX */
+ "Sintaxis: OINFO [ADD|DEL] nick <info>",
+ /* OINFO_ADD_SUCCESS */
+ "Una linea OperInfo ha sido agregada al nick %s",
+ /* OINFO_DEL_SUCCESS */
+ "La linea OperInfo ha sido removida del nick %s",
+ /* OCINFO_SYNTAX */
+ "Sintaxis: OINFO [ADD|DEL] chan <info>",
+ /* OCINFO_ADD_SUCCESS */
+ "Linea OperInfo ha sido agregada al canal %s",
+ /* OCINFO_DEL_SUCCESS */
+ "La linea OperInfo ha sido removida del canal %s",
+ /* OINFO_HELP */
+ "Sintaxis: OINFO [ADD|DEL] nick <info>\n"
+ "Agrega o elimina informacion para Operadores al nick dado\n"
+ "Esto se mostrara cuando cualquier operador haga /ns info nick\n"
+ "y puede ser usado para 'marcado' de usuarios, etc....",
+ /* OCINFO_HELP */
+ "Sintaxis: OINFO [ADD|DEL] chan <info>\n"
+ "Agrega o elimina informacion para Operadores al canal dado\n"
+ "Esto se mostrara cuando cualquier operador haga /cs info canal\n"
+ "y puede ser usado para 'marcado' de canales, etc....",
+ /* OINFO_HELP_CMD */
+ " OINFO Agrega / Elimina una linea OperInfo al nick",
+ /* OCINFO_HELP_CMD */
+ " OINFO Agrega / Elimina una linea OperInfo al canal"
+ };
+
+ char *langtable_nl[] = {
+ /* OINFO_SYNTAX */
+ "Gebruik: OINFO [ADD|DEL] nick <info>",
+ /* OINFO_ADD_SUCCESS */
+ "OperInfo regel is toegevoegd aan nick %s",
+ /* OINFO_DEL_SUCCESS */
+ "OperInfo regel is weggehaald van nick %s",
+ /* OCINFO_SYNTAX */
+ "Gebruik: OINFO [ADD|DEL] kanaal <info>",
+ /* OCINFO_ADD_SUCCESS */
+ "OperInfo regel is toegevoegd aan kanaal %s",
+ /* OCINFO_DEL_SUCCESS */
+ "OperInfo regel is weggehaald van kanaal %s",
+ /* OINFO_HELP */
+ "Gebruik: OINFO [ADD|DEL] nick <info>\n"
+ "Voeg een Oper informatie regel toe aan de gegeven nick, of\n"
+ "verwijder deze. Deze regel zal worden weergegeven wanneer\n"
+ "een oper /ns info nick doet voor deze gebruiker, en kan worden\n"
+ "gebruikt om een gebruiker te 'markeren' etc...",
+ /* OCINFO_HELP */
+ "Gebruik: OINFO [ADD|DEL] kanaal <info>\n"
+ "Voeg een Oper informatie regel toe aan de gegeven kanaal, of\n"
+ "verwijder deze. Deze regel zal worden weergegeven wanneer\n"
+ "een oper /cs info kanaal doet voor dit kanaal, en kan worden\n"
+ "gebruikt om een kanaal te 'markeren' etc...",
+ /* OINFO_HELP_CMD */
+ " OINFO Voeg een OperInfo regel toe aan een nick of verwijder deze",
+ /* OCINFO_HELP_CMD */
+ " OINFO Voeg een OperInfo regel toe aan een kanaal of verwijder deze"
+ };
+
+ char *langtable_de[] = {
+ /* OINFO_SYNTAX */
+ "Syntax: OINFO [ADD|DEL] Nickname <Information>",
+ /* OINFO_ADD_SUCCESS */
+ "Eine OperInfo Linie wurde zu den Nicknamen %s hinzugefügt",
+ /* OINFO_DEL_SUCCESS */
+ "Die OperInfo Linie wurde von den Nicknamen %s enfernt",
+ /* OCINFO_SYNTAX */
+ "Syntax: OINFO [ADD|DEL] Channel <Information>",
+ /* OCINFO_ADD_SUCCESS */
+ "Eine OperInfo Linie wurde zu den Channel %s hinzugefügt",
+ /* OCINFO_DEL_SUCCESS */
+ "Die OperInfo Linie wurde von den Channel %s enfernt",
+ /* OINFO_HELP */
+ "Syntax: OINFO [ADD|DEL] Nickname <Information>\n"
+ "Addiert oder löscht eine OperInfo Linie zu den angegebenen\n"
+ "Nicknamen.Sie wird angezeigt wenn ein Oper mit /ns info sich\n"
+ "über den Nicknamen informiert.",
+ /* OCINFO_HELP */
+ "Syntax: OINFO [ADD|DEL] chan <info>\n"
+ "Addiert oder löscht eine OperInfo Linie zu den angegebenen\n"
+ "Channel.Sie wird angezeigt wenn ein Oper mit /cs info sich\n"
+ "über den Channel informiert.",
+ /* OINFO_HELP_CMD */
+ " OINFO Addiert / Löscht eine OperInfo Linie zu / von einen Nicknamen",
+ /* OCINFO_HELP_CMD */
+ " OINFO Addiert / Löscht eine OperInfo Linie zu / von einen Channel"
+ };
+
+ char *langtable_pt[] = {
+ /* OINFO_SYNTAX */
+ "Sintaxe: OINFO [ADD|DEL] nick <informação>",
+ /* OINFO_ADD_SUCCESS */
+ "A linha OperInfo foi adicionada ao nick %s",
+ /* OINFO_DEL_SUCCESS */
+ "A linha OperInfo foi removida do nick %s",
+ /* OCINFO_SYNTAX */
+ "Sintaxe: OINFO [ADD|DEL] canal <informação>",
+ /* OCINFO_ADD_SUCCESS */
+ "A linha OperInfo foi adicionada ao canal %s",
+ /* OCINFO_DEL_SUCCESS */
+ "A linha OperInfo foi removida do canal %s",
+ /* OINFO_HELP */
+ "Sintaxe: OINFO [ADD|DEL] nick <informação>\n"
+ "Adiciona ou apaga informação para Operadores ao nick fornecido\n"
+ "Isto será mostrado quando qualquer Operador usar /ns info nick\n"
+ "e pode ser usado para 'etiquetar' usuários etc...",
+ /* OCINFO_HELP */
+ "Sintaxe: OINFO [ADD|DEL] canal <informação>\n"
+ "Adiciona ou apaga informação para Operadores ao canal fornecido\n"
+ "Isto será mostrado quando qualquer Operador usar /cs info canal\n"
+ "e pode ser usado para 'etiquetar' canais etc...",
+ /* OINFO_HELP_CMD */
+ " OINFO Adiciona ou Apaga a linha OperInfo para um nick",
+ /* OCINFO_HELP_CMD */
+ " OINFO Adiciona ou Apaga a linha OperInfo para um canal"
+ };
+
+ char *langtable_ru[] = {
+ /* OINFO_SYNTAX */
+ "Ñèíòàêñèñ: OINFO ADD|DEL íèê òåñò",
+ /* OINFO_ADD_SUCCESS */
+ "Îïåð-Èíôîðìàöèÿ äëÿ íèêà %s äîáàâëåíà",
+ /* OINFO_DEL_SUCCESS */
+ "Îïåð-Èíôîðìàöèÿ äëÿ íèêà %s áûëà óäàëåíà",
+ /* OCINFO_SYNTAX */
+ "Ñèíòàêñèñ: OINFO ADD|DEL #êàíàë òåêñò",
+ /* OCINFO_ADD_SUCCESS */
+ "Îïåð-Èíôîðìàöèÿ äëÿ êàíàëà %s óñïåøíî óñòàíîâëåíà",
+ /* OCINFO_DEL_SUCCESS */
+ "Îïåð-Èíôîðìàöèÿ äëÿ êàíàëà %s áûëà óäàëåíà",
+ /* OINFO_HELP */
+ "Ñèíòàêñèñ: OINFO ADD|DEL íèê òåêñò\n"
+ "Óñòàíàâëèâàåò èëè óäàëÿåò Îïåð-Èíôîðìàöèþ äëÿ óêàçàííîãî íèêà,\n"
+ "êîòîðàÿ áóäåò ïîêàçàíà ëþáîìó îïåðàòîðó, çàïðàøèâàþùåìó INFO íèêà.\n"
+ "Ìîæåò áûòü èñïîëüçîâàíà äëÿ 'ïîìåòêè' ïîëüçîâàòåëåé è ò. ä...",
+ /* OCINFO_HELP */
+ "Ñèíòàêñèñ: OINFO ADD|DEL #êàíàë òåêñò\n"
+ "Óñòàíàâëèâàåò èëè óäàëÿåò Îïåð-Èíôîðìàöèþ äëÿ óêàçàííîãî êàíàëà,\n"
+ "êîòîðàÿ áóäåò ïîêàçàíà ëþáîìó îïåðàòîðó, çàïðàøèâàþùåìó INFO êàíàëà.\n"
+ "Ìîæåò áûòü èñïîëüçîâàíà äëÿ 'ïîìåòêè' êàíàëîâ è ò. ä...",
+ /* OINFO_HELP_CMD */
+ " OINFO Äîáàâëÿåò/Óäàëÿåò îïåð-èíôî äëÿ íèêà",
+ /* OCINFO_HELP_CMD */
+ " OINFO Äîáàâëÿåò/Óäàëÿåò îïåð-èíôî äëÿ êàíàëà"
+ };
+
+ char *langtable_it[] = {
+ /* OINFO_SYNTAX */
+ "Sintassi: OINFO [ADD|DEL] nick <info>",
+ /* OINFO_ADD_SUCCESS */
+ "Linea OperInfo aggiunta al nick %s",
+ /* OINFO_DEL_SUCCESS */
+ "Linea OperInfo rimossa dal nick %s",
+ /* OCINFO_SYNTAX */
+ "Sintassi: OINFO [ADD|DEL] chan <info>",
+ /* OCINFO_ADD_SUCCESS */
+ "Linea OperInfo aggiunta al canale %s",
+ /* OCINFO_DEL_SUCCESS */
+ "Linea OperInfo rimossa dal canale %s",
+ /* OINFO_HELP */
+ "Sintassi: OINFO [ADD|DEL] nick <info>\n"
+ "Aggiunge o rimuove informazioni Oper per il nick specificato\n"
+ "Queste vengono mostrate quando un oper esegue il comando /ns info <nick>\n"
+ "e possono essere utilizzate per 'marchiare' gli utenti ecc...",
+ /* OCINFO_HELP */
+ "Sintassi: OINFO [ADD|DEL] chan <info>\n"
+ "Aggiunge o rimuove informazioni Oper per il canale specificato\n"
+ "Queste vengono mostrate quando un oper esegue il comando /cs info <canale>\n"
+ "e possono essere utilizzate per 'marchiare' i canali ecc...",
+ /* OINFO_HELP_CMD */
+ " OINFO Aggiunge/Rimuove una linea OperInfo ad/da un nick",
+ /* OCINFO_HELP_CMD */
+ " OINFO Aggiunge/Rimuove una linea OperInfo ad/da un canale"
+ };
+
+ moduleInsertLanguage(LANG_EN_US, LANG_NUM_STRINGS, langtable_en_us);
+ moduleInsertLanguage(LANG_ES, LANG_NUM_STRINGS, langtable_es);
+ moduleInsertLanguage(LANG_NL, LANG_NUM_STRINGS, langtable_nl);
+ moduleInsertLanguage(LANG_DE, LANG_NUM_STRINGS, langtable_de);
+ moduleInsertLanguage(LANG_PT, LANG_NUM_STRINGS, langtable_pt);
+ moduleInsertLanguage(LANG_RU, LANG_NUM_STRINGS, langtable_ru);
+ moduleInsertLanguage(LANG_IT, LANG_NUM_STRINGS, langtable_it);
+}
+
+/*************************************************************************/
+
+int mNickHelp(User * u)
+{
+ if (is_oper(u)) {
+ moduleNoticeLang(s_NickServ, u, OINFO_HELP);
+ } else {
+ notice_lang(s_NickServ, u, NO_HELP_AVAILABLE, "OINFO");
+ }
+ return MOD_CONT;
+}
+
+int mChanHelp(User * u)
+{
+ if (is_oper(u)) {
+ moduleNoticeLang(s_ChanServ, u, OCINFO_HELP);
+ } else {
+ notice_lang(s_ChanServ, u, NO_HELP_AVAILABLE, "OINFO");
+ }
+ return MOD_CONT;
+}
+
+/* This help will be added to the main NickServ list */
+void mMainNickHelp(User * u)
+{
+ if (is_oper(u)) {
+ moduleNoticeLang(s_NickServ, u, OINFO_HELP_CMD);
+ }
+}
+
+/* This help will be added to the main NickServ list */
+void mMainChanHelp(User * u)
+{
+ if (is_oper(u)) {
+ moduleNoticeLang(s_ChanServ, u, OCINFO_HELP_CMD);
+ }
+}
+
+/*************************************************************************/
+
+/* EOF */
diff --git a/src/mypasql.c b/src/mypasql.c
new file mode 100644
index 000000000..a66850c84
--- /dev/null
+++ b/src/mypasql.c
@@ -0,0 +1,122 @@
+#include <winsock.h>
+#include <stdio.h>
+#include <mysql.h>
+
+MYSQL *mysql;
+MYSQL_RES *result = NULL;
+MYSQL_ROW row;
+
+int __stdcall mysql_Connect(char *server, char *user, char *pass)
+{
+ mysql = mysql_init(NULL);
+ return (int) mysql_real_connect(mysql, server, user, pass, NULL, 0,
+ NULL, 0);
+}
+
+int __stdcall mysql_SelectDb(char *db)
+{
+ return (int) mysql_select_db(mysql, db);
+}
+
+const char *__stdcall mysql_Error()
+{
+ return mysql_error(mysql);
+}
+
+int __stdcall mysql_Query(char *query)
+{
+ if (result) {
+ mysql_free_result(result);
+ result = NULL;
+ }
+ return (int) mysql_real_query(mysql, query, strlen(query));
+}
+
+int __stdcall mysql_NumRows()
+{
+ if (!result)
+ result = mysql_store_result(mysql);
+ return mysql_num_rows(result);
+}
+
+char *strip(char *str)
+{
+ char *c;
+ if ((c = strrchr(str, '\n')))
+ *c = 0;
+ if ((c = strrchr(str, '\r')))
+ *c = 0;
+ return str;
+}
+
+void add_line(char **buf, char *line)
+{
+ int oldlen;
+ char *tmp;
+
+ if (*buf != NULL) {
+ oldlen = strlen(*buf);
+ tmp = malloc(oldlen + 1);
+ strcpy(tmp, *buf);
+ *buf = realloc(*buf, oldlen + strlen(line) + 1);
+ strcpy(*buf, tmp);
+ strcat(*buf, line);
+ free(tmp);
+ } else
+ *buf = strdup(line);
+}
+
+int __stdcall mysql_LoadFromFile(char *file)
+{
+ FILE *fd = fopen(file, "r");
+ char line[1024];
+ char *query = NULL;
+
+
+ if (!fd)
+ return 0;
+ while (fgets(line, 1024, fd)) {
+ int len;
+ strip(line);
+ len = strlen(line);
+ if (!*line || (*line == '-' && *(line + 1) == '-'))
+ continue;
+ else if (line[len - 1] == ';') { /* End of a query */
+ line[len - 1] = 0;
+ add_line(&query, line);
+ if (mysql_real_query(mysql, query, strlen(query))) {
+ free(query);
+ return 0;
+ }
+ free(query);
+ query = NULL;
+ }
+
+ else
+ add_line(&query, line);
+ }
+ return 1;
+}
+
+int __stdcall mysql_NumFields()
+{
+ if (!result)
+ result = mysql_store_result(mysql);
+ return mysql_num_fields(result);
+}
+
+int __stdcall mysql_FetchRow()
+{
+ if (!result)
+ result = mysql_store_result(mysql);
+ row = mysql_fetch_row(result);
+ return (int) row;
+}
+
+char *__stdcall mysql_FetchField(int i)
+{
+ if (i >= mysql_num_fields(result))
+ return NULL;
+ else
+ return row[i];
+}
diff --git a/src/mypasql.def b/src/mypasql.def
new file mode 100644
index 000000000..f04df9556
--- /dev/null
+++ b/src/mypasql.def
@@ -0,0 +1,10 @@
+EXPORTS
+mysql_Connect
+mysql_Error
+mysql_SelectDb
+mysql_Query
+mysql_NumRows
+mysql_NumFields
+mysql_LoadFromFile
+mysql_FetchRow
+mysql_FetchField
diff --git a/src/mysql.c b/src/mysql.c
new file mode 100644
index 000000000..c4db94252
--- /dev/null
+++ b/src/mysql.c
@@ -0,0 +1,2058 @@
+
+/* MySQL functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+#include "services.h"
+
+/*************************************************************************/
+
+/* Database Global Variables */
+MYSQL *mysql; /* MySQL Handler */
+MYSQL_RES *mysql_res; /* MySQL Result */
+MYSQL_FIELD *mysql_fields; /* MySQL Fields */
+MYSQL_ROW mysql_row; /* MySQL Row */
+
+int mysql_is_connected = 0; /* Are we currently connected? */
+
+/*************************************************************************/
+
+/* Throw a mysql error into the logs. If severity is MYSQL_ERROR, we
+ * also exit Anope...
+ */
+void db_mysql_error(int severity, char *msg)
+{
+ static char buf[512];
+
+ if (mysql_error(mysql)) {
+ snprintf(buf, sizeof(buf), "MySQL %s %s: %s", msg,
+ severity == MYSQL_WARNING ? "warning" : "error",
+ mysql_error(mysql));
+ } else {
+ snprintf(buf, sizeof(buf), "MySQL %s %s", msg,
+ severity == MYSQL_WARNING ? "warning" : "error");
+ }
+
+ log_perror(buf);
+
+ if (severity == MYSQL_ERROR) {
+ log_perror("MySQL FATAL error... aborting.");
+ exit(0);
+ }
+
+}
+
+/*************************************************************************/
+
+/* Initialize the MySQL code */
+int db_mysql_init()
+{
+
+ /* If the host is not defined, assume we don't want MySQL */
+ if (!MysqlHost) {
+ do_mysql = 0;
+ alog("MySQL: has been disabled.");
+ return 0;
+ } else {
+ do_mysql = 1;
+ alog("MySQL: has been enabled.");
+ alog("MySQL: client version %s.", mysql_get_client_info());
+ }
+
+ /* The following configuration options are required.
+ * If missing disable MySQL to avoid any problems.
+ */
+
+ if ((do_mysql) && (!MysqlName || !MysqlUser)) {
+ do_mysql = 0;
+ alog("MySQL Error: Set all required configuration options.");
+ return 0;
+ }
+
+ if (!db_mysql_open()) {
+ do_mysql = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Open a connection to the mysql database. Return 0 on failure, or
+ * 1 on success. If this succeeds, we're guaranteed of a working
+ * mysql connection (unless something unexpected happens ofcourse...)
+ */
+int db_mysql_open()
+{
+ /* If MySQL is disabled, return 0 */
+ if (!do_mysql)
+ return 0;
+
+ /* If we are reported to be connected, ping MySQL to see if we really are
+ * still connected. (yes mysql_ping() returns 0 on success)
+ */
+ if (mysql_is_connected && !mysql_ping(mysql))
+ return 1;
+
+ mysql_is_connected = 0;
+
+ mysql = mysql_init(NULL);
+ if (mysql == NULL) {
+ db_mysql_error(MYSQL_WARNING, "Unable to create mysql object");
+ return 0;
+ }
+
+ if (!MysqlPort)
+ MysqlPort = MYSQL_DEFAULT_PORT;
+
+ if (!mysql_real_connect(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort, MysqlSock, 0)) {
+ log_perror("MySQL Error: Cant connect to MySQL: %s\n", mysql_error(mysql));
+ return 0;
+ }
+
+ mysql_is_connected = 1;
+
+ return 1;
+
+}
+
+
+/*************************************************************************/
+
+/* Perform a MySQL query. Return 1 if the query succeeded and 0 if the
+ * query failed. Before returning failure, re-try the query a few times
+ * and die if it still fails.
+ */
+int db_mysql_query(char *sql)
+{
+ int lcv;
+
+ if (!do_mysql)
+ return 0;
+
+ if (debug)
+ alog("debug: MySQL: %s", sql);
+
+ /* Try as many times as configured in MysqlRetries */
+ for (lcv = 0; lcv < MysqlRetries; lcv++) {
+ if (db_mysql_open() && (mysql_query(mysql, sql) == 0))
+ return 1;
+
+ /* If we get here, we could not run the query */
+ log_perror("Unable to run query: %s\n", mysql_error(mysql));
+
+ /* Wait for MysqlRetryGap seconds and try again */
+ sleep(MysqlRetryGap);
+ }
+
+ /* Unable to run the query even after MysqlRetries tries */
+ db_mysql_error(MYSQL_WARNING, "query");
+
+ return 0;
+
+}
+
+/*************************************************************************/
+
+/* Quote a string to be safely included in a query. The result of this
+ * function is allocated; it MUST be freed by the caller.
+ */
+char *db_mysql_quote(char *sql)
+{
+ int slen;
+ char *quoted;
+
+
+ if (!sql)
+ return sstrdup("");
+
+ slen = strlen(sql);
+ quoted = malloc((1 + (slen * 2)) * sizeof(char));
+
+ mysql_real_escape_string(mysql, quoted, sql, slen);
+
+ return quoted;
+
+}
+
+/**
+ * Quote a buffer to be safely included in a query.
+ * The result is allocated and needs to be freed by caller.
+ **/
+char *db_mysql_quote_buffer(char *sql, int size)
+{
+ char *ret;
+ ret = scalloc((1 + 2 * size), sizeof(char));
+
+ mysql_real_escape_string(mysql, ret, sql, size);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/* Close the MySQL database connection. */
+int db_mysql_close()
+{
+ mysql_close(mysql);
+
+ mysql_is_connected = 0;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Try to execute a query and issue a warning when failed. Return 1 on
+ * success and 0 on failure.
+ */
+int db_mysql_try(const char *fmt, ...)
+{
+ va_list args;
+ static char sql[MAX_SQL_BUF];
+
+ va_start(args, fmt);
+ vsnprintf(sql, MAX_SQL_BUF, fmt, args);
+ va_end(args);
+
+ if (!db_mysql_query(sql)) {
+ log_perror("Can't create sql query: %s", sql);
+ db_mysql_error(MYSQL_WARNING, "query");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns a string (buffer) to insert into a SQL query.
+ * The string will, once evaluated by MySQL, result in the given pass
+ * encoded in the encryption type selected for MysqlSecure
+ *
+ * This should be removed since Rob properly did encryption modules... -GD
+ *
+ * @param dest Destination buffer to store the password/ encryption string in. Needs to be at least size+14.
+ * @param pass The buffer containing the password to secure.
+ * @param bufsize The size of the destination buffer.
+ * @param size The size of the password-to-secure buffer.
+ * @return Returns -1 on failure, 1 if the result needs to be made MySQL safe (hash), 0 if it s ready.
+ **/
+int db_mysql_secure(char *dest, char *pass, int bufsize, int size)
+{
+ char tmp_pass[PASSMAX];
+
+ if (bufsize < size+14)
+ return -1;
+
+ /* Initialize the buffer. Bug #86 */
+ memset(tmp_pass, 0, PASSMAX);
+ memset(dest, 0, bufsize);
+
+ /* Return all zeros if no pass is set. */
+ if (!pass)
+ return 1;
+
+ /* We couldnt decrypt the pass... */
+ if (enc_decrypt(pass, tmp_pass, PASSMAX - 1) != 1) {
+ memcpy(dest, pass, size);
+ return 1;
+ } else { /* if we could decrypt the pass */
+ if ((!MysqlSecure) || (strcmp(MysqlSecure, "") == 0)) {
+ snprintf(dest, bufsize, "'%s'", tmp_pass);
+ } else if (strcmp(MysqlSecure, "des") == 0) {
+ snprintf(dest, bufsize, "ENCRYPT('%s')", tmp_pass);
+ } else if (strcmp(MysqlSecure, "md5") == 0) {
+ snprintf(dest, bufsize, "MD5('%s')", tmp_pass);
+ } else if (strcmp(MysqlSecure, "sha") == 0) {
+ snprintf(dest, bufsize, "SHA('%s')", tmp_pass);
+ } else {
+ snprintf(dest, bufsize, "ENCODE('%s','%s')", tmp_pass,
+ MysqlSecure);
+ }
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/*
+ * NickServ Specific Secion
+ */
+
+/*************************************************************************/
+
+/* Save the given NickRequest into the database
+ * Return 1 on success, 0 on failure
+ * These tables are tagged and will be cleaned:
+ * - anope_ns_request
+ */
+int db_mysql_save_ns_req(NickRequest * nr)
+{
+ int ret;
+ char *q_nick, *q_passcode, *q_password, *q_email;
+
+ q_nick = db_mysql_quote(nr->nick);
+ q_passcode = db_mysql_quote(nr->passcode);
+ q_password = db_mysql_quote_buffer(nr->password, PASSMAX);
+ q_email = db_mysql_quote(nr->email);
+
+ ret = db_mysql_try("UPDATE anope_ns_request "
+ "SET passcode = '%s', password = '%s', email = '%s', requested = %d, active = 1 "
+ "WHERE nick = '%s'",
+ q_passcode, q_password, q_email, (int) nr->requested,
+ q_nick);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_ns_request "
+ "(nick, passcode, password, email, requested, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, 1)",
+ q_nick, q_passcode, q_password, q_email,
+ (int) nr->requested);
+ }
+
+ free(q_nick);
+ free(q_passcode);
+ free(q_password);
+ free(q_email);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/* Save the given NickCore into the database
+ * Also save the access list and memo's for this user
+ * Return 1 on success, 0 on failure
+ * These tables are tagged and will be cleaned:
+ * - anope_ns_core
+ * - anope_ns_alias
+ * - anope_ns_access
+ * - anope_ms_info (serv='NICK')
+ */
+int db_mysql_save_ns_core(NickCore * nc)
+{
+ int ret, res;
+ int i;
+ char epass[PASSMAX+15];
+ char *q_display, *q_pass = NULL, *q_email, *q_greet, *q_url,
+ *q_access, *q_sender, *q_text;
+
+ q_display = db_mysql_quote(nc->display);
+ q_email = db_mysql_quote(nc->email);
+ q_greet = db_mysql_quote(nc->greet);
+ q_url = db_mysql_quote(nc->url);
+
+ /* First secure the pass, then make it MySQL safe.. - Viper */
+ res = db_mysql_secure(epass, nc->pass, PASSMAX+15, PASSMAX);
+ if (res < 0)
+ fatal("Unable to encrypt password for MySQL");
+ else if (res)
+ q_pass = db_mysql_quote_buffer(epass, PASSMAX+15);
+ else {
+ q_pass = scalloc(PASSMAX+15,sizeof(char));
+ memcpy(q_pass, epass, PASSMAX+15);
+ }
+
+ /* If it has been made MySQL safe, it still needs the 's.
+ * I know it s an ugly solution, but it works without breaking anything.. - Viper */
+ /* Let's take care of the core itself */
+ /* Update the existing records */
+ if (res)
+ ret = db_mysql_try("UPDATE anope_ns_core "
+ "SET pass = '%s', email = '%s', greet = '%s', icq = %d, url = '%s', flags = %d, language = %d, accesscount = %d, memocount = %d, "
+ " memomax = %d, channelcount = %d, channelmax = %d, active = 1 "
+ "WHERE display = '%s'",
+ q_pass, q_email, q_greet, nc->icq, q_url, nc->flags,
+ nc->language, nc->accesscount, nc->memos.memocount,
+ nc->memos.memomax, nc->channelcount, nc->channelmax,
+ q_display);
+ else
+ ret = db_mysql_try("UPDATE anope_ns_core "
+ "SET pass = %s, email = '%s', greet = '%s', icq = %d, url = '%s', flags = %d, language = %d, accesscount = %d, memocount = %d, "
+ " memomax = %d, channelcount = %d, channelmax = %d, active = 1 "
+ "WHERE display = '%s'",
+ q_pass, q_email, q_greet, nc->icq, q_url, nc->flags,
+ nc->language, nc->accesscount, nc->memos.memocount,
+ nc->memos.memomax, nc->channelcount, nc->channelmax,
+ q_display);
+
+ /* Our previous UPDATE affected no rows, therefore this is a new record */
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ if (res)
+ ret = db_mysql_try("INSERT DELAYED INTO anope_ns_core "
+ "(display, pass, email, greet, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, %d, %d, 1)",
+ q_display, q_pass, q_email, q_greet, nc->icq, q_url,
+ nc->flags, nc->language, nc->accesscount,
+ nc->memos.memocount, nc->memos.memomax,
+ nc->channelcount, nc->channelmax);
+ else
+ ret = db_mysql_try("INSERT DELAYED INTO anope_ns_core "
+ "(display, pass, email, greet, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, active) "
+ "VALUES ('%s', %s, '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, %d, %d, 1)",
+ q_display, q_pass, q_email, q_greet, nc->icq, q_url,
+ nc->flags, nc->language, nc->accesscount,
+ nc->memos.memocount, nc->memos.memomax,
+ nc->channelcount, nc->channelmax);
+ }
+
+ /* Now let's do the access */
+ for (i = 0; ret && (i < nc->accesscount); i++) {
+ q_access = db_mysql_quote(nc->access[i]);
+/**
+ ret = db_mysql_try("UPDATE anope_ns_access "
+ "SET access = '%s' "
+ "WHERE display = '%s'",
+ q_access, q_display);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {**/
+
+ ret = db_mysql_try("INSERT DELAYED INTO anope_ns_access "
+ "(display, access) "
+ "VALUES ('%s','%s')",
+ q_display, q_access);
+/* } */
+
+ free(q_access);
+ }
+
+ /* Memos */
+ for (i = 0; ret && (i < nc->memos.memocount); i++) {
+ q_sender = db_mysql_quote(nc->memos.memos[i].sender);
+ q_text = db_mysql_quote(nc->memos.memos[i].text);
+
+ ret = db_mysql_try("UPDATE anope_ms_info "
+ "SET receiver = '%s', number = %d, flags = %d, time = %d, sender = '%s', text = '%s', active = 1 "
+ "WHERE nm_id = %d AND serv = 'NICK'",
+ q_display, nc->memos.memos[i].number,
+ nc->memos.memos[i].flags,
+ (int) nc->memos.memos[i].time, q_sender, q_text,
+ nc->memos.memos[i].id);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT INTO anope_ms_info "
+ "(receiver, number, flags, time, sender, text, serv, active) "
+ "VALUES ('%s', %d, %d, %d, '%s', '%s', 'NICK', 1)",
+ q_display, nc->memos.memos[i].number,
+ nc->memos.memos[i].flags,
+ (int) nc->memos.memos[i].time, q_sender,
+ q_text);
+
+ /* This is to make sure we can UPDATE memos instead of TRUNCATE
+ * the table each time and then INSERT them all again. Ideally
+ * everything in core would have it's dbase-id stored, but that's
+ * something for phase 3. -GD
+ */
+ if (ret)
+ nc->memos.memos[i].id = mysql_insert_id(mysql);
+ }
+
+ free(q_sender);
+ free(q_text);
+ }
+
+ free(q_display);
+ free(q_pass);
+ free(q_email);
+ free(q_greet);
+ free(q_url);
+
+ return ret;
+}
+
+
+/*************************************************************************/
+
+/* Save the given NickAlias into the database
+ * Return 1 on success, 0 on failure
+ * These tables are tagged and will be cleaned:
+ * - anope_ns_core
+ * - anope_ns_alias
+ * - anope_ns_access
+ * - anope_ms_info (serv='NICK')
+ */
+int db_mysql_save_ns_alias(NickAlias * na)
+{
+ int ret;
+ char *q_nick, *q_lastmask, *q_lastrname, *q_lastquit, *q_display;
+
+ q_nick = db_mysql_quote(na->nick);
+ q_lastmask = db_mysql_quote(na->last_usermask);
+ q_lastrname = db_mysql_quote(na->last_realname);
+ q_lastquit = db_mysql_quote(na->last_quit);
+ q_display = db_mysql_quote(na->nc->display);
+
+ ret = db_mysql_try("UPDATE anope_ns_alias "
+ "SET last_usermask = '%s', last_realname = '%s', last_quit = '%s', time_registered = %d, last_seen = %d, status = %d, "
+ " display = '%s', active = 1 "
+ "WHERE nick = '%s'",
+ q_lastmask, q_lastrname, q_lastquit,
+ (int) na->time_registered, (int) na->last_seen,
+ (int) na->status, q_display, q_nick);
+
+ /* Our previous UPDATE affected no rows, therefore this is a new record */
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_ns_alias "
+ "(nick, last_usermask, last_realname, last_quit, time_registered, last_seen, status, display, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, '%s', 1)",
+ q_nick, q_lastmask, q_lastrname, q_lastquit,
+ (int) na->time_registered, (int) na->last_seen,
+ (int) na->status, q_display);
+ }
+
+ free(q_nick);
+ free(q_lastmask);
+ free(q_lastrname);
+ free(q_lastquit);
+ free(q_display);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/*
+ * ChanServ Specific Secion
+ */
+
+/*************************************************************************/
+
+/* Save the given ChannelInfo into the database
+ * Also save the access list, levels, akicks, badwords, ttb, and memo's for this channel
+ * Return 1 on success, 0 on failure
+ * These tables are tagged and will be cleaned:
+ * - anope_cs_info
+ * - anope_cs_access
+ * - anope_cs_levels
+ * - anope_cs_akicks
+ * - anope_cs_badwords
+ * - anope_cs_ttb
+ * - anope_ms_info (serv='CHAN')
+ */
+int db_mysql_save_cs_info(ChannelInfo * ci)
+{
+ int ret, res, i;
+ char epass[PASSMAX+15];
+ char *q_name;
+ char *q_founder;
+ char *q_successor;
+ char *q_pass = NULL;
+ char *q_desc;
+ char *q_url;
+ char *q_email;
+ char *q_lasttopic;
+ char *q_lasttopicsetter;
+ char *q_forbidby;
+ char *q_forbidreason;
+ char *q_mlock_key;
+ char *q_mlock_flood;
+ char *q_mlock_redirect;
+ char *q_entrymsg;
+ char *q_botnick;
+ char *q_sender;
+ char *q_text;
+ char *q_accessdisp;
+ char *q_akickdisp;
+ char *q_akickreason;
+ char *q_akickcreator;
+ char *q_badwords;
+
+ q_name = db_mysql_quote(ci->name);
+ if (ci->founder) {
+ q_founder = db_mysql_quote(ci->founder->display);
+ } else {
+ q_founder = db_mysql_quote("");
+ }
+ if (ci->successor) {
+ q_successor = db_mysql_quote(ci->successor->display);
+ } else {
+ q_successor = db_mysql_quote("");
+ }
+ q_desc = db_mysql_quote(ci->desc);
+ q_url = db_mysql_quote(ci->url);
+ q_email = db_mysql_quote(ci->email);
+ q_lasttopic = db_mysql_quote(ci->last_topic);
+ q_lasttopicsetter = db_mysql_quote(ci->last_topic_setter);
+ q_forbidby = db_mysql_quote(ci->forbidby);
+ q_forbidreason = db_mysql_quote(ci->forbidreason);
+ q_mlock_key = db_mysql_quote(ci->mlock_key);
+ q_mlock_flood = db_mysql_quote(ci->mlock_flood);
+ q_mlock_redirect = db_mysql_quote(ci->mlock_redirect);
+ q_entrymsg = db_mysql_quote(ci->entry_message);
+ if (ci->bi) {
+ q_botnick = db_mysql_quote(ci->bi->nick);
+ } else {
+ q_botnick = db_mysql_quote("");
+ }
+
+ /* First secure the pass, then make it MySQL safe.. - Viper */
+ res = db_mysql_secure(epass, ci->founderpass, PASSMAX+15, PASSMAX);
+ if (res < 0)
+ fatal("Unable to encrypt password for MySQL");
+ else if (res)
+ q_pass = db_mysql_quote_buffer(epass, PASSMAX+15);
+ else {
+ q_pass = scalloc(PASSMAX+15,sizeof(char));
+ memcpy(q_pass, epass, PASSMAX+15);
+ }
+
+ /* If it has been made MySQL safe, it still needs the 's.
+ * I know it s an ugly solution, but it works without breaking anything.. - Viper */
+ /* Let's take care of the core itself */
+ if (res)
+ ret = db_mysql_try("UPDATE anope_cs_info "
+ "SET founder = '%s', successor = '%s', founderpass = '%s', descr = '%s', url = '%s', email = '%s', time_registered = %d, "
+ " last_used = %d, last_topic = '%s', last_topic_setter = '%s', last_topic_time = %d, flags = %d, forbidby = '%s', "
+ " forbidreason = '%s', bantype = %d, accesscount = %d, akickcount = %d, mlock_on = %d, mlock_off = %d, mlock_limit = %d, "
+ " mlock_key = '%s', mlock_flood = '%s', mlock_redirect = '%s', entry_message = '%s', memomax = %d, botnick = '%s', botflags = %d, "
+ " bwcount = %d, capsmin = %d, capspercent = %d, floodlines = %d, floodsecs = %d, repeattimes = %d, active = 1 "
+ "WHERE name = '%s'",
+ q_founder, q_successor, q_pass, q_desc, q_url, q_email,
+ (int) ci->time_registered, (int) ci->last_used,
+ q_lasttopic, q_lasttopicsetter,
+ (int) ci->last_topic_time, (int) ci->flags, q_forbidby,
+ q_forbidreason, (int) ci->bantype,
+ (int) ci->accesscount, (int) ci->akickcount,
+ (int) ci->mlock_on, (int) ci->mlock_off,
+ (int) ci->mlock_limit, q_mlock_key, q_mlock_flood,
+ q_mlock_redirect, q_entrymsg, (int) ci->memos.memomax,
+ q_botnick, (int) ci->botflags, (int) ci->bwcount,
+ (int) ci->capsmin, (int) ci->capspercent,
+ (int) ci->floodlines, (int) ci->floodsecs,
+ (int) ci->repeattimes, q_name);
+ else
+ ret = db_mysql_try("UPDATE anope_cs_info "
+ "SET founder = '%s', successor = '%s', founderpass = %s, descr = '%s', url = '%s', email = '%s', time_registered = %d, "
+ " last_used = %d, last_topic = '%s', last_topic_setter = '%s', last_topic_time = %d, flags = %d, forbidby = '%s', "
+ " forbidreason = '%s', bantype = %d, accesscount = %d, akickcount = %d, mlock_on = %d, mlock_off = %d, mlock_limit = %d, "
+ " mlock_key = '%s', mlock_flood = '%s', mlock_redirect = '%s', entry_message = '%s', memomax = %d, botnick = '%s', botflags = %d, "
+ " bwcount = %d, capsmin = %d, capspercent = %d, floodlines = %d, floodsecs = %d, repeattimes = %d, active = 1 "
+ "WHERE name = '%s'",
+ q_founder, q_successor, q_pass, q_desc, q_url, q_email,
+ (int) ci->time_registered, (int) ci->last_used,
+ q_lasttopic, q_lasttopicsetter,
+ (int) ci->last_topic_time, (int) ci->flags, q_forbidby,
+ q_forbidreason, (int) ci->bantype,
+ (int) ci->accesscount, (int) ci->akickcount,
+ (int) ci->mlock_on, (int) ci->mlock_off,
+ (int) ci->mlock_limit, q_mlock_key, q_mlock_flood,
+ q_mlock_redirect, q_entrymsg, (int) ci->memos.memomax,
+ q_botnick, (int) ci->botflags, (int) ci->bwcount,
+ (int) ci->capsmin, (int) ci->capspercent,
+ (int) ci->floodlines, (int) ci->floodsecs,
+ (int) ci->repeattimes, q_name);
+
+ /* Our previous UPDATE affected no rows, therefore this is a new record */
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ if (res)
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_info "
+ "(name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, "
+ " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, "
+ " mlock_key, mlock_flood, mlock_redirect, entry_message, botnick, botflags, bwcount, capsmin, capspercent, floodlines, "
+ " floodsecs, repeattimes, active) "
+ "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', %d, %d, %d, %d, %d, %d, '%s', '%s', "
+ " '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d, 1)",
+ q_name, q_founder, q_successor, q_pass, q_desc,
+ q_url, q_email, (int) ci->time_registered,
+ (int) ci->last_used, q_lasttopic,
+ q_lasttopicsetter, (int) ci->last_topic_time,
+ (int) ci->flags, q_forbidby, q_forbidreason,
+ (int) ci->bantype, (int) ci->accesscount,
+ (int) ci->akickcount, (int) ci->mlock_on,
+ (int) ci->mlock_off, (int) ci->mlock_limit,
+ q_mlock_key, q_mlock_flood, q_mlock_redirect,
+ q_entrymsg, q_botnick, (int) ci->botflags,
+ (int) ci->bwcount, (int) ci->capsmin,
+ (int) ci->capspercent, (int) ci->floodlines,
+ (int) ci->floodsecs, (int) ci->repeattimes);
+ else
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_info "
+ "(name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, "
+ " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, "
+ " mlock_key, mlock_flood, mlock_redirect, entry_message, botnick, botflags, bwcount, capsmin, capspercent, floodlines, "
+ " floodsecs, repeattimes, active) "
+ "VALUES ('%s', '%s', '%s', %s, '%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', %d, %d, %d, %d, %d, %d, '%s', '%s', "
+ " '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d, 1)",
+ q_name, q_founder, q_successor, q_pass, q_desc,
+ q_url, q_email, (int) ci->time_registered,
+ (int) ci->last_used, q_lasttopic,
+ q_lasttopicsetter, (int) ci->last_topic_time,
+ (int) ci->flags, q_forbidby, q_forbidreason,
+ (int) ci->bantype, (int) ci->accesscount,
+ (int) ci->akickcount, (int) ci->mlock_on,
+ (int) ci->mlock_off, (int) ci->mlock_limit,
+ q_mlock_key, q_mlock_flood, q_mlock_redirect,
+ q_entrymsg, q_botnick, (int) ci->botflags,
+ (int) ci->bwcount, (int) ci->capsmin,
+ (int) ci->capspercent, (int) ci->floodlines,
+ (int) ci->floodsecs, (int) ci->repeattimes);
+ }
+
+ /* Memos */
+ for (i = 0; ret && (i < ci->memos.memocount); i++) {
+ q_sender = db_mysql_quote(ci->memos.memos[i].sender);
+ q_text = db_mysql_quote(ci->memos.memos[i].text);
+
+ ret = db_mysql_try("UPDATE anope_ms_info "
+ "SET receiver = '%s', number = %d, flags = %d, time = %d, sender = '%s', text = '%s', active = 1 "
+ "WHERE nm_id = %d AND serv = 'CHAN'",
+ q_name, ci->memos.memos[i].number,
+ ci->memos.memos[i].flags,
+ (int) ci->memos.memos[i].time, q_sender, q_text,
+ ci->memos.memos[i].id);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT INTO anope_ms_info "
+ "(receiver, number,flags, time, sender, text, serv, active) "
+ "VALUES ('%s', %d, %d, %d, '%s', '%s', 'CHAN', 1)",
+ q_name, ci->memos.memos[i].number,
+ ci->memos.memos[i].flags,
+ (int) ci->memos.memos[i].time, q_sender,
+ q_text);
+
+ /* See comment at db_mysql_save_ns_core */
+ if (ret)
+ ci->memos.memos[i].id = mysql_insert_id(mysql);
+ }
+
+ free(q_sender);
+ free(q_text);
+ }
+
+ /* Access */
+ for (i = 0; ret && (i < ci->accesscount); i++) {
+ if (ci->access[i].in_use) {
+ q_accessdisp = db_mysql_quote(ci->access[i].nc->display);
+
+ ret = db_mysql_try("UPDATE anope_cs_access "
+ "SET in_use = %d, level = %d, last_seen = %d, active = 1 "
+ "WHERE channel = '%s' AND display = '%s'",
+ (int) ci->access[i].in_use,
+ (int) ci->access[i].level,
+ (int) ci->access[i].last_seen,
+ q_name, q_accessdisp);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_access "
+ "(channel, display, in_use, level, last_seen, active) "
+ "VALUES ('%s', '%s', %d, %d, %d, 1)",
+ q_name, q_accessdisp,
+ (int) ci->access[i].in_use,
+ (int) ci->access[i].level,
+ (int) ci->access[i].last_seen);
+ }
+
+ free(q_accessdisp);
+ }
+ }
+
+ /* Levels */
+ for (i = 0; ret && (i < CA_SIZE); i++) {
+ ret = db_mysql_try("UPDATE anope_cs_levels "
+ "SET level = %d, active = 1 "
+ "WHERE channel = '%s' AND position = %d",
+ (int) ci->levels[i], q_name, i);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_levels "
+ "(channel, position, level, active) "
+ "VALUES ('%s', %d, %d, 1)",
+ q_name, i, (int) ci->levels[i]);
+ }
+ }
+
+ /* Akicks */
+ for (i = 0; ret && (i < ci->akickcount); i++) {
+ if (ci->akick[i].flags & AK_USED) {
+ if (ci->akick[i].flags & AK_ISNICK)
+ q_akickdisp = db_mysql_quote(ci->akick[i].u.nc->display);
+ else
+ q_akickdisp = db_mysql_quote(ci->akick[i].u.mask);
+
+ q_akickreason = db_mysql_quote(ci->akick[i].reason);
+ q_akickcreator = db_mysql_quote(ci->akick[i].creator);
+ } else {
+ q_akickdisp = "";
+ q_akickreason = "";
+ q_akickcreator = "";
+ }
+
+ ret = db_mysql_try("UPDATE anope_cs_akicks "
+ "SET flags = %d, reason = '%s', creator = '%s', addtime = %d, active = 1 "
+ "WHERE channel = '%s' AND dmask = '%s'",
+ (int) ci->akick[i].flags, q_akickreason,
+ q_akickcreator, (ci->akick[i].flags & AK_USED ?
+ (int) ci->akick[i].addtime : 0),
+ q_name, q_akickdisp);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_akicks "
+ "(channel, dmask, flags, reason, creator, addtime, active) "
+ "VALUES ('%s', '%s', %d, '%s', '%s', %d, 1)",
+ q_name, q_akickdisp, (int) ci->akick[i].flags,
+ q_akickreason, q_akickcreator,
+ (ci->akick[i].flags & AK_USED ?
+ (int) ci->akick[i].addtime : 0));
+ }
+
+ if (ci->akick[i].flags & AK_USED) {
+ free(q_akickdisp);
+ free(q_akickreason);
+ free(q_akickcreator);
+ }
+ }
+
+ /* Bad Words */
+ for (i = 0; ret && (i < ci->bwcount); i++) {
+ if (ci->badwords[i].in_use) {
+ q_badwords = db_mysql_quote(ci->badwords[i].word);
+
+ ret = db_mysql_try("UPDATE anope_cs_badwords "
+ "SET type = %d, active = 1 "
+ "WHERE channel = '%s' AND word = '%s'",
+ (int) ci->badwords[i].type, q_name,
+ q_badwords);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_badwords "
+ "(channel, word, type, active) "
+ "VALUES ('%s', '%s', %d, 1)",
+ q_name, q_badwords,
+ (int) ci->badwords[i].type);
+ }
+
+ free(q_badwords);
+ }
+ }
+
+ /* TTB's */
+ for (i = 0; ret && (i < TTB_SIZE); i++) {
+ ret = db_mysql_try("UPDATE anope_cs_ttb "
+ "SET value = %d, active = 1 "
+ "WHERE channel = '%s' AND ttb_id = %d",
+ ci->ttb[i], q_name, i);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_cs_ttb "
+ "(channel, ttb_id, value, active) "
+ "VALUES ('%s', %d, %d, 1)",
+ q_name, i, ci->ttb[i]);
+ }
+ }
+
+ free(q_name);
+ free(q_founder);
+ free(q_successor);
+ free(q_pass);
+ free(q_desc);
+ free(q_url);
+ free(q_email);
+ free(q_lasttopic);
+ free(q_lasttopicsetter);
+ free(q_mlock_key);
+ free(q_mlock_flood);
+ free(q_mlock_redirect);
+ free(q_entrymsg);
+ free(q_botnick);
+ free(q_forbidby);
+ free(q_forbidreason);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+
+/*
+ * OperServ Specific Section
+ */
+
+/*************************************************************************/
+
+/* Save the OperServ database into MySQL
+ * Return 1 on success, 0 on failure
+ * These tables are tagged and will be cleaned:
+ * - anope_os_akills
+ * - anope_os_sglines
+ * - anope_os_sqlines
+ * - anope_os_szlines
+ * These tables are emptied:
+ * - anope_os_core
+ */
+
+int db_mysql_save_os_db(unsigned int maxucnt, unsigned int maxutime,
+ SList * ak, SList * sgl, SList * sql, SList * szl)
+{
+ int ret;
+ int i;
+ Akill *akl;
+ SXLine *sl;
+ char *q_user;
+ char *q_host;
+ char *q_mask;
+ char *q_by;
+ char *q_reason;
+
+
+ /* First save the core info */
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_core "
+ "(maxusercnt, maxusertime, akills_count, sglines_count, sqlines_count, szlines_count) "
+ "VALUES (%d, %d, %d, %d, %d, %d)",
+ maxucnt, maxutime, ak->count, sgl->count, sql->count,
+ szl->count);
+
+ /* Next save all AKILLs */
+ for (i = 0; ret && (i < ak->count); i++) {
+ akl = ak->list[i];
+ q_user = db_mysql_quote(akl->user);
+ q_host = db_mysql_quote(akl->host);
+ q_by = db_mysql_quote(akl->by);
+ q_reason = db_mysql_quote(akl->reason);
+
+ ret = db_mysql_try("UPDATE anope_os_akills "
+ "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 "
+ "WHERE user = '%s' AND host = '%s'",
+ q_by, q_reason, (int) akl->seton,
+ (int) akl->expires, q_user, q_host);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_akills "
+ "(user, host, xby, reason, seton, expire, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, %d, 1)",
+ q_user, q_host, q_by, q_reason,
+ (int) akl->seton, (int) akl->expires);
+ }
+
+ free(q_user);
+ free(q_host);
+ free(q_by);
+ free(q_reason);
+ }
+
+ /* Time to save the SGLINEs */
+ for (i = 0; ret && (i < sgl->count); i++) {
+ sl = sgl->list[i];
+ q_mask = db_mysql_quote(sl->mask);
+ q_by = db_mysql_quote(sl->by);
+ q_reason = db_mysql_quote(sl->reason);
+
+ ret = db_mysql_try("UPDATE anope_os_sglines "
+ "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 "
+ "WHERE mask = '%s'",
+ q_by, q_reason, (int) sl->seton, (int) sl->expires,
+ q_mask);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_sglines "
+ "(mask, xby, reason, seton, expire, active) "
+ "VALUES ('%s', '%s', '%s', %d, %d, 1)",
+ q_mask, q_by, q_reason, (int) sl->seton,
+ (int) sl->expires);
+ }
+
+ free(q_mask);
+ free(q_by);
+ free(q_reason);
+ }
+
+ /* Save the SQLINEs */
+ for (i = 0; ret && (i < sql->count); i++) {
+ sl = sql->list[i];
+
+ q_mask = db_mysql_quote(sl->mask);
+ q_by = db_mysql_quote(sl->by);
+ q_reason = db_mysql_quote(sl->reason);
+
+ ret = db_mysql_try("UPDATE anope_os_sqlines "
+ "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 "
+ "WHERE mask = '%s'",
+ q_by, q_reason, (int) sl->seton, (int) sl->expires,
+ q_mask);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_sqlines "
+ "(mask, xby, reason, seton, expire, active) "
+ "VALUES ('%s', '%s', '%s', %d, %d, 1)",
+ q_mask, q_by, q_reason, (int) sl->seton,
+ (int) sl->expires);
+ }
+
+ free(q_mask);
+ free(q_by);
+ free(q_reason);
+ }
+
+ /* Now save the SZLINEs */
+ for (i = 0; ret && (i < szl->count); i++) {
+ sl = szl->list[i];
+
+ q_mask = db_mysql_quote(sl->mask);
+ q_by = db_mysql_quote(sl->by);
+ q_reason = db_mysql_quote(sl->reason);
+
+ ret = db_mysql_try("UPDATE anope_os_szlines "
+ "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 "
+ "WHERE mask = '%s'",
+ q_by, q_reason, (int) sl->seton, (int) sl->expires,
+ q_mask);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_szlines "
+ "(mask, xby, reason, seton, expire, active) "
+ "VALUES ('%s', '%s', '%s', %d, %d, 1)",
+ q_mask, q_by, q_reason, (int) sl->seton,
+ (int) sl->expires);
+ }
+
+ free(q_mask);
+ free(q_by);
+ free(q_reason);
+ }
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/* Save the given NewsItem
+ * These tables are tagged and will be cleaned:
+ * - anope_os_news
+ */
+int db_mysql_save_news(NewsItem * ni)
+{
+ int ret;
+ char *q_text;
+ char *q_who;
+
+ q_text = db_mysql_quote(ni->text);
+ q_who = db_mysql_quote(ni->who);
+
+ ret = db_mysql_try("UPDATE anope_os_news "
+ "SET ntext = '%s', who = '%s', active = 1 "
+ "WHERE type = %d AND num = %d AND `time` = %d",
+ q_text, q_who, ni->type, ni->num, (int) ni->time);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_news "
+ "(type, num, ntext, who, `time`, active) "
+ "VALUES (%d, %d, '%s', '%s', %d, 1)",
+ ni->type, ni->num, q_text, q_who, (int) ni->time);
+ }
+
+ free(q_text);
+ free(q_who);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/* Save the given Exception
+ * These tables are tagged and will be cleaned:
+ * - anope_os_exceptions
+ */
+
+int db_mysql_save_exceptions(Exception * e)
+{
+ int ret;
+ char *q_mask;
+ char *q_who;
+ char *q_reason;
+
+ q_mask = db_mysql_quote(e->mask);
+ q_who = db_mysql_quote(e->who);
+ q_reason = db_mysql_quote(e->reason);
+
+ ret = db_mysql_try("UPDATE anope_os_exceptions "
+ "SET lim = %d, who = '%s', reason = '%s', `time` = %d, expires = %d, active = 1 "
+ "WHERE mask = '%s'",
+ e->limit, q_who, q_reason, (int) e->time,
+ (int) e->expires, q_mask);
+
+ if (ret && (mysql_affected_rows(mysql)) == 0) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_os_exceptions "
+ "(mask, lim, who, reason, `time`, expires, active) "
+ "VALUES ('%s', %d, '%s', '%s', %d, %d, 1)",
+ q_mask, e->limit, q_who, q_reason, (int) e->time,
+ (int) e->expires);
+ }
+
+ free(q_mask);
+ free(q_who);
+ free(q_reason);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+
+/*
+ * HostServ Specific Section
+ */
+
+/*************************************************************************/
+
+/* Save the given HostCore
+ * These tables are tagged and will be cleaned:
+ * - anope_hs_core
+ */
+
+int db_mysql_save_hs_core(HostCore * hc)
+{
+ int ret;
+ char *q_nick;
+ char *q_ident;
+ char *q_host;
+ char *q_creator;
+
+ q_nick = db_mysql_quote(hc->nick);
+ q_ident = db_mysql_quote(hc->vIdent);
+ q_host = db_mysql_quote(hc->vHost);
+ q_creator = db_mysql_quote(hc->creator);
+
+ ret = db_mysql_try("UPDATE anope_hs_core "
+ "SET vident = '%s', vhost = '%s', creator = '%s', `time` = %d, active = 1 "
+ "WHERE nick = '%s'",
+ q_ident, q_host, q_creator, (int) hc->time, q_nick);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_hs_core "
+ "(nick, vident, vhost, creator, `time`, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, 1)",
+ q_nick, q_ident, q_host, q_creator,
+ (int) hc->time);
+ }
+
+ free(q_nick);
+ free(q_ident);
+ free(q_host);
+ free(q_creator);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+/*
+ * BotServ Specific Section
+ */
+
+/*************************************************************************/
+
+int db_mysql_save_bs_core(BotInfo * bi)
+{
+ int ret;
+ char *q_nick;
+ char *q_user;
+ char *q_host;
+ char *q_real;
+
+ q_nick = db_mysql_quote(bi->nick);
+ q_user = db_mysql_quote(bi->user);
+ q_host = db_mysql_quote(bi->host);
+ q_real = db_mysql_quote(bi->real);
+
+ ret = db_mysql_try("UPDATE anope_bs_core "
+ "SET user = '%s', host = '%s', rname = '%s', flags = %d, created = %d, chancount = %d, active = 1 "
+ "WHERE nick = '%s'",
+ q_user, q_host, q_real, bi->flags, (int) bi->created,
+ bi->chancount, q_nick);
+
+ if (ret && (mysql_affected_rows(mysql) == 0)) {
+ ret = db_mysql_try("INSERT DELAYED INTO anope_bs_core "
+ "(nick, user, host, rname, flags, created, chancount, active) "
+ "VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, 1)",
+ q_nick, q_user, q_host, q_real, bi->flags,
+ (int) bi->created, bi->chancount);
+ }
+
+ free(q_nick);
+ free(q_user);
+ free(q_host);
+ free(q_real);
+
+ return ret;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Some loading code! */
+
+/*************************************************************************/
+/*************************************************************************/
+
+int db_mysql_load_bs_dbase(void)
+{
+ int ret;
+ BotInfo *bi;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT nick, user, host, rname, flags, created, chancount "
+ "FROM anope_bs_core "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ bi = makebot(mysql_row[0]);
+ bi->user = sstrdup(mysql_row[1]);
+ bi->host = sstrdup(mysql_row[2]);
+ bi->real = sstrdup(mysql_row[3]);
+ bi->flags = strtol(mysql_row[4], (char **) NULL, 10);
+ bi->created = strtol(mysql_row[5], (char **) NULL, 10);
+ bi->chancount = strtol(mysql_row[6], (char **) NULL, 10);
+ }
+
+ mysql_free_result(mysql_res);
+
+ return 1;
+}
+
+int db_mysql_load_hs_dbase(void)
+{
+ int ret;
+ int32 time;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT nick, vident, vhost, creator, `time` "
+ "FROM anope_hs_core "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ time = strtol(mysql_row[4], (char **) NULL, 10);
+ addHostCore(mysql_row[0], mysql_row[1], mysql_row[2], mysql_row[3],
+ time);
+ }
+
+ mysql_free_result(mysql_res);
+
+ return 1;
+}
+
+int db_mysql_load_news(void)
+{
+ int ret;
+ int i;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT type, num, ntext, who, `time` "
+ "FROM anope_os_news "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_store_result(mysql);
+
+ nnews = mysql_num_rows(mysql_res);
+ if (nnews < 8) /* 2^3 */
+ news_size = 16; /* 2^4 */
+ else if (nnews >= 16384) /* 2^14 */
+ news_size = 32767; /* 2^15 - 1 */
+ else
+ news_size = 2 * nnews;
+
+ news = scalloc(news_size, sizeof(*news));
+
+ i = 0;
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ news[i].type = strtol(mysql_row[0], (char **) NULL, 10);
+ news[i].num = strtol(mysql_row[1], (char **) NULL, 10);
+ news[i].text = sstrdup(mysql_row[2]);
+ snprintf(news[i].who, NICKMAX, "%s", mysql_row[3]);
+ news[i].time = strtol(mysql_row[4], (char **) NULL, 10);
+ i++;
+ }
+
+ mysql_free_result(mysql_res);
+
+ return 1;
+}
+
+int db_mysql_load_exceptions(void)
+{
+ int ret;
+ int i;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT mask, lim, who, reason, `time`, expires "
+ "FROM anope_os_exceptions "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_store_result(mysql);
+ nexceptions = mysql_num_rows(mysql_res);
+ exceptions = scalloc(nexceptions, sizeof(Exception));
+
+ i = 0;
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ exceptions[i].mask = sstrdup(mysql_row[0]);
+ exceptions[i].limit = strtol(mysql_row[1], (char **) NULL, 10);
+ snprintf(exceptions[i].who, NICKMAX, "%s", mysql_row[2]);
+ exceptions[i].reason = sstrdup(mysql_row[3]);
+ exceptions[i].time = strtol(mysql_row[4], (char **) NULL, 10);
+ exceptions[i].expires = strtol(mysql_row[5], (char **) NULL, 10);
+ i++;
+ }
+
+ mysql_free_result(mysql_res);
+
+ return 1;
+}
+
+int db_mysql_load_os_dbase(void)
+{
+ int ret;
+ Akill *ak;
+ SXLine *sl;
+ int akc, sglc, sqlc, szlc;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT maxusercnt, maxusertime, akills_count, sglines_count, sqlines_count, szlines_count "
+ "FROM anope_os_core");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+
+ if ((mysql_row = mysql_fetch_row(mysql_res))) {
+ maxusercnt = strtol(mysql_row[0], (char **) NULL, 10);
+ maxusertime = strtol(mysql_row[1], (char **) NULL, 10);
+ /* I'm not too happy with the idea of storing thse counts in a field
+ * instead of just using mysql_num_rows on the actual tables when
+ * filling the data. For now this will do, but it's bound to give
+ * problems sooner or later... (it probably does if you are looking
+ * at this) -GD
+ */
+ akc = strtol(mysql_row[2], (char **) NULL, 10);
+ sglc = strtol(mysql_row[3], (char **) NULL, 10);
+ sqlc = strtol(mysql_row[4], (char **) NULL, 10);
+ szlc = strtol(mysql_row[5], (char **) NULL, 10);
+ } else {
+ maxusercnt = 0;
+ maxusertime = time(NULL);
+ akc = 0;
+ sglc = 0;
+ sqlc = 0;
+ szlc = 0;
+ }
+
+ mysql_free_result(mysql_res);
+
+
+ /* Load the AKILLs */
+
+ ret = db_mysql_try("SELECT user, host, xby, reason, seton, expire "
+ "FROM anope_os_akills "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+ slist_setcapacity(&akills, akc);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ ak = scalloc(1, sizeof(Akill));
+ ak->user = sstrdup(mysql_row[0]);
+ ak->host = sstrdup(mysql_row[1]);
+ ak->by = sstrdup(mysql_row[2]);
+ ak->reason = sstrdup(mysql_row[3]);
+ ak->seton = strtol(mysql_row[4], (char **) NULL, 10);
+ ak->expires = strtol(mysql_row[5], (char **) NULL, 10);
+ slist_add(&akills, ak);
+ }
+
+ mysql_free_result(mysql_res);
+
+
+ /* Load the SGLINEs */
+
+ ret = db_mysql_try("SELECT mask, xby, reason, seton, expire "
+ "FROM anope_os_sglines "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+ slist_setcapacity(&sglines, sglc);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ sl = scalloc(1, sizeof(SXLine));
+ sl->mask = sstrdup(mysql_row[0]);
+ sl->by = sstrdup(mysql_row[1]);
+ sl->reason = sstrdup(mysql_row[2]);
+ sl->seton = strtol(mysql_row[3], (char **) NULL, 10);
+ sl->expires = strtol(mysql_row[4], (char **) NULL, 10);
+ slist_add(&sglines, sl);
+ }
+
+ mysql_free_result(mysql_res);
+
+
+ /* Load the SQLINEs */
+
+ ret = db_mysql_try("SELECT mask, xby, reason, seton, expire "
+ "FROM anope_os_sqlines "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+ slist_setcapacity(&sqlines, sqlc);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ sl = scalloc(1, sizeof(SXLine));
+ sl->mask = sstrdup(mysql_row[0]);
+ sl->by = sstrdup(mysql_row[1]);
+ sl->reason = sstrdup(mysql_row[2]);
+ sl->seton = strtol(mysql_row[3], (char **) NULL, 10);
+ sl->expires = strtol(mysql_row[4], (char **) NULL, 10);
+ slist_add(&sqlines, sl);
+ }
+
+ mysql_free_result(mysql_res);
+
+
+ /* Load the SZLINEs */
+
+ ret = db_mysql_try("SELECT mask, xby, reason, seton, expire "
+ "FROM anope_os_szlines "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+ slist_setcapacity(&szlines, szlc);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ sl = scalloc(1, sizeof(SXLine));
+ sl->mask = sstrdup(mysql_row[0]);
+ sl->by = sstrdup(mysql_row[1]);
+ sl->reason = sstrdup(mysql_row[2]);
+ sl->seton = strtol(mysql_row[3], (char **) NULL, 10);
+ sl->expires = strtol(mysql_row[4], (char **) NULL, 10);
+ slist_add(&szlines, sl);
+ }
+
+ mysql_free_result(mysql_res);
+
+ return 1;
+}
+
+int db_mysql_load_cs_dbase(void)
+{
+ int ret;
+ char *q_name;
+ ChannelInfo *ci;
+ int i;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ unsigned long *lengths;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, "
+ " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, "
+ " mlock_key, mlock_flood, mlock_redirect, entry_message, memomax, botnick, botflags, bwcount, capsmin, capspercent, floodlines, "
+ " floodsecs, repeattimes "
+ "FROM anope_cs_info "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ /* I'd really like to use mysql_use_result here, but it'd tie up with
+ * all the queries being run inside each iteration... -GD
+ */
+ mysql_res = mysql_store_result(mysql);
+
+ while (ret && (mysql_row = mysql_fetch_row(mysql_res))) {
+ /* We need to get the length of the password.. - Viper */
+ lengths = mysql_fetch_lengths(mysql_res);
+ ci = scalloc(1, sizeof(ChannelInfo));
+
+ /* Name, founder, successor, password */
+ snprintf(ci->name, CHANMAX, "%s", mysql_row[0]);
+ ci->founder = findcore(mysql_row[1]);
+ if (mysql_row[2] && *(mysql_row[2]))
+ ci->successor = findcore(mysql_row[2]);
+ else
+ ci->successor = NULL;
+
+ /* Copy the password from what we got back from the DB and
+ * keep in mind that lengths may vary. We should never
+ * use more than we have. - Viper */
+ memset(ci->founderpass, 0, PASSMAX);
+ if (lengths[3] >= PASSMAX)
+ memcpy(ci->founderpass, mysql_row[3], PASSMAX - 1);
+ else
+ memcpy(ci->founderpass, mysql_row[3], lengths[3]);
+
+ /* Description, URL, email -- scalloc() initializes to 0/NULL */
+ ci->desc = sstrdup(mysql_row[4]);
+ if (mysql_row[5] && *(mysql_row[5]))
+ ci->url = sstrdup(mysql_row[5]);
+ if (mysql_row[6] && *(mysql_row[6]))
+ ci->email = sstrdup(mysql_row[6]);
+
+ /* Time registered, last used, last topic, last topic setter + time */
+ ci->time_registered = strtol(mysql_row[7], (char **) NULL, 10);
+ ci->last_used = strtol(mysql_row[8], (char **) NULL, 10);
+ if (mysql_row[9] && *(mysql_row[9])) {
+ ci->last_topic = sstrdup(mysql_row[9]);
+ snprintf(ci->last_topic_setter, NICKMAX, "%s", mysql_row[10]);
+ ci->last_topic_time = strtol(mysql_row[11], (char **) NULL, 10);
+ }
+
+ /* Flags, forbidden by, forbid reason, bantype
+ * NOTE: CI_INHABIT will be disabled in flags!!
+ */
+ ci->flags =
+ strtol(mysql_row[12], (char **) NULL, 10) & ~CI_INHABIT;
+
+ if (mysql_row[13] && *(mysql_row[13])) {
+ ci->forbidby = sstrdup(mysql_row[13]);
+ if (mysql_row[14] && *(mysql_row[14]))
+ ci->forbidreason = sstrdup(mysql_row[14]);
+ }
+
+ ci->bantype = strtol(mysql_row[15], (char **) NULL, 10);
+
+ /* Accesscount, akickcount */
+ ci->accesscount = strtol(mysql_row[16], (char **) NULL, 10);
+ ci->akickcount = strtol(mysql_row[17], (char **) NULL, 10);
+
+ /* Mlock: on, off, limit, key, flood, redirect */
+ ci->mlock_on = strtol(mysql_row[18], (char **) NULL, 10);
+ ci->mlock_off = strtol(mysql_row[19], (char **) NULL, 10);
+ ci->mlock_limit = strtol(mysql_row[20], (char **) NULL, 10);
+ if (mysql_row[21] && *(mysql_row[21])) {
+ ci->mlock_key = sstrdup(mysql_row[21]);
+ if (mysql_row[22] && *(mysql_row[22])) {
+ ci->mlock_flood = sstrdup(mysql_row[22]);
+ }
+ if (mysql_row[23] && *(mysql_row[23])) {
+ ci->mlock_redirect = sstrdup(mysql_row[23]);
+ }
+ }
+
+ /* MemoMax, entrymessage, botinfo, botflags, badwordcount */
+ ci->memos.memomax = strtol(mysql_row[25], (char **) NULL, 10);
+ if (mysql_row[24] && *(mysql_row[24]))
+ ci->entry_message = sstrdup(mysql_row[24]);
+ ci->bi = findbot(mysql_row[26]);
+ ci->botflags = strtol(mysql_row[27], (char **) NULL, 10);
+ ci->bwcount = strtol(mysql_row[28], (char **) NULL, 10);
+
+ /* Capsmin, capspercent, floodlines, floodsecs, repeattimes */
+ ci->capsmin = strtol(mysql_row[29], (char **) NULL, 10);
+ ci->capspercent = strtol(mysql_row[30], (char **) NULL, 10);
+ ci->floodlines = strtol(mysql_row[31], (char **) NULL, 10);
+ ci->floodsecs = strtol(mysql_row[32], (char **) NULL, 10);
+ ci->repeattimes = strtol(mysql_row[33], (char **) NULL, 10);
+
+
+ /* Get info from other tables; we'll need the channel name */
+ q_name = db_mysql_quote(ci->name);
+
+ /* Get the LEVELS list */
+ ret = db_mysql_try("SELECT position, level "
+ "FROM anope_cs_levels "
+ "WHERE channel = '%s' AND active = 1",
+ q_name);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+ ci->levels = scalloc(CA_SIZE, sizeof(*ci->levels));
+ reset_levels(ci);
+
+ while ((row = mysql_fetch_row(res))) {
+ i = strtol(row[0], (char **) NULL, 10);
+ ci->levels[i] = strtol(row[1], (char **) NULL, 10);
+ }
+
+ mysql_free_result(res);
+ }
+
+ /* Get the channel ACCESS list */
+ if (ret && (ci->accesscount > 0)) {
+ ci->access = scalloc(ci->accesscount, sizeof(ChanAccess));
+
+ ret = db_mysql_try("SELECT level, display, last_seen "
+ "FROM anope_cs_access "
+ "WHERE channel = '%s' AND in_use = 1 AND active = 1",
+ q_name);
+
+ if (ret) {
+ res = mysql_store_result(mysql);
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ ci->access[i].in_use = 1;
+ ci->access[i].level = strtol(row[0], (char **) NULL, 10);
+ ci->access[i].nc = findcore(row[1]);
+ if (!(ci->access[i].nc))
+ ci->access[i].in_use = 0;
+ ci->access[i].last_seen =
+ strtol(row[2], (char **) NULL, 10);
+ i++;
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* Get the channel AKICK list */
+ if (ret && (ci->akickcount > 0)) {
+ ci->akick = scalloc(ci->akickcount, sizeof(AutoKick));
+
+ ret = db_mysql_try("SELECT flags, dmask, reason, creator, addtime "
+ "FROM anope_cs_akicks "
+ "WHERE channel = '%s' AND active = 1 AND (flags & %d) <> 0",
+ q_name, AK_USED);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ ci->akick[i].flags = strtol(row[0], (char **) NULL, 10);
+ if (ci->akick[i].flags & AK_ISNICK) {
+ ci->akick[i].u.nc = findcore(row[1]);
+ if (!(ci->akick[i].u.nc))
+ ci->akick[i].flags &= ~AK_USED;
+ } else {
+ ci->akick[i].u.mask = sstrdup(row[1]);
+ }
+ if (row[2] && *(row[2])) {
+ ci->akick[i].reason = sstrdup(row[2]);
+ }
+ ci->akick[i].creator = sstrdup(row[3]);
+ ci->akick[i].addtime = strtol(row[4], (char **) NULL, 10);
+ i++;
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ if (ret) {
+ /* Get the channel memos */
+ ret = db_mysql_try("SELECT nm_id, number, flags, time, sender, text "
+ "FROM anope_ms_info "
+ "WHERE receiver = '%s' AND serv = 'CHAN' AND active = 1",
+ q_name);
+
+ if (ret) {
+ res = mysql_store_result(mysql);
+ ci->memos.memocount = mysql_num_rows(res);
+
+ if (ci->memos.memocount > 0) {
+ Memo *memos;
+
+ memos = scalloc(ci->memos.memocount, sizeof(Memo));
+ ci->memos.memos = memos;
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ memos[i].id = strtol(row[0], (char **) NULL, 10);
+ memos[i].number = strtol(row[1], (char **) NULL, 10);
+ memos[i].flags = strtol(row[2], (char **) NULL, 10);
+ memos[i].time = strtol(row[3], (char **) NULL, 10);
+ snprintf(memos[i].sender, NICKMAX, "%s", row[4]);
+ memos[i].text = sstrdup(row[5]);
+ i++;
+ }
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* Get the TTB data */
+ if (ret) {
+ ci->ttb = scalloc(TTB_SIZE, sizeof(*ci->ttb));
+
+ ret = db_mysql_try("SELECT ttb_id, value "
+ "FROM anope_cs_ttb "
+ "WHERE channel = '%s' AND active = 1",
+ q_name);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+
+ while ((row = mysql_fetch_row(res))) {
+ i = strtol(row[0], (char **) NULL, 10);
+ /* Should we do a sanity check on the value of i? -GD */
+ ci->ttb[i] = strtol(row[1], (char **) NULL, 10);
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* Get the badwords */
+ if (ret && (ci->bwcount > 0)) {
+ ci->badwords = scalloc(ci->bwcount, sizeof(BadWord));
+
+ ret = db_mysql_try("SELECT word, type "
+ "FROM anope_cs_badwords "
+ "WHERE channel = '%s' AND active = 1",
+ q_name);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ ci->badwords[i].in_use = 1;
+ ci->badwords[i].word = sstrdup(row[0]);
+ ci->badwords[i].type = strtol(row[1], (char **) NULL, 10);
+ i++;
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* YAY! all done; free q_name and insert the channel */
+ free(q_name);
+ alpha_insert_chan(ci);
+ }
+
+ mysql_free_result(mysql_res);
+
+ /* Check to be sure that all channels still have a founder. If not,
+ * delete them. This code seems to be required in the old mysql code
+ * so i'll leave it in just to be sure. I also wonder why they didn't
+ * do that check up above immediately when it was known there was no
+ * founder... -GD
+ */
+ for (i = 0; i < 256; i++) {
+ ChannelInfo *next;
+ for (ci = chanlists[i]; ci; ci = next) {
+ next = ci->next;
+ if (!(ci->flags & CI_VERBOTEN) && !ci->founder) {
+ alog("%s: database load: Deleting founderless channel %s",
+ s_ChanServ, ci->name);
+ delchan(ci);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int db_mysql_load_ns_req_dbase(void)
+{
+ int ret;
+ NickRequest *nr;
+ unsigned long *lengths;
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT nick, passcode, password, email, requested "
+ "FROM anope_ns_request "
+ "WHERE active = 1");
+
+ if (ret) {
+ mysql_res = mysql_use_result(mysql);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ /* We need to get the length of the password.. - Viper */
+ lengths = mysql_fetch_lengths(mysql_res);
+ nr = scalloc(1, sizeof(NickRequest));
+
+ nr->nick = sstrdup(mysql_row[0]);
+ nr->passcode = sstrdup(mysql_row[1]);
+ nr->email = sstrdup(mysql_row[3]);
+ nr->requested = strtol(mysql_row[4], (char **) NULL, 10);
+
+ /* Copy the password from what we got back from the DB and
+ * keep in mind that lengths may vary. We should never
+ * use more than we have. - Viper */
+ memset(nr->password, 0, PASSMAX);
+ if (lengths[2] >= PASSMAX)
+ memcpy(nr->password, mysql_row[2], PASSMAX - 1);
+ else
+ memcpy(nr->password, mysql_row[2], lengths[2]);
+
+
+ insert_requestnick(nr);
+ }
+
+ mysql_free_result(mysql_res);
+ }
+
+ return ret;
+}
+
+int db_mysql_load_ns_dbase(void)
+{
+ int ret;
+ char *q_display;
+ NickCore *nc;
+ NickAlias *na;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int i;
+ unsigned long *lengths;
+
+
+ if (!do_mysql)
+ return 0;
+
+ ret = db_mysql_try("SELECT display, pass, email, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, greet "
+ "FROM anope_ns_core "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ /* I'd really like to use mysql_use_result here, but it'd tie up with
+ * all the queries being run inside each iteration... -GD
+ */
+ mysql_res = mysql_store_result(mysql);
+
+ while (ret && (mysql_row = mysql_fetch_row(mysql_res))) {
+ /* We need to get the length of the password.. - Viper */
+ lengths = mysql_fetch_lengths(mysql_res);
+
+ nc = scalloc(1, sizeof(NickCore));
+
+ /* Display, password, email, ICQ, URL, flags */
+ nc->display = sstrdup(mysql_row[0]);
+ if (mysql_row[2] && *(mysql_row[2])) {
+ nc->email = sstrdup(mysql_row[2]);
+ }
+ nc->icq = strtol(mysql_row[3], (char **) NULL, 10);
+ if (mysql_row[4] && *(mysql_row[4])) {
+ nc->url = sstrdup(mysql_row[4]);
+ }
+ nc->flags = strtol(mysql_row[5], (char **) NULL, 10);
+
+ /* Copy the password from what we got back from the DB and
+ * keep in mind that lengths may vary. We should never
+ * use more than we have. - Viper */
+ memset(nc->pass, 0, PASSMAX);
+ if (lengths[1] >= PASSMAX)
+ memcpy(nc->pass, mysql_row[1], PASSMAX - 1);
+ else
+ memcpy(nc->pass, mysql_row[1], lengths[1]);
+
+ /* Language, accesscount, memocount, memomax */
+ nc->language = strtol(mysql_row[6], (char **) NULL, 10);
+ nc->accesscount = strtol(mysql_row[7], (char **) NULL, 10);
+ nc->memos.memocount = strtol(mysql_row[8], (char **) NULL, 10);
+ nc->memos.memomax = strtol(mysql_row[9], (char **) NULL, 10);
+
+ /* Channelcount, channelmax, greet */
+ nc->channelcount = strtol(mysql_row[10], (char **) NULL, 10);
+ nc->channelmax = strtol(mysql_row[11], (char **) NULL, 10);
+ if (mysql_row[12] && *(mysql_row[12]))
+ nc->greet = sstrdup(mysql_row[12]);
+
+ /* Don't allow KILL_IMMED if the config doesn't allow it */
+ if (!NSAllowKillImmed)
+ nc->flags &= ~NI_KILL_IMMED;
+
+ /* Check if the current user is important enough to be added to
+ * services admin or services oper lists
+ */
+ if (nc->flags & NI_SERVICES_ADMIN)
+ slist_add(&servadmins, nc);
+ if (nc->flags & NI_SERVICES_OPER)
+ slist_add(&servopers, nc);
+
+ /* Unset the SERVICES_ROOT flag; we will set it again later if this
+ * user is really a services root (checked per NickAlias) -GD
+ */
+ nc->flags &= ~NI_SERVICES_ROOT;
+
+ /* Get info from other tables; we'll need the display */
+ q_display = db_mysql_quote(nc->display);
+
+ /* Fill the accesslist */
+ if (ret && (nc->accesscount > 0)) {
+ nc->access = scalloc(nc->accesscount, sizeof(char *));
+
+ ret = db_mysql_try("SELECT access "
+ "FROM anope_ns_access "
+ "WHERE display = '%s' AND active = 1",
+ q_display);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ if (row[0] && *(row[0])) {
+ nc->access[i] = sstrdup(row[0]);
+ i++;
+ }
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* Load the memos */
+ if (ret && (nc->memos.memocount > 0)) {
+ nc->memos.memos = scalloc(nc->memos.memocount, sizeof(Memo));
+
+ ret = db_mysql_try("SELECT nm_id, number, flags, time, sender, text "
+ "FROM anope_ms_info "
+ "WHERE receiver = '%s' AND active = 1 AND serv = 'NICK' "
+ "ORDER BY number ASC",
+ q_display);
+
+ if (ret) {
+ res = mysql_use_result(mysql);
+
+ i = 0;
+ while ((row = mysql_fetch_row(res))) {
+ nc->memos.memos[i].id = strtol(row[0], (char **) NULL, 10);
+ nc->memos.memos[i].number = strtol(row[1], (char **) NULL, 10);
+ nc->memos.memos[i].flags = strtol(row[2], (char **) NULL, 10);
+ nc->memos.memos[i].time = strtol(row[3], (char **) NULL, 10);
+ snprintf(nc->memos.memos[i].sender, NICKMAX, "%s", row[4]);
+ nc->memos.memos[i].text = sstrdup(row[5]);
+
+ i++;
+ }
+
+ mysql_free_result(res);
+ }
+ }
+
+ /* Done with the core; insert it */
+ insert_core(nc);
+ }
+
+ mysql_free_result(mysql_res);
+
+ if (!ret)
+ return 0;
+
+ /* Load the nickaliases */
+ ret = db_mysql_try("SELECT nick, display, time_registered, last_seen, status, last_usermask, last_realname, last_quit "
+ "FROM anope_ns_alias "
+ "WHERE active = 1");
+
+ if (!ret)
+ return 0;
+
+ mysql_res = mysql_use_result(mysql);
+
+ while ((mysql_row = mysql_fetch_row(mysql_res))) {
+ /* First make sure this NickAlias has a NickCore; else we don't even
+ * bother adding it to the aliases at all...
+ */
+ NickCore *nc;
+
+ if (!(nc = findcore(mysql_row[1])))
+ continue;
+
+ na = scalloc(1, sizeof(NickAlias));
+
+ /* nick, time_registered, last_seen, status
+ * NOTE: remove NS_TEMPORARY from status on load
+ */
+ na->nick = sstrdup(mysql_row[0]);
+ na->nc = nc;
+ na->time_registered = strtol(mysql_row[2], (char **) NULL, 10);
+ na->last_seen = strtol(mysql_row[3], (char **) NULL, 10);
+ na->status =
+ strtol(mysql_row[4], (char **) NULL, 10) & ~NS_TEMPORARY;
+
+ /* last_usermask, last_realname, last_quit */
+ na->last_usermask = sstrdup(mysql_row[5]);
+ na->last_realname = sstrdup(mysql_row[6]);
+
+ if (mysql_row[7] && *(mysql_row[7])) {
+ na->last_quit = sstrdup(mysql_row[7]);
+ }
+
+ /* Assign to the nickcore aliases */
+ slist_add(&na->nc->aliases, na);
+
+ /* Check if this user is a services root */
+ for (i = 0; i < RootNumber; i++) {
+ if (stricmp(ServicesRoots[i], na->nick) == 0)
+ na->nc->flags |= NI_SERVICES_ROOT;
+ }
+
+ /* Last, but not least: insert the alias! */
+ alpha_insert_alias(na);
+ }
+
+ mysql_free_result(mysql_res);
+
+ return ret;
+}
+
+/* get random mysql number for the generator */
+unsigned int mysql_rand(void)
+{
+ unsigned int num = 0;
+
+ if (!do_mysql)
+ return 0;
+
+ db_mysql_try("SELECT RAND()");
+
+ mysql_res = mysql_store_result(mysql);
+
+ if (!(mysql_row = mysql_fetch_row(mysql_res))) {
+ mysql_free_result(mysql_res);
+ return 0;
+ }
+
+ num = UserKey3 * strtol(mysql_row[0], (char **) NULL, 10);
+
+ mysql_free_result(mysql_res);
+
+ return num;
+}
diff --git a/src/news.c b/src/news.c
new file mode 100644
index 000000000..45dbbd6b3
--- /dev/null
+++ b/src/news.c
@@ -0,0 +1,554 @@
+
+/* News functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+
+int32 nnews = 0;
+int32 news_size = 0;
+NewsItem *news = NULL;
+
+/*************************************************************************/
+
+/* List of messages for each news type. This simplifies message sending. */
+
+#define MSG_SYNTAX 0
+#define MSG_LIST_HEADER 1
+#define MSG_LIST_ENTRY 2
+#define MSG_LIST_NONE 3
+#define MSG_ADD_SYNTAX 4
+#define MSG_ADD_FULL 5
+#define MSG_ADDED 6
+#define MSG_DEL_SYNTAX 7
+#define MSG_DEL_NOT_FOUND 8
+#define MSG_DELETED 9
+#define MSG_DEL_NONE 10
+#define MSG_DELETED_ALL 11
+#define MSG_MAX 11
+
+struct newsmsgs {
+ int16 type;
+ char *name;
+ int msgs[MSG_MAX + 1];
+};
+
+struct newsmsgs msgarray[] = {
+ {NEWS_LOGON, "LOGON",
+ {NEWS_LOGON_SYNTAX,
+ NEWS_LOGON_LIST_HEADER,
+ NEWS_LOGON_LIST_ENTRY,
+ NEWS_LOGON_LIST_NONE,
+ NEWS_LOGON_ADD_SYNTAX,
+ NEWS_LOGON_ADD_FULL,
+ NEWS_LOGON_ADDED,
+ NEWS_LOGON_DEL_SYNTAX,
+ NEWS_LOGON_DEL_NOT_FOUND,
+ NEWS_LOGON_DELETED,
+ NEWS_LOGON_DEL_NONE,
+ NEWS_LOGON_DELETED_ALL}
+ },
+ {NEWS_OPER, "OPER",
+ {NEWS_OPER_SYNTAX,
+ NEWS_OPER_LIST_HEADER,
+ NEWS_OPER_LIST_ENTRY,
+ NEWS_OPER_LIST_NONE,
+ NEWS_OPER_ADD_SYNTAX,
+ NEWS_OPER_ADD_FULL,
+ NEWS_OPER_ADDED,
+ NEWS_OPER_DEL_SYNTAX,
+ NEWS_OPER_DEL_NOT_FOUND,
+ NEWS_OPER_DELETED,
+ NEWS_OPER_DEL_NONE,
+ NEWS_OPER_DELETED_ALL}
+ },
+ {NEWS_RANDOM, "RANDOM",
+ {NEWS_RANDOM_SYNTAX,
+ NEWS_RANDOM_LIST_HEADER,
+ NEWS_RANDOM_LIST_ENTRY,
+ NEWS_RANDOM_LIST_NONE,
+ NEWS_RANDOM_ADD_SYNTAX,
+ NEWS_RANDOM_ADD_FULL,
+ NEWS_RANDOM_ADDED,
+ NEWS_RANDOM_DEL_SYNTAX,
+ NEWS_RANDOM_DEL_NOT_FOUND,
+ NEWS_RANDOM_DELETED,
+ NEWS_RANDOM_DEL_NONE,
+ NEWS_RANDOM_DELETED_ALL}
+ }
+};
+
+static int *findmsgs(int16 type, char **typename)
+{
+ int i;
+ for (i = 0; i < lenof(msgarray); i++) {
+ if (msgarray[i].type == type) {
+ if (typename)
+ *typename = msgarray[i].name;
+ return msgarray[i].msgs;
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Called by the main OperServ routine in response to a NEWS command. */
+static void do_news(User * u, int16 type);
+
+/* Lists all a certain type of news. */
+static void do_news_list(User * u, int16 type, int *msgs);
+
+/* Add news items. */
+static void do_news_add(User * u, int16 type, int *msgs,
+ const char *typename);
+static int add_newsitem(User * u, const char *text, int16 type);
+
+/* Delete news items. */
+static void do_news_del(User * u, int16 type, int *msgs,
+ const char *typename);
+static int del_newsitem(int num, int16 type);
+
+/*************************************************************************/
+/****************************** Statistics *******************************/
+/*************************************************************************/
+
+void get_news_stats(long *nrec, long *memuse)
+{
+ long mem;
+ int i;
+
+ mem = sizeof(NewsItem) * news_size;
+ for (i = 0; i < nnews; i++)
+ mem += strlen(news[i].text) + 1;
+ *nrec = nnews;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+/*********************** News item loading/saving ************************/
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", NewsDBName); \
+ nnews = i; \
+ break; \
+ } \
+} while (0)
+
+void load_news()
+{
+ dbFILE *f;
+ int i;
+ uint16 n;
+ uint32 tmp32;
+
+ if (!(f = open_db(s_OperServ, NewsDBName, "r", NEWS_VERSION)))
+ return;
+ switch (i = get_file_version(f)) {
+ case 9:
+ case 8:
+ case 7:
+ SAFE(read_int16(&n, f));
+ nnews = n;
+ if (nnews < 8)
+ news_size = 16;
+ else if (nnews >= 16384)
+ news_size = 32767;
+ else
+ news_size = 2 * nnews;
+ news = scalloc(sizeof(*news) * news_size, 1);
+ if (!nnews) {
+ close_db(f);
+ return;
+ }
+ for (i = 0; i < nnews; i++) {
+ SAFE(read_int16(&news[i].type, f));
+ SAFE(read_int32(&news[i].num, f));
+ SAFE(read_string(&news[i].text, f));
+ SAFE(read_buffer(news[i].who, f));
+ SAFE(read_int32(&tmp32, f));
+ news[i].time = tmp32;
+ }
+ break;
+
+ default:
+ fatal("Unsupported version (%d) on %s", i, NewsDBName);
+ } /* switch (ver) */
+
+ close_db(f);
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", NewsDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", NewsDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_news()
+{
+ dbFILE *f;
+ int i;
+ static time_t lastwarn = 0;
+
+ if (!(f = open_db(s_OperServ, NewsDBName, "w", NEWS_VERSION)))
+ return;
+ SAFE(write_int16(nnews, f));
+ for (i = 0; i < nnews; i++) {
+ SAFE(write_int16(news[i].type, f));
+ SAFE(write_int32(news[i].num, f));
+ SAFE(write_string(news[i].text, f));
+ SAFE(write_buffer(news[i].who, f));
+ SAFE(write_int32(news[i].time, f));
+ }
+ close_db(f);
+}
+
+#undef SAFE
+
+void save_rdb_news()
+{
+#ifdef USE_RDB
+ int i;
+ NewsItem *ni;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_os_news") == 0) {
+ alog("Unable to tag table 'anope_os_news' - News RDB save failed.");
+ return;
+ }
+
+ for (i = 0; i < nnews; i++) {
+ ni = &news[i];
+ if (rdb_save_news(ni) == 0) {
+ alog("Unable to save NewsItem %d - News RDB save failed.", ni->num);
+ return;
+ }
+ }
+
+ if (rdb_clean_table("anope_os_news") == 0) {
+ alog("Unable to clean table 'anope_os_news' - News RDB save failed.");
+ return;
+ }
+
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+/***************************** News display ******************************/
+/*************************************************************************/
+
+void display_news(User * u, int16 type)
+{
+ int msg;
+
+ if (type == NEWS_LOGON) {
+ msg = NEWS_LOGON_TEXT;
+ } else if (type == NEWS_OPER) {
+ msg = NEWS_OPER_TEXT;
+ } else if (type == NEWS_RANDOM) {
+ msg = NEWS_RANDOM_TEXT;
+ } else {
+ alog("news: Invalid type (%d) to display_news()", type);
+ return;
+ }
+
+ if (type == NEWS_RANDOM) {
+ static int current_news = -1;
+ int count = 0;
+
+ if (!nnews)
+ return;
+
+ while (count++ < nnews) {
+ if (++current_news >= nnews)
+ current_news = 0;
+
+ if (news[current_news].type == type) {
+ struct tm *tm;
+ char timebuf[64];
+
+ tm = localtime(&news[current_news].time);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_SHORT_DATE_FORMAT, tm);
+ notice_lang(s_GlobalNoticer, u, msg, timebuf,
+ news[current_news].text);
+
+ return;
+ }
+ }
+ } else {
+ int i, count = 0;
+
+ for (i = nnews - 1; i >= 0; i--) {
+ if (count >= NewsCount)
+ break;
+ if (news[i].type == type)
+ count++;
+ }
+ while (++i < nnews) {
+ if (news[i].type == type) {
+ struct tm *tm;
+ char timebuf[64];
+
+ tm = localtime(&news[i].time);
+ strftime_lang(timebuf, sizeof(timebuf), u,
+ STRFTIME_SHORT_DATE_FORMAT, tm);
+ notice_lang(s_GlobalNoticer, u, msg, timebuf,
+ news[i].text);
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+/***************************** News editing ******************************/
+/*************************************************************************/
+/* Declared in extern.h */
+int do_logonnews(User * u)
+{
+ do_news(u, NEWS_LOGON);
+ return MOD_CONT;
+}
+
+
+/* Declared in extern.h */
+int do_opernews(User * u)
+{
+ do_news(u, NEWS_OPER);
+ return MOD_CONT;
+}
+
+/* Declared in extern.h */
+int do_randomnews(User * u)
+{
+ do_news(u, NEWS_RANDOM);
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+
+/* Main news command handling routine. */
+void do_news(User * u, short type)
+{
+ int is_servadmin = is_services_admin(u);
+ char *cmd = strtok(NULL, " ");
+ char *typename;
+ int *msgs;
+
+ msgs = findmsgs(type, &typename);
+ if (!msgs) {
+ alog("news: Invalid type to do_news()");
+ return;
+ }
+
+ if (!cmd)
+ cmd = "";
+
+ if (stricmp(cmd, "LIST") == 0) {
+ do_news_list(u, type, msgs);
+ } else if (stricmp(cmd, "ADD") == 0) {
+ if (is_servadmin)
+ do_news_add(u, type, msgs, typename);
+ else
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+
+ } else if (stricmp(cmd, "DEL") == 0) {
+ if (is_servadmin)
+ do_news_del(u, type, msgs, typename);
+ else
+ notice_lang(s_OperServ, u, PERMISSION_DENIED);
+
+ } else {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%sNEWS", typename);
+ syntax_error(s_OperServ, u, buf, msgs[MSG_SYNTAX]);
+ }
+}
+
+/*************************************************************************/
+
+/* Handle a {LOGON,OPER}NEWS LIST command. */
+
+static void do_news_list(User * u, int16 type, int *msgs)
+{
+ int i, count = 0;
+ char timebuf[64];
+ struct tm *tm;
+
+ for (i = 0; i < nnews; i++) {
+ if (news[i].type == type) {
+ if (count == 0)
+ notice_lang(s_OperServ, u, msgs[MSG_LIST_HEADER]);
+ tm = localtime(&news[i].time);
+ strftime_lang(timebuf, sizeof(timebuf),
+ u, STRFTIME_DATE_TIME_FORMAT, tm);
+ notice_lang(s_OperServ, u, msgs[MSG_LIST_ENTRY],
+ news[i].num, timebuf,
+ *news[i].who ? news[i].who : "<unknown>",
+ news[i].text);
+ count++;
+ }
+ }
+ if (count == 0)
+ notice_lang(s_OperServ, u, msgs[MSG_LIST_NONE]);
+ else {
+ notice_lang(s_OperServ, u, END_OF_ANY_LIST, "News");
+ }
+}
+
+/*************************************************************************/
+
+/* Handle a {LOGON,OPER}NEWS ADD command. */
+
+static void do_news_add(User * u, int16 type, int *msgs,
+ const char *typename)
+{
+ char *text = strtok(NULL, "");
+ int n;
+
+ if (!text) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%sNEWS", typename);
+ syntax_error(s_OperServ, u, buf, msgs[MSG_ADD_SYNTAX]);
+ } else {
+ if (readonly) {
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ return;
+ }
+ n = add_newsitem(u, text, type);
+ if (n < 0)
+ notice_lang(s_OperServ, u, msgs[MSG_ADD_FULL]);
+ else
+ notice_lang(s_OperServ, u, msgs[MSG_ADDED], n);
+ }
+}
+
+
+/* Actually add a news item. Return the number assigned to the item, or -1
+ * if the news list is full (32767 items).
+ */
+
+static int add_newsitem(User * u, const char *text, short type)
+{
+ int i, num;
+
+ if (nnews >= 32767)
+ return -1;
+
+ if (nnews >= news_size) {
+ if (news_size < 8)
+ news_size = 8;
+ else
+ news_size *= 2;
+ news = srealloc(news, sizeof(*news) * news_size);
+ }
+ num = 0;
+ for (i = nnews - 1; i >= 0; i--) {
+ if (news[i].type == type) {
+ num = news[i].num;
+ break;
+ }
+ }
+ news[nnews].type = type;
+ news[nnews].num = num + 1;
+ news[nnews].text = sstrdup(text);
+ news[nnews].time = time(NULL);
+ strscpy(news[nnews].who, u->nick, NICKMAX);
+ nnews++;
+ return num + 1;
+}
+
+/*************************************************************************/
+
+/* Handle a {LOGON,OPER}NEWS DEL command. */
+
+static void do_news_del(User * u, int16 type, int *msgs,
+ const char *typename)
+{
+ char *text = strtok(NULL, " ");
+ int i, num;
+
+ if (!text) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%sNEWS", typename);
+ syntax_error(s_OperServ, u, buf, msgs[MSG_DEL_SYNTAX]);
+ } else {
+ if (readonly) {
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ return;
+ }
+ if (stricmp(text, "ALL") != 0) {
+ num = atoi(text);
+ if (num > 0 && del_newsitem(num, type)) {
+ notice_lang(s_OperServ, u, msgs[MSG_DELETED], num);
+ /* Reset the order - #0000397 */
+ for (i = 0; i < nnews; i++) {
+ if ((news[i].type == type) && (news[i].num > num))
+ news[i].num--;
+ }
+ } else
+ notice_lang(s_OperServ, u, msgs[MSG_DEL_NOT_FOUND], num);
+ } else {
+ if (del_newsitem(0, type))
+ notice_lang(s_OperServ, u, msgs[MSG_DELETED_ALL]);
+ else
+ notice_lang(s_OperServ, u, msgs[MSG_DEL_NONE]);
+ }
+ }
+}
+
+
+/* Actually delete a news item. If `num' is 0, delete all news items of
+ * the given type. Returns the number of items deleted.
+ */
+
+static int del_newsitem(int num, short type)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0; i < nnews; i++) {
+ if (news[i].type == type && (num == 0 || news[i].num == num)) {
+ free(news[i].text);
+ count++;
+ nnews--;
+ if (i < nnews)
+ memcpy(news + i, news + i + 1,
+ sizeof(*news) * (nnews - i));
+ i--;
+ }
+ }
+ return count;
+}
+
+/*************************************************************************/
diff --git a/src/nickserv.c b/src/nickserv.c
new file mode 100644
index 000000000..a14877b8b
--- /dev/null
+++ b/src/nickserv.c
@@ -0,0 +1,1995 @@
+
+/* NickServ functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+
+#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
+
+NickAlias *nalists[1024];
+NickCore *nclists[1024];
+NickRequest *nrlists[1024];
+
+unsigned int guestnum; /* Current guest number */
+
+#define TO_COLLIDE 0 /* Collide the user with this nick */
+#define TO_RELEASE 1 /* Release a collided nick */
+
+/*************************************************************************/
+
+static void add_ns_timeout(NickAlias * na, int type, time_t delay);
+
+/*************************************************************************/
+/* *INDENT-OFF* */
+void moduleAddNickServCmds(void) {
+ modules_core_init(NickServCoreNumber, NickServCoreModules);
+}
+/* *INDENT-ON* */
+/*************************************************************************/
+
+/* Display total number of registered nicks and info about each; or, if
+ * a specific nick is given, display information about that nick (like
+ * /msg NickServ INFO <nick>). If count_only != 0, then only display the
+ * number of registered nicks (the nick parameter is ignored).
+ */
+
+void listnicks(int count_only, const char *nick)
+{
+ int count = 0;
+ NickAlias *na;
+ int i;
+ char *end;
+
+ if (count_only) {
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next)
+ count++;
+ }
+ printf("%d nicknames registered.\n", count);
+
+ } else if (nick) {
+
+ struct tm *tm;
+ char buf[512];
+ static const char commastr[] = ", ";
+ int need_comma = 0;
+
+ if (!(na = findnick(nick))) {
+ printf("%s not registered.\n", nick);
+ return;
+ } else if (na->status & NS_VERBOTEN) {
+ printf("%s is FORBIDden.\n", nick);
+ return;
+ }
+ printf("%s is %s\n", nick, na->last_realname);
+ printf("Last seen address: %s\n", na->last_usermask);
+ tm = localtime(&na->time_registered);
+ strftime(buf, sizeof(buf),
+ getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
+ printf(" Time registered: %s\n", buf);
+ tm = localtime(&na->last_seen);
+ strftime(buf, sizeof(buf),
+ getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
+ printf(" Last seen time: %s\n", buf);
+ if (na->nc->url)
+ printf(" URL: %s\n", na->nc->url);
+ if (na->nc->email)
+ printf(" E-mail address: %s\n", na->nc->email);
+ if (na->nc->icq)
+ printf(" ICQ #: %d\n", na->nc->icq);
+ if (na->nc->greet)
+ printf(" Greet: %s\n", na->nc->greet);
+ *buf = 0;
+ end = buf;
+ if (na->nc->flags & NI_KILLPROTECT) {
+ end +=
+ snprintf(end, sizeof(buf) - (end - buf),
+ "Kill protection");
+ need_comma = 1;
+ }
+ if (na->nc->flags & NI_SECURE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%sSecurity",
+ need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (na->nc->flags & NI_PRIVATE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%sPrivate",
+ need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ if (na->status & NS_NO_EXPIRE) {
+ end += snprintf(end, sizeof(buf) - (end - buf), "%sNo Expire",
+ need_comma ? commastr : "");
+ need_comma = 1;
+ }
+ printf(" Options: %s\n", *buf ? buf : "None");
+
+ if (na->nc->flags & NI_SUSPENDED) {
+ if (na->last_quit) {
+ printf
+ ("This nickname is currently suspended, reason: %s\n",
+ na->last_quit);
+ } else {
+ printf("This nickname is currently suspended.\n");
+ }
+ }
+
+
+ } else {
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ printf(" %s %-20s %s\n",
+ na->status & NS_NO_EXPIRE ? "!" : " ",
+ na->nick, na->status & NS_VERBOTEN ?
+ "Disallowed (FORBID)" : (na->nc->
+ flags & NI_SUSPENDED ?
+ "Disallowed (SUSPENDED)" :
+ na->last_usermask));
+ count++;
+ }
+ }
+ printf("%d nicknames registered.\n", count);
+
+ }
+}
+
+/*************************************************************************/
+
+/* Return information on memory use. Assumes pointers are valid. */
+
+void get_aliases_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i;
+ NickAlias *na;
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ count++;
+ mem += sizeof(*na);
+ if (na->nick)
+ mem += strlen(na->nick) + 1;
+ if (na->last_usermask)
+ mem += strlen(na->last_usermask) + 1;
+ if (na->last_realname)
+ mem += strlen(na->last_realname) + 1;
+ if (na->last_quit)
+ mem += strlen(na->last_quit) + 1;
+ }
+ }
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+
+/* Return information on memory use. Assumes pointers are valid. */
+
+void get_core_stats(long *nrec, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i, j;
+ NickCore *nc;
+ char **accptr;
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ count++;
+ mem += sizeof(*nc);
+
+ if (nc->display)
+ mem += strlen(nc->display) + 1;
+ if (nc->pass)
+ mem += strlen(nc->pass) + 1;
+
+ if (nc->url)
+ mem += strlen(nc->url) + 1;
+ if (nc->email)
+ mem += strlen(nc->email) + 1;
+ if (nc->greet)
+ mem += strlen(nc->greet) + 1;
+
+ mem += sizeof(char *) * nc->accesscount;
+ for (accptr = nc->access, j = 0; j < nc->accesscount;
+ accptr++, j++) {
+ if (*accptr)
+ mem += strlen(*accptr) + 1;
+ }
+
+ mem += nc->memos.memocount * sizeof(Memo);
+ for (j = 0; j < nc->memos.memocount; j++) {
+ if (nc->memos.memos[j].text)
+ mem += strlen(nc->memos.memos[j].text) + 1;
+ }
+
+ mem += sizeof(void *) * nc->aliases.count;
+ }
+ }
+ *nrec = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* NickServ initialization. */
+
+void ns_init(void)
+{
+ moduleAddNickServCmds();
+ guestnum = time(NULL);
+ while (guestnum > 9999999)
+ guestnum -= 10000000;
+}
+
+/*************************************************************************/
+
+/* Main NickServ routine. */
+
+void nickserv(User * u, char *buf)
+{
+ char *cmd, *s;
+
+ cmd = strtok(buf, " ");
+
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_NickServ, u->nick, "PING %s", s);
+ } else if (skeleton) {
+ notice_lang(s_NickServ, u, SERVICE_OFFLINE, s_NickServ);
+ } else {
+ mod_run_cmd(s_NickServ, u, NICKSERV, cmd);
+ }
+
+}
+
+/*************************************************************************/
+
+/* Load/save data files. */
+
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", NickDBName); \
+ failed = 1; \
+ break; \
+ } \
+} while (0)
+
+/* Loads NickServ database versions 5 to 11 (<= 4 is not supported) */
+
+void load_old_ns_dbase(void)
+{
+ dbFILE *f;
+ int ver, i, j, c;
+ NickAlias *na, *na2, *next;
+ NickCore *nc;
+ int failed = 0;
+
+ uint16 tmp16;
+ uint32 tmp32;
+
+ char bufn[NICKMAX], bufp[PASSMAX];
+ char *email, *greet, *url, *forbidby, *forbidreason;
+ uint32 icq;
+
+ if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION)))
+ return;
+
+ ver = get_file_version(f);
+ if (ver <= 4) {
+ fatal("Unsupported version number (%d) on %s", ver, NickDBName);
+ close_db(f);
+ return;
+ }
+
+ for (i = 0; i < 256 && !failed; i++) {
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1)
+ fatal("Invalid format in %s", NickDBName);
+
+ na = scalloc(sizeof(NickAlias), 1);
+
+ SAFE(read_buffer(bufn, f));
+ na->nick = sstrdup(bufn);
+ SAFE(read_buffer(bufp, f)); /* Will be used later if needed */
+
+ SAFE(read_string(&url, f));
+ SAFE(read_string(&email, f));
+ if (ver >= 10)
+ SAFE(read_int32(&icq, f));
+ else
+ icq = 0;
+ if (ver >= 9)
+ SAFE(read_string(&greet, f));
+ else
+ greet = NULL;
+
+ SAFE(read_string(&na->last_usermask, f));
+ SAFE(read_string(&na->last_realname, f));
+ SAFE(read_string(&na->last_quit, f));
+
+ SAFE(read_int32(&tmp32, f));
+ na->time_registered = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ na->last_seen = tmp32;
+
+ SAFE(read_int16(&na->status, f));
+ na->status &= ~NS_TEMPORARY;
+
+ if (ver >= 9) {
+ SAFE(read_string(&forbidby, f));
+ SAFE(read_string(&forbidreason, f));
+ /* Cleanup */
+ if (forbidby && *forbidby == '@') {
+ free(forbidby);
+ forbidby = NULL;
+ }
+ if (forbidreason && *forbidreason == 0) {
+ free(forbidreason);
+ forbidreason = NULL;
+ }
+ } else {
+ forbidby = NULL;
+ forbidreason = NULL;
+ }
+
+ if (na->status & NS_VERBOTEN) {
+ if (na->last_usermask)
+ free(na->last_usermask);
+ if (na->last_realname)
+ free(na->last_realname);
+
+ na->last_usermask = forbidby;
+ na->last_realname = forbidreason;
+ } else {
+ if (!na->last_usermask)
+ na->last_usermask = sstrdup("");
+ if (!na->last_realname)
+ na->last_realname = sstrdup("");
+ }
+
+ /* Store the reference for later resolving */
+ SAFE(read_string((char **) &na->nc, f));
+ SAFE(read_int16(&tmp16, f)); /* Was linkcount */
+
+ if (na->nc) {
+ SAFE(read_int16(&tmp16, f)); /* Was channelcount */
+ } else {
+ /* This nick was a master nick, so it also has all the
+ * core info! =)
+ */
+ nc = scalloc(1, sizeof(NickCore));
+ slist_init(&nc->aliases);
+
+ /* The initial display is what used to be the master nick */
+ nc->display = sstrdup(na->nick);
+
+ /* We grabbed info before; fill the appropriate fields now */
+ if (*bufp)
+ memcpy(nc->pass, bufp, PASSMAX);
+ else
+ memset(nc->pass, 0, PASSMAX); /* Which may be the case for forbidden nicks .. */
+
+ nc->email = email;
+ nc->greet = greet;
+ nc->icq = icq;
+ nc->url = url;
+
+ /* We check whether the e-mail is valid because it was not tested
+ * in older versions.
+ */
+ if (ver <= 10 && nc->email && !MailValidate(nc->email)) {
+ free(nc->email);
+ nc->email = NULL;
+ }
+
+ SAFE(read_int32(&nc->flags, f));
+ if (!NSAllowKillImmed)
+ nc->flags &= ~NI_KILL_IMMED;
+
+ /* Status flags cleanup */
+ if (na->status & NS_OLD_ENCRYPTEDPW) {
+ nc->flags |= NI_ENCRYPTEDPW;
+ na->status &= ~NS_OLD_ENCRYPTEDPW;
+ }
+
+ /* Add services opers and admins to the appropriate list, but
+ only if the database version is equal to or more than 10. */
+ if (ver >= 10) {
+ if (nc->flags & NI_SERVICES_ADMIN)
+ slist_add(&servadmins, nc);
+ if (nc->flags & NI_SERVICES_OPER)
+ slist_add(&servopers, nc);
+ }
+
+ /* Add the Services root flag if needed. */
+ if (nc)
+ for (j = 0; j < RootNumber; j++)
+ if (!stricmp(ServicesRoots[j], na->nick))
+ nc->flags |= NI_SERVICES_ROOT;
+
+ SAFE(read_int16(&nc->accesscount, f));
+ if (nc->accesscount) {
+ char **access;
+ access = scalloc(sizeof(char *) * nc->accesscount, 1);
+ nc->access = access;
+ for (j = 0; j < nc->accesscount; j++, access++)
+ SAFE(read_string(access, f));
+ }
+
+ SAFE(read_int16(&tmp16, f));
+ nc->memos.memocount = (int16) tmp16;
+ SAFE(read_int16(&tmp16, f));
+ nc->memos.memomax = (int16) tmp16;
+ if (nc->memos.memocount) {
+ Memo *memos;
+ memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1);
+ nc->memos.memos = memos;
+
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ SAFE(read_int32(&memos->number, f));
+ SAFE(read_int16(&memos->flags, f));
+ SAFE(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ SAFE(read_buffer(memos->sender, f));
+ SAFE(read_string(&memos->text, f));
+ memos->moduleData = NULL;
+ }
+ }
+
+ /* We read the channel count, but don't take care of it.
+ load_cs_dbase will regenerate it correctly. */
+ SAFE(read_int16(&tmp16, f));
+ SAFE(read_int16(&nc->channelmax, f));
+ if (ver == 5)
+ nc->channelmax = CSMaxReg;
+
+ SAFE(read_int16(&nc->language, f));
+
+ if (ver >= 11 && ver < 13) {
+ char *s;
+
+ SAFE(read_int16(&tmp16, f));
+ SAFE(read_int32(&tmp32, f));
+ SAFE(read_int16(&tmp16, f));
+ SAFE(read_string(&s, f));
+ }
+
+ /* Set us as being a master nick; fill the nc field also.
+ The NS_MASTER flag will not be cleared in this function. */
+ na->status |= NS_MASTER;
+ na->nc = nc;
+ slist_add(&nc->aliases, na);
+
+ /* Insert our new core in the core list */
+ insert_core(nc);
+ }
+
+ alpha_insert_alias(na);
+
+ } /* while (getc_db(f) != 0) */
+ } /* for (i) */
+
+ /* Now resolve what were called links */
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = next) {
+ next = na->next;
+
+ /* Master nicks are already resolved */
+ if (na->status & NS_MASTER)
+ continue;
+
+ na2 = na;
+ /* While the reference resolves and it's not a master nick */
+ while ((na2 = findnick((char *) na2->nc))
+ && !(na2->status & NS_MASTER));
+
+ /* It didn't resolve. This is problematic since there is no core. :/
+ We delete the nick. */
+ if (!na2) {
+ alog("%s: while loading database: %s was linked to inexistant %s", s_NickServ, na->nick, (char *) na->nc);
+ delnick(na);
+ continue;
+ }
+
+ /* OK we have information on the core. We mark the current alias
+ as a master nick because it now contains a valid core. */
+ na->nc = na2->nc;
+ na->status |= NS_MASTER;
+ slist_add(&na->nc->aliases, na);
+ }
+ }
+
+ close_db(f);
+}
+
+void load_ns_req_db(void)
+{
+ dbFILE *f;
+ int i, c, ver;
+ NickRequest *nr;
+ uint32 tmp32;
+ int failed = 0, len;
+ char *pass;
+
+ if (!(f = open_db(s_NickServ, PreNickDBName, "r", PRE_NICK_VERSION)))
+ return;
+ ver = get_file_version(f);
+ for (i = 0; i < 1024 && !failed; i++) {
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1)
+ fatal("Invalid format in %s", PreNickDBName);
+ nr = scalloc(1, sizeof(NickRequest));
+ SAFE(read_string(&nr->nick, f));
+ SAFE(read_string(&nr->passcode, f));
+ if (ver < 2) {
+ SAFE(read_string(&pass, f));
+ len = strlen(pass);
+ enc_encrypt(pass, len, nr->password, PASSMAX);
+ memset(pass, 0, len);
+ free(pass);
+ } else
+ SAFE(read_buffer(nr->password, f));
+ SAFE(read_string(&nr->email, f));
+ SAFE(read_int32(&tmp32, f));
+ nr->requested = tmp32;
+ insert_requestnick(nr);
+ }
+ }
+ close_db(f);
+}
+
+void load_ns_dbase(void)
+{
+ dbFILE *f;
+ int ver, i, j, c;
+ NickAlias *na, **nalast, *naprev;
+ NickCore *nc, **nclast, *ncprev;
+ int failed = 0;
+ uint16 tmp16;
+ uint32 tmp32;
+ char *s, *pass;
+
+ if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION)))
+ return;
+
+ ver = get_file_version(f);
+
+ if (ver <= 11) {
+ close_db(f);
+ load_old_ns_dbase();
+ return;
+ }
+
+ /* First we load nick cores */
+ for (i = 0; i < 1024 && !failed; i++) {
+ nclast = &nclists[i];
+ ncprev = NULL;
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1)
+ fatal("Invalid format in %s", NickDBName);
+
+ nc = scalloc(1, sizeof(NickCore));
+ *nclast = nc;
+ nclast = &nc->next;
+ nc->prev = ncprev;
+ ncprev = nc;
+
+ slist_init(&nc->aliases);
+
+ SAFE(read_string(&nc->display, f));
+ if (ver < 14) {
+ SAFE(read_string(&pass, f));
+ if (pass) {
+ memset(nc->pass, 0, PASSMAX);
+ memcpy(nc->pass, pass, strlen(pass));
+ } else
+ memset(nc->pass, 0, PASSMAX);
+ } else
+ SAFE(read_buffer(nc->pass, f));
+
+ SAFE(read_string(&nc->email, f));
+ SAFE(read_string(&nc->greet, f));
+ SAFE(read_int32(&nc->icq, f));
+ SAFE(read_string(&nc->url, f));
+
+ SAFE(read_int32(&nc->flags, f));
+ if (!NSAllowKillImmed)
+ nc->flags &= ~NI_KILL_IMMED;
+ SAFE(read_int16(&nc->language, f));
+
+ /* Add services opers and admins to the appropriate list, but
+ only if the database version is more than 10. */
+ if (nc->flags & NI_SERVICES_ADMIN)
+ slist_add(&servadmins, nc);
+ if (nc->flags & NI_SERVICES_OPER)
+ slist_add(&servopers, nc);
+
+ SAFE(read_int16(&nc->accesscount, f));
+ if (nc->accesscount) {
+ char **access;
+ access = scalloc(sizeof(char *) * nc->accesscount, 1);
+ nc->access = access;
+ for (j = 0; j < nc->accesscount; j++, access++)
+ SAFE(read_string(access, f));
+ }
+
+ SAFE(read_int16(&tmp16, f));
+ nc->memos.memocount = (int16) tmp16;
+ SAFE(read_int16(&tmp16, f));
+ nc->memos.memomax = (int16) tmp16;
+ if (nc->memos.memocount) {
+ Memo *memos;
+ memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1);
+ nc->memos.memos = memos;
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ SAFE(read_int32(&memos->number, f));
+ SAFE(read_int16(&memos->flags, f));
+ SAFE(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ SAFE(read_buffer(memos->sender, f));
+ SAFE(read_string(&memos->text, f));
+ memos->moduleData = NULL;
+ }
+ }
+
+ SAFE(read_int16(&nc->channelcount, f));
+ SAFE(read_int16(&tmp16, f));
+ nc->channelmax = CSMaxReg;
+
+ if (ver < 13) {
+ /* Used to be dead authentication system */
+ SAFE(read_int16(&tmp16, f));
+ SAFE(read_int32(&tmp32, f));
+ SAFE(read_int16(&tmp16, f));
+ SAFE(read_string(&s, f));
+ }
+
+ } /* while (getc_db(f) != 0) */
+ *nclast = NULL;
+ } /* for (i) */
+
+ for (i = 0; i < 1024 && !failed; i++) {
+ nalast = &nalists[i];
+ naprev = NULL;
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1)
+ fatal("Invalid format in %s", NickDBName);
+
+ na = scalloc(1, sizeof(NickAlias));
+
+ SAFE(read_string(&na->nick, f));
+
+ SAFE(read_string(&na->last_usermask, f));
+ SAFE(read_string(&na->last_realname, f));
+ SAFE(read_string(&na->last_quit, f));
+
+ SAFE(read_int32(&tmp32, f));
+ na->time_registered = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ na->last_seen = tmp32;
+ SAFE(read_int16(&na->status, f));
+ na->status &= ~NS_TEMPORARY;
+
+ SAFE(read_string(&s, f));
+ na->nc = findcore(s);
+ free(s);
+
+ slist_add(&na->nc->aliases, na);
+
+ if (!(na->status & NS_VERBOTEN)) {
+ if (!na->last_usermask)
+ na->last_usermask = sstrdup("");
+ if (!na->last_realname)
+ na->last_realname = sstrdup("");
+ }
+
+ na->nc->flags &= ~NI_SERVICES_ROOT;
+
+ *nalast = na;
+ nalast = &na->next;
+ na->prev = naprev;
+ naprev = na;
+
+ } /* while (getc_db(f) != 0) */
+
+ *nalast = NULL;
+ } /* for (i) */
+
+ close_db(f);
+
+ for (i = 0; i < 1024; i++) {
+ NickAlias *next;
+
+ for (na = nalists[i]; na; na = next) {
+ next = na->next;
+ /* We check for coreless nicks (although it should never happen) */
+ if (!na->nc) {
+ alog("%s: while loading database: %s has no core! We delete it.", s_NickServ, na->nick);
+ delnick(na);
+ continue;
+ }
+
+ /* Add the Services root flag if needed. */
+ for (j = 0; j < RootNumber; j++)
+ if (!stricmp(ServicesRoots[j], na->nick))
+ na->nc->flags |= NI_SERVICES_ROOT;
+ }
+ }
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", NickDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", NickDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+
+
+void save_ns_dbase(void)
+{
+ dbFILE *f;
+ int i, j;
+ NickAlias *na;
+ NickCore *nc;
+ char **access;
+ Memo *memos;
+ static time_t lastwarn = 0;
+
+ if (!(f = open_db(s_NickServ, NickDBName, "w", NICK_VERSION)))
+ return;
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ SAFE(write_int8(1, f));
+
+ SAFE(write_string(nc->display, f));
+ SAFE(write_buffer(nc->pass, f));
+
+ SAFE(write_string(nc->email, f));
+ SAFE(write_string(nc->greet, f));
+ SAFE(write_int32(nc->icq, f));
+ SAFE(write_string(nc->url, f));
+
+ SAFE(write_int32(nc->flags, f));
+ SAFE(write_int16(nc->language, f));
+
+ SAFE(write_int16(nc->accesscount, f));
+ for (j = 0, access = nc->access; j < nc->accesscount;
+ j++, access++)
+ SAFE(write_string(*access, f));
+
+ SAFE(write_int16(nc->memos.memocount, f));
+ SAFE(write_int16(nc->memos.memomax, f));
+ memos = nc->memos.memos;
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ SAFE(write_int32(memos->number, f));
+ SAFE(write_int16(memos->flags, f));
+ SAFE(write_int32(memos->time, f));
+ SAFE(write_buffer(memos->sender, f));
+ SAFE(write_string(memos->text, f));
+ }
+
+ SAFE(write_int16(nc->channelcount, f));
+ SAFE(write_int16(nc->channelmax, f));
+
+ } /* for (nc) */
+
+ SAFE(write_int8(0, f));
+
+ } /* for (i) */
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ SAFE(write_int8(1, f));
+
+ SAFE(write_string(na->nick, f));
+
+ SAFE(write_string(na->last_usermask, f));
+ SAFE(write_string(na->last_realname, f));
+ SAFE(write_string(na->last_quit, f));
+
+ SAFE(write_int32(na->time_registered, f));
+ SAFE(write_int32(na->last_seen, f));
+
+ SAFE(write_int16(na->status, f));
+
+ SAFE(write_string(na->nc->display, f));
+
+ } /* for (na) */
+ SAFE(write_int8(0, f));
+ } /* for (i) */
+
+ close_db(f);
+
+}
+
+void save_ns_req_dbase(void)
+{
+ dbFILE *f;
+ int i;
+ NickRequest *nr;
+ static time_t lastwarn = 0;
+
+ if (!(f = open_db(s_NickServ, PreNickDBName, "w", PRE_NICK_VERSION)))
+ return;
+
+ for (i = 0; i < 1024; i++) {
+ for (nr = nrlists[i]; nr; nr = nr->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(nr->nick, f));
+ SAFE(write_string(nr->passcode, f));
+ SAFE(write_buffer(nr->password, f));
+ SAFE(write_string(nr->email, f));
+ SAFE(write_int32(nr->requested, f));
+ SAFE(write_int8(0, f));
+ }
+ }
+ close_db(f);
+
+}
+
+#undef SAFE
+
+void save_ns_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ int i;
+ NickAlias *na;
+ NickCore *nc;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_ns_core") == 0) {
+ alog("Unable to tag 'anope_ns_core' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_ns_alias") == 0) {
+ alog("Unable to tag 'anope_ns_alias' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_ns_access") == 0) {
+ alog("Unable to tag 'anope_ns_access' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table_where("anope_ms_info", "serv='NICK'") == 0) {
+ alog("Unable to tag 'anope_ms_info' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ if (rdb_save_ns_core(nc) == 0) {
+ alog("Unable to save NickCore for '%s' - NickServ RDB save failed.", nc->display);
+ rdb_close();
+ return;
+ }
+ } /* for (nc) */
+ } /* for (i) */
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ if (rdb_save_ns_alias(na) == 0) {
+ alog("Unable to save NickAlias for '%s' - NickServ RDB save failed.", na->nick);
+ rdb_close();
+ return;
+ }
+ } /* for (na) */
+ } /* for (i) */
+
+ if (rdb_clean_table("anope_ns_core") == 0) {
+ alog("Unable to clean table 'anope_ns_core' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_ns_alias") == 0) {
+ alog("Unable to clean table 'anope_ns_alias' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_ns_access") == 0) {
+ alog("Unable to clean table 'anope_ns_access' - NickServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table_where("anope_ms_info", "serv='NICK'") == 0)
+ alog("Unable to clean table 'anope_ms_info' - NickServ RDB save failed.");
+
+ rdb_close();
+#endif
+}
+
+void save_ns_req_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ int i;
+ NickRequest *nr;
+
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_ns_request") == 0) {
+ alog("Unable to tag table 'anope_ns_request' - NickServ Request RDB save failed.");
+ rdb_close();
+ return;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ for (nr = nrlists[i]; nr; nr = nr->next) {
+ if (rdb_save_ns_req(nr) == 0) {
+ /* Something went wrong - abort saving */
+ alog("Unable to save NickRequest (nick '%s') - NickServ Request RDB save failed.", nr->nick);
+ rdb_close();
+ return;
+ }
+ }
+ }
+
+ if (rdb_clean_table("anope_ns_request") == 0)
+ alog("Unable to clean table 'anope_ns_request' - NickServ Request RDB save failed.");
+
+ rdb_close();
+#endif
+
+}
+
+/*************************************************************************/
+
+/* Check whether a user is on the access list of the nick they're using If
+ * not, send warnings as appropriate. If so (and not NI_SECURE), update
+ * last seen info.
+ * Return 1 if the user is valid and recognized, 0 otherwise (note
+ * that this means an NI_SECURE nick will return 0 from here).
+ * If the user's nick is not registered, 0 is returned.
+ */
+
+int validate_user(User * u)
+{
+ NickAlias *na;
+ NickRequest *nr;
+
+ int on_access;
+
+ if ((nr = findrequestnick(u->nick))) {
+ notice_lang(s_NickServ, u, NICK_IS_PREREG);
+ }
+
+ if (!(na = u->na))
+ return 0;
+
+ if (na->status & NS_VERBOTEN) {
+ notice_lang(s_NickServ, u, NICK_MAY_NOT_BE_USED);
+ collide(na, 0);
+ return 0;
+ }
+
+ if (na->nc->flags & NI_SUSPENDED) {
+ notice_lang(s_NickServ, u, NICK_X_SUSPENDED, u->nick);
+ collide(na, 0);
+ return 0;
+ }
+
+ on_access = is_on_access(u, na->nc);
+ if (on_access)
+ na->status |= NS_ON_ACCESS;
+
+ if (!(na->nc->flags & NI_SECURE) && on_access) {
+ na->status |= NS_RECOGNIZED;
+ na->last_seen = time(NULL);
+ if (na->last_usermask)
+ free(na->last_usermask);
+ na->last_usermask =
+ scalloc(strlen(common_get_vident(u)) +
+ strlen(common_get_vhost(u)) + 2, 1);
+ sprintf(na->last_usermask, "%s@%s", common_get_vident(u),
+ common_get_vhost(u));
+ if (na->last_realname)
+ free(na->last_realname);
+ na->last_realname = sstrdup(u->realname);
+ return 1;
+ }
+
+ if (on_access || !(na->nc->flags & NI_KILL_IMMED)) {
+ if (na->nc->flags & NI_SECURE)
+ notice_lang(s_NickServ, u, NICK_IS_SECURE, s_NickServ);
+ else
+ notice_lang(s_NickServ, u, NICK_IS_REGISTERED, s_NickServ);
+ }
+
+ if ((na->nc->flags & NI_KILLPROTECT) && !on_access) {
+ if (na->nc->flags & NI_KILL_IMMED) {
+ notice_lang(s_NickServ, u, FORCENICKCHANGE_NOW);
+ collide(na, 0);
+ } else if (na->nc->flags & NI_KILL_QUICK) {
+ notice_lang(s_NickServ, u, FORCENICKCHANGE_IN_20_SECONDS);
+ add_ns_timeout(na, TO_COLLIDE, 20);
+ } else {
+ notice_lang(s_NickServ, u, FORCENICKCHANGE_IN_1_MINUTE);
+ add_ns_timeout(na, TO_COLLIDE, 60);
+ }
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Cancel validation flags for a nick (i.e. when the user with that nick
+ * signs off or changes nicks). Also cancels any impending collide. */
+
+void cancel_user(User * u)
+{
+ NickAlias *na = u->na;
+
+ if (na) {
+ if (na->status & NS_GUESTED) {
+ if (ircd->svshold) {
+ if (UseSVSHOLD) {
+ anope_cmd_svshold(na->nick);
+ } else {
+ if (ircd->svsnick) {
+ anope_cmd_guest_nick(u->nick, NSEnforcerUser,
+ NSEnforcerHost,
+ "Services Enforcer", "+");
+ add_ns_timeout(na, TO_RELEASE, NSReleaseTimeout);
+ } else {
+ anope_cmd_svskill(s_NickServ, u->nick,
+ "Killing to enforce nick");
+ }
+ }
+ } else {
+ if (ircd->svsnick) {
+ anope_cmd_guest_nick(u->nick, NSEnforcerUser,
+ NSEnforcerHost,
+ "Services Enforcer", "+");
+ add_ns_timeout(na, TO_RELEASE, NSReleaseTimeout);
+ } else {
+ anope_cmd_svskill(s_NickServ, u->nick,
+ "Killing to enforce nick");
+ }
+ }
+ na->status &= ~NS_TEMPORARY;
+ na->status |= NS_KILL_HELD;
+ } else {
+ na->status &= ~NS_TEMPORARY;
+ }
+ del_ns_timeout(na, TO_COLLIDE);
+ }
+}
+
+/*************************************************************************/
+
+/* Return whether a user has identified for their nickname. */
+
+int nick_identified(User * u)
+{
+ if (u) {
+ if (u->na) {
+ if (u->na->status) {
+ return (u->na->status & NS_IDENTIFIED);
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Return whether a user is recognized for their nickname. */
+
+int nick_recognized(User * u)
+{
+ if (u) {
+ if (u->na) {
+ if (u->na->status) {
+ return (u->na->status & (NS_IDENTIFIED | NS_RECOGNIZED));
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Returns whether a user is identified AND in the group nc */
+
+int group_identified(User * u, NickCore * nc)
+{
+ return nick_identified(u) && u->na->nc == nc;
+}
+
+/*************************************************************************/
+
+/* Remove all nicks which have expired. Also update last-seen time for all
+ * nicks.
+ */
+
+void expire_nicks()
+{
+ int i;
+ NickAlias *na, *next;
+ time_t now = time(NULL);
+ char *tmpnick;
+
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = next) {
+ next = na->next;
+
+ if (na->u
+ && ((na->nc->flags & NI_SECURE) ? nick_identified(na->u) :
+ nick_recognized(na->u))) {
+ if (debug >= 2)
+ alog("debug: NickServ: updating last seen time for %s",
+ na->nick);
+ na->last_seen = now;
+ continue;
+ }
+
+ if (NSExpire && now - na->last_seen >= NSExpire
+ && !(na->status & (NS_VERBOTEN | NS_NO_EXPIRE))
+ && !(na->nc->flags & (NI_SUSPENDED))) {
+ alog("Expiring nickname %s (group: %s) (e-mail: %s)",
+ na->nick, na->nc->display,
+ (na->nc->email ? na->nc->email : "none"));
+ tmpnick = sstrdup(na->nick);
+ delnick(na);
+ send_event(EVENT_NICK_EXPIRE, 1, tmpnick);
+ free(tmpnick);
+ }
+ }
+ }
+}
+
+void expire_requests()
+{
+ int i;
+ NickRequest *nr, *next;
+ time_t now = time(NULL);
+ for (i = 0; i < 1024; i++) {
+ for (nr = nrlists[i]; nr; nr = next) {
+ next = nr->next;
+ if (NSRExpire && now - nr->requested >= NSRExpire) {
+ alog("Request for nick %s expiring", nr->nick);
+ delnickrequest(nr);
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+/*************************************************************************/
+/* Return the NickRequest structire for the given nick, or NULL */
+
+NickRequest *findrequestnick(const char *nick)
+{
+ NickRequest *nr;
+
+ if (!*nick || !nick) {
+ if (debug) {
+ alog("debug: findrequestnick() called with NULL values");
+ }
+ return NULL;
+ }
+
+ for (nr = nrlists[HASH(nick)]; nr; nr = nr->next) {
+ if (stricmp(nr->nick, nick) == 0)
+ return nr;
+ }
+ return NULL;
+}
+
+/* Return the NickAlias structure for the given nick, or NULL if the nick
+ * isn't registered. */
+
+NickAlias *findnick(const char *nick)
+{
+ NickAlias *na;
+
+ if (!nick || !*nick) {
+ if (debug) {
+ alog("debug: findnick() called with NULL values");
+ }
+ return NULL;
+ }
+
+ for (na = nalists[HASH(nick)]; na; na = na->next) {
+ if (stricmp(na->nick, nick) == 0)
+ return na;
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+
+/* Return the NickCore structure for the given nick, or NULL if the core
+ * doesn't exist. */
+
+NickCore *findcore(const char *nick)
+{
+ NickCore *nc;
+
+ if (!nick || !*nick) {
+ if (debug) {
+ alog("debug: findcore() called with NULL values");
+ }
+ return NULL;
+ }
+
+ for (nc = nclists[HASH(nick)]; nc; nc = nc->next) {
+ if (stricmp(nc->display, nick) == 0)
+ return nc;
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+/*********************** NickServ private routines ***********************/
+/*************************************************************************/
+
+/* Is the given user's address on the given nick's access list? Return 1
+ * if so, 0 if not. */
+
+int is_on_access(User * u, NickCore * nc)
+{
+ int i;
+ char *buf;
+ char *buf2 = NULL;
+
+ if (nc->accesscount == 0)
+ return 0;
+
+ buf = scalloc(strlen(u->username) + strlen(u->host) + 2, 1);
+ sprintf(buf, "%s@%s", u->username, u->host);
+ if (ircd->vhost) {
+ if (u->vhost) {
+ buf2 = scalloc(strlen(u->username) + strlen(u->vhost) + 2, 1);
+ sprintf(buf2, "%s@%s", u->username, u->vhost);
+ }
+ }
+
+ for (i = 0; i < nc->accesscount; i++) {
+ if (match_wild_nocase(nc->access[i], buf)
+ || (ircd->vhost ? match_wild_nocase(nc->access[i], buf2) : 0)) {
+ free(buf);
+ if (ircd->vhost) {
+ if (u->vhost) {
+ free(buf2);
+ }
+ }
+ return 1;
+ }
+ }
+ free(buf);
+ if (ircd->vhost) {
+ free(buf2);
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Insert a nick alias alphabetically into the database. */
+
+void alpha_insert_alias(NickAlias * na)
+{
+ NickAlias *ptr, *prev;
+ char *nick;
+ int index;
+
+ if (!na) {
+ if (debug) {
+ alog("debug: alpha_insert_alias called with NULL values");
+ }
+ return;
+ }
+
+ nick = na->nick;
+ index = HASH(nick);
+
+ for (prev = NULL, ptr = nalists[index];
+ ptr && stricmp(ptr->nick, nick) < 0; prev = ptr, ptr = ptr->next);
+ na->prev = prev;
+ na->next = ptr;
+ if (!prev)
+ nalists[index] = na;
+ else
+ prev->next = na;
+ if (ptr)
+ ptr->prev = na;
+}
+
+/*************************************************************************/
+
+/* Insert a nick core into the database. */
+
+void insert_core(NickCore * nc)
+{
+ int index;
+
+ if (!nc) {
+ if (debug) {
+ alog("debug: insert_core called with NULL values");
+ }
+ return;
+ }
+
+ index = HASH(nc->display);
+
+ nc->prev = NULL;
+ nc->next = nclists[index];
+ if (nc->next)
+ nc->next->prev = nc;
+ nclists[index] = nc;
+}
+
+/*************************************************************************/
+void insert_requestnick(NickRequest * nr)
+{
+ int index = HASH(nr->nick);
+ if (!nr) {
+ if (debug) {
+ alog("debug: insert_requestnick called with NULL values");
+ }
+ return;
+ }
+
+
+ nr->prev = NULL;
+ nr->next = nrlists[index];
+ if (nr->next)
+ nr->next->prev = nr;
+ nrlists[index] = nr;
+}
+
+/*************************************************************************/
+
+/* Sets nc->display to newdisplay. If newdisplay is NULL, it will change
+ * it to the first alias in the list.
+ */
+
+void change_core_display(NickCore * nc, char *newdisplay)
+{
+ if (!newdisplay) {
+ NickAlias *na;
+
+ if (nc->aliases.count <= 0)
+ return;
+
+ na = nc->aliases.list[0];
+ newdisplay = na->nick;
+ }
+
+ /* Log ... */
+ alog("%s: changing %s nickname group display to %s", s_NickServ,
+ nc->display, newdisplay);
+
+#ifdef USE_RDB
+ /* Reflect this change in the database right away. This
+ * ensures that we know how to deal with this "new" nick
+ * on the next /OS UPDATE might need it on /NS DROP too...
+ */
+ if (rdb_open()) {
+ if (rdb_ns_set_display(newdisplay, nc->display) == 0) {
+ alog("Unable to update display for %s - Nick Display RDB update failed.", nc->display);
+ }
+ rdb_close();
+ }
+#endif
+
+ /* Remove the core from the list */
+ if (nc->next)
+ nc->next->prev = nc->prev;
+ if (nc->prev)
+ nc->prev->next = nc->next;
+ else
+ nclists[HASH(nc->display)] = nc->next;
+
+ free(nc->display);
+ nc->display = sstrdup(newdisplay);
+ insert_core(nc);
+
+}
+
+/*************************************************************************/
+
+/* Deletes the core. This must be called only when there is no more
+ * aliases for it, because no cleanup is done.
+ * This function removes all references to the core as well.
+ */
+
+static int delcore(NickCore * nc)
+{
+ int i;
+#ifdef USE_RDB
+ static char clause[128];
+ char *q_display;
+#endif
+ /* (Hopefully complete) cleanup */
+ cs_remove_nick(nc);
+ os_remove_nick(nc);
+
+ /* Remove the core from the list */
+ if (nc->next)
+ nc->next->prev = nc->prev;
+ if (nc->prev)
+ nc->prev->next = nc->next;
+ else
+ nclists[HASH(nc->display)] = nc->next;
+
+ /* Log .. */
+ alog("%s: deleting nickname group %s", s_NickServ, nc->display);
+
+#ifdef USE_RDB
+ /* Reflect this change in the database right away. */
+ if (rdb_open()) {
+ q_display = rdb_quote(nc->display);
+ snprintf(clause, sizeof(clause), "display='%s'", q_display);
+ if (rdb_scrub_table("anope_ns_access", clause) == 0)
+ alog("Unable to scrub table 'anope_ns_access' - RDB update failed.");
+ else if (rdb_scrub_table("anope_ns_core", clause) == 0)
+ alog("Unable to scrub table 'anope_ns_core' - RDB update failed.");
+ else if (rdb_scrub_table("anope_cs_access", clause) == 0)
+ alog("Unable to scrub table 'anope_cs_access' - RDB update failed.");
+ else {
+ /* I'm unsure how to clean up the OS ADMIN/OPER list on the db */
+ /* I wish the "display" primary key would be the same on all tables */
+ snprintf(clause, sizeof(clause),
+ "receiver='%s' AND serv='NICK'", q_display);
+ if (rdb_scrub_table("anope_ms_info", clause) == 0)
+ alog("Unable to scrub table 'anope_ms_info' - RDB update failed.");
+ }
+ rdb_close();
+ free(q_display);
+ }
+#endif
+
+ /* Now we can safely free it. */
+ free(nc->display);
+
+ if (nc->email)
+ free(nc->email);
+ if (nc->greet)
+ free(nc->greet);
+ if (nc->url)
+ free(nc->url);
+
+ if (nc->access) {
+ for (i = 0; i < nc->accesscount; i++) {
+ if (nc->access[i])
+ free(nc->access[i]);
+ }
+ free(nc->access);
+ }
+
+ if (nc->memos.memos) {
+ for (i = 0; i < nc->memos.memocount; i++) {
+ if (nc->memos.memos[i].text)
+ free(nc->memos.memos[i].text);
+ moduleCleanStruct(&nc->memos.memos[i].moduleData);
+ }
+ free(nc->memos.memos);
+ }
+
+ moduleCleanStruct(&nc->moduleData);
+
+ free(nc);
+
+ return 1;
+}
+
+
+/*************************************************************************/
+int delnickrequest(NickRequest * nr)
+{
+ if (nr) {
+ nrlists[HASH(nr->nick)] = nr->next;
+ if (nr->nick)
+ free(nr->nick);
+ if (nr->passcode)
+ free(nr->passcode);
+ if (nr->email)
+ free(nr->email);
+ free(nr);
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Deletes an alias. The core will also be deleted if it has no more
+ * nicks attached to it. Easy but powerful.
+ * Well, we must also take care that the nick being deleted is not
+ * the core display, and if so, change it to the next alias in the list,
+ * otherwise weird things will happen.
+ * Returns 1 on success, 0 otherwise.
+ */
+
+int delnick(NickAlias * na)
+{
+#ifdef USE_RDB
+ static char clause[128];
+ char *q_nick;
+#endif
+ /* First thing to do: remove any timeout belonging to the nick we're deleting */
+ clean_ns_timeouts(na);
+
+ /* Second thing to do: look for an user using the alias
+ * being deleted, and make appropriate changes */
+
+ if (na->u) {
+ na->u->na = NULL;
+
+ if (ircd->modeonunreg)
+ common_svsmode(na->u, ircd->modeonunreg, "1");
+
+ }
+
+ delHostCore(na->nick); /* delete any vHost's for this nick */
+
+ /* Accept nicks that have no core, because of database load functions */
+ if (na->nc) {
+ /* Next: see if our core is still useful. */
+ slist_remove(&na->nc->aliases, na);
+ if (na->nc->aliases.count == 0) {
+ if (!delcore(na->nc))
+ return 0;
+ na->nc = NULL;
+ } else {
+ /* Display updating stuff */
+ if (!stricmp(na->nick, na->nc->display))
+ change_core_display(na->nc, NULL);
+ }
+ }
+
+ /* Remove us from the aliases list */
+ if (na->next)
+ na->next->prev = na->prev;
+ if (na->prev)
+ na->prev->next = na->next;
+ else
+ nalists[HASH(na->nick)] = na->next;
+
+#ifdef USE_RDB
+ /* Reflect this change in the database right away. */
+ if (rdb_open()) {
+ q_nick = rdb_quote(na->nick);
+ snprintf(clause, sizeof(clause), "nick='%s'", q_nick);
+ if (rdb_scrub_table("anope_ns_alias", clause) == 0)
+ alog("Unable to scrub table 'anope_ns_alias' - RDB update failed");
+ rdb_close();
+ free(q_nick);
+ }
+#endif
+
+ free(na->nick);
+ if (na->last_usermask)
+ free(na->last_usermask);
+ if (na->last_realname)
+ free(na->last_realname);
+ if (na->last_quit)
+ free(na->last_quit);
+
+ moduleCleanStruct(&na->moduleData);
+
+ free(na);
+
+
+ return 1;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Collide a nick.
+ *
+ * When connected to a network using DALnet servers, version 4.4.15 and above,
+ * Services is now able to force a nick change instead of killing the user.
+ * The new nick takes the form "Guest######". If a nick change is forced, we
+ * do not introduce the enforcer nick until the user's nick actually changes.
+ * This is watched for and done in cancel_user(). -TheShadow
+ */
+
+void collide(NickAlias * na, int from_timeout)
+{
+ char guestnick[NICKMAX];
+
+ if (!from_timeout)
+ del_ns_timeout(na, TO_COLLIDE);
+
+ /* Old system was unsure since there can be more than one collide
+ * per second. So let use another safer method.
+ * --lara
+ */
+ /* So you should check the length of NSGuestNickPrefix, eh Lara?
+ * --Certus
+ */
+
+ if (ircd->svsnick) {
+ /* We need to make sure the guestnick is free -- heinz */
+ do {
+ snprintf(guestnick, sizeof(guestnick), "%s%d",
+ NSGuestNickPrefix, getrandom16());
+ } while (finduser(guestnick));
+ notice_lang(s_NickServ, na->u, FORCENICKCHANGE_CHANGING,
+ guestnick);
+ anope_cmd_svsnick(na->nick, guestnick, time(NULL));
+ na->status |= NS_GUESTED;
+ } else {
+ kill_user(s_NickServ, na->nick, "Services nickname-enforcer kill");
+ }
+}
+
+/*************************************************************************/
+
+/* Release hold on a nick. */
+
+void release(NickAlias * na, int from_timeout)
+{
+ if (!from_timeout)
+ del_ns_timeout(na, TO_RELEASE);
+ if (ircd->svshold) {
+ if (UseSVSHOLD) {
+ anope_cmd_release_svshold(na->nick);
+ } else {
+ anope_cmd_quit(na->nick, NULL);
+ }
+ } else {
+ anope_cmd_quit(na->nick, NULL);
+ }
+ na->status &= ~NS_KILL_HELD;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+static struct my_timeout {
+ struct my_timeout *next, *prev;
+ NickAlias *na;
+ Timeout *to;
+ int type;
+} *my_timeouts;
+
+/*************************************************************************/
+
+/* Remove a collide/release timeout from our private list. */
+
+static void rem_ns_timeout(NickAlias * na, int type)
+{
+ struct my_timeout *t, *t2;
+
+ t = my_timeouts;
+ while (t) {
+ if (t->na == na && t->type == type) {
+ t2 = t->next;
+ if (t->next)
+ t->next->prev = t->prev;
+ if (t->prev)
+ t->prev->next = t->next;
+ else
+ my_timeouts = t->next;
+ free(t);
+ t = t2;
+ } else {
+ t = t->next;
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Collide a nick on timeout. */
+
+static void timeout_collide(Timeout * t)
+{
+ NickAlias *na = t->data;
+
+ rem_ns_timeout(na, TO_COLLIDE);
+ /* If they identified or don't exist anymore, don't kill them. */
+ if ((na->status & NS_IDENTIFIED) || !na->u
+ || na->u->my_signon > t->settime)
+ return;
+ /* The RELEASE timeout will always add to the beginning of the
+ * list, so we won't see it. Which is fine because it can't be
+ * triggered yet anyway. */
+ collide(na, 1);
+}
+
+/*************************************************************************/
+
+/* Release a nick on timeout. */
+
+static void timeout_release(Timeout * t)
+{
+ NickAlias *na = t->data;
+
+ rem_ns_timeout(na, TO_RELEASE);
+ release(na, 1);
+}
+
+/*************************************************************************/
+
+/* Add a collide/release timeout. */
+
+static void add_ns_timeout(NickAlias * na, int type, time_t delay)
+{
+ Timeout *to;
+ struct my_timeout *t;
+ void (*timeout_routine) (Timeout *);
+
+ if (type == TO_COLLIDE)
+ timeout_routine = timeout_collide;
+ else if (type == TO_RELEASE)
+ timeout_routine = timeout_release;
+ else {
+ alog("NickServ: unknown timeout type %d! na=0x%p (%s), delay=%ld",
+ type, (void *) na, na->nick, (long int) delay);
+ return;
+ }
+
+ to = add_timeout(delay, timeout_routine, 0);
+ to->data = na;
+
+ t = scalloc(sizeof(struct my_timeout), 1);
+ t->na = na;
+ t->to = to;
+ t->type = type;
+
+ t->prev = NULL;
+ t->next = my_timeouts;
+ my_timeouts = t;
+ /* Andy Church should stop coding while being drunk.
+ * Here's the two lines he forgot that produced the timed_update evil bug
+ * and a *big* memory leak.
+ */
+ if (t->next)
+ t->next->prev = t;
+}
+
+/*************************************************************************/
+
+/* Delete a collide/release timeout. */
+
+void del_ns_timeout(NickAlias * na, int type)
+{
+ struct my_timeout *t, *t2;
+
+ t = my_timeouts;
+ while (t) {
+ if (t->na == na && t->type == type) {
+ t2 = t->next;
+ if (t->next)
+ t->next->prev = t->prev;
+ if (t->prev)
+ t->prev->next = t->next;
+ else
+ my_timeouts = t->next;
+ del_timeout(t->to);
+ free(t);
+ t = t2;
+ } else {
+ t = t->next;
+ }
+ }
+}
+
+/*************************************************************************/
+
+/* Deletes all timeouts belonging to a given nick.
+ * This should only be called before nick deletion.
+ */
+
+void clean_ns_timeouts(NickAlias * na)
+{
+ struct my_timeout *t, *next;
+
+ for (t = my_timeouts; t; t = next) {
+ next = t->next;
+ if (t->na == na) {
+ if (debug)
+ alog("debug: %s deleting timeout type %d from %s",
+ s_NickServ, t->type, t->na->nick);
+ /* If the timeout has the TO_RELEASE type, we should release the user */
+ if (t->type == TO_RELEASE)
+ release(na, 1);
+ if (t->next)
+ t->next->prev = t->prev;
+ if (t->prev)
+ t->prev->next = t->next;
+ else
+ my_timeouts = t->next;
+ del_timeout(t->to);
+ free(t);
+ }
+ }
+}
+
+/*************************************************************************/
+/*********************** NickServ command routines ***********************/
+/*************************************************************************/
+
+
+/* We don't use this function but we keep it for module coders -certus */
+int should_mode_change(int16 status, int16 mode)
+{
+ switch (mode) {
+ case CUS_OP:
+ if (status & CUS_OP) {
+ return 0;
+ }
+ break;
+ case CUS_VOICE:
+ if (status & CUS_OP) {
+ return 0;
+ }
+ if (status & CUS_HALFOP) {
+ return 0;
+ }
+ if (status & CUS_VOICE) {
+ return 0;
+ }
+ return 1;
+ break;
+ case CUS_HALFOP:
+ if (status & CUS_OP) {
+ return 0;
+ }
+ if (status & CUS_HALFOP) {
+ return 0;
+ }
+ return 1;
+ break;
+ case CUS_OWNER:
+ if (ircd->owner) {
+ if (status & CUS_OWNER) {
+ return 0;
+ }
+ }
+ break;
+ case CUS_PROTECT:
+ if (ircd->protect) {
+ if (status & CUS_PROTECT) {
+ return 0;
+ }
+ }
+ break;
+ }
+ return 1;
+}
+
+/*************************************************************************/
+
+int do_setmodes(User * u)
+{
+ struct u_chanlist *uc;
+ Channel *c;
+
+ /* Walk users current channels */
+ for (uc = u->chans; uc; uc = uc->next) {
+ if ((c = uc->chan))
+ chan_set_correct_modes(u, c, 1);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+/*
+ * Nick tracking
+ */
+
+/**
+ * Start Nick tracking and store the nick core display under the user struct.
+ * @param u The user to track nicks for
+ **/
+void nsStartNickTracking(User * u)
+{
+ NickCore *nc;
+
+ /* We only track identified users */
+ if (nick_identified(u)) {
+ nc = u->na->nc;
+
+ /* Release memory if needed */
+ if (u->nickTrack)
+ free(u->nickTrack);
+
+ /* Copy the nick core displayed nick to
+ the user structure for further checks */
+ u->nickTrack = sstrdup(nc->display);
+ }
+}
+
+/**
+ * Stop Nick tracking and remove the nick core display under the user struct.
+ * @param u The user to stop tracking for
+ **/
+void nsStopNickTracking(User * u)
+{
+ /* Simple enough. If its there, release it */
+ if (u->nickTrack) {
+ free(u->nickTrack);
+ u->nickTrack = NULL;
+ }
+}
+
+/**
+ * Boolean function to check if the user requesting a nick has the tracking
+ * signature of that core in its structure.
+ * @param u The user whom to check tracking for
+ **/
+int nsCheckNickTracking(User * u)
+{
+ NickCore *nc;
+ NickAlias *na;
+ char *nick;
+
+ /* No nick alias or nick return false by default */
+ if ((!(na = u->na)) || (!(nick = na->nick))) {
+ return 0;
+ }
+
+ /* nick is forbidden best return 0 */
+ if (na->status & NS_VERBOTEN) {
+ return 0;
+ }
+
+ /* Get the core for the requested nick */
+ nc = na->nc;
+
+ /* If the core and the tracking displayed nick are there,
+ * and they match, return true
+ */
+ if (nc && u->nickTrack && (strcmp(nc->display, u->nickTrack) == 0))
+ return 1;
+ else
+ return 0;
+}
diff --git a/src/operserv.c b/src/operserv.c
new file mode 100644
index 000000000..ded9069eb
--- /dev/null
+++ b/src/operserv.c
@@ -0,0 +1,1774 @@
+/* OperServ functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+
+/* List of Services administrators */
+SList servadmins;
+/* List of Services operators */
+SList servopers;
+/* AKILL, SGLINE, SQLINE and SZLINE lists */
+SList akills, sglines, sqlines, szlines;
+
+/*************************************************************************/
+
+static int compare_adminlist_entries(SList * slist, void *item1,
+ void *item2);
+static int compare_operlist_entries(SList * slist, void *item1,
+ void *item2);
+static void free_adminlist_entry(SList * slist, void *item);
+static void free_operlist_entry(SList * slist, void *item);
+
+static int is_akill_entry_equal(SList * slist, void *item1, void *item2);
+static void free_akill_entry(SList * slist, void *item);
+static int is_sgline_entry_equal(SList * slist, void *item1, void *item2);
+static void free_sgline_entry(SList * slist, void *item);
+static int is_sqline_entry_equal(SList * slist, void *item1, void *item2);
+static void free_sqline_entry(SList * slist, void *item);
+static int is_szline_entry_equal(SList * slist, void *item1, void *item2);
+static void free_szline_entry(SList * slist, void *item);
+
+time_t DefContimer;
+int DefConModesSet = 0;
+char *defconReverseModes(const char *modes);
+
+uint32 DefConModesOn; /* Modes to be enabled during DefCon */
+uint32 DefConModesOff; /* Modes to be disabled during DefCon */
+ChannelInfo DefConModesCI; /* ChannelInfo containg params for locked modes
+ * during DefCon; I would've done this nicer if i
+ * could, but all damn mode functions require a
+ * ChannelInfo struct! --gdex
+ */
+
+
+#ifdef DEBUG_COMMANDS
+static int do_matchwild(User * u);
+#endif
+
+void moduleAddOperServCmds(void);
+/*************************************************************************/
+
+/* Options for the lists */
+SListOpts akopts = { 0, NULL, &is_akill_entry_equal, &free_akill_entry };
+SListOpts saopts = { SLISTF_SORT, &compare_adminlist_entries, NULL,
+ &free_adminlist_entry
+};
+
+SListOpts sgopts = { 0, NULL, &is_sgline_entry_equal, &free_sgline_entry };
+SListOpts soopts =
+ { SLISTF_SORT, &compare_operlist_entries, NULL, &free_operlist_entry };
+SListOpts sqopts =
+ { SLISTF_SORT, NULL, &is_sqline_entry_equal, &free_sqline_entry };
+SListOpts szopts = { 0, NULL, &is_szline_entry_equal, &free_szline_entry };
+
+/*************************************************************************/
+/* *INDENT-OFF* */
+void moduleAddOperServCmds(void) {
+#ifdef DEBUG_COMMANDS
+ Command *c;
+#endif
+
+ modules_core_init(OperServCoreNumber, OperServCoreModules);
+
+#ifdef DEBUG_COMMANDS
+ c = createCommand("LISTTIMERS", send_timeout_list, is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c);
+ c = createCommand("MATCHWILD", do_matchwild, is_services_root, -1,-1,-1,-1,-1); addCoreCommand(OPERSERV,c);
+#endif
+}
+
+/* *INDENT-ON* */
+/*************************************************************************/
+/*************************************************************************/
+
+/* OperServ initialization. */
+
+void os_init(void)
+{
+ moduleAddOperServCmds();
+
+ /* Initialization of the lists */
+ slist_init(&servadmins);
+ servadmins.opts = &saopts;
+ slist_init(&servopers);
+ servopers.opts = &soopts;
+
+ slist_init(&akills);
+ akills.opts = &akopts;
+
+ if (ircd->sgline) {
+ slist_init(&sglines);
+ sglines.opts = &sgopts;
+ }
+ if (ircd->sqline) {
+ slist_init(&sqlines);
+ sqlines.opts = &sqopts;
+ }
+ if (ircd->szline) {
+ slist_init(&szlines);
+ szlines.opts = &szopts;
+ }
+}
+
+/*************************************************************************/
+
+/* Main OperServ routine. */
+
+void operserv(User * u, char *buf)
+{
+ char *cmd;
+ char *s;
+
+ alog("%s: %s: %s", s_OperServ, u->nick, buf);
+
+ cmd = strtok(buf, " ");
+ if (!cmd) {
+ return;
+ } else if (stricmp(cmd, "\1PING") == 0) {
+ if (!(s = strtok(NULL, ""))) {
+ s = "";
+ }
+ anope_cmd_ctcp(s_OperServ, u->nick, "PING %s", s);
+ } else {
+ mod_run_cmd(s_OperServ, u, OPERSERV, cmd);
+ }
+}
+
+/*************************************************************************/
+/**************************** Privilege checks ***************************/
+/*************************************************************************/
+
+/* Load old AKILL data. */
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", AutokillDBName); \
+ break; \
+ } \
+} while (0)
+
+static void load_old_akill(void)
+{
+ dbFILE *f;
+ int i, j;
+ uint16 tmp16;
+ uint32 tmp32;
+ char buf[NICKMAX], mask2[BUFSIZE], *mask, *s;
+ Akill *ak, *entry;
+
+ if (!
+ (f =
+ open_db("AKILL", AutokillDBName ? AutokillDBName : "akill.db",
+ "r", 9)))
+ return;
+
+ get_file_version(f);
+
+ read_int16(&tmp16, f);
+ slist_setcapacity(&akills, tmp16);
+
+ for (j = 0; j < akills.capacity; j++) {
+ ak = scalloc(sizeof(Akill), 1);
+
+ SAFE(read_string(&mask, f));
+ s = strchr(mask, '@');
+ *s = 0;
+ s++;
+ ak->user = sstrdup(mask);
+ ak->host = sstrdup(s);
+ SAFE(read_string(&ak->reason, f));
+ SAFE(read_buffer(buf, f));
+ if (!*buf)
+ ak->by = sstrdup("<unknown>");
+ else
+ ak->by = sstrdup(buf);
+ SAFE(read_int32(&tmp32, f));
+ ak->seton = tmp32 ? tmp32 : time(NULL);
+ SAFE(read_int32(&tmp32, f));
+ ak->expires = tmp32;
+
+ /* Sanity checks *sigh* */
+
+ /* No nicknames allowed! */
+ if (strchr(ak->user, '!')) {
+ anope_cmd_remove_akill(ak->user, ak->host);
+ free(ak);
+ continue;
+ }
+
+ snprintf(mask2, sizeof(mask2), "%s@%s", ak->user, ak->host);
+
+ /* Is the mask already in the AKILL list? */
+ if (slist_indexof(&akills, mask2) != -1) {
+ free(ak);
+ continue;
+ }
+
+ /* Checks whether there is an AKILL that already covers
+ * the one we want to add, and whether there are AKILLs
+ * that would be covered by this one. Expiry time
+ * does *also* matter.
+ */
+
+ if (akills.count > 0) {
+
+ for (i = akills.count - 1; i >= 0; i--) {
+
+ char amask[BUFSIZE];
+
+ entry = akills.list[i];
+
+ if (!entry)
+ continue;
+
+ snprintf(amask, sizeof(amask), "%s@%s", entry->user,
+ entry->host);
+
+ if (match_wild_nocase(amask, mask2)
+ && (entry->expires >= ak->expires
+ || entry->expires == 0)) {
+ anope_cmd_remove_akill(ak->user, ak->host);
+ free(ak);
+ ak = NULL;
+ break;
+ }
+
+ if (match_wild_nocase(mask2, amask)
+ && (entry->expires <= ak->expires || ak->expires == 0))
+ slist_delete(&akills, i);
+ }
+
+ }
+
+ if (ak)
+ slist_add(&akills, ak);
+ }
+
+ close_db(f);
+}
+
+#undef SAFE
+
+/* Load OperServ data. */
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", OperDBName); \
+ failed = 1; \
+ break; \
+ } \
+} while (0)
+
+void load_os_dbase(void)
+{
+ dbFILE *f;
+ int16 i, ver;
+ uint16 tmp16, n;
+ uint32 tmp32;
+ char *s;
+ int failed = 0;
+
+ if (!(f = open_db(s_OperServ, OperDBName, "r", OPER_VERSION)))
+ return;
+
+ ver = get_file_version(f);
+
+ if (ver <= 9) {
+ NickAlias *na;
+
+ SAFE(read_int16(&n, f));
+ for (i = 0; i < n && !failed; i++) {
+ SAFE(read_string(&s, f));
+ if (s) {
+ na = findnick(s);
+ if (na) {
+ na->nc->flags |= NI_SERVICES_ADMIN;
+ if (slist_indexof(&servadmins, na) == -1)
+ slist_add(&servadmins, na);
+ }
+ free(s);
+ }
+ }
+ if (!failed)
+ SAFE(read_int16(&n, f));
+ for (i = 0; i < n && !failed; i++) {
+ SAFE(read_string(&s, f));
+ if (s) {
+ na = findnick(s);
+ if (na) {
+ na->nc->flags |= NI_SERVICES_OPER;
+ if (slist_indexof(&servopers, na) == -1)
+ slist_add(&servopers, na);
+ }
+ free(s);
+ }
+ }
+ }
+
+ if (ver >= 7) {
+ uint32 tmp32;
+ SAFE(read_int32(&maxusercnt, f));
+ SAFE(read_int32(&tmp32, f));
+ maxusertime = tmp32;
+ }
+
+ if (ver <= 10)
+ load_old_akill();
+ else {
+ Akill *ak;
+
+ read_int16(&tmp16, f);
+ slist_setcapacity(&akills, tmp16);
+
+ for (i = 0; i < akills.capacity; i++) {
+ ak = scalloc(sizeof(Akill), 1);
+
+ SAFE(read_string(&ak->user, f));
+ SAFE(read_string(&ak->host, f));
+ SAFE(read_string(&ak->by, f));
+ SAFE(read_string(&ak->reason, f));
+ SAFE(read_int32(&tmp32, f));
+ ak->seton = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ ak->expires = tmp32;
+
+ slist_add(&akills, ak);
+ }
+ }
+
+ if (ver >= 11) {
+ SXLine *sx;
+
+ read_int16(&tmp16, f);
+ slist_setcapacity(&sglines, tmp16);
+
+ for (i = 0; i < sglines.capacity; i++) {
+ sx = scalloc(sizeof(SXLine), 1);
+
+ SAFE(read_string(&sx->mask, f));
+ SAFE(read_string(&sx->by, f));
+ SAFE(read_string(&sx->reason, f));
+ SAFE(read_int32(&tmp32, f));
+ sx->seton = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ sx->expires = tmp32;
+
+ slist_add(&sglines, sx);
+ }
+
+ if (ver >= 13) {
+ read_int16(&tmp16, f);
+ slist_setcapacity(&sqlines, tmp16);
+
+ for (i = 0; i < sqlines.capacity; i++) {
+ sx = scalloc(sizeof(SXLine), 1);
+
+ SAFE(read_string(&sx->mask, f));
+ SAFE(read_string(&sx->by, f));
+ SAFE(read_string(&sx->reason, f));
+ SAFE(read_int32(&tmp32, f));
+ sx->seton = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ sx->expires = tmp32;
+
+ slist_add(&sqlines, sx);
+ }
+ }
+
+ read_int16(&tmp16, f);
+ slist_setcapacity(&szlines, tmp16);
+
+ for (i = 0; i < szlines.capacity; i++) {
+ sx = scalloc(sizeof(SXLine), 1);
+
+ SAFE(read_string(&sx->mask, f));
+ SAFE(read_string(&sx->by, f));
+ SAFE(read_string(&sx->reason, f));
+ SAFE(read_int32(&tmp32, f));
+ sx->seton = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ sx->expires = tmp32;
+
+ slist_add(&szlines, sx);
+ }
+ }
+
+ close_db(f);
+
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+/* Save OperServ data. */
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", OperDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", OperDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_os_dbase(void)
+{
+ int i;
+ dbFILE *f;
+ static time_t lastwarn = 0;
+ Akill *ak;
+ SXLine *sx;
+
+ if (!(f = open_db(s_OperServ, OperDBName, "w", OPER_VERSION)))
+ return;
+ SAFE(write_int32(maxusercnt, f));
+ SAFE(write_int32(maxusertime, f));
+
+ SAFE(write_int16(akills.count, f));
+ for (i = 0; i < akills.count; i++) {
+ ak = akills.list[i];
+
+ SAFE(write_string(ak->user, f));
+ SAFE(write_string(ak->host, f));
+ SAFE(write_string(ak->by, f));
+ SAFE(write_string(ak->reason, f));
+ SAFE(write_int32(ak->seton, f));
+ SAFE(write_int32(ak->expires, f));
+ }
+
+ SAFE(write_int16(sglines.count, f));
+ for (i = 0; i < sglines.count; i++) {
+ sx = sglines.list[i];
+
+ SAFE(write_string(sx->mask, f));
+ SAFE(write_string(sx->by, f));
+ SAFE(write_string(sx->reason, f));
+ SAFE(write_int32(sx->seton, f));
+ SAFE(write_int32(sx->expires, f));
+ }
+
+ SAFE(write_int16(sqlines.count, f));
+ for (i = 0; i < sqlines.count; i++) {
+ sx = sqlines.list[i];
+
+ SAFE(write_string(sx->mask, f));
+ SAFE(write_string(sx->by, f));
+ SAFE(write_string(sx->reason, f));
+ SAFE(write_int32(sx->seton, f));
+ SAFE(write_int32(sx->expires, f));
+ }
+
+ SAFE(write_int16(szlines.count, f));
+ for (i = 0; i < szlines.count; i++) {
+ sx = szlines.list[i];
+
+ SAFE(write_string(sx->mask, f));
+ SAFE(write_string(sx->by, f));
+ SAFE(write_string(sx->reason, f));
+ SAFE(write_int32(sx->seton, f));
+ SAFE(write_int32(sx->expires, f));
+ }
+
+ close_db(f);
+
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+void save_os_rdb_dbase(void)
+{
+#ifdef USE_RDB
+ if (!rdb_open())
+ return;
+
+ if (rdb_tag_table("anope_os_akills") == 0) {
+ alog("Unable to tag table 'anope_os_akills' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_os_sglines") == 0) {
+ alog("Unable to tag table 'anope_os_sglines' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_os_sqlines") == 0) {
+ alog("Unable to tag table 'anope_os_sqlines' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_tag_table("anope_os_szlines") == 0) {
+ alog("Unable to tag table 'anope_os_szlines' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ /* We empty anope_os_core as required */
+ if (rdb_empty_table("anope_os_core") == 0) {
+ alog("Unable to empty table 'anope_os_core' - OperServ RDB save failed");
+ rdb_close();
+ return;
+ }
+
+ if (rdb_save_os_db
+ (maxusercnt, maxusertime, &akills, &sglines, &sqlines,
+ &szlines) == 0) {
+ alog("Unable to save OperServ data - OperServ RDB save failed");
+ rdb_close();
+ return;
+ }
+
+ if (rdb_clean_table("anope_os_akills") == 0) {
+ alog("Unable to clean table 'anope_os_akills' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_os_sglines") == 0) {
+ alog("Unable to clean table 'anope_os_sglines' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_os_sqlines") == 0) {
+ alog("Unable to clean table 'anope_os_sqlines' - OperServ RDB save failed.");
+ rdb_close();
+ return;
+ }
+ if (rdb_clean_table("anope_os_szlines") == 0)
+ alog("Unable to clean table 'anope_os_szlines' - OperServ RDB save failed.");
+
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+
+/* Removes the nick structure from OperServ lists. */
+
+void os_remove_nick(NickCore * nc)
+{
+ slist_remove(&servadmins, nc);
+ slist_remove(&servopers, nc);
+}
+
+/*************************************************************************/
+
+/* Does the given user have Services root privileges?
+ Now enhanced. */
+
+int is_services_root(User * u)
+{
+ if ((NSStrictPrivileges && !is_oper(u))
+ || (!skeleton && !nick_identified(u)))
+ return 0;
+ if (skeleton || (u->na->nc->flags & NI_SERVICES_ROOT))
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Does the given user have Services admin privileges? */
+
+int is_services_admin(User * u)
+{
+ if ((NSStrictPrivileges && !is_oper(u))
+ || (!skeleton && !nick_identified(u)))
+ return 0;
+ if (skeleton
+ || (u->na->nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT)))
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Does the given user have Services oper privileges? */
+
+int is_services_oper(User * u)
+{
+ if ((NSStrictPrivileges && !is_oper(u))
+ || (!skeleton && !nick_identified(u)))
+ return 0;
+ if (skeleton
+ || (u->na->nc->
+ flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN |
+ NI_SERVICES_ROOT)))
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Is the given nick a Services root nick? */
+
+int nick_is_services_root(NickCore * nc)
+{
+ if (nc) {
+ if (nc->flags & (NI_SERVICES_ROOT))
+ return 1;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Is the given nick a Services admin/root nick? */
+
+int nick_is_services_admin(NickCore * nc)
+{
+ if (nc) {
+ if (nc->flags & (NI_SERVICES_ADMIN | NI_SERVICES_ROOT))
+ return 1;
+ }
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Is the given nick a Services oper/admin/root nick? */
+
+int nick_is_services_oper(NickCore * nc)
+{
+ if (nc) {
+ if (nc->
+ flags & (NI_SERVICES_OPER | NI_SERVICES_ADMIN |
+ NI_SERVICES_ROOT))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*************************************************************************/
+/*********************** OperServ command functions **********************/
+/*************************************************************************/
+
+/*************************************************************************/
+
+
+Server *server_global(Server * s, char *msg)
+{
+ Server *sl;
+
+ while (s) {
+ /* Do not send the notice to ourselves our juped servers */
+ if (!(s->flags & (SERVER_ISME | SERVER_JUPED)))
+ notice_server(s_GlobalNoticer, s, "%s", msg);
+
+ if (s->links) {
+ sl = server_global(s->links, msg);
+ if (sl)
+ s = sl;
+ else
+ s = s->next;
+ } else {
+ s = s->next;
+ }
+ }
+ return s;
+
+}
+
+void oper_global(char *nick, char *fmt, ...)
+{
+ va_list args;
+ char msg[2048]; /* largest valid message is 512, this should cover any global */
+ char dmsg[2048]; /* largest valid message is 512, this should cover any global */
+
+ va_start(args, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, args);
+ va_end(args);
+
+ /* I don't like the way this is coded... */
+ if ((nick) && (!AnonymousGlobal)) {
+ snprintf(dmsg, sizeof(dmsg), "[%s] %s", nick, msg);
+ server_global(servlist, dmsg);
+ } else {
+ server_global(servlist, msg);
+ }
+
+}
+
+/**************************************************************************/
+
+
+/************************************************************************/
+/*************************************************************************/
+
+/* Adds an AKILL to the list. Returns >= 0 on success, -1 if it fails, -2
+ * if only the expiry time was changed.
+ * The success result is the number of AKILLs that were deleted to successfully add one.
+ */
+
+int add_akill(User * u, char *mask, const char *by, const time_t expires,
+ const char *reason)
+{
+ int deleted = 0, i;
+ char *user, *mask2, *host;
+ Akill *entry;
+
+ if (!mask) {
+ return -1;
+ }
+
+ /* Checks whether there is an AKILL that already covers
+ * the one we want to add, and whether there are AKILLs
+ * that would be covered by this one. The masks AND the
+ * expiry times are used to determine this, because some
+ * AKILLs may become useful when another one expires.
+ * If so, warn the user in the first case and cleanup
+ * the useless AKILLs in the second.
+ */
+
+ if (akills.count > 0) {
+
+ for (i = akills.count - 1; i >= 0; i--) {
+ char amask[BUFSIZE];
+
+ entry = akills.list[i];
+
+ if (!entry)
+ continue;
+
+ snprintf(amask, sizeof(amask), "%s@%s", entry->user,
+ entry->host);
+
+ if (!stricmp(amask, mask)) {
+ /* We change the AKILL expiry time if its current one is less than the new.
+ * This is preferable to be sure we don't change an important AKILL
+ * accidentely.
+ */
+ if (entry->expires >= expires || entry->expires == 0) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_AKILL_EXISTS,
+ mask);
+ return -1;
+ } else {
+ entry->expires = expires;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_AKILL_CHANGED,
+ amask);
+ return -2;
+ }
+ }
+
+ if (match_wild_nocase(amask, mask)
+ && (entry->expires >= expires || entry->expires == 0)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_AKILL_ALREADY_COVERED,
+ mask, amask);
+ return -1;
+ }
+
+ if (match_wild_nocase(mask, amask)
+ && (entry->expires <= expires || expires == 0)) {
+ slist_delete(&akills, i);
+ deleted++;
+ }
+ }
+
+ }
+
+ /* We can now check whether the list is full or not. */
+ if (slist_full(&akills)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_AKILL_REACHED_LIMIT,
+ akills.limit);
+ return -1;
+ }
+
+ /* We can now (really) add the AKILL. */
+ mask2 = sstrdup(mask);
+ host = strchr(mask2, '@');
+
+ if (!host) {
+ free(mask2);
+ return -1;
+ }
+
+ user = mask2;
+ *host = 0;
+ host++;
+
+ entry = scalloc(sizeof(Akill), 1);
+
+ if (!entry) {
+ free(mask2);
+ return -1;
+ }
+
+ entry->user = sstrdup(user);
+ entry->host = sstrdup(host);
+ entry->by = sstrdup(by);
+ entry->reason = sstrdup(reason);
+ entry->seton = time(NULL);
+ entry->expires = expires;
+
+ slist_add(&akills, entry);
+
+ if (AkillOnAdd)
+ anope_cmd_akill(entry->user, entry->host, entry->by, entry->seton,
+ entry->expires, entry->reason);
+
+ free(mask2);
+
+ return deleted;
+}
+
+/* Does the user match any AKILLs? */
+
+int check_akill(char *nick, const char *username, const char *host,
+ const char *vhost, const char *ip)
+{
+ int i;
+ Akill *ak;
+
+ /**
+ * If DefCon is set to NO new users - kill the user ;).
+ **/
+ if (checkDefCon(DEFCON_NO_NEW_CLIENTS)) {
+ kill_user(s_OperServ, nick, DefConAkillReason);
+ return 1;
+ }
+
+ if (akills.count == 0)
+ return 0;
+
+ for (i = 0; i < akills.count; i++) {
+ ak = akills.list[i];
+ if (!ak)
+ continue;
+ if (match_wild_nocase(ak->user, username)
+ && match_wild_nocase(ak->host, host)) {
+ anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
+ ak->expires, ak->reason);
+ return 1;
+ }
+ if (ircd->vhost) {
+ if (vhost) {
+ if (match_wild_nocase(ak->user, username)
+ && match_wild_nocase(ak->host, vhost)) {
+ anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
+ ak->expires, ak->reason);
+ return 1;
+ }
+ }
+ }
+ if (ircd->nickip) {
+ if (ip) {
+ if (match_wild_nocase(ak->user, username)
+ && match_wild_nocase(ak->host, ip)) {
+ anope_cmd_akill(ak->user, ak->host, ak->by, ak->seton,
+ ak->expires, ak->reason);
+ return 1;
+ }
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+/* Delete any expired autokills. */
+
+void expire_akills(void)
+{
+ int i;
+ time_t now = time(NULL);
+ Akill *ak;
+
+ for (i = akills.count - 1; i >= 0; i--) {
+ ak = akills.list[i];
+
+ if (!ak->expires || ak->expires > now)
+ continue;
+
+ if (WallAkillExpire)
+ anope_cmd_global(s_OperServ, "AKILL on %s@%s has expired",
+ ak->user, ak->host);
+ slist_delete(&akills, i);
+ }
+}
+
+static void free_akill_entry(SList * slist, void *item)
+{
+ Akill *ak = item;
+
+ /* Remove the AKILLs from all the servers */
+ anope_cmd_remove_akill(ak->user, ak->host);
+
+ /* Free the structure */
+ free(ak->user);
+ free(ak->host);
+ free(ak->by);
+ free(ak->reason);
+ free(ak);
+}
+
+/* item1 is not an Akill pointer, but a char
+ */
+
+static int is_akill_entry_equal(SList * slist, void *item1, void *item2)
+{
+ char *ak1 = item1, buf[BUFSIZE];
+ Akill *ak2 = item2;
+
+ if (!ak1 || !ak2)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "%s@%s", ak2->user, ak2->host);
+
+ if (!stricmp(ak1, buf))
+ return 1;
+ else
+ return 0;
+}
+
+
+/*************************************************************************/
+
+/* Adds an SGLINE to the list. Returns >= 0 on success, -1 if it failed, -2 if
+ * only the expiry time changed.
+ * The success result is the number of SGLINEs that were deleted to successfully add one.
+ */
+
+int add_sgline(User * u, char *mask, const char *by, const time_t expires,
+ const char *reason)
+{
+ int deleted = 0, i;
+ SXLine *entry;
+ User *u2, *next;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ /* Checks whether there is an SGLINE that already covers
+ * the one we want to add, and whether there are SGLINEs
+ * that would be covered by this one.
+ * If so, warn the user in the first case and cleanup
+ * the useless SGLINEs in the second.
+ */
+
+ if (!mask) {
+ return -1;
+ }
+
+ if (sglines.count > 0) {
+
+ for (i = sglines.count - 1; i >= 0; i--) {
+ entry = sglines.list[i];
+
+ if (!entry)
+ continue;
+
+ if (!stricmp(entry->mask, mask)) {
+ if (entry->expires >= expires || entry->expires == 0) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SGLINE_EXISTS,
+ mask);
+ return -1;
+ } else {
+ entry->expires = expires;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SGLINE_CHANGED,
+ entry->mask);
+ return -2;
+ }
+ }
+
+ if (match_wild_nocase(entry->mask, mask)
+ && (entry->expires >= expires || entry->expires == 0)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SGLINE_ALREADY_COVERED,
+ mask, entry->mask);
+ return -1;
+ }
+
+ if (match_wild_nocase(mask, entry->mask)
+ && (entry->expires <= expires || expires == 0)) {
+ slist_delete(&sglines, i);
+ deleted++;
+ }
+ }
+
+ }
+
+ /* We can now check whether the list is full or not. */
+ if (slist_full(&sglines)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SGLINE_REACHED_LIMIT,
+ sglines.limit);
+ return -1;
+ }
+
+ /* We can now (really) add the SGLINE. */
+ entry = scalloc(sizeof(SXLine), 1);
+ if (!entry)
+ return -1;
+
+ entry->mask = sstrdup(mask);
+ entry->by = sstrdup(by);
+ entry->reason = sstrdup(reason);
+ entry->seton = time(NULL);
+ entry->expires = expires;
+
+ slist_add(&sglines, entry);
+
+ anope_cmd_sgline(entry->mask, entry->reason);
+
+ if (KillonSGline && !ircd->sglineenforce) {
+ snprintf(buf, (BUFSIZE - 1), "G-Lined: %s", entry->reason);
+ u2 = firstuser();
+ while (u2) {
+ next = nextuser();
+ if (!is_oper(u2)) {
+ if (match_wild_nocase(entry->mask, u2->realname)) {
+ kill_user(ServerName, u2->nick, buf);
+ }
+ }
+ u2 = next;
+ }
+ }
+ return deleted;
+}
+
+/* Does the user match any SGLINEs? */
+
+int check_sgline(char *nick, const char *realname)
+{
+ int i;
+ SXLine *sx;
+
+ if (sglines.count == 0)
+ return 0;
+
+ for (i = 0; i < sglines.count; i++) {
+ sx = sglines.list[i];
+ if (!sx)
+ continue;
+
+ if (match_wild_nocase(sx->mask, realname)) {
+ anope_cmd_sgline(sx->mask, sx->reason);
+ /* We kill nick since s_sgline can't */
+ anope_cmd_svskill(ServerName, nick, "G-Lined: %s", sx->reason);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Delete any expired SGLINEs. */
+
+void expire_sglines(void)
+{
+ int i;
+ time_t now = time(NULL);
+ SXLine *sx;
+
+ for (i = sglines.count - 1; i >= 0; i--) {
+ sx = sglines.list[i];
+
+ if (!sx->expires || sx->expires > now)
+ continue;
+
+ if (WallSGLineExpire)
+ anope_cmd_global(s_OperServ, "SGLINE on \2%s\2 has expired",
+ sx->mask);
+ slist_delete(&sglines, i);
+ }
+}
+
+static void free_sgline_entry(SList * slist, void *item)
+{
+ SXLine *sx = item;
+
+ /* Remove the SGLINE from all the servers */
+ anope_cmd_unsgline(sx->mask);
+
+ /* Free the structure */
+ free(sx->mask);
+ free(sx->by);
+ free(sx->reason);
+ free(sx);
+}
+
+/* item1 is not an SXLine pointer, but a char */
+
+static int is_sgline_entry_equal(SList * slist, void *item1, void *item2)
+{
+ char *sx1 = item1;
+ SXLine *sx2 = item2;
+
+ if (!sx1 || !sx2)
+ return 0;
+
+ if (!stricmp(sx1, sx2->mask))
+ return 1;
+ else
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Adds an SQLINE to the list. Returns >= 0 on success, -1 if it failed, -2 if
+ * only the expiry time changed.
+ * The success result is the number of SQLINEs that were deleted to successfully add one.
+ */
+
+int add_sqline(User * u, char *mask, const char *by, const time_t expires,
+ const char *reason)
+{
+ int deleted = 0, i;
+ User *u2, *next;
+ SXLine *entry;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ /* Checks whether there is an SQLINE that already covers
+ * the one we want to add, and whether there are SQLINEs
+ * that would be covered by this one.
+ * If so, warn the user in the first case and cleanup
+ * the useless SQLINEs in the second.
+ */
+
+ if (!mask) {
+ return -1;
+ }
+
+ if (sqlines.count > 0) {
+
+ for (i = sqlines.count - 1; i >= 0; i--) {
+ entry = sqlines.list[i];
+
+ if (!entry)
+ continue;
+
+ if ((*mask == '#' && *entry->mask != '#') ||
+ (*mask != '#' && *entry->mask == '#'))
+ continue;
+
+ if (!stricmp(entry->mask, mask)) {
+ if (entry->expires >= expires || entry->expires == 0) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SQLINE_EXISTS,
+ mask);
+ return -1;
+ } else {
+ entry->expires = expires;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SQLINE_CHANGED,
+ entry->mask);
+ return -2;
+ }
+ }
+
+ if (match_wild_nocase(entry->mask, mask)
+ && (entry->expires >= expires || entry->expires == 0)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SQLINE_ALREADY_COVERED,
+ mask, entry->mask);
+ return -1;
+ }
+
+ if (match_wild_nocase(mask, entry->mask)
+ && (entry->expires <= expires || expires == 0)) {
+ slist_delete(&sqlines, i);
+ deleted++;
+ }
+ }
+
+ }
+
+ /* We can now check whether the list is full or not. */
+ if (slist_full(&sqlines)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SQLINE_REACHED_LIMIT,
+ sqlines.limit);
+ return -1;
+ }
+
+ /* We can now (really) add the SQLINE. */
+ entry = scalloc(sizeof(SXLine), 1);
+ if (!entry)
+ return -1;
+
+ entry->mask = sstrdup(mask);
+ entry->by = sstrdup(by);
+ entry->reason = sstrdup(reason);
+ entry->seton = time(NULL);
+ entry->expires = expires;
+
+ slist_add(&sqlines, entry);
+
+ sqline(entry->mask, entry->reason);
+
+ if (KillonSQline) {
+ snprintf(buf, (BUFSIZE - 1), "Q-Lined: %s", entry->reason);
+ u2 = firstuser();
+ while (u2) {
+ next = nextuser();
+ if (!is_oper(u2)) {
+ if (match_wild_nocase(entry->mask, u2->nick)) {
+ kill_user(ServerName, u2->nick, buf);
+ }
+ }
+ u2 = next;
+ }
+ }
+
+ return deleted;
+}
+
+/* Does the user match any SQLINEs? */
+
+int check_sqline(char *nick, int nick_change)
+{
+ int i;
+ SXLine *sx;
+ char reason[300];
+
+ if (sqlines.count == 0)
+ return 0;
+
+ for (i = 0; i < sqlines.count; i++) {
+ sx = sqlines.list[i];
+ if (!sx)
+ continue;
+
+ if (ircd->chansqline) {
+ if (*sx->mask == '#')
+ continue;
+ }
+
+ if (match_wild_nocase(sx->mask, nick)) {
+ sqline(sx->mask, sx->reason);
+ /* We kill nick since s_sqline can't */
+ snprintf(reason, sizeof(reason), "Q-Lined: %s", sx->reason);
+ kill_user(s_OperServ, nick, reason);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int check_chan_sqline(const char *chan)
+{
+ int i;
+ SXLine *sx;
+
+ if (sqlines.count == 0)
+ return 0;
+
+ for (i = 0; i < sqlines.count; i++) {
+ sx = sqlines.list[i];
+ if (!sx)
+ continue;
+
+ if (*sx->mask != '#')
+ continue;
+
+ if (match_wild_nocase(sx->mask, chan)) {
+ sqline(sx->mask, sx->reason);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Delete any expired SQLINEs. */
+
+void expire_sqlines(void)
+{
+ int i;
+ time_t now = time(NULL);
+ SXLine *sx;
+
+ for (i = sqlines.count - 1; i >= 0; i--) {
+ sx = sqlines.list[i];
+
+ if (!sx->expires || sx->expires > now)
+ continue;
+
+ if (WallSQLineExpire)
+ anope_cmd_global(s_OperServ, "SQLINE on \2%s\2 has expired",
+ sx->mask);
+
+ slist_delete(&sqlines, i);
+ }
+}
+
+static void free_sqline_entry(SList * slist, void *item)
+{
+ SXLine *sx = item;
+
+ /* Remove the SQLINE from all the servers */
+ anope_cmd_unsqline(sx->mask);
+
+ /* Free the structure */
+ free(sx->mask);
+ free(sx->by);
+ free(sx->reason);
+ free(sx);
+}
+
+/* item1 is not an SXLine pointer, but a char */
+
+static int is_sqline_entry_equal(SList * slist, void *item1, void *item2)
+{
+ char *sx1 = item1;
+ SXLine *sx2 = item2;
+
+ if (!sx1 || !sx2)
+ return 0;
+
+ if (!stricmp(sx1, sx2->mask))
+ return 1;
+ else
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Adds an SZLINE to the list. Returns >= 0 on success, -1 on error, -2 if
+ * only the expiry time changed.
+ * The success result is the number of SZLINEs that were deleted to successfully add one.
+ */
+
+int add_szline(User * u, char *mask, const char *by, const time_t expires,
+ const char *reason)
+{
+ int deleted = 0, i;
+ SXLine *entry;
+
+ if (!mask) {
+ return -1;
+ }
+
+ /* Checks whether there is an SZLINE that already covers
+ * the one we want to add, and whether there are SZLINEs
+ * that would be covered by this one.
+ * If so, warn the user in the first case and cleanup
+ * the useless SZLINEs in the second.
+ */
+
+ if (szlines.count > 0) {
+
+ for (i = szlines.count - 1; i >= 0; i--) {
+ entry = szlines.list[i];
+
+ if (!entry)
+ continue;
+
+ if (!stricmp(entry->mask, mask)) {
+ if (entry->expires >= expires || entry->expires == 0) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SZLINE_EXISTS,
+ mask);
+ return -1;
+ } else {
+ entry->expires = expires;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SZLINE_EXISTS,
+ mask);
+ return -2;
+ }
+ }
+
+ if (match_wild_nocase(entry->mask, mask)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SZLINE_ALREADY_COVERED,
+ mask, entry->mask);
+ return -1;
+ }
+
+ if (match_wild_nocase(mask, entry->mask)) {
+ slist_delete(&szlines, i);
+ deleted++;
+ }
+ }
+
+ }
+
+ /* We can now check whether the list is full or not. */
+ if (slist_full(&szlines)) {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_SZLINE_REACHED_LIMIT,
+ szlines.limit);
+ return -1;
+ }
+
+ /* We can now (really) add the SZLINE. */
+ entry = scalloc(sizeof(SXLine), 1);
+ if (!entry)
+ return -1;
+
+ entry->mask = sstrdup(mask);
+ entry->by = sstrdup(by);
+ entry->reason = sstrdup(reason);
+ entry->seton = time(NULL);
+ entry->expires = expires;
+
+ slist_add(&szlines, entry);
+ anope_cmd_szline(entry->mask, entry->reason, entry->by);
+
+ return deleted;
+}
+
+/* Check and enforce any Zlines that we have */
+int check_szline(char *nick, char *ip)
+{
+ int i;
+ SXLine *sx;
+
+ if (szlines.count == 0) {
+ return 0;
+ }
+
+ if (!ip) {
+ return 0;
+ }
+
+ for (i = 0; i < szlines.count; i++) {
+ sx = szlines.list[i];
+ if (!sx) {
+ continue;
+ }
+
+ if (match_wild_nocase(sx->mask, ip)) {
+ anope_cmd_szline(sx->mask, sx->reason, sx->by);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Delete any expired SZLINEs. */
+
+void expire_szlines(void)
+{
+ int i;
+ time_t now = time(NULL);
+ SXLine *sx;
+
+ for (i = szlines.count - 1; i >= 0; i--) {
+ sx = szlines.list[i];
+
+ if (!sx->expires || sx->expires > now)
+ continue;
+
+ if (WallSZLineExpire)
+ anope_cmd_global(s_OperServ, "SZLINE on \2%s\2 has expired",
+ sx->mask);
+ slist_delete(&szlines, i);
+ }
+}
+
+static void free_szline_entry(SList * slist, void *item)
+{
+ SXLine *sx = item;
+
+ /* Remove the SZLINE from all the servers */
+ anope_cmd_unszline(sx->mask);
+
+ /* Free the structure */
+ free(sx->mask);
+ free(sx->by);
+ free(sx->reason);
+ free(sx);
+}
+
+/* item1 is not an SXLine pointer, but a char
+ */
+
+static int is_szline_entry_equal(SList * slist, void *item1, void *item2)
+{
+ char *sx1 = item1;
+ SXLine *sx2 = item2;
+
+ if (!sx1 || !sx2)
+ return 0;
+
+ if (!stricmp(sx1, sx2->mask))
+ return 1;
+ else
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Callback function used to sort the admin list */
+
+static int compare_adminlist_entries(SList * slist, void *item1,
+ void *item2)
+{
+ NickCore *nc1 = item1, *nc2 = item2;
+ if (!nc1 || !nc2)
+ return -1; /* To tell to continue */
+ return stricmp(nc1->display, nc2->display);
+}
+
+/* Callback function used when an admin list entry is deleted */
+
+static void free_adminlist_entry(SList * slist, void *item)
+{
+ NickCore *nc = item;
+ nc->flags &= ~NI_SERVICES_ADMIN;
+}
+
+/*************************************************************************/
+
+/* Callback function used to sort the oper list */
+
+static int compare_operlist_entries(SList * slist, void *item1,
+ void *item2)
+{
+ NickCore *nc1 = item1, *nc2 = item2;
+ if (!nc1 || !nc2)
+ return -1; /* To tell to continue */
+ return stricmp(nc1->display, nc2->display);
+}
+
+/* Callback function used when an oper list entry is deleted */
+
+static void free_operlist_entry(SList * slist, void *item)
+{
+ NickCore *nc = item;
+ nc->flags &= ~NI_SERVICES_OPER;
+}
+
+/*************************************************************************/
+
+#ifdef DEBUG_COMMANDS
+
+static int do_matchwild(User * u)
+{
+ char *pat = strtok(NULL, " ");
+ char *str = strtok(NULL, " ");
+ if (pat && str)
+ notice_user(s_OperServ, u, "%d", match_wild(pat, str));
+ else
+ notice_user(s_OperServ, u, "Syntax error.");
+ return MOD_CONT;
+}
+
+#endif /* DEBUG_COMMANDS */
+
+/*************************************************************************/
+/**
+ * Returns 1 if the passed level is part of the CURRENT defcon, else 0 is returned
+ **/
+int checkDefCon(int level)
+{
+ return DefCon[DefConLevel] & level;
+}
+
+/**
+ * Automaticaly re-set the DefCon level if the time limit has expired.
+ **/
+void resetDefCon(int level)
+{
+ char strLevel[5];
+ snprintf(strLevel, 4, "%d", level);
+ if (DefConLevel != level) {
+ if ((DefContimer)
+ && (time(NULL) - DefContimer >= dotime(DefConTimeOut))) {
+ DefConLevel = level;
+ send_event(EVENT_DEFCON_LEVEL, 1, strLevel);
+ alog("Defcon level timeout, returning to lvl %d", level);
+ anope_cmd_global(s_OperServ,
+ getstring2(NULL, OPER_DEFCON_WALL),
+ s_OperServ, level);
+ if (GlobalOnDefcon) {
+ if (DefConOffMessage) {
+ oper_global(NULL, "%s", DefConOffMessage);
+ } else {
+ oper_global(NULL, getstring(NULL, DEFCON_GLOBAL),
+ DefConLevel);
+ }
+ }
+ if (GlobalOnDefconMore && !DefConOffMessage) {
+ oper_global(NULL, "%s", DefconMessage);
+ }
+ runDefCon();
+ }
+ }
+}
+
+/**
+ * Run DefCon level specific Functions.
+ **/
+void runDefCon(void)
+{
+ char *newmodes;
+ if (checkDefCon(DEFCON_FORCE_CHAN_MODES)) {
+ if (DefConChanModes && !DefConModesSet) {
+ if (DefConChanModes[0] == '+' || DefConChanModes[0] == '-') {
+ alog("DEFCON: setting %s on all chan's", DefConChanModes);
+ do_mass_mode(DefConChanModes);
+ DefConModesSet = 1;
+ }
+ }
+ } else {
+ if (DefConChanModes && (DefConModesSet != 0)) {
+ if (DefConChanModes[0] == '+' || DefConChanModes[0] == '-') {
+ DefConModesSet = 0;
+ if ((newmodes = defconReverseModes(DefConChanModes))) {
+ alog("DEFCON: setting %s on all chan's", newmodes);
+ do_mass_mode(newmodes);
+ free(newmodes);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Reverse the mode string, used for remove DEFCON chan modes.
+ **/
+char *defconReverseModes(const char *modes)
+{
+ char *newmodes = NULL;
+ int i = 0;
+ if (!modes) {
+ return NULL;
+ }
+ if (!(newmodes = malloc(sizeof(char) * strlen(modes) + 1))) {
+ return NULL;
+ }
+ for (i = 0; i < strlen(modes); i++) {
+ if (modes[i] == '+')
+ newmodes[i] = '-';
+ else if (modes[i] == '-')
+ newmodes[i] = '+';
+ else
+ newmodes[i] = modes[i];
+ }
+ newmodes[i] = '\0';
+ return newmodes;
+}
+
+/* Parse the defcon mlock mode string and set the correct global vars.
+ *
+ * @param str mode string to parse
+ * @return 1 if accepted, 0 if failed
+ */
+int defconParseModeString(const char *str)
+{
+ int add = -1; /* 1 if adding, 0 if deleting, -1 if neither */
+ unsigned char mode;
+ CBMode *cbm;
+ char *str_copy = sstrdup(str); /* We need this copy as str is const -GD */
+ char *param; /* Store parameters during mode parsing */
+
+ /* Reinitialize everything */
+ DefConModesOn = 0;
+ DefConModesOff = 0;
+ DefConModesCI.mlock_limit = 0;
+ DefConModesCI.mlock_key = NULL;
+ DefConModesCI.mlock_flood = NULL;
+ DefConModesCI.mlock_redirect = NULL;
+
+ /* Initialize strtok() internal buffer */
+ strtok(str_copy, " ");
+
+ /* Loop while there are modes to set */
+ while ((mode = *str++) && (mode != ' ')) {
+ switch (mode) {
+ case '+':
+ add = 1;
+ continue;
+ case '-':
+ add = 0;
+ continue;
+ default:
+ if (add < 0)
+ continue;
+ }
+
+ if ((int) mode < 128 && (cbm = &cbmodes[(int) mode])->flag != 0) {
+ if (cbm->flags & CBM_NO_MLOCK) {
+ alog("DefConChanModes mode character '%c' cannot be locked", mode);
+ free(str_copy);
+ return 0;
+ } else if (add) {
+ DefConModesOn |= cbm->flag;
+ DefConModesOff &= ~cbm->flag;
+ if (cbm->cssetvalue) {
+ if (!(param = strtok(NULL, " "))) {
+ alog("DefConChanModes mode character '%c' has no parameter while one is expected", mode);
+ free(str_copy);
+ return 0;
+ }
+ cbm->cssetvalue(&DefConModesCI, param);
+ }
+ } else {
+ DefConModesOff |= cbm->flag;
+ if (DefConModesOn & cbm->flag) {
+ DefConModesOn &= ~cbm->flag;
+ if (cbm->cssetvalue) {
+ cbm->cssetvalue(&DefConModesCI, NULL);
+ }
+ }
+ }
+ } else {
+ alog("DefConChanModes unknown mode character '%c'", mode);
+ free(str_copy);
+ return 0;
+ }
+ } /* while (*param) */
+
+ free(str_copy);
+
+ if (ircd->Lmode) {
+ /* We can't mlock +L if +l is not mlocked as well. */
+ if ((DefConModesOn & ircd->chan_lmode)
+ && !(DefConModesOn & anope_get_limit_mode())) {
+ DefConModesOn &= ~ircd->chan_lmode;
+ free(DefConModesCI.mlock_redirect);
+ DefConModesCI.mlock_redirect = NULL;
+ alog("DefConChanModes must lock mode +l as well to lock mode +L");
+ return 0;
+ }
+ }
+
+ /* Some ircd we can't set NOKNOCK without INVITE */
+ /* So check if we need there is a NOKNOCK MODE and that we need INVITEONLY */
+ if (ircd->noknock && ircd->knock_needs_i) {
+ if ((DefConModesOn & ircd->noknock)
+ && !(DefConModesOn & anope_get_invite_mode())) {
+ DefConModesOn &= ~ircd->noknock;
+ alog("DefConChanModes must lock mode +i as well to lock mode +K");
+ return 0;
+ }
+ }
+
+ /* Everything is set fine, return 1 */
+ return 1;
+}
+
+/*************************************************************************/
diff --git a/src/process.c b/src/process.c
new file mode 100644
index 000000000..9f94f4ff8
--- /dev/null
+++ b/src/process.c
@@ -0,0 +1,417 @@
+/* Main processing code for Services.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "messages.h"
+#include "modules.h"
+
+/*************************************************************************/
+
+/* Use ignore code? */
+int allow_ignore = 1;
+
+/* Masks to ignore. */
+IgnoreData *ignore;
+
+/*************************************************************************/
+
+/**
+ * Add a mask/nick to the ignorelits for delta seconds.
+ * @param nick Nick or (nick!)user@host to add to the ignorelist.
+ * @param delta Seconds untill new entry is set to expire. 0 for permanent.
+ */
+void add_ignore(const char *nick, time_t delta)
+{
+ IgnoreData *ign;
+ char tmp[BUFSIZE];
+ char *mask, *user, *host;
+ User *u;
+ time_t now;
+ if (!nick)
+ return;
+ now = time(NULL);
+
+ /* If it s an existing user, we ignore the hostmask. */
+ if ((u = finduser(nick))) {
+ snprintf(tmp, sizeof(tmp), "*!*@%s", u->host);
+ mask = sstrdup(tmp);
+
+ /* Determine whether we get a nick or a mask. */
+ } else if ((host = strchr(nick, '@'))) {
+ /* Check whether we have a nick too.. */
+ if ((user = strchr(nick, '!'))) {
+ /* this should never happen */
+ if (user > host)
+ return;
+ mask = sstrdup(nick);
+ } else {
+ /* We have user@host. Add nick wildcard. */
+ snprintf(tmp, sizeof(tmp), "*!%s", nick);
+ mask = sstrdup(tmp);
+ }
+
+ /* We only got a nick.. */
+ } else {
+ snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
+ mask = sstrdup(tmp);
+ }
+
+ /* Check if we already got an identical entry. */
+ for (ign = ignore; ign; ign = ign->next)
+ if (stricmp(ign->mask, mask) == 0)
+ break;
+
+ /* Found one.. */
+ if (ign) {
+ if (delta == 0)
+ ign->time = 0;
+ else if (ign->time < now + delta)
+ ign->time = now + delta;
+
+ /* Create new entry.. */
+ } else {
+ ign = scalloc(sizeof(*ign), 1);
+ ign->mask = mask;
+ ign->time = (delta == 0 ? 0 : now + delta);
+ ign->prev = NULL;
+ ign->next = ignore;
+ if (ignore)
+ ignore->prev = ign;
+ ignore = ign;
+ if (debug)
+ alog("debug: Added new ignore entry for %s", mask);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Retrieve an ignorance record for a nick or mask.
+ * If the nick isn't being ignored, we return NULL and if necesary
+ * flush the record from the ignore list (i.e. ignore timed out).
+ * @param nick Nick or (nick!)user@host to look for on the ignorelist.
+ * @return Pointer to the ignore record, NULL if none was found.
+ */
+IgnoreData *get_ignore(const char *nick)
+{
+ IgnoreData *ign;
+ char tmp[BUFSIZE];
+ char *user, *host;
+ time_t now;
+ User *u;
+ if (!nick)
+ return NULL;
+
+ /* User has disabled the IGNORE system */
+ if (!allow_ignore)
+ return NULL;
+ now = time(NULL);
+ u = finduser(nick);
+
+ /* If we find a real user, match his mask against the ignorelist. */
+ if (u) {
+ /* Opers are not ignored, even if a matching entry may be present. */
+ if (is_oper(u))
+ return NULL;
+ for (ign = ignore; ign; ign = ign->next)
+ if (match_usermask(ign->mask, u))
+ break;
+ } else {
+ /* We didn't get a user.. generate a valid mask. */
+ if ((host = strchr(nick, '@'))) {
+ if ((user = strchr(nick, '!'))) {
+ /* this should never happen */
+ if (user > host)
+ return NULL;
+ snprintf(tmp, sizeof(tmp), "%s", nick);
+ } else {
+ /* We have user@host. Add nick wildcard. */
+ snprintf(tmp, sizeof(tmp), "*!%s", nick);
+ }
+
+ /* We only got a nick.. */
+ } else
+ snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
+ for (ign = ignore; ign; ign = ign->next)
+ if (match_wild_nocase(ign->mask, tmp))
+ break;
+ }
+
+ /* Check whether the entry has timed out */
+ if (ign && ign->time != 0 && ign->time <= now) {
+ if (debug)
+ alog("debug: Expiring ignore entry %s", ign->mask);
+ if (ign->prev)
+ ign->prev->next = ign->next;
+ else if (ignore == ign)
+ ignore = ign->next;
+ if (ign->next)
+ ign->next->prev = ign->prev;
+ free(ign->mask);
+ free(ign);
+ ign = NULL;
+ }
+ if (ign && debug)
+ alog("debug: Found ignore entry (%s) for %s", ign->mask, nick);
+ return ign;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Deletes a given nick/mask from the ignorelist.
+ * @param nick Nick or (nick!)user@host to delete from the ignorelist.
+ * @return Returns 1 on success, 0 if no entry is found.
+ */
+int delete_ignore(const char *nick)
+{
+ IgnoreData *ign;
+ char tmp[BUFSIZE];
+ char *user, *host;
+ User *u;
+ if (!nick)
+ return 0;
+
+ /* If it s an existing user, we ignore the hostmask. */
+ if ((u = finduser(nick))) {
+ snprintf(tmp, sizeof(tmp), "*!*@%s", u->host);
+
+ /* Determine whether we get a nick or a mask. */
+ } else if ((host = strchr(nick, '@'))) {
+ /* Check whether we have a nick too.. */
+ if ((user = strchr(nick, '!'))) {
+ /* this should never happen */
+ if (user > host)
+ return 0;
+ snprintf(tmp, sizeof(tmp), "%s", nick);
+ } else {
+ /* We have user@host. Add nick wildcard. */
+ snprintf(tmp, sizeof(tmp), "*!%s", nick);
+ }
+
+ /* We only got a nick.. */
+ } else
+ snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
+
+ for (ign = ignore; ign; ign = ign->next)
+ if (stricmp(ign->mask, tmp) == 0)
+ break;
+
+ /* No matching ignore found. */
+ if (!ign)
+ return 0;
+ if (debug)
+ alog("Deleting ignore entry %s", ign->mask);
+
+ /* Delete the entry and all references to it. */
+ if (ign->prev)
+ ign->prev->next = ign->next;
+ else if (ignore == ign)
+ ignore = ign->next;
+ if (ign->next)
+ ign->next->prev = ign->prev;
+ free(ign->mask);
+ free(ign);
+ ign = NULL;
+ return 1;
+ }
+
+
+/*************************************************************************/
+
+/**
+ * Clear the ignorelist.
+ * @return The number of entries deleted.
+ */
+int clear_ignores()
+{
+ IgnoreData *ign, *next;
+ int i = 0;
+ if (!ignore)
+ return 0;
+ for (ign = ignore; ign; ign = next) {
+ next = ign->next;
+ if (debug)
+ alog("Deleting ignore entry %s", ign->mask);
+ free(ign->mask);
+ free(ign);
+ i++;
+ }
+ ignore = NULL;
+ return i;
+ }
+
+
+/*************************************************************************/
+/* split_buf: Split a buffer into arguments and store the arguments in an
+ * argument vector pointed to by argv (which will be malloc'd
+ * as necessary); return the argument count. If colon_special
+ * is non-zero, then treat a parameter with a leading ':' as
+ * the last parameter of the line, per the IRC RFC. Destroys
+ * the buffer by side effect.
+ */
+int split_buf(char *buf, char ***argv, int colon_special)
+{
+ int argvsize = 8;
+ int argc;
+ char *s;
+
+ *argv = scalloc(sizeof(char *) * argvsize, 1);
+ argc = 0;
+ while (*buf) {
+ if (argc == argvsize) {
+ argvsize += 8;
+ *argv = srealloc(*argv, sizeof(char *) * argvsize);
+ }
+ if (*buf == ':') {
+ (*argv)[argc++] = buf + 1;
+ buf = "";
+ } else {
+ s = strpbrk(buf, " ");
+ if (s) {
+ *s++ = 0;
+ while (*s == ' ')
+ s++;
+ } else {
+ s = buf + strlen(buf);
+ }
+ (*argv)[argc++] = buf;
+ buf = s;
+ }
+ }
+ return argc;
+}
+
+/*************************************************************************/
+
+/* process: Main processing routine. Takes the string in inbuf (global
+ * variable) and does something appropriate with it. */
+
+void process()
+{
+ int retVal = 0;
+ Message *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;
+ Message *m;
+
+ /* zero out the buffers before we do much else */
+ *buf = '\0';
+ *source = '\0';
+ *cmd = '\0';
+
+ /* If debugging, log the buffer */
+ if (debug) {
+ alog("debug: Received: %s", inbuf);
+ }
+
+ /* First make a copy of the buffer so we have the original in case we
+ * crash - in that case, we want to know what we crashed on. */
+ strscpy(buf, inbuf, 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);
+ if (protocoldebug) {
+ protocol_debug(source, cmd, ac, av);
+ }
+ if (mod_current_buffer) {
+ free(mod_current_buffer);
+ }
+ /* fix to moduleGetLastBuffer() bug 296 */
+ /* old logic was that since its meant for PRIVMSG that we would get
+ the NICK as AV[0] and the rest would be in av[1], however on Bahamut
+ based systems when you do /cs it assumes we will translate the command
+ to the NICK and thus AV[0] is the message. The new logic is to check
+ 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 */
+ /* First check if the ircd proto module overrides this -GD */
+ /* fix to moduleGetLastBuffer() bug 476:
+ fixed in part by adding {} to nickIsServices()
+ however if you have a pseudo they could not use moduleGetLastBuffer()
+ cause they are not part of nickIsServices, even those the ac count is 2
+ that was ignored and only the first param was passed on which is fine for
+ Bahmut ircd aliases but not for pseudo clients on. So additional logic is
+ that if the ac is greater then 1 copy av[1] else copy av[0]
+ I also changed from if statments, cause attempting to access a array member
+ that is not set can lead to odd things - TSL (3/12/06) */
+ if (!anope_set_mod_current_buffer(ac, av)) {
+ if (ac >= 1) {
+ if (nickIsServices(av[0], 1)) {
+ mod_current_buffer =
+ (ac > 1 ? sstrdup(av[1]) : sstrdup(av[0]));
+ } else {
+ mod_current_buffer =
+ (ac > 1 ? sstrdup(av[1]) : sstrdup(av[0]));
+ }
+ } else {
+ mod_current_buffer = NULL;
+ }
+ }
+ /* Do something with the message. */
+ m = find_message(cmd);
+ if (m) {
+ if (m->func) {
+ mod_current_module_name = m->mod_name;
+ retVal = m->func(source, ac, av);
+ mod_current_module_name = NULL;
+ if (retVal == MOD_CONT) {
+ current = m->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;
+ }
+ }
+ }
+ } else {
+ if (debug)
+ alog("debug: unknown message from server (%s)", inbuf);
+ }
+
+ /* Load/unload modules if needed */
+ handleModuleOperationQueue();
+
+ /* Free argument list we created */
+ free(av);
+}
+
+/*************************************************************************/
diff --git a/src/protocol/Makefile b/src/protocol/Makefile
new file mode 100644
index 000000000..ab837e459
--- /dev/null
+++ b/src/protocol/Makefile
@@ -0,0 +1,45 @@
+include ./Makefile.inc
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: modules subs
+
+modules: $(OBJECTS) $(SO_FILES)
+
+install:
+ $(CP) ./*.so $(MODULE_PATH)
+
+distclean: clean spotless
+
+.c.o:
+ $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../${INCLUDEDIR} -c $<
+
+.o.s:
+ $(CC) ${SHARED} ../mod_version.o $< -o $*.so ${PROFILE}
+ @$(TOUCH) $*.s
+
+subs:
+ @for i in $(SUBS); do \
+ echo "make all in $$i..."; \
+ (cd $$i; $(MAKE) $(MAKEARGS) all); done
+
+subs_clean:
+ @for i in $(SUBS); do \
+ echo "cleaning in $$i..."; \
+ (cd $$i; $(MAKE) clean); done
+
+clean: subs_clean
+ rm -f *.o *.s *.so *.c~ core
+
+spotless: subs_clean
+ rm -f *.o *.s *.so *.c~ core *.so Makefile.inc
+
diff --git a/src/protocol/Makefile.sub b/src/protocol/Makefile.sub
new file mode 100644
index 000000000..a2d6a414a
--- /dev/null
+++ b/src/protocol/Makefile.sub
@@ -0,0 +1,29 @@
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}' 'MODULE_PATH=${MODULE_PATH}' \
+ 'PROFILE=${PROFILE}' 'SHARED=${SHARED}' 'MODULEFLAGS=${MODULEFLAGS}'
+
+OBJECTS= $(SRCS:.c=.o)
+SO_FILES=$(OBJECTS:.o=.s)
+CDEFS= -rdynamic -Wall
+
+all: module
+
+module: $(OBJECTS) so
+
+distclean: spotless
+
+.c.o:
+ $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../ -I../../${INCLUDEDIR} -c $<
+
+so:
+ $(CC) ${SHARED} $(OBJECTS) -o ../$(TARGET).so ${PROFILE}
+
+clean:
+ rm -f *.o *.so *.c~ core
+
+spotless: clean
+ rm -f *~ *.o *.so *.c~ core
+
diff --git a/src/protocol/Makefile.win32 b/src/protocol/Makefile.win32
new file mode 100644
index 000000000..32e3ae1d5
--- /dev/null
+++ b/src/protocol/Makefile.win32
@@ -0,0 +1,26 @@
+include ../../Makefile.inc.win32
+
+SRCS=bahamut.c charybdis.c dreamforge.c hybrid.c inspircd10.c inspircd11.c plexus2.c plexus3.c ptlink.c rageircd.c \
+ ratbox.c shadowircd.c solidircd.c ultimate2.c ultimate3.c unreal31.c unreal32.c viagra.c
+
+OBJECTS= $(SRCS:.c=.dll)
+CFLAGS=/LD /MD /D MODULE_COMPILE $(CFLAGS) /I"../../include"
+LFLAGS=/link ../anope.lib wsock32.lib $(LIBS) $(LFLAGS) $(MYSQL_LIB_PATH) /export:AnopeInit /VERSION:$(VERSION)
+
+all: $(OBJECTS)
+
+distclean: clean spotless
+
+.c.dll:
+ $(CC) $(CFLAGS) $< ..\mod_version.c $(LFLAGS)
+
+clean:
+ -@del *.obj
+
+spotless: clean
+ -@del *.dll *.lib *.exp *.manifest
+
+install:
+ -@mkdir ..\..\$(DATDEST)\modules
+ -@mkdir ..\..\$(DATDEST)\modules\runtime
+ -@copy *.dll ..\..\$(DATDEST)\modules
diff --git a/src/protocol/bahamut.c b/src/protocol/bahamut.c
new file mode 100644
index 000000000..e00fa2a45
--- /dev/null
+++ b/src/protocol/bahamut.c
@@ -0,0 +1,1680 @@
+/* Bahamut functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "bahamut.h"
+
+IRCDVar myIrcd[] = {
+ {"BahamutIRCd 1.4.*/1.8.*", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ "+", /* hostserv mode */
+ "+io", /* operserv mode */
+ "+o", /* botserv mode */
+ "+h", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-cilmnpstOR", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 0, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for channel admin */
+ NULL, /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 0, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 1, /* Quit on Kill */
+ 1, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 0, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ 0, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ 0, /* Vhost Mode */
+ 1, /* +f */
+ 0, /* +L */
+ CMODE_j, /* Mode */
+ 0, /* Mode */
+ 1,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ CAPAB_TSMODE, /* TSMODE */
+ CAPAB_UNCONNECT, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ CAPAB_BURST, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ CAPAB_DKEY, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ CAPAB_DOZIP, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+void bahamut_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'a':
+ if (UnRestrictSAdmin) {
+ break;
+ }
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ }
+ }
+}
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, 0, /* A B C */
+ UMODE_D, 0, UMODE_F, /* D E F */
+ 0, 0, UMODE_I, /* G H I */
+ 0, UMODE_K, 0, /* J K L */
+ 0, 0, UMODE_O, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, UMODE_X, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, UMODE_c, /* a b c */
+ UMODE_d, UMODE_e, UMODE_f, /* d e f */
+ UMODE_g, UMODE_h, UMODE_i, /* g h i */
+ UMODE_j, UMODE_k, 0, /* j k l */
+ UMODE_m, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ UMODE_s, 0, 0, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ UMODE_y, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite}, /* I */
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban}, /* b */
+ {NULL}, {NULL}, /* cd */
+ {add_exception, del_exception},
+ {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {0}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {CMODE_j, 0, set_flood, cs_set_flood}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'j', CMODE_j, 0, get_flood, cs_get_flood},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void bahamut_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (ircdcap->tsmode) {
+ if (uplink_capab & ircdcap->tsmode) {
+ send_cmd(source, "MODE %s 0 %s", dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+/* SVSHOLD - set */
+void bahamut_cmd_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s %d :%s", nick, NSReleaseTimeout,
+ "Being held for registered user");
+}
+
+/* SVSHOLD - release */
+void bahamut_cmd_release_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s 0", nick);
+}
+
+/* SVSMODE -b */
+void bahamut_cmd_unban(char *name, char *nick)
+{
+ bahamut_cmd_svsmode_chan(name, "-b", nick);
+}
+
+
+/* SVSMODE channel modes */
+
+void bahamut_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "SVSMODE %s %s %s", name, mode, nick);
+ } else {
+ send_cmd(ServerName, "SVSMODE %s %s", name, mode);
+ }
+}
+
+void bahamut_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+/* EVENT: SJOIN */
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+** NICK - new
+** source = NULL
+** parv[0] = nickname
+** parv[1] = hopcount
+** parv[2] = timestamp
+** parv[3] = modes
+** parv[4] = username
+** parv[5] = hostname
+** parv[6] = server
+** parv[7] = servicestamp
+** parv[8] = IP
+** parv[9] = info
+** NICK - change
+** source = oldnick
+** parv[0] = new nickname
+** parv[1] = hopcount
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[7], NULL, 0),
+ strtoul(av[8], NULL, 0), NULL, NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT : CAPAB */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT : OS */
+int anope_event_os(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_OperServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : NS */
+int anope_event_ns(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_NickServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : MS */
+int anope_event_ms(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_MemoServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : HS */
+int anope_event_hs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_HostServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : CS */
+int anope_event_cs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_ChanServ, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+
+ /* first update the cs protect info about this ircd */
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ /* now add the commands */
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_gnotice); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m);
+ m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m);
+ m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m);
+ m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m);
+ m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m);
+ m = createMessage("RS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("SZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("LUSERSLOCK",anope_event_luserslock); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+
+}
+
+/* *INDENT-ON* */
+
+/* SQLINE */
+void bahamut_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+/* UNSGLINE */
+void bahamut_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "UNSGLINE 0 :%s", mask);
+}
+
+/* UNSZLINE */
+void bahamut_cmd_unszline(char *mask)
+{
+ /* this will likely fail so its only here for legacy */
+ send_cmd(NULL, "UNSZLINE 0 %s", mask);
+ /* this is how we are supposed to deal with it */
+ send_cmd(NULL, "RAKILL %s *", mask);
+}
+
+/* SZLINE */
+void bahamut_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* this will likely fail so its only here for legacy */
+ send_cmd(NULL, "SZLINE %s :%s", mask, reason);
+ /* this is how we are supposed to deal with it */
+ send_cmd(NULL, "AKILL %s * %d %s %ld :%s", mask, 86400 * 2, whom,
+ (long int) time(NULL), reason);
+}
+
+/* SVSNOOP */
+void bahamut_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void bahamut_cmd_svsadmin(char *server, int set)
+{
+ bahamut_cmd_svsnoop(server, set);
+}
+
+/* SGLINE */
+void bahamut_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
+}
+
+/* RAKILL */
+void bahamut_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+/* PART */
+void bahamut_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/* TOPIC */
+void bahamut_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+/* UNSQLINE */
+void bahamut_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+/* JOIN - SJOIN */
+void bahamut_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "SJOIN %ld %s", (long int) chantime, channel);
+}
+
+void bahamut_cmd_burst()
+{
+ send_cmd(NULL, "BURST");
+}
+
+/* AKILL */
+/* parv[1]=host
+ * parv[2]=user
+ * parv[3]=length
+ * parv[4]=akiller
+ * parv[5]=time set
+ * parv[6]=reason
+ */
+void bahamut_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400 * 2, who,
+ (long int) time(NULL), reason);
+}
+
+/* SVSKILL */
+/* parv[0] = servername
+ * parv[1] = client
+ * parv[2] = nick stamp
+ * parv[3] = kill message
+ */
+/*
+ Note: if the stamp is null 0, the below usage is correct of Bahamut
+*/
+void bahamut_cmd_svskill(char *source, char *user, char *buf)
+{
+
+ if (!source || !user || !buf) {
+ return;
+ }
+
+ send_cmd(source, "SVSKILL %s :%s", user, buf);
+}
+
+/* SVSMODE */
+/* parv[0] - sender
+ * parv[1] - nick
+ * parv[2] - TS (or mode, depending on svs version)
+ * parv[3] - mode (or services id if old svs version)
+ * parv[4] - optional arguement (services id)
+ */
+void bahamut_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+/* SQUIT */
+/*
+ * parv[0] = sender prefix
+ * parv[1] = server name
+ * parv[2] = comment
+*/
+void bahamut_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* PONG */
+void bahamut_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void bahamut_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 3 1 0 :%ld", (long int) time(NULL));
+}
+
+/* PASS */
+void bahamut_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER */
+void bahamut_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+/* CAPAB */
+void bahamut_cmd_capab()
+{
+ send_cmd(NULL,
+ "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE TS3");
+}
+
+void bahamut_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1) {
+ bahamut_cmd_pass(RemotePassword);
+ } else if (servernum == 2) {
+ bahamut_cmd_pass(RemotePassword2);
+ } else if (servernum == 3) {
+ bahamut_cmd_pass(RemotePassword3);
+ }
+ bahamut_cmd_capab();
+ bahamut_cmd_server(ServerName, 1, ServerDesc);
+ bahamut_cmd_svinfo();
+ bahamut_cmd_burst();
+}
+
+
+
+
+
+/* EVENT : SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+/* EVENT : PRIVMSG */
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT : SVINFO */
+/*
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: MODE */
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: KILL */
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT: KICK */
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: JOIN */
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: MOTD */
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+void bahamut_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+/* NOTICE */
+void bahamut_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ bahamut_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void bahamut_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void bahamut_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void bahamut_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void bahamut_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void bahamut_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+/* GLOBOPS */
+void bahamut_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* 391 */
+void bahamut_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void bahamut_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void bahamut_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void bahamut_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void bahamut_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void bahamut_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void bahamut_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void bahamut_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void bahamut_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void bahamut_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void bahamut_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void bahamut_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void bahamut_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, ServiceUser, ServiceHost,
+ ServerName, name);
+ bahamut_cmd_sqline(nick, "Reserved for services");
+}
+
+void bahamut_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void bahamut_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void bahamut_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void bahamut_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void bahamut_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* INVITE */
+void bahamut_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* QUIT */
+void bahamut_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ bahamut_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void bahamut_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+
+}
+
+void bahamut_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+ bahamut_cmd_sqline(nick, "Reserved for services");
+}
+
+/* SVSNICK */
+/* parv[0] = sender
+ * parv[1] = old nickname
+ * parv[2] = new nickname
+ * parv[3] = timestamp
+ */
+void bahamut_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void bahamut_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+}
+
+void bahamut_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void bahamut_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ /* Not Supported by this IRCD */
+}
+
+void bahamut_cmd_vhost_off(User * u)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void bahamut_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void bahamut_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void bahamut_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used by bahamut ircds */
+}
+
+
+void bahamut_cmd_svid_umode3(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+/* NICK <newnick> */
+void bahamut_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+
+int anope_event_gnotice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+void bahamut_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Can not find any reference to these in Bahamut */
+}
+
+void bahamut_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Can not find any reference to these in Bahamut */
+}
+
+void bahamut_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+
+void bahamut_cmd_eob()
+{
+ send_cmd(NULL, "BURST 0");
+}
+
+int anope_event_burst(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ if (!ac) {
+ /* for future use - start burst */
+ } else {
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_luserslock(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int bahamut_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void bahamut_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ bahamut_cmd_squit(jserver, rbuf);
+ bahamut_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void bahamut_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int bahamut_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = nick is in chan
+*/
+int bahamut_valid_chan(char *chan)
+{
+ /* no silly invalid chans */
+ return 1;
+}
+
+void bahamut_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+/* this avoids "undefined symbol" messages of those whom try to load mods that
+ call on this function */
+void bahamut_cmd_chghost(char *nick, char *vhost)
+{
+ if (debug) {
+ alog("debug: This IRCD does not support vhosting");
+ }
+}
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(bahamut_cmd_svsnoop);
+ pmodule_cmd_remove_akill(bahamut_cmd_remove_akill);
+ pmodule_cmd_topic(bahamut_cmd_topic);
+ pmodule_cmd_vhost_off(bahamut_cmd_vhost_off);
+ pmodule_cmd_akill(bahamut_cmd_akill);
+ pmodule_cmd_svskill(bahamut_cmd_svskill);
+ pmodule_cmd_svsmode(bahamut_cmd_svsmode);
+ pmodule_cmd_372(bahamut_cmd_372);
+ pmodule_cmd_372_error(bahamut_cmd_372_error);
+ pmodule_cmd_375(bahamut_cmd_375);
+ pmodule_cmd_376(bahamut_cmd_376);
+ pmodule_cmd_nick(bahamut_cmd_nick);
+ pmodule_cmd_guest_nick(bahamut_cmd_guest_nick);
+ pmodule_cmd_mode(bahamut_cmd_mode);
+ pmodule_cmd_bot_nick(bahamut_cmd_bot_nick);
+ pmodule_cmd_kick(bahamut_cmd_kick);
+ pmodule_cmd_notice_ops(bahamut_cmd_notice_ops);
+ pmodule_cmd_notice(bahamut_cmd_notice);
+ pmodule_cmd_notice2(bahamut_cmd_notice2);
+ pmodule_cmd_privmsg(bahamut_cmd_privmsg);
+ pmodule_cmd_privmsg2(bahamut_cmd_privmsg2);
+ pmodule_cmd_serv_notice(bahamut_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(bahamut_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(bahamut_cmd_bot_chan_mode);
+ pmodule_cmd_351(bahamut_cmd_351);
+ pmodule_cmd_quit(bahamut_cmd_quit);
+ pmodule_cmd_pong(bahamut_cmd_pong);
+ pmodule_cmd_join(bahamut_cmd_join);
+ pmodule_cmd_unsqline(bahamut_cmd_unsqline);
+ pmodule_cmd_invite(bahamut_cmd_invite);
+ pmodule_cmd_part(bahamut_cmd_part);
+ pmodule_cmd_391(bahamut_cmd_391);
+ pmodule_cmd_250(bahamut_cmd_250);
+ pmodule_cmd_307(bahamut_cmd_307);
+ pmodule_cmd_311(bahamut_cmd_311);
+ pmodule_cmd_312(bahamut_cmd_312);
+ pmodule_cmd_317(bahamut_cmd_317);
+ pmodule_cmd_219(bahamut_cmd_219);
+ pmodule_cmd_401(bahamut_cmd_401);
+ pmodule_cmd_318(bahamut_cmd_318);
+ pmodule_cmd_242(bahamut_cmd_242);
+ pmodule_cmd_243(bahamut_cmd_243);
+ pmodule_cmd_211(bahamut_cmd_211);
+ pmodule_cmd_global(bahamut_cmd_global);
+ pmodule_cmd_global_legacy(bahamut_cmd_global_legacy);
+ pmodule_cmd_sqline(bahamut_cmd_sqline);
+ pmodule_cmd_squit(bahamut_cmd_squit);
+ pmodule_cmd_svso(bahamut_cmd_svso);
+ pmodule_cmd_chg_nick(bahamut_cmd_chg_nick);
+ pmodule_cmd_svsnick(bahamut_cmd_svsnick);
+ pmodule_cmd_vhost_on(bahamut_cmd_vhost_on);
+ pmodule_cmd_connect(bahamut_cmd_connect);
+ pmodule_cmd_svshold(bahamut_cmd_svshold);
+ pmodule_cmd_release_svshold(bahamut_cmd_release_svshold);
+ pmodule_cmd_unsgline(bahamut_cmd_unsgline);
+ pmodule_cmd_unszline(bahamut_cmd_unszline);
+ pmodule_cmd_szline(bahamut_cmd_szline);
+ pmodule_cmd_sgline(bahamut_cmd_sgline);
+ pmodule_cmd_unban(bahamut_cmd_unban);
+ pmodule_cmd_svsmode_chan(bahamut_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(bahamut_cmd_svid_umode);
+ pmodule_cmd_nc_change(bahamut_cmd_nc_change);
+ pmodule_cmd_svid_umode2(bahamut_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(bahamut_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(bahamut_cmd_svsjoin);
+ pmodule_cmd_svspart(bahamut_cmd_svspart);
+ pmodule_cmd_swhois(bahamut_cmd_swhois);
+ pmodule_cmd_eob(bahamut_cmd_eob);
+ pmodule_flood_mode_check(bahamut_flood_mode_check);
+ pmodule_cmd_jupe(bahamut_cmd_jupe);
+ pmodule_valid_nick(bahamut_valid_nick);
+ pmodule_valid_chan(bahamut_valid_chan);
+ pmodule_cmd_ctcp(bahamut_cmd_ctcp);
+ pmodule_set_umode(bahamut_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("BahamutIRCd 1.4.*/1.8.*");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+j");
+ pmodule_ircd_flood_mode_char_remove("-j");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/bahamut.h b/src/protocol/bahamut.h
new file mode 100644
index 000000000..1b60733a9
--- /dev/null
+++ b/src/protocol/bahamut.h
@@ -0,0 +1,131 @@
+/* Bahamut functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+#define UMODE_a 0x00000001 /* umode +a - Services Admin */
+#define UMODE_h 0x00000002 /* umode +h - Helper */
+#define UMODE_i 0x00000004 /* umode +i - Invisible */
+#define UMODE_o 0x00000008 /* umode +o - Oper */
+#define UMODE_r 0x00000010 /* umode +r - registered nick */
+#define UMODE_w 0x00000020 /* umode +w - Get wallops */
+#define UMODE_A 0x00000040 /* umode +A - Server Admin */
+#define UMODE_x 0x00000080 /* umode +x - Squelch with notice */
+#define UMODE_X 0x00000100 /* umode +X - Squelch without notice */
+#define UMODE_F 0x00000200 /* umode +F - no cptr->since message rate throttle */
+#define UMODE_j 0x00000400 /* umode +j - client rejection notices */
+#define UMODE_K 0x00000800 /* umode +K - U: lined server kill messages */
+#define UMODE_O 0x00001000 /* umode +O - Local Oper */
+#define UMODE_s 0x00002000 /* umode +s - Server notices */
+#define UMODE_c 0x00004000 /* umode +c - Client connections/exits */
+#define UMODE_k 0x00008000 /* umode +k - Server kill messages */
+#define UMODE_f 0x00010000 /* umode +f - Server flood messages */
+#define UMODE_y 0x00020000 /* umode +y - Stats/links */
+#define UMODE_d 0x00040000 /* umode +d - Debug info */
+#define UMODE_g 0x00080000 /* umode +g - Globops */
+#define UMODE_b 0x00100000 /* umode +b - Chatops */
+#define UMODE_n 0x00200000 /* umode +n - Routing Notices */
+#define UMODE_m 0x00400000 /* umode +m - spambot notices */
+#define UMODE_e 0x00800000 /* umode +e - oper notices for the above +D */
+#define UMODE_D 0x01000000 /* umode +D - Hidden dccallow umode */
+#define UMODE_I 0x02000000 /* umode +I - invisible oper (masked) */
+#define UMODE_R 0x80000000 /* unmode +R - No non registered msgs */
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_c 0x00000400 /* Colors can't be used */
+#define CMODE_M 0x00000800 /* Non-regged nicks can't send messages */
+#define CMODE_j 0x00001000 /* join throttle */
+#define CMODE_O 0x00008000 /* Only opers can join */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void bahamut_set_umode(User * user, int ac, char **av);
+void bahamut_cmd_svsnoop(char *server, int set);
+void bahamut_cmd_remove_akill(char *user, char *host);
+void bahamut_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void bahamut_cmd_vhost_off(User * u);
+void bahamut_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void bahamut_cmd_svskill(char *source, char *user, char *buf);
+void bahamut_cmd_svsmode(User * u, int ac, char **av);
+void bahamut_cmd_372(char *source, char *msg);
+void bahamut_cmd_372_error(char *source);
+void bahamut_cmd_375(char *source);
+void bahamut_cmd_376(char *source);
+void bahamut_cmd_nick(char *nick, char *name, char *modes);
+void bahamut_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void bahamut_cmd_mode(char *source, char *dest, char *buf);
+void bahamut_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void bahamut_cmd_kick(char *source, char *chan, char *user, char *buf);
+void bahamut_cmd_notice_ops(char *source, char *dest, char *buf);
+void bahamut_cmd_notice(char *source, char *dest, char *buf);
+void bahamut_cmd_notice2(char *source, char *dest, char *msg);
+void bahamut_cmd_privmsg(char *source, char *dest, char *buf);
+void bahamut_cmd_privmsg2(char *source, char *dest, char *msg);
+void bahamut_cmd_serv_notice(char *source, char *dest, char *msg);
+void bahamut_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void bahamut_cmd_bot_chan_mode(char *nick, char *chan);
+void bahamut_cmd_351(char *source);
+void bahamut_cmd_quit(char *source, char *buf);
+void bahamut_cmd_pong(char *servname, char *who);
+void bahamut_cmd_join(char *user, char *channel, time_t chantime);
+void bahamut_cmd_unsqline(char *user);
+void bahamut_cmd_invite(char *source, char *chan, char *nick);
+void bahamut_cmd_part(char *nick, char *chan, char *buf);
+void bahamut_cmd_391(char *source, char *timestr);
+void bahamut_cmd_250(char *buf);
+void bahamut_cmd_307(char *buf);
+void bahamut_cmd_311(char *buf);
+void bahamut_cmd_312(char *buf);
+void bahamut_cmd_317(char *buf);
+void bahamut_cmd_219(char *source, char *letter);
+void bahamut_cmd_401(char *source, char *who);
+void bahamut_cmd_318(char *source, char *who);
+void bahamut_cmd_242(char *buf);
+void bahamut_cmd_243(char *buf);
+void bahamut_cmd_211(char *buf);
+void bahamut_cmd_global(char *source, char *buf);
+void bahamut_cmd_global_legacy(char *source, char *fmt);
+void bahamut_cmd_sqline(char *mask, char *reason);
+void bahamut_cmd_squit(char *servname, char *message);
+void bahamut_cmd_svso(char *source, char *nick, char *flag);
+void bahamut_cmd_chg_nick(char *oldnick, char *newnick);
+void bahamut_cmd_svsnick(char *source, char *guest, time_t when);
+void bahamut_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void bahamut_cmd_connect(int servernum);
+void bahamut_cmd_svshold(char *nick);
+void bahamut_cmd_release_svshold(char *nick);
+void bahamut_cmd_unsgline(char *mask);
+void bahamut_cmd_unszline(char *mask);
+void bahamut_cmd_szline(char *mask, char *reason, char *whom);
+void bahamut_cmd_sgline(char *mask, char *reason);
+void bahamut_cmd_unban(char *name, char *nick);
+void bahamut_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void bahamut_cmd_svid_umode(char *nick, time_t ts);
+void bahamut_cmd_nc_change(User * u);
+void bahamut_cmd_svid_umode2(User * u, char *ts);
+void bahamut_cmd_svid_umode3(User * u, char *ts);
+void bahamut_cmd_eob();
+int bahamut_flood_mode_check(char *value);
+void bahamut_cmd_jupe(char *jserver, char *who, char *reason);
+int bahamut_valid_nick(char *nick);
+void bahamut_cmd_ctcp(char *source, char *dest, char *buf);
+
diff --git a/src/protocol/charybdis.c b/src/protocol/charybdis.c
new file mode 100644
index 000000000..c5bd8a740
--- /dev/null
+++ b/src/protocol/charybdis.c
@@ -0,0 +1,2008 @@
+/* Charybdis IRCD functions
+ *
+ * (C) 2006 William Pitcock <nenolod -at- charybdis.be>
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "charybdis.h"
+
+IRCDVar myIrcd[] = {
+ {"Charybdis 1.0+", /* ircd name */
+ "+oiS", /* nickserv mode */
+ "+oiS", /* chanserv mode */
+ "+oiS", /* memoserv mode */
+ "+oiS", /* hostserv mode */
+ "+oaiS", /* operserv mode */
+ "+oiS", /* botserv mode */
+ "+oiS", /* helpserv mode */
+ "+oiS", /* Dev/Null mode */
+ "+oiS", /* Global mode */
+ "+oiS", /* nickserv alias mode */
+ "+oiS", /* chanserv alias mode */
+ "+oiS", /* memoserv alias mode */
+ "+oiS", /* hostserv alias mode */
+ "+oaiS", /* operserv alias mode */
+ "+oiS", /* botserv alias mode */
+ "+oiS", /* helpserv alias mode */
+ "+oiS", /* Dev/Null alias mode */
+ "+oiS", /* Global alias mode */
+ "+oiS", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-cilmnpstrgzQF", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to unset for chan admin */
+ NULL, /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ NULL, /* Mode on UnReg */
+ NULL, /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 0, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 1, /* Join 2 Set */
+ 1, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 0, /* Chan Reg */
+ 0, /* Channel Mode */
+ 0, /* vidents */
+ 1, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* UMODE */
+ 0, /* O:LINE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ 0, /* Vhost Mode */
+ 1, /* +f */
+ 1, /* +L */
+ CMODE_j, /* +f Mode */
+ CMODE_f, /* +L Mode (+f <target>) */
+ 1, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 1, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 1, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ CAPAB_QS, /* QS */
+ CAPAB_UID, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+/*******************************************************************/
+
+void charybdis_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ 0, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, 0, /* M N O */
+ 0, UMODE_Q, UMODE_R, /* P Q R */
+ UMODE_S, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ 0, 0, 0, /* d e f */
+ UMODE_g, 0, UMODE_i, /* g h i */
+ 0, 0, UMODE_l, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ 0, 0, 0, /* p q r */
+ UMODE_s, 0, 0, /* s t u */
+ 0, UMODE_w, 0, /* v w x */
+ 0, /* y */
+ UMODE_z, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {CMODE_F, 0, NULL, NULL}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {CMODE_L, CBM_NO_USER_MLOCK, NULL, NULL}, /* L */
+ {0}, /* M */
+ {0}, /* N */
+ {0}, /* O */
+ {CMODE_P, CBM_NO_USER_MLOCK, NULL, NULL}, /* P */
+ {CMODE_Q, 0, NULL, NULL}, /* Q */
+ {0}, /* R */
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {CMODE_f, 0, set_redirect, cs_set_redirect}, /* f */
+ {CMODE_g, 0, NULL, NULL}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {CMODE_j, 0, set_flood, cs_set_flood}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, 0, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'f', CMODE_f, CBM_MINUS_NO_ARG, get_redirect, cs_get_redirect},
+ {'g', CMODE_g, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'j', CMODE_j, CBM_MINUS_NO_ARG, get_flood, cs_get_flood},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'F', CMODE_F, 0, NULL, NULL},
+ {'L', CMODE_L, 0, NULL, NULL},
+ {'P', CMODE_P, 0, NULL, NULL},
+ {'Q', CMODE_Q, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void charybdis_cmd_notice(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ charybdis_cmd_privmsg2(source, dest, buf);
+ } else {
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source),
+ "NOTICE %s :%s", (UseTS6 ? (u ? u->uid : dest) : dest),
+ buf);
+ }
+}
+
+void charybdis_cmd_notice2(char *source, char *dest, char *msg)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "NOTICE %s :%s",
+ (UseTS6 ? (u ? u->uid : dest) : dest), msg);
+}
+
+void charybdis_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ Uid *ud, *ud2;
+
+ if (!buf) {
+ return;
+ }
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "PRIVMSG %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : dest) : dest), buf);
+}
+
+void charybdis_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ Uid *ud, *ud2;
+
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "PRIVMSG %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : dest) : dest), msg);
+}
+
+void charybdis_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void charybdis_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void charybdis_cmd_global(char *source, char *buf)
+{
+ Uid *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((UseTS6 ? u->uid : source), "OPERWALL :%s", buf);
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "WALLOPS :%s", buf);
+ }
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "WALLOPS :%s", buf);
+ }
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void charybdis_cmd_global_legacy(char *source, char *fmt)
+{
+ Uid *u;
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((UseTS6 ? u->uid : source), "OPERWALL :%s", fmt);
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "WALLOPS :%s", fmt);
+ }
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "WALLOPS :%s", fmt);
+ }
+
+ send_cmd(source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+ Non TS6
+
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = server
+ av[7] = info
+
+ TS6
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = IP
+ av[7] = UID
+ av[8] = info
+
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ Server *s;
+ User *user;
+
+ if (UseTS6 && ac == 9) {
+ s = findserver_uid(servlist, source);
+ /* Source is always the server */
+ *source = '\0';
+ user = do_nick(source, av[0], av[4], av[5], s->name, av[8],
+ strtoul(av[2], NULL, 10), 0, 0, NULL, av[7]);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[7],
+ strtoul(av[2], NULL, 10), 0, 0, NULL, NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ }
+ return MOD_CONT;
+}
+
+/*
+ TS6
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = vhost
+ av[6] = IP
+ av[7] = UID
+ ac[8] = host or *
+ ac[9] = services login
+ av[10] = info
+
+*/
+int anope_event_euid(char *source, int ac, char **av)
+{
+ Server *s;
+ User *user;
+ time_t ts;
+
+ if (UseTS6 && ac == 11) {
+ s = findserver_uid(servlist, source);
+ /* Source is always the server */
+ *source = '\0';
+ ts = strtoul(av[2], NULL, 10);
+ user = do_nick(source, av[0], av[4], !strcmp(av[8], "*") ? av[5] : av[8], s->name, av[10],
+ ts, !stricmp(av[0], av[9]) ? ts : 0, 0, av[5], av[7]);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac == 4) {
+ do_topic(source, ac, av);
+ } else {
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ if (UseTS6) {
+ u = find_byuid(source);
+ if (u) {
+ strscpy(c->topic_setter, u->nick, sizeof(c->topic_setter));
+ } else {
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ }
+ } else {
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ }
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tburst(char *source, int ac, char **av)
+{
+ char *setter;
+ Channel *c;
+ time_t topic_time;
+
+ if (ac != 4) {
+ return MOD_CONT;
+ }
+
+ setter = myStrGetToken(av[2], '!', 0);
+
+ c = findchan(av[0]);
+ topic_time = strtol(av[1], NULL, 10);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time)) {
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[3])
+ c->topic = sstrdup(av[3]);
+
+ strscpy(c->topic_setter, setter, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[3])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[3]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ if (setter)
+ free(setter);
+
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void)
+{
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ if (UseTS6) {
+ TS6SID = sstrdup(Numeric);
+ }
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("TMODE", anope_event_tmode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("BMASK", anope_event_bmask); addCoreMessage(IRCD,m);
+ m = createMessage("UID", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("TB", anope_event_tburst); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("421", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ENCAP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SID", anope_event_sid); addCoreMessage(IRCD,m);
+ m = createMessage("EUID", anope_event_euid); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+void charybdis_cmd_sqline(char *mask, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "RESV * %s :%s", mask, reason);
+}
+
+void charybdis_cmd_unsgline(char *mask)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNXLINE * %s", mask);
+}
+
+void charybdis_cmd_unszline(char *mask)
+{
+ /* not supported */
+}
+
+void charybdis_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* not supported */
+}
+
+void charybdis_cmd_svsnoop(char *server, int set)
+{
+ /* does not support */
+}
+
+void charybdis_cmd_svsadmin(char *server, int set)
+{
+ charybdis_cmd_svsnoop(server, set);
+}
+
+void charybdis_cmd_sgline(char *mask, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "XLINE * %s 0 :%s", mask, reason);
+}
+
+void charybdis_cmd_remove_akill(char *user, char *host)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNKLINE * %s %s", user, host);
+}
+
+void charybdis_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ Uid *ud;
+
+ ud = find_uid(whosets);
+ send_cmd((UseTS6 ? (ud ? ud->uid : whosets) : whosets), "TOPIC %s :%s",
+ chan, topic);
+}
+
+void charybdis_cmd_vhost_off(User * u)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "ENCAP * CHGHOST %s :%s",
+ u->nick, u->host);
+}
+
+void charybdis_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "ENCAP * CHGHOST %s :%s",
+ nick, vhost);
+}
+
+void charybdis_cmd_unsqline(char *user)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNRESV * %s", user);
+}
+
+void charybdis_cmd_join(char *user, char *channel, time_t chantime)
+{
+ Uid *ud;
+
+ ud = find_uid(user);
+ send_cmd(NULL, "SJOIN %ld %s + :%s", (long int) chantime,
+ channel, (UseTS6 ? (ud ? ud->uid : user) : user));
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void charybdis_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time(NULL)), user, host, reason);
+}
+
+void charybdis_cmd_svskill(char *source, char *user, char *buf)
+{
+ Uid *ud, *ud2;
+
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ ud = find_uid(source);
+ ud2 = find_uid(user);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "KILL %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : user) : user), buf);
+}
+
+void charybdis_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "SVSMODE %s %s", u->nick,
+ av[0]);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void charybdis_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 6 3 0 :%ld", (long int) time(NULL));
+}
+
+void charybdis_cmd_svsinfo()
+{
+
+}
+
+/* CAPAB */
+/*
+ QS - Can handle quit storm removal
+ EX - Can do channel +e exemptions
+ CHW - Can do channel wall @#
+ LL - Can do lazy links
+ IE - Can do invite exceptions
+ EOB - Can do EOB message
+ KLN - Can do KLINE message
+ GLN - Can do GLINE message
+ HUB - This server is a HUB
+ UID - Can do UIDs
+ ZIP - Can do ZIPlinks
+ ENC - Can do ENCrypted links
+ KNOCK - supports KNOCK
+ TBURST - supports TBURST
+ PARA - supports invite broadcasting for +p
+ ENCAP - supports message encapsulation
+ SERVICES - supports services-oriented TS6 extensions
+ EUID - supports EUID and non-ENCAP CHGHOST
+*/
+void charybdis_cmd_capab()
+{
+ send_cmd(NULL,
+ "CAPAB :QS EX CHW IE KLN GLN KNOCK TB UNKLN CLUSTER ENCAP SERVICES EUID");
+}
+
+/* PASS */
+void charybdis_cmd_pass(char *pass)
+{
+ if (UseTS6) {
+ send_cmd(NULL, "PASS %s TS 6 :%s", pass, TS6SID);
+ } else {
+ send_cmd(NULL, "PASS %s :TS", pass);
+ }
+}
+
+/* SERVER name hop descript */
+void charybdis_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void charybdis_cmd_connect(int servernum)
+{
+ /* Make myself known to myself in the serverlist */
+ if (UseTS6) {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, TS6SID);
+ } else {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+ }
+ if (servernum == 1)
+ charybdis_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ charybdis_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ charybdis_cmd_pass(RemotePassword3);
+
+ charybdis_cmd_capab();
+ charybdis_cmd_server(ServerName, 1, ServerDesc);
+ charybdis_cmd_svinfo();
+}
+
+void charybdis_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ if (UseTS6) {
+ char *uidbuf = ts6_uid_retrieve();
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick,
+ (long int) time(NULL), modes, user, host, uidbuf,
+ real);
+ new_uid(nick, uidbuf);
+ } else {
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName,
+ real);
+ }
+ charybdis_cmd_sqline(nick, "Reserved for services");
+}
+
+void charybdis_cmd_part(char *nick, char *chan, char *buf)
+{
+ Uid *ud;
+
+ ud = find_uid(nick);
+
+ if (buf) {
+ send_cmd((UseTS6 ? ud->uid : nick), "PART %s :%s", chan, buf);
+ } else {
+ send_cmd((UseTS6 ? ud->uid : nick), "PART %s", chan);
+ }
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ charybdis_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ User *u = NULL;
+
+ if (UseTS6) {
+ u = find_byuid(source);
+ }
+
+ m_away((UseTS6 ? (u ? u->nick : source) : source),
+ (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ User *u = NULL;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ if (UseTS6) {
+ u = find_byuid(av[0]);
+ }
+
+ m_kill(u ? u->nick : av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+void charybdis_cmd_eob()
+{
+ /* doesn't support EOB */
+}
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1) {
+ /* ignore cmodes in JOIN as per TS6 v8 */
+ do_sjoin(source, ac > 2 ? 2 : ac, av);
+ return MOD_CONT;
+ } else {
+ do_join(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ User *u;
+ Uid *ud;
+
+ if (ac != 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ ud = find_nickuid(av[0]);
+ m_privmsg((UseTS6 ? (u ? u->nick : source) : source),
+ (UseTS6 ? (ud ? ud->nick : av[0]) : av[0]), av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac < 1 || ac > 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ do_part((UseTS6 ? (u ? u->nick : source) : source), ac, av);
+
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ Uid *ud;
+
+ if (source && ac >= 1) {
+ ud = find_nickuid(av[0]);
+ m_whois(source, (UseTS6 ? (ud ? ud->nick : av[0]) : av[0]));
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ if (UseTS6 && TS6UPLINK) {
+ do_server(source, av[0], av[1], av[2], TS6UPLINK);
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_sid(char *source, int ac, char **av)
+{
+ Server *s;
+
+ /* :42X SID trystan.nomadirc.net 2 43X :ircd-charybdis test server */
+
+ s = findserver_uid(servlist, source);
+
+ do_server(s->name, av[0], av[1], av[3], av[2]);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+
+ do_quit((UseTS6 ? (u ? u->nick : source) : source), ac, av);
+ return MOD_CONT;
+}
+
+void charybdis_cmd_372(char *source, char *msg)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "372 %s :- %s", source, msg);
+}
+
+void charybdis_cmd_372_error(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void charybdis_cmd_375(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "375 %s :- %s Message of the Day", source, ServerName);
+}
+
+void charybdis_cmd_376(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void charybdis_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void charybdis_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void charybdis_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "307 %s", buf);
+}
+
+/* 311 */
+void charybdis_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "311 %s", buf);
+}
+
+/* 312 */
+void charybdis_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "312 %s", buf);
+}
+
+/* 317 */
+void charybdis_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "317 %s", buf);
+}
+
+/* 219 */
+void charybdis_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void charybdis_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd((UseTS6 ? TS6SID : ServerName), "401 %s %s :No such service.",
+ source, who);
+}
+
+/* 318 */
+void charybdis_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void charybdis_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void charybdis_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void charybdis_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void charybdis_cmd_mode(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ ud = find_uid(source);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "MODE %s %s",
+ dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+void charybdis_cmd_tmode(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ if (!*buf) {
+ return;
+ }
+
+ send_cmd(NULL, "MODE %s %s", dest, buf);
+}
+
+void charybdis_cmd_nick(char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick(nick, NULL);
+ if (UseTS6) {
+ char *uidbuf = ts6_uid_retrieve();
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ uidbuf, name);
+ new_uid(nick, uidbuf);
+ } else {
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ ServerName, name);
+ }
+ charybdis_cmd_sqline(nick, "Reserved for services");
+}
+
+void charybdis_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(user);
+
+ if (buf) {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source),
+ "KICK %s %s :%s", chan,
+ (UseTS6 ? (u ? u->uid : user) : user), buf);
+ } else {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "KICK %s %s",
+ chan, (UseTS6 ? (u ? u->uid : user) : user));
+ }
+}
+
+void charybdis_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ ud = find_uid(source);
+
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "NOTICE @%s :%s", dest, buf);
+}
+
+void charybdis_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ Uid *u;
+
+ if (UseTS6) {
+ u = find_uid(nick);
+ charybdis_cmd_tmode(nick, chan, "%s %s", ircd->botchanumode,
+ (u ? u->uid : nick));
+ } else {
+ anope_cmd_mode(ServerName, chan, "%s %s", ircd->botchanumode, nick);
+ }
+}
+
+/* QUIT */
+void charybdis_cmd_quit(char *source, char *buf)
+{
+ Uid *ud;
+ ud = find_uid(source);
+
+ if (buf) {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "QUIT :%s",
+ buf);
+ } else {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "QUIT");
+ }
+}
+
+/* PONG */
+void charybdis_cmd_pong(char *servname, char *who)
+{
+ if (UseTS6) {
+ /* deliberately no SID in the first parameter -- jilles */
+ send_cmd(TS6SID, "PONG %s :%s", servname, who);
+ } else {
+ send_cmd(servname, "PONG %s :%s", servname, who);
+ }
+}
+
+/* INVITE */
+void charybdis_cmd_invite(char *source, char *chan, char *nick)
+{
+ Uid *ud;
+ User *u;
+
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ ud = find_uid(source);
+ u = finduser(nick);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "INVITE %s %s",
+ (UseTS6 ? (u ? u->uid : nick) : nick), chan);
+}
+
+/* SQUIT */
+void charybdis_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ User *u, *u2;
+
+ if (ac < 2) {
+ return MOD_CONT;
+ }
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ if (UseTS6) {
+ u = find_byuid(source);
+ u2 = find_byuid(av[0]);
+ av[0] = u2->nick;
+ do_umode(u->nick, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tmode(char *source, int ac, char **av)
+{
+ if (ac > 2 && (*av[1] == '#' || *av[1] == '&')) {
+ do_cmode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+void charybdis_cmd_351(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "351 %s Anope-%s %s :%s - %s (%s) -- %s", source, version_number,
+ ServerName, ircd->name, version_flags, EncModule, version_build);
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ int argvsize = 8;
+ int argc;
+ char **argv;
+ char *str;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ /* We get the params as one arg, we should split it for capab_parse */
+ argv = scalloc(argvsize, sizeof(char *));
+ argc = 0;
+ while ((str = myStrGetToken(av[0], ' ', argc))) {
+ if (argc == argvsize) {
+ argvsize += 8;
+ argv = srealloc(argv, argvsize * sizeof(char *));
+ }
+ argv[argc] = str;
+ argc++;
+ }
+
+ capab_parse(argc, argv);
+
+ /* Free our built ac/av */
+ for (argvsize = 0; argvsize < argc; argvsize++) {
+ free(argv[argvsize]);
+ }
+ free(argv);
+
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void charybdis_cmd_svshold(char *nick)
+{
+ send_cmd(NULL, "ENCAP * NICKDELAY 300 %s", nick);
+}
+
+/* SVSHOLD - release */
+void charybdis_cmd_release_svshold(char *nick)
+{
+ send_cmd(NULL, "ENCAP * NICKDELAY 0 %s", nick);
+}
+
+/* SVSNICK */
+void charybdis_cmd_svsnick(char *nick, char *newnick, time_t when)
+{
+ User *u;
+
+ if (!nick || !newnick) {
+ return;
+ }
+
+ u = finduser(nick);
+ if (!u)
+ return;
+ send_cmd(NULL, "ENCAP %s RSFNC %s %s %ld %ld", u->server->name,
+ u->nick, newnick, (long int)when, (long int)u->timestamp);
+}
+
+void charybdis_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ /* not supported */
+}
+
+void charybdis_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void charybdis_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void charybdis_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void charybdis_cmd_svid_umode(char *nick, time_t ts)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void charybdis_cmd_nc_change(User * u)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+void charybdis_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not supported */
+}
+
+void charybdis_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void charybdis_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ if (UseTS6) {
+ TS6UPLINK = sstrdup(av[3]);
+ }
+ return MOD_CONT;
+}
+
+void charybdis_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void charybdis_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void charybdis_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_bmask(char *source, int ac, char **av)
+{
+ Channel *c;
+ char *bans;
+ char *b;
+ int count, i;
+
+ /* :42X BMASK 1106409026 #ircops b :*!*@*.aol.com */
+ /* 0 1 2 3 */
+ c = findchan(av[1]);
+
+ if (c) {
+ bans = sstrdup(av[3]);
+ count = myNumToken(bans, ' ');
+ for (i = 0; i <= count - 1; i++) {
+ b = myStrGetToken(bans, ' ', i);
+ if (!stricmp(av[2], "b")) {
+ add_ban(c, b);
+ }
+ if (!stricmp(av[2], "e")) {
+ add_exception(c, b);
+ }
+ if (!stricmp(av[2], "I")) {
+ add_invite(c, b);
+ }
+ if (b)
+ free(b);
+ }
+ free(bans);
+ }
+ return MOD_CONT;
+}
+
+int charybdis_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+ return 0;
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void charybdis_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ charybdis_cmd_squit(jserver, rbuf);
+ charybdis_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int charybdis_valid_nick(char *nick)
+{
+ /* TS6 Save extension -Certus */
+ if (isdigit(*nick))
+ return 0;
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is invalid
+*/
+int charybdis_valid_chan(char *chan)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void charybdis_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+int charybdis_send_account(int argc, char **argv)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "ENCAP * SU %s :%s",
+ argv[0], argv[0]);
+
+ return MOD_CONT;
+}
+
+/* XXX: We need a hook on /ns logout before this is useful! --nenolod */
+/* We have one now! -GD */
+int charybdis_send_deaccount(int argc, char **argv)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "ENCAP * SU %s",
+ argv[0]);
+
+ return MOD_CONT;
+}
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(charybdis_cmd_svsnoop);
+ pmodule_cmd_remove_akill(charybdis_cmd_remove_akill);
+ pmodule_cmd_topic(charybdis_cmd_topic);
+ pmodule_cmd_vhost_off(charybdis_cmd_vhost_off);
+ pmodule_cmd_akill(charybdis_cmd_akill);
+ pmodule_cmd_svskill(charybdis_cmd_svskill);
+ pmodule_cmd_svsmode(charybdis_cmd_svsmode);
+ pmodule_cmd_372(charybdis_cmd_372);
+ pmodule_cmd_372_error(charybdis_cmd_372_error);
+ pmodule_cmd_375(charybdis_cmd_375);
+ pmodule_cmd_376(charybdis_cmd_376);
+ pmodule_cmd_nick(charybdis_cmd_nick);
+ pmodule_cmd_guest_nick(charybdis_cmd_guest_nick);
+ pmodule_cmd_mode(charybdis_cmd_mode);
+ pmodule_cmd_bot_nick(charybdis_cmd_bot_nick);
+ pmodule_cmd_kick(charybdis_cmd_kick);
+ pmodule_cmd_notice_ops(charybdis_cmd_notice_ops);
+ pmodule_cmd_notice(charybdis_cmd_notice);
+ pmodule_cmd_notice2(charybdis_cmd_notice2);
+ pmodule_cmd_privmsg(charybdis_cmd_privmsg);
+ pmodule_cmd_privmsg2(charybdis_cmd_privmsg2);
+ pmodule_cmd_serv_notice(charybdis_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(charybdis_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(charybdis_cmd_bot_chan_mode);
+ pmodule_cmd_351(charybdis_cmd_351);
+ pmodule_cmd_quit(charybdis_cmd_quit);
+ pmodule_cmd_pong(charybdis_cmd_pong);
+ pmodule_cmd_join(charybdis_cmd_join);
+ pmodule_cmd_unsqline(charybdis_cmd_unsqline);
+ pmodule_cmd_invite(charybdis_cmd_invite);
+ pmodule_cmd_part(charybdis_cmd_part);
+ pmodule_cmd_391(charybdis_cmd_391);
+ pmodule_cmd_250(charybdis_cmd_250);
+ pmodule_cmd_307(charybdis_cmd_307);
+ pmodule_cmd_311(charybdis_cmd_311);
+ pmodule_cmd_312(charybdis_cmd_312);
+ pmodule_cmd_317(charybdis_cmd_317);
+ pmodule_cmd_219(charybdis_cmd_219);
+ pmodule_cmd_401(charybdis_cmd_401);
+ pmodule_cmd_318(charybdis_cmd_318);
+ pmodule_cmd_242(charybdis_cmd_242);
+ pmodule_cmd_243(charybdis_cmd_243);
+ pmodule_cmd_211(charybdis_cmd_211);
+ pmodule_cmd_global(charybdis_cmd_global);
+ pmodule_cmd_global_legacy(charybdis_cmd_global_legacy);
+ pmodule_cmd_sqline(charybdis_cmd_sqline);
+ pmodule_cmd_squit(charybdis_cmd_squit);
+ pmodule_cmd_svso(charybdis_cmd_svso);
+ pmodule_cmd_chg_nick(charybdis_cmd_chg_nick);
+ pmodule_cmd_svsnick(charybdis_cmd_svsnick);
+ pmodule_cmd_vhost_on(charybdis_cmd_vhost_on);
+ pmodule_cmd_connect(charybdis_cmd_connect);
+ pmodule_cmd_svshold(charybdis_cmd_svshold);
+ pmodule_cmd_release_svshold(charybdis_cmd_release_svshold);
+ pmodule_cmd_unsgline(charybdis_cmd_unsgline);
+ pmodule_cmd_unszline(charybdis_cmd_unszline);
+ pmodule_cmd_szline(charybdis_cmd_szline);
+ pmodule_cmd_sgline(charybdis_cmd_sgline);
+ pmodule_cmd_unban(charybdis_cmd_unban);
+ pmodule_cmd_svsmode_chan(charybdis_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(charybdis_cmd_svid_umode);
+ pmodule_cmd_nc_change(charybdis_cmd_nc_change);
+ pmodule_cmd_svid_umode2(charybdis_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(charybdis_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(charybdis_cmd_svsjoin);
+ pmodule_cmd_svspart(charybdis_cmd_svspart);
+ pmodule_cmd_swhois(charybdis_cmd_swhois);
+ pmodule_cmd_eob(charybdis_cmd_eob);
+ pmodule_flood_mode_check(charybdis_flood_mode_check);
+ pmodule_cmd_jupe(charybdis_cmd_jupe);
+ pmodule_valid_nick(charybdis_valid_nick);
+ pmodule_valid_chan(charybdis_valid_chan);
+ pmodule_cmd_ctcp(charybdis_cmd_ctcp);
+ pmodule_set_umode(charybdis_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+ EvtHook *hk;
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("Charybdis 1.0/1.1+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ hk = createEventHook(EVENT_NICK_IDENTIFY, charybdis_send_account);
+ moduleAddEventHook(hk);
+
+ hk = createEventHook(EVENT_NICK_REGISTERED, charybdis_send_account);
+ moduleAddEventHook(hk);
+
+ /* XXX: It'd be nice if we could have an event like this, but it's not there yet :( */
+ /* It's there now! Trystan said so! -GD */
+ hk = createEventHook(EVENT_NICK_LOGOUT, charybdis_send_deaccount);
+ moduleAddEventHook(hk);
+
+ return MOD_CONT;
+}
+
+/* Clean up allocated things in here */
+void AnopeFini(void)
+{
+ if (UseTS6)
+ free(TS6SID);
+}
+
+/* EOF */
diff --git a/src/protocol/charybdis.h b/src/protocol/charybdis.h
new file mode 100644
index 000000000..4208c4d43
--- /dev/null
+++ b/src/protocol/charybdis.h
@@ -0,0 +1,120 @@
+/* Ratbox IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001 /* umode a - admin */
+#define UMODE_g 0x00000002 /* umode g - caller ID */
+#define UMODE_i 0x00000004 /* umode i - invisible */
+#define UMODE_o 0x00000008 /* umode o - operator */
+#define UMODE_z 0x00000010 /* umode u - operwall */
+#define UMODE_w 0x00000020 /* umode w - wallops */
+#define UMODE_s 0x00000040 /* umode s - server notices */
+#define UMODE_Q 0x00000080 /* umode Q - block forwarding */
+#define UMODE_R 0x00000200 /* umode R - reject messages from unauthenticated users */
+#define UMODE_S 0x00000400 /* umode S - network service */
+#define UMODE_l 0x00020000 /* umode l - locops */
+
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040
+#define CMODE_l 0x00000080
+#define CMODE_f 0x00000100
+#define CMODE_c 0x00000200
+#define CMODE_r 0x00000400
+#define CMODE_P 0x00000800
+#define CMODE_g 0x00001000
+#define CMODE_z 0x00002000
+#define CMODE_j 0x00004000
+#define CMODE_F 0x00008000
+#define CMODE_L 0x00010000
+#define CMODE_Q 0x00020000
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t
+
+
+void charybdis_set_umode(User * user, int ac, char **av);
+void charybdis_cmd_svsnoop(char *server, int set);
+void charybdis_cmd_remove_akill(char *user, char *host);
+void charybdis_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void charybdis_cmd_vhost_off(User * u);
+void charybdis_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void charybdis_cmd_svskill(char *source, char *user, char *buf);
+void charybdis_cmd_svsmode(User * u, int ac, char **av);
+void charybdis_cmd_372(char *source, char *msg);
+void charybdis_cmd_372_error(char *source);
+void charybdis_cmd_375(char *source);
+void charybdis_cmd_376(char *source);
+void charybdis_cmd_nick(char *nick, char *name, char *modes);
+void charybdis_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void charybdis_cmd_mode(char *source, char *dest, char *buf);
+void charybdis_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void charybdis_cmd_kick(char *source, char *chan, char *user, char *buf);
+void charybdis_cmd_notice_ops(char *source, char *dest, char *buf);
+void charybdis_cmd_notice(char *source, char *dest, char *buf);
+void charybdis_cmd_notice2(char *source, char *dest, char *msg);
+void charybdis_cmd_privmsg(char *source, char *dest, char *buf);
+void charybdis_cmd_privmsg2(char *source, char *dest, char *msg);
+void charybdis_cmd_serv_notice(char *source, char *dest, char *msg);
+void charybdis_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void charybdis_cmd_bot_chan_mode(char *nick, char *chan);
+void charybdis_cmd_351(char *source);
+void charybdis_cmd_quit(char *source, char *buf);
+void charybdis_cmd_pong(char *servname, char *who);
+void charybdis_cmd_join(char *user, char *channel, time_t chantime);
+void charybdis_cmd_unsqline(char *user);
+void charybdis_cmd_invite(char *source, char *chan, char *nick);
+void charybdis_cmd_part(char *nick, char *chan, char *buf);
+void charybdis_cmd_391(char *source, char *timestr);
+void charybdis_cmd_250(char *buf);
+void charybdis_cmd_307(char *buf);
+void charybdis_cmd_311(char *buf);
+void charybdis_cmd_312(char *buf);
+void charybdis_cmd_317(char *buf);
+void charybdis_cmd_219(char *source, char *letter);
+void charybdis_cmd_401(char *source, char *who);
+void charybdis_cmd_318(char *source, char *who);
+void charybdis_cmd_242(char *buf);
+void charybdis_cmd_243(char *buf);
+void charybdis_cmd_211(char *buf);
+void charybdis_cmd_global(char *source, char *buf);
+void charybdis_cmd_global_legacy(char *source, char *fmt);
+void charybdis_cmd_sqline(char *mask, char *reason);
+void charybdis_cmd_squit(char *servname, char *message);
+void charybdis_cmd_svso(char *source, char *nick, char *flag);
+void charybdis_cmd_chg_nick(char *oldnick, char *newnick);
+void charybdis_cmd_svsnick(char *source, char *guest, time_t when);
+void charybdis_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void charybdis_cmd_connect(int servernum);
+void charybdis_cmd_svshold(char *nick);
+void charybdis_cmd_release_svshold(char *nick);
+void charybdis_cmd_unsgline(char *mask);
+void charybdis_cmd_unszline(char *mask);
+void charybdis_cmd_szline(char *mask, char *reason, char *whom);
+void charybdis_cmd_sgline(char *mask, char *reason);
+void charybdis_cmd_unban(char *name, char *nick);
+void charybdis_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void charybdis_cmd_svid_umode(char *nick, time_t ts);
+void charybdis_cmd_nc_change(User * u);
+void charybdis_cmd_svid_umode2(User * u, char *ts);
+void charybdis_cmd_svid_umode3(User * u, char *ts);
+void charybdis_cmd_eob();
+int charybdis_flood_mode_check(char *value);
+void charybdis_cmd_jupe(char *jserver, char *who, char *reason);
+int charybdis_valid_nick(char *nick);
+void charybdis_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/configure b/src/protocol/configure
new file mode 100755
index 000000000..68d2b7713
--- /dev/null
+++ b/src/protocol/configure
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+echo2 () {
+ $ECHO2 "$*$ECHO2SUF" # these are defined later
+}
+
+ECHO2SUF=''
+if [ "`echo -n a ; echo -n b`" = "ab" ] ; then
+ ECHO2='echo -n'
+elif [ "`echo 'a\c' ; echo 'b\c'`" = "ab" ] ; then
+ ECHO2='echo' ; ECHO2SUF='\c'
+elif [ "`printf 'a' 2>&1 ; printf 'b' 2>&1`" = "ab" ] ; then
+ ECHO2='printf "%s"'
+else
+ # oh well...
+ ECHO2='echo'
+fi
+export ECHO2 ECHO2SUF
+
+
+echo2 "SRCS=" > ./Makefile.inc
+FIRST=1
+for oldfile in *.c
+do
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$oldfile >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $oldfile >> ./Makefile.inc
+ fi
+ FIRST=0
+done
+echo "" >> ./Makefile.inc
+
+echo2 "SUBS=" >> ./Makefile.inc
+FIRST=1
+for dir in *
+do
+ if [ -d $dir ] ; then
+ if [ -f $dir/Makefile ] ; then
+ if [ "$FIRST" = 1 ] ; then
+ echo2 " "$dir >> ./Makefile.inc
+ else
+ echo "\\" >> ./Makefile.inc
+ echo2 " " $dir >> ./Makefile.inc
+ fi
+ FIRST=0
+ fi
+ fi
+done
+
+exit 0
+
diff --git a/src/protocol/dreamforge.c b/src/protocol/dreamforge.c
new file mode 100644
index 000000000..3809f3bd7
--- /dev/null
+++ b/src/protocol/dreamforge.c
@@ -0,0 +1,1384 @@
+/* DreamForge IRCD functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "dreamforge.h"
+
+IRCDVar myIrcd[] = {
+ {"DreamForge 4.6.7", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ "+", /* hostserv mode */
+ "+io", /* operserv mode */
+ "+o", /* botserv mode */
+ "+h", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-iklmnpstR", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 0, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to unset for chan admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "+d", /* Mode on Nick Change */
+ 0, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 0, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 0, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 1, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 1, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 0, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ 0, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ 0, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* Mode */
+ 0, /* Mode */
+ 0,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ CAPAB_TOKEN, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+void dreamforge_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ }
+ }
+}
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, UMODE_O, /* M N O */
+ 0, 0, 0, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, UMODE_c, /* a b c */
+ 0, 0, UMODE_f, /* d e f */
+ UMODE_g, UMODE_h, UMODE_i, /* g h i */
+ 0, UMODE_k, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ UMODE_s, 0, 0, /* s t u */
+ 0, UMODE_w, 0, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {0}, /* M */
+ {0}, /* N */
+ {0}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ if (ac != 2) {
+ do_nick(source, av[0], av[3], av[4], av[5], av[7],
+ strtoul(av[2], NULL, 10), strtoul(av[6], NULL, 0), 0, NULL,
+ NULL);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PROTOCTL", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+
+
+}
+
+/* *INDENT-ON* */
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+void dreamforge_cmd_sqline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+void dreamforge_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void dreamforge_cmd_svsadmin(char *server, int set)
+{
+ dreamforge_cmd_svsnoop(server, set);
+}
+
+void dreamforge_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+void dreamforge_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+/* PART */
+void dreamforge_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+
+void dreamforge_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+void dreamforge_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "JOIN %s", channel);
+}
+
+void dreamforge_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s :%s", host, user, reason);
+}
+
+
+void dreamforge_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+void dreamforge_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %s%s%s", u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+}
+
+
+void dreamforge_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+void anope_pong(char *servname)
+{
+ send_cmd(servname, "PONG %s", servname);
+}
+
+/* PASS */
+void dreamforge_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS :%s", pass);
+}
+
+void dreamforge_cmd_capab()
+{
+ send_cmd(NULL, "PROTOCTL NOQUIT");
+}
+
+/* SERVER name hop descript */
+void dreamforge_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void dreamforge_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ dreamforge_cmd_capab();
+ if (servernum == 1)
+ dreamforge_cmd_pass(RemotePassword);
+ if (servernum == 2)
+ dreamforge_cmd_pass(RemotePassword2);
+ if (servernum == 3)
+ dreamforge_cmd_pass(RemotePassword3);
+ dreamforge_cmd_server(ServerName, 1, ServerDesc);
+}
+
+void dreamforge_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+
+
+/* GLOBOPS */
+void dreamforge_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+void dreamforge_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+void dreamforge_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void dreamforge_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ dreamforge_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void dreamforge_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void dreamforge_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void dreamforge_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void dreamforge_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void dreamforge_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+void dreamforge_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+
+}
+
+/* QUIT */
+void dreamforge_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+/* 391 */
+void dreamforge_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void dreamforge_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void dreamforge_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void dreamforge_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void dreamforge_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void dreamforge_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void dreamforge_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void dreamforge_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void dreamforge_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void dreamforge_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void dreamforge_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void dreamforge_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void dreamforge_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), ServiceUser, ServiceHost, ServerName,
+ name);
+ anope_cmd_mode(nick, nick, "%s", modes);
+ dreamforge_cmd_sqline(nick, "Reserved for services");
+}
+
+void dreamforge_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ dreamforge_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void dreamforge_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void dreamforge_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void dreamforge_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void dreamforge_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* INVITE */
+void dreamforge_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PONG */
+void dreamforge_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+void dreamforge_cmd_bot_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), user, host, ServerName, real);
+ anope_cmd_mode(nick, nick, "MODE %s", modes);
+ dreamforge_cmd_sqline(nick, "Reserved for services");
+}
+
+/* SVSHOLD - set */
+void dreamforge_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void dreamforge_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSGLINE */
+void dreamforge_cmd_unsgline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSZLINE */
+void dreamforge_cmd_unszline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SZLINE */
+void dreamforge_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SGLINE */
+void dreamforge_cmd_sgline(char *mask, char *reason)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void dreamforge_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void dreamforge_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), user, host, ServerName, real);
+ anope_cmd_mode(nick, nick, "MODE %s", modes);
+}
+
+void dreamforge_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void dreamforge_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ /* Not Supported by this IRCD */
+}
+
+void dreamforge_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void dreamforge_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+void dreamforge_cmd_vhost_off(User * u)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void dreamforge_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s +d 1", nick);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void dreamforge_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "-r+d", "1");
+}
+
+/* SVSMODE +r */
+void dreamforge_cmd_svid_umode2(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+void dreamforge_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void dreamforge_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+void dreamforge_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void dreamforge_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void dreamforge_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int dreamforge_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+void dreamforge_cmd_eob()
+{
+ /* Not supported */
+}
+
+void dreamforge_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ dreamforge_cmd_squit(jserver, rbuf);
+ dreamforge_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void dreamforge_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int dreamforge_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int dreamforge_valid_chan(char *chan)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void dreamforge_cmd_ctcp(char *source, char *dest, char *buf)
+{
+
+ char *s;
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(dreamforge_cmd_svsnoop);
+ pmodule_cmd_remove_akill(dreamforge_cmd_remove_akill);
+ pmodule_cmd_topic(dreamforge_cmd_topic);
+ pmodule_cmd_vhost_off(dreamforge_cmd_vhost_off);
+ pmodule_cmd_akill(dreamforge_cmd_akill);
+ pmodule_cmd_svskill(dreamforge_cmd_svskill);
+ pmodule_cmd_svsmode(dreamforge_cmd_svsmode);
+ pmodule_cmd_372(dreamforge_cmd_372);
+ pmodule_cmd_372_error(dreamforge_cmd_372_error);
+ pmodule_cmd_375(dreamforge_cmd_375);
+ pmodule_cmd_376(dreamforge_cmd_376);
+ pmodule_cmd_nick(dreamforge_cmd_nick);
+ pmodule_cmd_guest_nick(dreamforge_cmd_guest_nick);
+ pmodule_cmd_mode(dreamforge_cmd_mode);
+ pmodule_cmd_bot_nick(dreamforge_cmd_bot_nick);
+ pmodule_cmd_kick(dreamforge_cmd_kick);
+ pmodule_cmd_notice_ops(dreamforge_cmd_notice_ops);
+ pmodule_cmd_notice(dreamforge_cmd_notice);
+ pmodule_cmd_notice2(dreamforge_cmd_notice2);
+ pmodule_cmd_privmsg(dreamforge_cmd_privmsg);
+ pmodule_cmd_privmsg2(dreamforge_cmd_privmsg2);
+ pmodule_cmd_serv_notice(dreamforge_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(dreamforge_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(dreamforge_cmd_bot_chan_mode);
+ pmodule_cmd_351(dreamforge_cmd_351);
+ pmodule_cmd_quit(dreamforge_cmd_quit);
+ pmodule_cmd_pong(dreamforge_cmd_pong);
+ pmodule_cmd_join(dreamforge_cmd_join);
+ pmodule_cmd_unsqline(dreamforge_cmd_unsqline);
+ pmodule_cmd_invite(dreamforge_cmd_invite);
+ pmodule_cmd_part(dreamforge_cmd_part);
+ pmodule_cmd_391(dreamforge_cmd_391);
+ pmodule_cmd_250(dreamforge_cmd_250);
+ pmodule_cmd_307(dreamforge_cmd_307);
+ pmodule_cmd_311(dreamforge_cmd_311);
+ pmodule_cmd_312(dreamforge_cmd_312);
+ pmodule_cmd_317(dreamforge_cmd_317);
+ pmodule_cmd_219(dreamforge_cmd_219);
+ pmodule_cmd_401(dreamforge_cmd_401);
+ pmodule_cmd_318(dreamforge_cmd_318);
+ pmodule_cmd_242(dreamforge_cmd_242);
+ pmodule_cmd_243(dreamforge_cmd_243);
+ pmodule_cmd_211(dreamforge_cmd_211);
+ pmodule_cmd_global(dreamforge_cmd_global);
+ pmodule_cmd_global_legacy(dreamforge_cmd_global_legacy);
+ pmodule_cmd_sqline(dreamforge_cmd_sqline);
+ pmodule_cmd_squit(dreamforge_cmd_squit);
+ pmodule_cmd_svso(dreamforge_cmd_svso);
+ pmodule_cmd_chg_nick(dreamforge_cmd_chg_nick);
+ pmodule_cmd_svsnick(dreamforge_cmd_svsnick);
+ pmodule_cmd_vhost_on(dreamforge_cmd_vhost_on);
+ pmodule_cmd_connect(dreamforge_cmd_connect);
+ pmodule_cmd_svshold(dreamforge_cmd_svshold);
+ pmodule_cmd_release_svshold(dreamforge_cmd_release_svshold);
+ pmodule_cmd_unsgline(dreamforge_cmd_unsgline);
+ pmodule_cmd_unszline(dreamforge_cmd_unszline);
+ pmodule_cmd_szline(dreamforge_cmd_szline);
+ pmodule_cmd_sgline(dreamforge_cmd_sgline);
+ pmodule_cmd_unban(dreamforge_cmd_unban);
+ pmodule_cmd_svsmode_chan(dreamforge_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(dreamforge_cmd_svid_umode);
+ pmodule_cmd_nc_change(dreamforge_cmd_nc_change);
+ pmodule_cmd_svid_umode2(dreamforge_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(dreamforge_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(dreamforge_cmd_svsjoin);
+ pmodule_cmd_svspart(dreamforge_cmd_svspart);
+ pmodule_cmd_swhois(dreamforge_cmd_swhois);
+ pmodule_cmd_eob(dreamforge_cmd_eob);
+ pmodule_flood_mode_check(dreamforge_flood_mode_check);
+ pmodule_cmd_jupe(dreamforge_cmd_jupe);
+ pmodule_valid_nick(dreamforge_valid_nick);
+ pmodule_valid_chan(dreamforge_valid_chan);
+ pmodule_cmd_ctcp(dreamforge_cmd_ctcp);
+ pmodule_set_umode(dreamforge_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("DreamForge 4.6.7");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/dreamforge.h b/src/protocol/dreamforge.h
new file mode 100644
index 000000000..057ea3b91
--- /dev/null
+++ b/src/protocol/dreamforge.h
@@ -0,0 +1,111 @@
+/* DreamForge IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001 /* Services Admin */
+#define UMODE_h 0x00000002 /* Help system operator */
+#define UMODE_i 0x00000004 /* makes user invisible */
+#define UMODE_o 0x00000008 /* Operator */
+#define UMODE_r 0x00000010 /* Nick set by services as registered */
+#define UMODE_w 0x00000020 /* send wallops to them */
+#define UMODE_A 0x00000040 /* Admin */
+#define UMODE_O 0x00000080 /* Local operator */
+#define UMODE_s 0x00000100 /* server notices such as kill */
+#define UMODE_k 0x00000200 /* Show server-kills... */
+#define UMODE_c 0x00000400 /* Show client information */
+#define UMODE_f 0x00000800 /* Receive flood warnings */
+#define UMODE_g 0x80000000 /* Shows some global messages */
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void dreamforge_set_umode(User * user, int ac, char **av);
+void dreamforge_cmd_svsnoop(char *server, int set);
+void dreamforge_cmd_remove_akill(char *user, char *host);
+void dreamforge_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void dreamforge_cmd_vhost_off(User * u);
+void dreamforge_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void dreamforge_cmd_svskill(char *source, char *user, char *buf);
+void dreamforge_cmd_svsmode(User * u, int ac, char **av);
+void dreamforge_cmd_372(char *source, char *msg);
+void dreamforge_cmd_372_error(char *source);
+void dreamforge_cmd_375(char *source);
+void dreamforge_cmd_376(char *source);
+void dreamforge_cmd_nick(char *nick, char *name, char *modes);
+void dreamforge_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void dreamforge_cmd_mode(char *source, char *dest, char *buf);
+void dreamforge_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void dreamforge_cmd_kick(char *source, char *chan, char *user, char *buf);
+void dreamforge_cmd_notice_ops(char *source, char *dest, char *buf);
+void dreamforge_cmd_notice(char *source, char *dest, char *buf);
+void dreamforge_cmd_notice2(char *source, char *dest, char *msg);
+void dreamforge_cmd_privmsg(char *source, char *dest, char *buf);
+void dreamforge_cmd_privmsg2(char *source, char *dest, char *msg);
+void dreamforge_cmd_serv_notice(char *source, char *dest, char *msg);
+void dreamforge_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void dreamforge_cmd_bot_chan_mode(char *nick, char *chan);
+void dreamforge_cmd_351(char *source);
+void dreamforge_cmd_quit(char *source, char *buf);
+void dreamforge_cmd_pong(char *servname, char *who);
+void dreamforge_cmd_join(char *user, char *channel, time_t chantime);
+void dreamforge_cmd_unsqline(char *user);
+void dreamforge_cmd_invite(char *source, char *chan, char *nick);
+void dreamforge_cmd_part(char *nick, char *chan, char *buf);
+void dreamforge_cmd_391(char *source, char *timestr);
+void dreamforge_cmd_250(char *buf);
+void dreamforge_cmd_307(char *buf);
+void dreamforge_cmd_311(char *buf);
+void dreamforge_cmd_312(char *buf);
+void dreamforge_cmd_317(char *buf);
+void dreamforge_cmd_219(char *source, char *letter);
+void dreamforge_cmd_401(char *source, char *who);
+void dreamforge_cmd_318(char *source, char *who);
+void dreamforge_cmd_242(char *buf);
+void dreamforge_cmd_243(char *buf);
+void dreamforge_cmd_211(char *buf);
+void dreamforge_cmd_global(char *source, char *buf);
+void dreamforge_cmd_global_legacy(char *source, char *fmt);
+void dreamforge_cmd_sqline(char *mask, char *reason);
+void dreamforge_cmd_squit(char *servname, char *message);
+void dreamforge_cmd_svso(char *source, char *nick, char *flag);
+void dreamforge_cmd_chg_nick(char *oldnick, char *newnick);
+void dreamforge_cmd_svsnick(char *source, char *guest, time_t when);
+void dreamforge_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void dreamforge_cmd_connect(int servernum);
+void dreamforge_cmd_svshold(char *nick);
+void dreamforge_cmd_release_svshold(char *nick);
+void dreamforge_cmd_unsgline(char *mask);
+void dreamforge_cmd_unszline(char *mask);
+void dreamforge_cmd_szline(char *mask, char *reason, char *whom);
+void dreamforge_cmd_sgline(char *mask, char *reason);
+void dreamforge_cmd_unban(char *name, char *nick);
+void dreamforge_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void dreamforge_cmd_svid_umode(char *nick, time_t ts);
+void dreamforge_cmd_nc_change(User * u);
+void dreamforge_cmd_svid_umode2(User * u, char *ts);
+void dreamforge_cmd_svid_umode3(User * u, char *ts);
+void dreamforge_cmd_eob();
+int dreamforge_flood_mode_check(char *value);
+void dreamforge_cmd_jupe(char *jserver, char *who, char *reason);
+int dreamforge_valid_nick(char *nick);
+void dreamforge_cmd_ctcp(char *source, char *dest, char *buf);
+
diff --git a/src/protocol/dummy/Makefile b/src/protocol/dummy/Makefile
new file mode 100644
index 000000000..ec93af36d
--- /dev/null
+++ b/src/protocol/dummy/Makefile
@@ -0,0 +1,6 @@
+all: DUMMY
+
+DUMMY:
+clean:
+distclean:
+install:
diff --git a/src/protocol/hybrid.c b/src/protocol/hybrid.c
new file mode 100644
index 000000000..454913517
--- /dev/null
+++ b/src/protocol/hybrid.c
@@ -0,0 +1,1573 @@
+/* Hybrid IRCD functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "hybrid.h"
+
+IRCDVar myIrcd[] = {
+ {"HybridIRCd 7.*", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ NULL, /* hostserv mode */
+ "+aio", /* operserv mode */
+ "+o", /* botserv mode */
+ "+h", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ NULL, /* hostserv alias mode */
+ "+aio", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 3, /* Chan Max Symbols */
+ "-ailmnpst", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 0, /* SVSNICK */
+ 0, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for admin */
+ NULL, /* Mode to unset for admin */
+ NULL, /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ NULL, /* Mode on UnReg */
+ NULL, /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 1, /* Join 2 Set */
+ 1, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 0, /* Chan Reg */
+ 0, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* UMODE */
+ 0, /* O:LINE */
+ 0, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ 0, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 0, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 0, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ CAPAB_QS, /* QS */
+ CAPAB_UID, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+
+void hybrid_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ send_cmd(ServerName, "SVSMODE %s -r", user->nick);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ 0, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, 0, /* M N O */
+ 0, 0, 0, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, UMODE_c, /* a b c */
+ UMODE_d, 0, UMODE_f, /* d e f */
+ UMODE_g, 0, UMODE_i, /* g h i */
+ 0, UMODE_k, UMODE_l, /* j k l */
+ 0, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ UMODE_s, 0, UMODE_u, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ UMODE_y, /* y */
+ UMODE_z, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 'a', /* (33) ! */
+ 0, 0, 0,
+ 'h',
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {0}, /* M */
+ {0}, /* N */
+ {0}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {0},
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {CMODE_a, 0, NULL, NULL},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {0},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'a', CMODE_a, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void hybrid_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ hybrid_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void hybrid_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void hybrid_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void hybrid_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void hybrid_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void hybrid_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void hybrid_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "OPERWALL :%s", buf);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void hybrid_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ if (ac != 2) {
+ User *user = do_nick(source, av[0], av[4], av[5], av[6], av[7],
+ strtoul(av[2], NULL, 10), 0, 0, NULL, NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac == 4) {
+ do_topic(source, ac, av);
+ } else {
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tburst(char *source, int ac, char **av)
+{
+ if (ac != 5)
+ return MOD_CONT;
+
+ av[0] = av[1];
+ av[1] = av[3];
+ av[3] = av[4];
+ do_topic(source, 4, av);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("TBURST", anope_event_tburst); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+/* m = createMessage("EOB", anope_event_eob); addCoreMessage(IRCD,m); */
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+void hybrid_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(ServerName, "RESV * %s :%s", mask, reason);
+}
+void hybrid_cmd_unsgline(char *mask)
+{
+ if (!mask) {
+ return;
+ }
+
+ send_cmd(ServerName, "UNXLINE * %s", mask);
+}
+
+void hybrid_cmd_unszline(char *mask)
+{
+ /* Does not support */
+}
+void hybrid_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* Does not support */
+}
+
+void hybrid_cmd_svsnoop(char *server, int set)
+{
+ /* does not support */
+}
+
+void hybrid_cmd_svsadmin(char *server, int set)
+{
+ hybrid_cmd_svsnoop(server, set);
+}
+
+void hybrid_cmd_sgline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(ServerName, "XLINE * %s 0 :%s", mask, reason);
+}
+
+void hybrid_cmd_remove_akill(char *user, char *host)
+{
+ /* hybrid seems to support UNKLINE -Certus */
+ send_cmd(s_OperServ, "UNKLINE * %s %s", user, host);
+}
+
+void hybrid_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s :%s", chan, topic);
+}
+
+void hybrid_cmd_vhost_off(User * u)
+{
+ /* does not support vhosting */
+}
+
+void hybrid_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ /* does not support vhosting */
+}
+
+void hybrid_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+
+ send_cmd(ServerName, "UNRESV * %s", user);
+}
+
+void hybrid_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(NULL, "SJOIN %ld %s + :%s", (long int) chantime, channel,
+ user);
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void hybrid_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(s_OperServ, "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time(NULL)), user, host, reason);
+}
+
+void hybrid_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+
+void hybrid_cmd_svsmode(User * u, int ac, char **av)
+{
+ /* Hybrid does not support SVSMODE */
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void hybrid_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 5 5 0 :%ld", (long int) time(NULL));
+}
+
+/* CAPAB */
+/*
+ QS - Can handle quit storm removal
+ EX - Can do channel +e exemptions
+ CHW - Can do channel wall @#
+ LL - Can do lazy links
+ IE - Can do invite exceptions
+ EOB - Can do EOB message
+ KLN - Can do KLINE message
+ GLN - Can do GLINE message
+ HOPS - can do half ops (+h)
+ HUB - This server is a HUB
+ AOPS - Can do anon ops (+a)
+ UID - Can do UIDs
+ ZIP - Can do ZIPlinks
+ ENC - Can do ENCrypted links
+ KNOCK - supports KNOCK
+ TBURST - supports TBURST
+ PARA - supports invite broadcasting for +p
+ ENCAP - ?
+*/
+void hybrid_cmd_capab()
+{
+ send_cmd(NULL,
+ "CAPAB :QS EX CHW IE KLN GLN HOPS HUB AOPS KNOCK TBURST PARA");
+}
+
+/* PASS */
+void hybrid_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER name hop descript */
+void hybrid_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+void hybrid_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1)
+ hybrid_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ hybrid_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ hybrid_cmd_pass(RemotePassword3);
+
+ hybrid_cmd_capab();
+ hybrid_cmd_server(ServerName, 1, ServerDesc);
+ hybrid_cmd_svinfo();
+}
+
+void hybrid_cmd_svsinfo()
+{
+ /* not used */
+}
+
+
+
+void hybrid_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+
+}
+
+void hybrid_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ hybrid_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_eob(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+
+ return MOD_CONT;
+}
+
+void hybrid_cmd_eob()
+{
+/* send_cmd(ServerName, "EOB"); */
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+void hybrid_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void hybrid_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void hybrid_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void hybrid_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void hybrid_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void hybrid_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void hybrid_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void hybrid_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void hybrid_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void hybrid_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void hybrid_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void hybrid_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void hybrid_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void hybrid_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void hybrid_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void hybrid_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void hybrid_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+void hybrid_cmd_nick(char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ ServerName, (name));
+}
+
+void hybrid_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void hybrid_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+void hybrid_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+/* QUIT */
+void hybrid_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+/* PONG */
+void hybrid_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/* INVITE */
+void hybrid_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* SQUIT */
+void hybrid_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+void hybrid_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ int argvsize = 8;
+ int argc;
+ char **argv;
+ char *str;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ /* We get the params as one arg, we should split it for capab_parse */
+ argv = scalloc(argvsize, sizeof(char *));
+ argc = 0;
+ while ((str = myStrGetToken(av[0], ' ', argc))) {
+ if (argc == argvsize) {
+ argvsize += 8;
+ argv = srealloc(argv, argvsize * sizeof(char *));
+ }
+ argv[argc] = str;
+ argc++;
+ }
+
+ capab_parse(argc, argv);
+
+ /* Free our built ac/av */
+ for (argvsize = 0; argvsize < argc; argvsize++) {
+ free(argv[argvsize]);
+ }
+ free(argv);
+
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void hybrid_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void hybrid_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void hybrid_cmd_svsnick(char *nick, char *newnick, time_t when)
+{
+ /* Not Supported by this IRCD */
+}
+
+void hybrid_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+}
+
+void hybrid_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void hybrid_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void hybrid_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void hybrid_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s +d 1", nick);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void hybrid_cmd_nc_change(User * u)
+{
+ /* not used */
+}
+
+/* SVSMODE +d */
+void hybrid_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used */
+}
+
+
+void hybrid_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void hybrid_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+void hybrid_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void hybrid_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void hybrid_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int hybrid_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void hybrid_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ hybrid_cmd_squit(jserver, rbuf);
+ hybrid_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int hybrid_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int hybrid_valid_chan(char *chan)
+{
+ /* no hard coded invalid chans */
+ return 1;
+}
+
+
+void hybrid_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(hybrid_cmd_svsnoop);
+ pmodule_cmd_remove_akill(hybrid_cmd_remove_akill);
+ pmodule_cmd_topic(hybrid_cmd_topic);
+ pmodule_cmd_vhost_off(hybrid_cmd_vhost_off);
+ pmodule_cmd_akill(hybrid_cmd_akill);
+ pmodule_cmd_svskill(hybrid_cmd_svskill);
+ pmodule_cmd_svsmode(hybrid_cmd_svsmode);
+ pmodule_cmd_372(hybrid_cmd_372);
+ pmodule_cmd_372_error(hybrid_cmd_372_error);
+ pmodule_cmd_375(hybrid_cmd_375);
+ pmodule_cmd_376(hybrid_cmd_376);
+ pmodule_cmd_nick(hybrid_cmd_nick);
+ pmodule_cmd_guest_nick(hybrid_cmd_guest_nick);
+ pmodule_cmd_mode(hybrid_cmd_mode);
+ pmodule_cmd_bot_nick(hybrid_cmd_bot_nick);
+ pmodule_cmd_kick(hybrid_cmd_kick);
+ pmodule_cmd_notice_ops(hybrid_cmd_notice_ops);
+ pmodule_cmd_notice(hybrid_cmd_notice);
+ pmodule_cmd_notice2(hybrid_cmd_notice2);
+ pmodule_cmd_privmsg(hybrid_cmd_privmsg);
+ pmodule_cmd_privmsg2(hybrid_cmd_privmsg2);
+ pmodule_cmd_serv_notice(hybrid_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(hybrid_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(hybrid_cmd_bot_chan_mode);
+ pmodule_cmd_351(hybrid_cmd_351);
+ pmodule_cmd_quit(hybrid_cmd_quit);
+ pmodule_cmd_pong(hybrid_cmd_pong);
+ pmodule_cmd_join(hybrid_cmd_join);
+ pmodule_cmd_unsqline(hybrid_cmd_unsqline);
+ pmodule_cmd_invite(hybrid_cmd_invite);
+ pmodule_cmd_part(hybrid_cmd_part);
+ pmodule_cmd_391(hybrid_cmd_391);
+ pmodule_cmd_250(hybrid_cmd_250);
+ pmodule_cmd_307(hybrid_cmd_307);
+ pmodule_cmd_311(hybrid_cmd_311);
+ pmodule_cmd_312(hybrid_cmd_312);
+ pmodule_cmd_317(hybrid_cmd_317);
+ pmodule_cmd_219(hybrid_cmd_219);
+ pmodule_cmd_401(hybrid_cmd_401);
+ pmodule_cmd_318(hybrid_cmd_318);
+ pmodule_cmd_242(hybrid_cmd_242);
+ pmodule_cmd_243(hybrid_cmd_243);
+ pmodule_cmd_211(hybrid_cmd_211);
+ pmodule_cmd_global(hybrid_cmd_global);
+ pmodule_cmd_global_legacy(hybrid_cmd_global_legacy);
+ pmodule_cmd_sqline(hybrid_cmd_sqline);
+ pmodule_cmd_squit(hybrid_cmd_squit);
+ pmodule_cmd_svso(hybrid_cmd_svso);
+ pmodule_cmd_chg_nick(hybrid_cmd_chg_nick);
+ pmodule_cmd_svsnick(hybrid_cmd_svsnick);
+ pmodule_cmd_vhost_on(hybrid_cmd_vhost_on);
+ pmodule_cmd_connect(hybrid_cmd_connect);
+ pmodule_cmd_svshold(hybrid_cmd_svshold);
+ pmodule_cmd_release_svshold(hybrid_cmd_release_svshold);
+ pmodule_cmd_unsgline(hybrid_cmd_unsgline);
+ pmodule_cmd_unszline(hybrid_cmd_unszline);
+ pmodule_cmd_szline(hybrid_cmd_szline);
+ pmodule_cmd_sgline(hybrid_cmd_sgline);
+ pmodule_cmd_unban(hybrid_cmd_unban);
+ pmodule_cmd_svsmode_chan(hybrid_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(hybrid_cmd_svid_umode);
+ pmodule_cmd_nc_change(hybrid_cmd_nc_change);
+ pmodule_cmd_svid_umode2(hybrid_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(hybrid_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(hybrid_cmd_svsjoin);
+ pmodule_cmd_svspart(hybrid_cmd_svspart);
+ pmodule_cmd_swhois(hybrid_cmd_swhois);
+ pmodule_cmd_eob(hybrid_cmd_eob);
+ pmodule_flood_mode_check(hybrid_flood_mode_check);
+ pmodule_cmd_jupe(hybrid_cmd_jupe);
+ pmodule_valid_nick(hybrid_valid_nick);
+ pmodule_valid_chan(hybrid_valid_chan);
+ pmodule_cmd_ctcp(hybrid_cmd_ctcp);
+ pmodule_set_umode(hybrid_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("Hybrid IRCd 7.0");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/hybrid.h b/src/protocol/hybrid.h
new file mode 100644
index 000000000..b4437888c
--- /dev/null
+++ b/src/protocol/hybrid.h
@@ -0,0 +1,115 @@
+/* Hybrid IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001 /* Admin status */
+#define UMODE_b 0x00000080 /* See bot and drone flooding notices */
+#define UMODE_c 0x00000100 /* Client connection/quit notices */
+#define UMODE_d 0x00000200 /* See debugging notices */
+#define UMODE_f 0x00000400 /* See I: line full notices */
+#define UMODE_g 0x00000800 /* Server Side Ignore */
+#define UMODE_i 0x00000004 /* Not shown in NAMES or WHO unless you share a channel */
+#define UMODE_k 0x00001000 /* See server generated KILL messages */
+#define UMODE_l 0x00002000 /* See LOCOPS messages */
+#define UMODE_n 0x00004000 /* See client nick changes */
+#define UMODE_o 0x00000008 /* Operator status */
+#define UMODE_r 0x00000010 /* See rejected client notices */
+#define UMODE_s 0x00008000 /* See general server notices */
+#define UMODE_u 0x00010000 /* See unauthorized client notices */
+#define UMODE_w 0x00000020 /* See server generated WALLOPS */
+#define UMODE_x 0x00020000 /* See remote server connection and split notices */
+#define UMODE_y 0x00040000 /* See LINKS, STATS (if configured), TRACE notices */
+#define UMODE_z 0x00080000 /* See oper generated WALLOPS */
+
+#define CMODE_i 0x00000001 /* Invite only */
+#define CMODE_m 0x00000002 /* Users without +v/h/o cannot send text to the channel */
+#define CMODE_n 0x00000004 /* Users must be in the channel to send text to it */
+#define CMODE_p 0x00000008 /* Private is obsolete, this now restricts KNOCK */
+#define CMODE_s 0x00000010 /* The channel does not show up on NAMES or LIST */
+#define CMODE_t 0x00000020 /* Only chanops can change the topic */
+#define CMODE_k 0x00000040 /* Key/password for the channel. */
+#define CMODE_l 0x00000080 /* Limit the number of users in a channel */
+#define CMODE_a 0x00000400 /* Anonymous ops, chanops are hidden */
+
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t
+
+void hybrid_set_umode(User * user, int ac, char **av);
+void hybrid_cmd_svsnoop(char *server, int set);
+void hybrid_cmd_remove_akill(char *user, char *host);
+void hybrid_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void hybrid_cmd_vhost_off(User * u);
+void hybrid_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void hybrid_cmd_svskill(char *source, char *user, char *buf);
+void hybrid_cmd_svsmode(User * u, int ac, char **av);
+void hybrid_cmd_372(char *source, char *msg);
+void hybrid_cmd_372_error(char *source);
+void hybrid_cmd_375(char *source);
+void hybrid_cmd_376(char *source);
+void hybrid_cmd_nick(char *nick, char *name, char *modes);
+void hybrid_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void hybrid_cmd_mode(char *source, char *dest, char *buf);
+void hybrid_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void hybrid_cmd_kick(char *source, char *chan, char *user, char *buf);
+void hybrid_cmd_notice_ops(char *source, char *dest, char *buf);
+void hybrid_cmd_notice(char *source, char *dest, char *buf);
+void hybrid_cmd_notice2(char *source, char *dest, char *msg);
+void hybrid_cmd_privmsg(char *source, char *dest, char *buf);
+void hybrid_cmd_privmsg2(char *source, char *dest, char *msg);
+void hybrid_cmd_serv_notice(char *source, char *dest, char *msg);
+void hybrid_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void hybrid_cmd_bot_chan_mode(char *nick, char *chan);
+void hybrid_cmd_351(char *source);
+void hybrid_cmd_quit(char *source, char *buf);
+void hybrid_cmd_pong(char *servname, char *who);
+void hybrid_cmd_join(char *user, char *channel, time_t chantime);
+void hybrid_cmd_unsqline(char *user);
+void hybrid_cmd_invite(char *source, char *chan, char *nick);
+void hybrid_cmd_part(char *nick, char *chan, char *buf);
+void hybrid_cmd_391(char *source, char *timestr);
+void hybrid_cmd_250(char *buf);
+void hybrid_cmd_307(char *buf);
+void hybrid_cmd_311(char *buf);
+void hybrid_cmd_312(char *buf);
+void hybrid_cmd_317(char *buf);
+void hybrid_cmd_219(char *source, char *letter);
+void hybrid_cmd_401(char *source, char *who);
+void hybrid_cmd_318(char *source, char *who);
+void hybrid_cmd_242(char *buf);
+void hybrid_cmd_243(char *buf);
+void hybrid_cmd_211(char *buf);
+void hybrid_cmd_global(char *source, char *buf);
+void hybrid_cmd_global_legacy(char *source, char *fmt);
+void hybrid_cmd_sqline(char *mask, char *reason);
+void hybrid_cmd_squit(char *servname, char *message);
+void hybrid_cmd_svso(char *source, char *nick, char *flag);
+void hybrid_cmd_chg_nick(char *oldnick, char *newnick);
+void hybrid_cmd_svsnick(char *source, char *guest, time_t when);
+void hybrid_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void hybrid_cmd_connect(int servernum);
+void hybrid_cmd_svshold(char *nick);
+void hybrid_cmd_release_svshold(char *nick);
+void hybrid_cmd_unsgline(char *mask);
+void hybrid_cmd_unszline(char *mask);
+void hybrid_cmd_szline(char *mask, char *reason, char *whom);
+void hybrid_cmd_sgline(char *mask, char *reason);
+void hybrid_cmd_unban(char *name, char *nick);
+void hybrid_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void hybrid_cmd_svid_umode(char *nick, time_t ts);
+void hybrid_cmd_nc_change(User * u);
+void hybrid_cmd_svid_umode2(User * u, char *ts);
+void hybrid_cmd_svid_umode3(User * u, char *ts);
+void hybrid_cmd_eob();
+int hybrid_flood_mode_check(char *value);
+void hybrid_cmd_jupe(char *jserver, char *who, char *reason);
+int hybrid_valid_nick(char *nick);
+void hybrid_cmd_ctcp(char *source, char *dest, char *buf);
diff --git a/src/protocol/inspircd10.c b/src/protocol/inspircd10.c
new file mode 100644
index 000000000..30ced466d
--- /dev/null
+++ b/src/protocol/inspircd10.c
@@ -0,0 +1,1713 @@
+/* inspircd beta 6+ functions
+ *
+ * (C) 2005 Craig Edwards <brain@inspircd.org>
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "inspircd10.h"
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef _WIN32
+#include "winsock.h"
+int inet_aton (const char *name, struct in_addr *addr)
+{
+ uint32 a = inet_addr (name);
+ addr->s_addr = a;
+ return a != (uint32)-1;
+}
+#endif
+
+IRCDVar myIrcd[] = {
+ {"InspIRCd 1.0", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ "+o", /* hostserv mode */
+ "+io", /* operserv mode */
+ "+o", /* botserv mode */
+ "+o", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+io", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+o", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+s", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-cilmnpstuzACGHKNOQRSV", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+r", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r", /* Mode on UnReg */
+ "-r", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 4, /* Number of server args */
+ 0, /* Join 2 Set */
+ 1, /* Join 2 Message */
+ 0, /* Has exceptions +e */
+ 1, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 1, /* O:LINE */
+ 0, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_K, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 1, /* +L */
+ CMODE_f,
+ CMODE_L,
+ 0,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support inspircd TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ CAPAB_SSJ3, /* SSJ3 */
+ CAPAB_NICK2, /* NICK2 */
+ 0, /* UMODE2 */
+ CAPAB_VL, /* VL */
+ CAPAB_TLKEXT, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0,
+ 0, 0}
+};
+
+unsigned long umodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, UMODE_A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0, UMODE_a, 0, 0, 0, 0, 0,
+ UMODE_g,
+ UMODE_h, UMODE_i, 0, 0, 0, 0, 0, UMODE_o,
+ 0,
+ 0, UMODE_r, 0, 0, 0, 0, UMODE_w,
+ UMODE_x,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 0,
+ 0, 0, 0,
+ 'q',
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'a', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {NULL, NULL},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {CMODE_C, 0, NULL, NULL}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {CMODE_G, 0, NULL, NULL}, /* G */
+ {CMODE_H, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, set_redirect, cs_set_redirect},
+ {0}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {CMODE_Q, 0, NULL, NULL}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {CMODE_V, 0, NULL, NULL}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {CMODE_f, 0, set_flood, cs_set_flood},
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {CMODE_u, 0, NULL, NULL},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL},
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'f', CMODE_f, 0, get_flood, cs_get_flood},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'u', CMODE_u, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'G', CMODE_G, 0, NULL, NULL},
+ {'H', CMODE_H, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, get_redirect, cs_get_redirect},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'Q', CMODE_Q, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {'V', CMODE_V, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op},
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+void inspircd_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","!protect","!deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SAMODE", anope_event_samode); addCoreMessage(IRCD,m);
+ m = createMessage("SANICK", anope_event_sanick); addCoreMessage(IRCD,m);
+ m = createMessage("SAJOIN", anope_event_sajoin); addCoreMessage(IRCD,m);
+ m = createMessage("SAPART", anope_event_sapart); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode) ;addCoreMessage(IRCD,m);
+ m = createMessage("QLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ELINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ADDLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("FHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ m = createMessage("FNAME", anope_event_chgname); addCoreMessage(IRCD,m);
+ m = createMessage("METADATA", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+ m = createMessage("FJOIN", anope_event_fjoin); addCoreMessage(IRCD,m);
+ m = createMessage("FMODE", anope_event_fmode); addCoreMessage(IRCD,m);
+ m = createMessage("FTOPIC", anope_event_ftopic); addCoreMessage(IRCD,m);
+ m = createMessage("VERSION", anope_event_version); addCoreMessage(IRCD,m);
+ m = createMessage("OPERTYPE", anope_event_opertype); addCoreMessage(IRCD,m);
+ m = createMessage("IDLE", anope_event_idle); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+void inspircd_cmd_svsnoop(char *server, int set)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_svsadmin(char *server, int set)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(s_OperServ, "GLINE %s@%s", user, host);
+}
+
+void inspircd_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "FTOPIC %s %lu %s :%s", chan, (unsigned long int) when, whosetit, topic);
+}
+
+void inspircd_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "MODE %s -x", u->nick);
+}
+
+void inspircd_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(ServerName, "ADDLINE G %s@%s %s %ld %ld :%s", user, host, who, (long int) when, (long int) 86400 * 2, reason);
+}
+
+void inspircd_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+void inspircd_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(s_NickServ, "MODE %s %s%s%s", u->nick, av[0], (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+}
+
+
+void inspircd_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void inspircd_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void inspircd_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void inspircd_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void inspircd_cmd_nick(char *nick, char *name, char *modes)
+{
+ /* :test.chatspike.net NICK 1133519355 Brain synapse.brainbox.winbot.co.uk netadmin.chatspike.net ~brain +xwsioS 10.0.0.2 :Craig Edwards */
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",(long int) time(NULL),nick,ServiceHost,ServiceHost,ServiceUser,modes,name);
+ send_cmd(ServerName, "OPERTYPE Service");
+}
+
+void inspircd_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",(long int) time(NULL),nick,host,host,user,modes,real);
+}
+
+void inspircd_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+ send_cmd(source ? source : s_OperServ, "MODE %s %s", dest, buf);
+}
+
+int anope_event_version(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_idle(char *source, int ac, char **av)
+{
+ if (ac == 1)
+ {
+ send_cmd(av[0],"IDLE %s %ld 0",source,(long int) time(NULL));
+ }
+ return MOD_CONT;
+}
+
+int anope_event_ftopic(char *source, int ac, char **av)
+{
+ /* :source FTOPIC channel ts setby :topic */
+ char* temp;
+ if (ac < 4)
+ return MOD_CONT;
+ temp = av[1]; /* temp now holds ts */
+ av[1] = av[2]; /* av[1] now holds set by */
+ av[2] = temp; /* av[2] now holds ts */
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_opertype(char* source, int ac, char**av)
+{
+ /* opertype is equivalent to mode +o because servers
+ dont do this directly */
+ User* u;
+ u = finduser(source);
+ if (u && !is_oper(u)) {
+ char* newav[2];
+ newav[0] = source;
+ newav[1] = "+o";
+ return anope_event_mode(source, 2, newav);
+ }
+ else return MOD_CONT;
+}
+
+int anope_event_fmode(char *source, int ac, char **av)
+{
+ /* :source FMODE #test +nt */
+ if (ac != 2)
+ return MOD_CONT;
+ return anope_event_mode(source, ac, av);
+}
+
+int anope_event_samode(char *source, int ac, char **av)
+{
+ /* :source SAMODE targets modes */
+ if (ac < 2)
+ return MOD_CONT;
+ return anope_event_mode(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_sanick(char *source, int ac, char **av)
+{
+ /* :source SANICK old new */
+ if (ac != 2)
+ return MOD_CONT;
+ do_nick(av[0], av[1], NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+ return MOD_CONT;
+}
+
+int anope_event_sajoin(char *source, int ac, char **av)
+{
+ char* newav[1];
+ if (ac != 2)
+ return MOD_CONT;
+ newav[0] = av[1];
+ do_join(av[0], 1, newav);
+ return MOD_CONT;
+}
+
+int anope_event_sapart(char *source, int ac, char **av)
+{
+ char* newav[1];
+ if (ac < 2)
+ return MOD_CONT;
+ newav[0] = av[1];
+ do_part(av[0], 1, newav);
+ return MOD_CONT;
+}
+
+int anope_event_fjoin(char *source, int ac, char **av)
+{
+ char* newav[127];
+ char people[1024];
+ int i = 0;
+
+ if (ac < 3)
+ return MOD_CONT;
+
+ newav[0] = av[1];
+ newav[1] = av[0];
+ newav[2] = "+";
+ newav[3] = people;
+
+ *people = '\0';
+
+ for (i = 2; i < ac; i++)
+ {
+ if (i > 2)
+ strncat(people," ",1023);
+ strncat(people,av[i],1023);
+ }
+ do_sjoin(source, 4, newav);
+ return MOD_CONT;
+}
+
+void inspircd_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",(long int) time(NULL),nick,host,host,user,modes,real);
+ send_cmd(ServerName, "OPERTYPE Bot");
+}
+
+void inspircd_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s :%s", chan, user, user);
+ }
+}
+
+void inspircd_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void inspircd_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ inspircd_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void inspircd_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void inspircd_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void inspircd_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void inspircd_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void inspircd_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+
+void inspircd_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+void inspircd_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* QUIT */
+void inspircd_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT :Exiting");
+ }
+}
+
+/* PROTOCTL */
+void inspircd_cmd_protoctl()
+{
+}
+
+static char currentpass[1024];
+
+/* PASS */
+void inspircd_cmd_pass(char *pass)
+{
+ strncpy(currentpass,pass,1024);
+}
+
+/* SERVER services-dev.chatspike.net password 0 :Description here */
+void inspircd_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(ServerName, "SERVER %s %s %d :%s", servname, currentpass, hop, descript);
+}
+
+/* PONG */
+void inspircd_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/* JOIN */
+/* Althought inspircd 3.2 does not need the timestamp others do so
+ we get it in the common function call */
+void inspircd_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "JOIN %s", channel);
+}
+
+/* UNSQLINE */
+void inspircd_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+ send_cmd(s_OperServ, "QLINE %s", user);
+}
+
+/* CHGHOST */
+void inspircd_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(s_OperServ,"CHGHOST %s %s", nick, vhost);
+}
+
+/* CHGIDENT */
+void inspircd_cmd_chgident(char *nick, char *vIdent)
+{
+ if (!nick || !vIdent) {
+ return;
+ }
+ send_cmd(s_OperServ, "CHGIDENT %s %s", nick, vIdent);
+}
+
+/* INVITE */
+void inspircd_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PART */
+void inspircd_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s :Leaving", chan);
+ }
+}
+
+/* 391 */
+void inspircd_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void inspircd_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void inspircd_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void inspircd_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void inspircd_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void inspircd_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void inspircd_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void inspircd_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void inspircd_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void inspircd_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void inspircd_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void inspircd_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void inspircd_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* SQLINE */
+void inspircd_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(ServerName, "ADDLINE Q %s %s %ld 0 :%s", mask, s_OperServ, (long int) time(NULL), reason);
+}
+
+/* SQUIT */
+void inspircd_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(ServerName, "SQUIT %s :%s", servname, message);
+}
+
+/* SVSO */
+void inspircd_cmd_svso(char *source, char *nick, char *flag)
+{
+}
+
+/* NICK <newnick> */
+void inspircd_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/* SVSNICK */
+void inspircd_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ /* Please note that inspircd will now echo back a nickchange for this SVSNICK */
+ send_cmd(ServerName, "SVSNICK %s %s :%lu", source, guest, (unsigned long)when);
+}
+
+/* Functions that use serval cmd functions */
+
+void inspircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (!nick) {
+ return;
+ }
+ if (vIdent) {
+ inspircd_cmd_chgident(nick, vIdent);
+ }
+ inspircd_cmd_chghost(nick, vhost);
+}
+
+void inspircd_cmd_connect(int servernum)
+{
+ if (servernum == 1) {
+ inspircd_cmd_pass(RemotePassword);
+ }
+ if (servernum == 2) {
+ inspircd_cmd_pass(RemotePassword2);
+ }
+ if (servernum == 3) {
+ inspircd_cmd_pass(RemotePassword3);
+ }
+ inspircd_cmd_server(ServerName, 0, ServerDesc);
+ send_cmd(NULL,"BURST");
+ send_cmd(ServerName, "VERSION :Anope-%s %s :%s - %s -- %s", version_number, ServerName, ircd->name, version_flags, version_build);
+
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ /* ((ac > 1) ? av[1] : ServerName) */
+ inspircd_cmd_pong(ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+/* Taken from hybrid.c, topic syntax is identical */
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ /* InspIRCd lets opers change another
+ users modes, we have to kludge this
+ as it slightly breaks RFC1459
+ */
+ if (!strcasecmp(source,av[0]))
+ {
+ do_umode(source, ac, av);
+ }
+ else
+ {
+ do_umode(av[0], ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: FNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+ struct in_addr addy;
+ uint32* ad = (uint32*)&addy;
+
+ if (ac != 1) {
+ if (ac == 8) {
+ inet_aton(av[6],&addy);
+ user = do_nick("", av[1], /* nick */
+ av[4], /* username */
+ av[2], /* realhost */
+ source, /* server */
+ av[7], /* realname */
+ strtoul(av[0], NULL, 10),
+ 0,
+ htonl(*ad),
+ av[3],
+ NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[5]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ 0, 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: FHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void inspircd_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void inspircd_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSGLINE */
+void inspircd_cmd_unsgline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSZLINE */
+void inspircd_cmd_unszline(char *mask)
+{
+ send_cmd(s_OperServ, "ZLINE %s", mask);
+}
+
+/* SZLINE */
+void inspircd_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(ServerName, "ADDLINE Z %s %s %ld 0 :%s", mask, whom, (long int) time(NULL), reason);
+}
+
+/* SGLINE */
+void inspircd_cmd_sgline(char *mask, char *reason)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void inspircd_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void inspircd_cmd_svid_umode(char *nick, time_t ts)
+{
+ if (debug)
+ alog("debug: common_svsmode(0)");
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void inspircd_cmd_nc_change(User * u)
+{
+ if (debug)
+ alog("debug: common_svsmode(1)");
+ common_svsmode(u, "-r", NULL);
+}
+
+/* SVSMODE +r */
+void inspircd_cmd_svid_umode2(User * u, char *ts)
+{
+ if (debug)
+ alog("debug: common_svsmode(2)");
+ common_svsmode(u, "+r", NULL);
+}
+
+void inspircd_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+void inspircd_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(source, "SAJOIN %s %s", nick, chan);
+}
+
+void inspircd_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SAPART %s %s", nick, chan);
+}
+
+void inspircd_cmd_swhois(char *source, char *who, char *mask)
+{
+}
+
+void inspircd_cmd_eob()
+{
+ send_cmd(NULL,"ENDBURST");
+}
+
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int inspircd_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void inspircd_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ inspircd_cmd_squit(jserver, rbuf);
+ inspircd_cmd_server(jserver, 1, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void inspircd_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : s_OperServ, "GLOBOPS :%s", fmt);
+}
+
+int inspircd_valid_nick(char *nick)
+{
+ return 1;
+}
+
+int inspircd_valid_chan(char *chan)
+{
+ return 1;
+}
+
+
+void inspircd_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s\1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(inspircd_cmd_svsnoop);
+ pmodule_cmd_remove_akill(inspircd_cmd_remove_akill);
+ pmodule_cmd_topic(inspircd_cmd_topic);
+ pmodule_cmd_vhost_off(inspircd_cmd_vhost_off);
+ pmodule_cmd_akill(inspircd_cmd_akill);
+ pmodule_cmd_svskill(inspircd_cmd_svskill);
+ pmodule_cmd_svsmode(inspircd_cmd_svsmode);
+ pmodule_cmd_372(inspircd_cmd_372);
+ pmodule_cmd_372_error(inspircd_cmd_372_error);
+ pmodule_cmd_375(inspircd_cmd_375);
+ pmodule_cmd_376(inspircd_cmd_376);
+ pmodule_cmd_nick(inspircd_cmd_nick);
+ pmodule_cmd_guest_nick(inspircd_cmd_guest_nick);
+ pmodule_cmd_mode(inspircd_cmd_mode);
+ pmodule_cmd_bot_nick(inspircd_cmd_bot_nick);
+ pmodule_cmd_kick(inspircd_cmd_kick);
+ pmodule_cmd_notice_ops(inspircd_cmd_notice_ops);
+ pmodule_cmd_notice(inspircd_cmd_notice);
+ pmodule_cmd_notice2(inspircd_cmd_notice2);
+ pmodule_cmd_privmsg(inspircd_cmd_privmsg);
+ pmodule_cmd_privmsg2(inspircd_cmd_privmsg2);
+ pmodule_cmd_serv_notice(inspircd_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(inspircd_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(inspircd_cmd_bot_chan_mode);
+ pmodule_cmd_351(inspircd_cmd_351);
+ pmodule_cmd_quit(inspircd_cmd_quit);
+ pmodule_cmd_pong(inspircd_cmd_pong);
+ pmodule_cmd_join(inspircd_cmd_join);
+ pmodule_cmd_unsqline(inspircd_cmd_unsqline);
+ pmodule_cmd_invite(inspircd_cmd_invite);
+ pmodule_cmd_part(inspircd_cmd_part);
+ pmodule_cmd_391(inspircd_cmd_391);
+ pmodule_cmd_250(inspircd_cmd_250);
+ pmodule_cmd_307(inspircd_cmd_307);
+ pmodule_cmd_311(inspircd_cmd_311);
+ pmodule_cmd_312(inspircd_cmd_312);
+ pmodule_cmd_317(inspircd_cmd_317);
+ pmodule_cmd_219(inspircd_cmd_219);
+ pmodule_cmd_401(inspircd_cmd_401);
+ pmodule_cmd_318(inspircd_cmd_318);
+ pmodule_cmd_242(inspircd_cmd_242);
+ pmodule_cmd_243(inspircd_cmd_243);
+ pmodule_cmd_211(inspircd_cmd_211);
+ pmodule_cmd_global(inspircd_cmd_global);
+ pmodule_cmd_global_legacy(inspircd_cmd_global_legacy);
+ pmodule_cmd_sqline(inspircd_cmd_sqline);
+ pmodule_cmd_squit(inspircd_cmd_squit);
+ pmodule_cmd_svso(inspircd_cmd_svso);
+ pmodule_cmd_chg_nick(inspircd_cmd_chg_nick);
+ pmodule_cmd_svsnick(inspircd_cmd_svsnick);
+ pmodule_cmd_vhost_on(inspircd_cmd_vhost_on);
+ pmodule_cmd_connect(inspircd_cmd_connect);
+ pmodule_cmd_svshold(inspircd_cmd_svshold);
+ pmodule_cmd_release_svshold(inspircd_cmd_release_svshold);
+ pmodule_cmd_unsgline(inspircd_cmd_unsqline);
+ pmodule_cmd_unszline(inspircd_cmd_unszline);
+ pmodule_cmd_szline(inspircd_cmd_szline);
+ pmodule_cmd_sgline(inspircd_cmd_sgline);
+ pmodule_cmd_unban(inspircd_cmd_unban);
+ pmodule_cmd_svsmode_chan(inspircd_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(inspircd_cmd_svid_umode);
+ pmodule_cmd_nc_change(inspircd_cmd_nc_change);
+ pmodule_cmd_svid_umode2(inspircd_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(inspircd_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(inspircd_cmd_svsjoin);
+ pmodule_cmd_svspart(inspircd_cmd_svspart);
+ pmodule_cmd_swhois(inspircd_cmd_swhois);
+ pmodule_cmd_eob(inspircd_cmd_eob);
+ pmodule_flood_mode_check(inspircd_flood_mode_check);
+ pmodule_cmd_jupe(inspircd_cmd_jupe);
+ pmodule_valid_nick(inspircd_valid_nick);
+ pmodule_valid_chan(inspircd_valid_chan);
+ pmodule_cmd_ctcp(inspircd_cmd_ctcp);
+ pmodule_set_umode(inspircd_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("inspircdIRCd 1.0");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/inspircd10.h b/src/protocol/inspircd10.h
new file mode 100644
index 000000000..d23876029
--- /dev/null
+++ b/src/protocol/inspircd10.h
@@ -0,0 +1,133 @@
+/* inspircd beta 6 functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_g 0x80000000
+#define UMODE_x 0x40000000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_c 0x00000400
+#define CMODE_A 0x00000800
+#define CMODE_H 0x00001000
+#define CMODE_K 0x00002000
+#define CMODE_L 0x00004000
+#define CMODE_O 0x00008000
+#define CMODE_Q 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_V 0x00040000
+#define CMODE_f 0x00080000
+#define CMODE_G 0x00100000
+#define CMODE_C 0x00200000
+#define CMODE_u 0x00400000
+#define CMODE_z 0x00800000
+#define CMODE_N 0x01000000
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void inspircd_set_umode(User * user, int ac, char **av);
+void inspircd_cmd_svsnoop(char *server, int set);
+void inspircd_cmd_remove_akill(char *user, char *host);
+void inspircd_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void inspircd_cmd_vhost_off(User * u);
+void inspircd_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void inspircd_cmd_svskill(char *source, char *user, char *buf);
+void inspircd_cmd_svsmode(User * u, int ac, char **av);
+void inspircd_cmd_372(char *source, char *msg);
+void inspircd_cmd_372_error(char *source);
+void inspircd_cmd_375(char *source);
+void inspircd_cmd_376(char *source);
+void inspircd_cmd_nick(char *nick, char *name, char *modes);
+void inspircd_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void inspircd_cmd_mode(char *source, char *dest, char *buf);
+void inspircd_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void inspircd_cmd_kick(char *source, char *chan, char *user, char *buf);
+void inspircd_cmd_notice_ops(char *source, char *dest, char *buf);
+void inspircd_cmd_notice(char *source, char *dest, char *buf);
+void inspircd_cmd_notice2(char *source, char *dest, char *msg);
+void inspircd_cmd_privmsg(char *source, char *dest, char *buf);
+void inspircd_cmd_privmsg2(char *source, char *dest, char *msg);
+void inspircd_cmd_serv_notice(char *source, char *dest, char *msg);
+void inspircd_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void inspircd_cmd_bot_chan_mode(char *nick, char *chan);
+void inspircd_cmd_351(char *source);
+void inspircd_cmd_quit(char *source, char *buf);
+void inspircd_cmd_pong(char *servname, char *who);
+void inspircd_cmd_join(char *user, char *channel, time_t chantime);
+void inspircd_cmd_unsqline(char *user);
+void inspircd_cmd_invite(char *source, char *chan, char *nick);
+void inspircd_cmd_part(char *nick, char *chan, char *buf);
+void inspircd_cmd_391(char *source, char *timestr);
+void inspircd_cmd_250(char *buf);
+void inspircd_cmd_307(char *buf);
+void inspircd_cmd_311(char *buf);
+void inspircd_cmd_312(char *buf);
+void inspircd_cmd_317(char *buf);
+void inspircd_cmd_219(char *source, char *letter);
+void inspircd_cmd_401(char *source, char *who);
+void inspircd_cmd_318(char *source, char *who);
+void inspircd_cmd_242(char *buf);
+void inspircd_cmd_243(char *buf);
+void inspircd_cmd_211(char *buf);
+void inspircd_cmd_global(char *source, char *buf);
+void inspircd_cmd_global_legacy(char *source, char *fmt);
+void inspircd_cmd_sqline(char *mask, char *reason);
+void inspircd_cmd_squit(char *servname, char *message);
+void inspircd_cmd_svso(char *source, char *nick, char *flag);
+void inspircd_cmd_chg_nick(char *oldnick, char *newnick);
+void inspircd_cmd_svsnick(char *source, char *guest, time_t when);
+void inspircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void inspircd_cmd_connect(int servernum);
+void inspircd_cmd_svshold(char *nick);
+void inspircd_cmd_release_svshold(char *nick);
+void inspircd_cmd_unsgline(char *mask);
+void inspircd_cmd_unszline(char *mask);
+void inspircd_cmd_szline(char *mask, char *reason, char *whom);
+void inspircd_cmd_sgline(char *mask, char *reason);
+void inspircd_cmd_unban(char *name, char *nick);
+void inspircd_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void inspircd_cmd_svid_umode(char *nick, time_t ts);
+void inspircd_cmd_nc_change(User * u);
+void inspircd_cmd_svid_umode2(User * u, char *ts);
+void inspircd_cmd_svid_umode3(User * u, char *ts);
+void inspircd_cmd_eob();
+int inspircd_flood_mode_check(char *value);
+void inspircd_cmd_jupe(char *jserver, char *who, char *reason);
+int inspircd_valid_nick(char *nick);
+void inspircd_cmd_ctcp(char *source, char *dest, char *buf);
+int anope_event_fjoin(char *source, int ac, char **av);
+int anope_event_fmode(char *source, int ac, char **av);
+int anope_event_ftopic(char *source, int ac, char **av);
+int anope_event_sanick(char *source, int ac, char **av);
+int anope_event_samode(char *source, int ac, char **av);
+int anope_event_sajoin(char *source, int ac, char **av);
+int anope_event_sapart(char *source, int ac, char **av);
+int anope_event_version(char *source, int ac, char **av);
+int anope_event_opertype(char *source, int ac, char **av);
+int anope_event_idle(char* source, int ac, char **av);
diff --git a/src/protocol/inspircd11.c b/src/protocol/inspircd11.c
new file mode 100644
index 000000000..eb2b3c4a2
--- /dev/null
+++ b/src/protocol/inspircd11.c
@@ -0,0 +1,1928 @@
+/* inspircd 1.1 beta 6+ functions
+ *
+ * (C) 2005-2007 Craig Edwards <brain@inspircd.org>
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "inspircd11.h"
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef _WIN32
+#include "winsock.h"
+int inet_aton(const char *name, struct in_addr *addr)
+{
+ uint32 a = inet_addr(name);
+ addr->s_addr = a;
+ return a != (uint32) - 1;
+}
+#endif
+
+IRCDVar myIrcd[] = {
+ {"InspIRCd 1.1", /* ircd name */
+ "+oI", /* nickserv mode */
+ "+oI", /* chanserv mode */
+ "+oI", /* memoserv mode */
+ "+oI", /* hostserv mode */
+ "+ioI", /* operserv mode */
+ "+oI", /* botserv mode */
+ "+oI", /* helpserv mode */
+ "+iI", /* Dev/Null mode */
+ "+ioI", /* Global mode */
+ "+oI", /* nickserv alias mode */
+ "+oI", /* chanserv alias mode */
+ "+oI", /* memoserv alias mode */
+ "+ioI", /* hostserv alias mode */
+ "+ioI", /* operserv alias mode */
+ "+oI", /* botserv alias mode */
+ "+oI", /* helpserv alias mode */
+ "+iI", /* Dev/Null alias mode */
+ "+ioI", /* Global alias mode */
+ "+sI", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-cilmnpstuzACGHKNOQRSV", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+r", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r", /* Mode on UnReg */
+ "-r", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 4, /* Number of server args */
+ 0, /* Join 2 Set */
+ 1, /* Join 2 Message */
+ 0, /* Has exceptions +e */
+ 1, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 1, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_K, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 1, /* +L */
+ CMODE_f,
+ CMODE_L,
+ 0,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support inspircd TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 1, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 1, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ CAPAB_SSJ3, /* SSJ3 */
+ CAPAB_NICK2, /* NICK2 */
+ 0, /* UMODE2 */
+ CAPAB_VL, /* VL */
+ CAPAB_TLKEXT, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0,
+ 0, 0}
+};
+
+unsigned long umodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, UMODE_A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0, UMODE_a, 0, 0, 0, 0, 0,
+ UMODE_g,
+ UMODE_h, UMODE_i, 0, 0, 0, 0, 0, UMODE_o,
+ 0,
+ 0, UMODE_r, 0, 0, 0, 0, UMODE_w,
+ UMODE_x,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 'a',
+ 0, 0, 0, 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'q', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {NULL, NULL},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {CMODE_C, 0, NULL, NULL}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {CMODE_G, 0, NULL, NULL}, /* G */
+ {CMODE_H, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, set_redirect, cs_set_redirect},
+ {0}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {CMODE_Q, 0, NULL, NULL}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {CMODE_V, 0, NULL, NULL}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {CMODE_u, 0, NULL, NULL},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL},
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'f', CMODE_f, 0, NULL, NULL},
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'u', CMODE_u, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'G', CMODE_G, 0, NULL, NULL},
+ {'H', CMODE_H, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, get_redirect, cs_get_redirect},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'Q', CMODE_Q, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {'V', CMODE_V, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op},
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+static int has_servicesmod = 0;
+static int has_globopsmod = 0;
+
+/* These are sanity checks to insure we are supported.
+ The ircd tends to /squit us if we issue unsupported cmds.
+ - katsklaw */
+static int has_svsholdmod = 0;
+static int has_chghostmod = 0;
+static int has_chgidentmod = 0;
+static int has_messagefloodmod = 0;
+static int has_banexceptionmod = 0;
+static int has_inviteexceptionmod = 0;
+
+void inspircd_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'a':
+ if (UnRestrictSAdmin) {
+ break;
+ }
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'r':
+ user->svid = (add ? user->timestamp : 0);
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ENDBURST", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("RSQUIT", anope_event_rsquit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode) ;addCoreMessage(IRCD,m);
+ m = createMessage("QLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ELINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ADDLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("FHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ m = createMessage("FNAME", anope_event_chgname); addCoreMessage(IRCD,m);
+ m = createMessage("METADATA", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+ m = createMessage("FJOIN", anope_event_fjoin); addCoreMessage(IRCD,m);
+ m = createMessage("FMODE", anope_event_fmode); addCoreMessage(IRCD,m);
+ m = createMessage("FTOPIC", anope_event_ftopic); addCoreMessage(IRCD,m);
+ m = createMessage("VERSION", anope_event_version); addCoreMessage(IRCD,m);
+ m = createMessage("OPERTYPE", anope_event_opertype); addCoreMessage(IRCD,m);
+ m = createMessage("IDLE", anope_event_idle); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+void inspircd_cmd_svsnoop(char *server, int set)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_svsadmin(char *server, int set)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(s_OperServ, "GLINE %s@%s", user, host);
+}
+
+void
+inspircd_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "FTOPIC %s %lu %s :%s", chan,
+ (unsigned long int) when, whosetit, topic);
+}
+
+void inspircd_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "MODE %s -x", u->nick);
+}
+
+void
+inspircd_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(ServerName, "ADDLINE G %s@%s %s %ld %ld :%s", user, host, who,
+ (long int) when, (long int) 86400 * 2, reason);
+}
+
+void inspircd_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf || !source || !user)
+ return;
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+void inspircd_cmd_svsmode(User * u, int ac, char **av)
+{
+ /* This was originally done using this:
+ send_cmd(s_NickServ, "MODE %s %s%s%s", u->nick, av[0], (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+ * but that's the dirty way of doing things...
+ */
+ send_cmd(s_NickServ, "MODE %s %s", u->nick, merge_args(ac, av));
+}
+
+
+void inspircd_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void inspircd_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void inspircd_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void inspircd_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void inspircd_cmd_nick(char *nick, char *name, char *modes)
+{
+ /* :test.chatspike.net NICK 1133519355 Brain synapse.brainbox.winbot.co.uk netadmin.chatspike.net ~brain +xwsioS 10.0.0.2 :Craig Edwards */
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",
+ (long int) time(NULL), nick, ServiceHost, ServiceHost,
+ ServiceUser, modes, name);
+ /* Don't send ServerName as the source here... -GD */
+ send_cmd(nick, "OPERTYPE Service");
+}
+
+void
+inspircd_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",
+ (long int) time(NULL), nick, host, host, user, modes, real);
+}
+
+void inspircd_cmd_mode(char *source, char *dest, char *buf)
+{
+ Channel *c;
+ if (!buf) {
+ return;
+ }
+
+ c = findchan(dest);
+ send_cmd(source ? source : s_OperServ, "FMODE %s %u %s", dest, (unsigned int)((c) ? c->creation_time : time(NULL)), buf);
+}
+
+int anope_event_version(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_idle(char *source, int ac, char **av)
+{
+ if (ac == 1) {
+ send_cmd(av[0], "IDLE %s %ld 0", source, (long int) time(NULL));
+ }
+ return MOD_CONT;
+}
+
+int anope_event_ftopic(char *source, int ac, char **av)
+{
+ /* :source FTOPIC channel ts setby :topic */
+ char *temp;
+ if (ac < 4)
+ return MOD_CONT;
+ temp = av[1]; /* temp now holds ts */
+ av[1] = av[2]; /* av[1] now holds set by */
+ av[2] = temp; /* av[2] now holds ts */
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_opertype(char *source, int ac, char **av)
+{
+ /* opertype is equivalent to mode +o because servers
+ dont do this directly */
+ User *u;
+ u = finduser(source);
+ if (u && !is_oper(u)) {
+ char *newav[2];
+ newav[0] = source;
+ newav[1] = "+o";
+ return anope_event_mode(source, 2, newav);
+ } else
+ return MOD_CONT;
+}
+
+int anope_event_fmode(char *source, int ac, char **av)
+{
+ char *newav[25];
+ int n, o;
+ Channel *c;
+
+ /* :source FMODE #test 12345678 +nto foo */
+ if (ac < 3)
+ return MOD_CONT;
+
+ /* Checking the TS for validity to avoid desyncs */
+ if ((c = findchan(av[0]))) {
+ if (c->creation_time > strtol(av[1], NULL, 10)) {
+ /* Our TS is bigger, we should lower it */
+ c->creation_time = strtol(av[1], NULL, 10);
+ } else if (c->creation_time < strtol(av[1], NULL, 10)) {
+ /* The TS we got is bigger, we should ignore this message. */
+ return MOD_CONT;
+ }
+ } else {
+ /* Got FMODE for a non-existing channel */
+ return MOD_CONT;
+ }
+
+ /* TS's are equal now, so we can proceed with parsing */
+ n = o = 0;
+ while (n < ac) {
+ if (n != 1) {
+ newav[o] = av[n];
+ o++;
+ if (debug)
+ alog("Param: %s", newav[o - 1]);
+ }
+ n++;
+ }
+
+ return anope_event_mode(source, ac - 1, newav);
+}
+
+int anope_event_fjoin(char *source, int ac, char **av)
+{
+ char *newav[10];
+
+ /* value used for myStrGetToken */
+ int curtoken = 0;
+
+ /* storing the current nick */
+ char *curnick;
+
+ /* these are used to generate the final string that is passed to ircservices' core */
+ int nlen = 0;
+ char nicklist[514];
+
+ /* temporary buffer */
+ char prefixandnick[60];
+
+ *nicklist = '\0';
+ *prefixandnick = '\0';
+
+ if (ac < 3)
+ return MOD_CONT;
+
+ curnick = myStrGetToken(av[2], ' ', curtoken);
+ while (curnick != NULL) {
+ for (; *curnick; curnick++) {
+ /* I bet theres a better way to do this... */
+ if ((*curnick == '&') ||
+ (*curnick == '~') || (*curnick == '@') || (*curnick == '%')
+ || (*curnick == '+')) {
+ prefixandnick[nlen++] = *curnick;
+ continue;
+ } else {
+ if (*curnick == ',') {
+ curnick++;
+ strncpy(prefixandnick + nlen, curnick,
+ sizeof(prefixandnick) - nlen);
+ break;
+ } else {
+ alog("fjoin: unrecognised prefix: %c", *curnick);
+ }
+ }
+ }
+ strncat(nicklist, prefixandnick, 513);
+ strncat(nicklist, " ", 513);
+ curtoken++;
+ curnick = myStrGetToken(av[2], ' ', curtoken);
+ nlen = 0;
+ }
+
+ newav[0] = av[1]; /* timestamp */
+ newav[1] = av[0]; /* channel name */
+ newav[2] = "+"; /* channel modes */
+ newav[3] = nicklist;
+ do_sjoin(source, 4, newav);
+
+ return MOD_CONT;
+}
+
+void
+inspircd_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(ServerName, "NICK %ld %s %s %s %s +%s 0.0.0.0 :%s",
+ (long int) time(NULL), nick, host, host, user, modes, real);
+ send_cmd(nick, "OPERTYPE Bot");
+}
+
+void inspircd_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s :%s", chan, user, user);
+ }
+}
+
+void inspircd_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void inspircd_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ inspircd_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void inspircd_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void inspircd_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void inspircd_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void inspircd_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void inspircd_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+
+void inspircd_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+void inspircd_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* QUIT */
+void inspircd_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT :Exiting");
+ }
+}
+
+/* PROTOCTL */
+void inspircd_cmd_protoctl()
+{
+}
+
+static char currentpass[1024];
+
+/* PASS */
+void inspircd_cmd_pass(char *pass)
+{
+ strncpy(currentpass, pass, 1024);
+}
+
+/* SERVER services-dev.chatspike.net password 0 :Description here */
+void inspircd_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(ServerName, "SERVER %s %s %d :%s", servname, currentpass, hop,
+ descript);
+}
+
+/* PONG */
+void inspircd_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/* JOIN */
+void inspircd_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "JOIN %s", channel);
+}
+
+/* UNSQLINE */
+void inspircd_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+ send_cmd(s_OperServ, "QLINE %s", user);
+}
+
+/* CHGHOST */
+void inspircd_cmd_chghost(char *nick, char *vhost)
+{
+ if (has_chghostmod == 1) {
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(s_OperServ, "CHGHOST %s %s", nick, vhost);
+ } else {
+ anope_cmd_global(s_OperServ, "CHGHOST not loaded!");
+ }
+}
+
+/* CHGIDENT */
+void inspircd_cmd_chgident(char *nick, char *vIdent)
+{
+ if (has_chgidentmod == 1) {
+ if (!nick || !vIdent || !*vIdent) {
+ return;
+ }
+ send_cmd(s_OperServ, "CHGIDENT %s %s", nick, vIdent);
+ } else {
+ anope_cmd_global(s_OperServ, "CHGIDENT not loaded!");
+ }
+}
+
+/* INVITE */
+void inspircd_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PART */
+void inspircd_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s :Leaving", chan);
+ }
+}
+
+/* 391 */
+void inspircd_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void inspircd_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void inspircd_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void inspircd_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void inspircd_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void inspircd_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void inspircd_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void inspircd_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void inspircd_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void inspircd_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void inspircd_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void inspircd_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void inspircd_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* SQLINE */
+void inspircd_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(ServerName, "ADDLINE Q %s %s %ld 0 :%s", mask, s_OperServ,
+ (long int) time(NULL), reason);
+}
+
+/* SQUIT */
+void inspircd_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(ServerName, "SQUIT %s :%s", servname, message);
+}
+
+/* SVSO */
+void inspircd_cmd_svso(char *source, char *nick, char *flag)
+{
+}
+
+/* NICK <newnick> */
+void inspircd_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/* SVSNICK */
+void inspircd_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ /* Please note that inspircd will now echo back a nickchange for this SVSNICK */
+ send_cmd(ServerName, "SVSNICK %s %s :%lu", source, guest,
+ (unsigned long) when);
+}
+
+/* Functions that use serval cmd functions */
+
+void inspircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (!nick) {
+ return;
+ }
+ if (vIdent) {
+ inspircd_cmd_chgident(nick, vIdent);
+ }
+ inspircd_cmd_chghost(nick, vhost);
+}
+
+void inspircd_cmd_connect(int servernum)
+{
+ if (servernum == 1) {
+ inspircd_cmd_pass(RemotePassword);
+ }
+ if (servernum == 2) {
+ inspircd_cmd_pass(RemotePassword2);
+ }
+ if (servernum == 3) {
+ inspircd_cmd_pass(RemotePassword3);
+ }
+ inspircd_cmd_server(ServerName, 0, ServerDesc);
+ send_cmd(NULL, "BURST");
+ send_cmd(ServerName, "VERSION :Anope-%s %s :%s - %s (%s) -- %s",
+ version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ /* ((ac > 1) ? av[1] : ServerName) */
+ inspircd_cmd_pong(ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+/* Taken from hybrid.c, topic syntax is identical */
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_rsquit(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 3)
+ return MOD_CONT;
+
+ /* Horrible workaround to an insp bug (#) in how RSQUITs are sent - mark */
+ if (ac > 1 && strcmp(ServerName, av[0]) == 0)
+ do_squit(source, ac - 1, av + 1);
+ else
+ do_squit(source, ac, av);
+
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ /* InspIRCd lets opers change another
+ users modes, we have to kludge this
+ as it slightly breaks RFC1459
+ */
+ if (!strcasecmp(source, av[0])) {
+ do_umode(source, ac, av);
+ } else {
+ do_umode(av[0], ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: FNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+ struct in_addr addy;
+ uint32 *ad = (uint32 *) & addy;
+
+ if (ac != 1) {
+ if (ac == 8) {
+ int svid = 0;
+ int ts = strtoul(av[0], NULL, 10);
+
+ if (strchr(av[5], 'r') != NULL)
+ svid = ts;
+
+ inet_aton(av[6], &addy);
+ user = do_nick("", av[1], /* nick */
+ av[4], /* username */
+ av[2], /* realhost */
+ source, /* server */
+ av[7], /* realname */
+ ts, svid, htonl(*ad), av[3], NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[5]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL, 0, 0, 0, NULL,
+ NULL);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: FHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_capab(char *source, int ac, char **av)
+{
+ int argc;
+ char **argv;
+ CBModeInfo *cbmi;
+
+ if (strcasecmp(av[0], "START") == 0) {
+ /* reset CAPAB */
+ has_servicesmod = 0;
+ has_globopsmod = 0;
+ has_svsholdmod = 0;
+ has_chghostmod = 0;
+ has_chgidentmod = 0;
+
+ } else if (strcasecmp(av[0], "MODULES") == 0) {
+ if (strstr(av[1], "m_globops.so")) {
+ has_globopsmod = 1;
+ }
+ if (strstr(av[1], "m_services.so")) {
+ has_servicesmod = 1;
+ }
+ if (strstr(av[1], "m_svshold.so")) {
+ has_svsholdmod = 1;
+ }
+ if (strstr(av[1], "m_chghost.so")) {
+ has_chghostmod = 1;
+ }
+ if (strstr(av[1], "m_chgident.so")) {
+ has_chgidentmod = 1;
+ }
+ if (strstr(av[1], "m_messageflood.so")) {
+ has_messagefloodmod = 1;
+ }
+ if (strstr(av[1], "m_banexception.so")) {
+ has_banexceptionmod = 1;
+ }
+ if (strstr(av[1], "m_inviteexception.so")) {
+ has_inviteexceptionmod = 1;
+ }
+ } else if (strcasecmp(av[0], "END") == 0) {
+ if (!has_globopsmod) {
+ send_cmd(NULL,
+ "ERROR :m_globops is not loaded. This is required by Anope");
+ quitmsg = "Remote server does not have the m_globops module loaded, and this is required.";
+ quitting = 1;
+ return MOD_STOP;
+ }
+ if (!has_servicesmod) {
+ send_cmd(NULL,
+ "ERROR :m_services is not loaded. This is required by Anope");
+ quitmsg = "Remote server does not have the m_services module loaded, and this is required.";
+ quitting = 1;
+ return MOD_STOP;
+ }
+ if (!has_svsholdmod) {
+ anope_cmd_global(s_OperServ, "SVSHOLD missing, Usage disabled until module is loaded.");
+ }
+ if (!has_chghostmod) {
+ anope_cmd_global(s_OperServ, "CHGHOST missing, Usage disabled until module is loaded.");
+ }
+ if (!has_chgidentmod) {
+ anope_cmd_global(s_OperServ, "CHGIDENT missing, Usage disabled until module is loaded.");
+ }
+ if (has_messagefloodmod) {
+ cbmi = myCbmodeinfos;
+
+ /* Find 'f' in myCbmodeinfos and add the relevant bits to myCbmodes and myCbmodeinfos
+ * to enable +f support if found. This is needed because we're really not set up to
+ * handle modular ircds which can have modes enabled/disabled as they please :( - mark
+ */
+ while ((cbmi->mode != 'f')) {
+ cbmi++;
+ }
+ if (cbmi) {
+ cbmi->getvalue = get_flood;
+ cbmi->csgetvalue = cs_get_flood;
+
+ myCbmodes['f'].flag = CMODE_f;
+ myCbmodes['f'].flags = 0;
+ myCbmodes['f'].setvalue = set_flood;
+ myCbmodes['f'].cssetvalue = cs_set_flood;
+
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cbmodes(myCbmodes);
+
+ ircd->fmode = 1;
+ }
+ else {
+ alog("Support for channelmode +f can not be enabled");
+ if (debug) {
+ alog("debug: 'f' missing from myCbmodeinfos");
+ }
+ }
+ }
+ if (has_banexceptionmod) {
+ myCmmodes['e'].addmask = add_exception;
+ myCmmodes['e'].delmask = del_exception;
+ ircd->except = 1;
+ }
+ if (has_inviteexceptionmod) {
+ myCmmodes['I'].addmask = add_invite;
+ myCmmodes['I'].delmask = del_invite;
+ ircd->invitemode = 1;
+ }
+ ircd->svshold = has_svsholdmod;
+
+ if (has_banexceptionmod || has_inviteexceptionmod) {
+ pmodule_ircd_cmmodes(myCmmodes);
+ }
+
+ /* Generate a fake capabs parsing call so things like NOQUIT work
+ * fine. It's ugly, but it works....
+ */
+ argc = 6;
+ argv = scalloc(argc, sizeof(char *));
+ argv[0] = "NOQUIT";
+ argv[1] = "SSJ3";
+ argv[2] = "NICK2";
+ argv[3] = "VL";
+ argv[4] = "TLKEXT";
+ argv[5] = "UNCONNECT";
+
+ capab_parse(argc, argv);
+ }
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void inspircd_cmd_svshold(char *nick)
+{
+ send_cmd(s_OperServ, "SVSHOLD %s %ds :%s", nick, NSReleaseTimeout,
+ "Being held for registered user");
+}
+
+/* SVSHOLD - release */
+void inspircd_cmd_release_svshold(char *nick)
+{
+ send_cmd(s_OperServ, "SVSHOLD %s", nick);
+}
+
+/* UNSGLINE */
+void inspircd_cmd_unsgline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSZLINE */
+void inspircd_cmd_unszline(char *mask)
+{
+ send_cmd(s_OperServ, "ZLINE %s", mask);
+}
+
+/* SZLINE */
+void inspircd_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(ServerName, "ADDLINE Z %s %s %ld 0 :%s", mask, whom,
+ (long int) time(NULL), reason);
+}
+
+/* SGLINE */
+void inspircd_cmd_sgline(char *mask, char *reason)
+{
+ /* Not Supported by this IRCD */
+}
+
+void inspircd_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void inspircd_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void inspircd_cmd_svid_umode(char *nick, time_t ts)
+{
+ if (debug)
+ alog("debug: common_svsmode(0)");
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void inspircd_cmd_nc_change(User * u)
+{
+ if (debug)
+ alog("debug: common_svsmode(1)");
+ common_svsmode(u, "-r", NULL);
+}
+
+/* SVSMODE +r */
+void inspircd_cmd_svid_umode2(User * u, char *ts)
+{
+ if (debug)
+ alog("debug: common_svsmode(2)");
+ common_svsmode(u, "+r", NULL);
+}
+
+void inspircd_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+void inspircd_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(source, "SVSJOIN %s %s", nick, chan);
+}
+
+void inspircd_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SVSPART %s %s", nick, chan);
+}
+
+void inspircd_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* Not used currently */
+}
+
+void inspircd_cmd_eob()
+{
+ send_cmd(NULL, "ENDBURST");
+}
+
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int inspircd_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void inspircd_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ inspircd_cmd_squit(jserver, rbuf);
+ inspircd_cmd_server(jserver, 1, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void inspircd_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : s_OperServ, "GLOBOPS :%s", fmt);
+}
+
+int inspircd_valid_nick(char *nick)
+{
+ return 1;
+}
+
+int inspircd_valid_chan(char *chan)
+{
+ return 1;
+}
+
+
+void inspircd_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s\1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(inspircd_cmd_svsnoop);
+ pmodule_cmd_remove_akill(inspircd_cmd_remove_akill);
+ pmodule_cmd_topic(inspircd_cmd_topic);
+ pmodule_cmd_vhost_off(inspircd_cmd_vhost_off);
+ pmodule_cmd_akill(inspircd_cmd_akill);
+ pmodule_cmd_svskill(inspircd_cmd_svskill);
+ pmodule_cmd_svsmode(inspircd_cmd_svsmode);
+ pmodule_cmd_372(inspircd_cmd_372);
+ pmodule_cmd_372_error(inspircd_cmd_372_error);
+ pmodule_cmd_375(inspircd_cmd_375);
+ pmodule_cmd_376(inspircd_cmd_376);
+ pmodule_cmd_nick(inspircd_cmd_nick);
+ pmodule_cmd_guest_nick(inspircd_cmd_guest_nick);
+ pmodule_cmd_mode(inspircd_cmd_mode);
+ pmodule_cmd_bot_nick(inspircd_cmd_bot_nick);
+ pmodule_cmd_kick(inspircd_cmd_kick);
+ pmodule_cmd_notice_ops(inspircd_cmd_notice_ops);
+ pmodule_cmd_notice(inspircd_cmd_notice);
+ pmodule_cmd_notice2(inspircd_cmd_notice2);
+ pmodule_cmd_privmsg(inspircd_cmd_privmsg);
+ pmodule_cmd_privmsg2(inspircd_cmd_privmsg2);
+ pmodule_cmd_serv_notice(inspircd_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(inspircd_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(inspircd_cmd_bot_chan_mode);
+ pmodule_cmd_351(inspircd_cmd_351);
+ pmodule_cmd_quit(inspircd_cmd_quit);
+ pmodule_cmd_pong(inspircd_cmd_pong);
+ pmodule_cmd_join(inspircd_cmd_join);
+ pmodule_cmd_unsqline(inspircd_cmd_unsqline);
+ pmodule_cmd_invite(inspircd_cmd_invite);
+ pmodule_cmd_part(inspircd_cmd_part);
+ pmodule_cmd_391(inspircd_cmd_391);
+ pmodule_cmd_250(inspircd_cmd_250);
+ pmodule_cmd_307(inspircd_cmd_307);
+ pmodule_cmd_311(inspircd_cmd_311);
+ pmodule_cmd_312(inspircd_cmd_312);
+ pmodule_cmd_317(inspircd_cmd_317);
+ pmodule_cmd_219(inspircd_cmd_219);
+ pmodule_cmd_401(inspircd_cmd_401);
+ pmodule_cmd_318(inspircd_cmd_318);
+ pmodule_cmd_242(inspircd_cmd_242);
+ pmodule_cmd_243(inspircd_cmd_243);
+ pmodule_cmd_211(inspircd_cmd_211);
+ pmodule_cmd_global(inspircd_cmd_global);
+ pmodule_cmd_global_legacy(inspircd_cmd_global_legacy);
+ pmodule_cmd_sqline(inspircd_cmd_sqline);
+ pmodule_cmd_squit(inspircd_cmd_squit);
+ pmodule_cmd_svso(inspircd_cmd_svso);
+ pmodule_cmd_chg_nick(inspircd_cmd_chg_nick);
+ pmodule_cmd_svsnick(inspircd_cmd_svsnick);
+ pmodule_cmd_vhost_on(inspircd_cmd_vhost_on);
+ pmodule_cmd_connect(inspircd_cmd_connect);
+ pmodule_cmd_svshold(inspircd_cmd_svshold);
+ pmodule_cmd_release_svshold(inspircd_cmd_release_svshold);
+ pmodule_cmd_unsgline(inspircd_cmd_unsqline);
+ pmodule_cmd_unszline(inspircd_cmd_unszline);
+ pmodule_cmd_szline(inspircd_cmd_szline);
+ pmodule_cmd_sgline(inspircd_cmd_sgline);
+ pmodule_cmd_unban(inspircd_cmd_unban);
+ pmodule_cmd_svsmode_chan(inspircd_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(inspircd_cmd_svid_umode);
+ pmodule_cmd_nc_change(inspircd_cmd_nc_change);
+ pmodule_cmd_svid_umode2(inspircd_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(inspircd_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(inspircd_cmd_svsjoin);
+ pmodule_cmd_svspart(inspircd_cmd_svspart);
+ pmodule_cmd_swhois(inspircd_cmd_swhois);
+ pmodule_cmd_eob(inspircd_cmd_eob);
+ pmodule_flood_mode_check(inspircd_flood_mode_check);
+ pmodule_cmd_jupe(inspircd_cmd_jupe);
+ pmodule_valid_nick(inspircd_valid_nick);
+ pmodule_valid_chan(inspircd_valid_chan);
+ pmodule_cmd_ctcp(inspircd_cmd_ctcp);
+ pmodule_set_umode(inspircd_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("inspircdIRCd 1.1");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
+
diff --git a/src/protocol/inspircd11.h b/src/protocol/inspircd11.h
new file mode 100755
index 000000000..d079b2c97
--- /dev/null
+++ b/src/protocol/inspircd11.h
@@ -0,0 +1,134 @@
+/* inspircd beta 6 functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_g 0x80000000
+#define UMODE_x 0x40000000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_c 0x00000400
+#define CMODE_A 0x00000800
+#define CMODE_H 0x00001000
+#define CMODE_K 0x00002000
+#define CMODE_L 0x00004000
+#define CMODE_O 0x00008000
+#define CMODE_Q 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_V 0x00040000
+#define CMODE_f 0x00080000
+#define CMODE_G 0x00100000
+#define CMODE_C 0x00200000
+#define CMODE_u 0x00400000
+#define CMODE_z 0x00800000
+#define CMODE_N 0x01000000
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void inspircd_set_umode(User * user, int ac, char **av);
+void inspircd_cmd_svsnoop(char *server, int set);
+void inspircd_cmd_remove_akill(char *user, char *host);
+void inspircd_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void inspircd_cmd_vhost_off(User * u);
+void inspircd_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void inspircd_cmd_svskill(char *source, char *user, char *buf);
+void inspircd_cmd_svsmode(User * u, int ac, char **av);
+void inspircd_cmd_372(char *source, char *msg);
+void inspircd_cmd_372_error(char *source);
+void inspircd_cmd_375(char *source);
+void inspircd_cmd_376(char *source);
+void inspircd_cmd_nick(char *nick, char *name, char *modes);
+void inspircd_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void inspircd_cmd_mode(char *source, char *dest, char *buf);
+void inspircd_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void inspircd_cmd_kick(char *source, char *chan, char *user, char *buf);
+void inspircd_cmd_notice_ops(char *source, char *dest, char *buf);
+void inspircd_cmd_notice(char *source, char *dest, char *buf);
+void inspircd_cmd_notice2(char *source, char *dest, char *msg);
+void inspircd_cmd_privmsg(char *source, char *dest, char *buf);
+void inspircd_cmd_privmsg2(char *source, char *dest, char *msg);
+void inspircd_cmd_serv_notice(char *source, char *dest, char *msg);
+void inspircd_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void inspircd_cmd_bot_chan_mode(char *nick, char *chan);
+void inspircd_cmd_351(char *source);
+void inspircd_cmd_quit(char *source, char *buf);
+void inspircd_cmd_pong(char *servname, char *who);
+void inspircd_cmd_join(char *user, char *channel, time_t chantime);
+void inspircd_cmd_unsqline(char *user);
+void inspircd_cmd_invite(char *source, char *chan, char *nick);
+void inspircd_cmd_part(char *nick, char *chan, char *buf);
+void inspircd_cmd_391(char *source, char *timestr);
+void inspircd_cmd_250(char *buf);
+void inspircd_cmd_307(char *buf);
+void inspircd_cmd_311(char *buf);
+void inspircd_cmd_312(char *buf);
+void inspircd_cmd_317(char *buf);
+void inspircd_cmd_219(char *source, char *letter);
+void inspircd_cmd_401(char *source, char *who);
+void inspircd_cmd_318(char *source, char *who);
+void inspircd_cmd_242(char *buf);
+void inspircd_cmd_243(char *buf);
+void inspircd_cmd_211(char *buf);
+void inspircd_cmd_global(char *source, char *buf);
+void inspircd_cmd_global_legacy(char *source, char *fmt);
+void inspircd_cmd_sqline(char *mask, char *reason);
+void inspircd_cmd_squit(char *servname, char *message);
+void inspircd_cmd_svso(char *source, char *nick, char *flag);
+void inspircd_cmd_chg_nick(char *oldnick, char *newnick);
+void inspircd_cmd_svsnick(char *source, char *guest, time_t when);
+void inspircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void inspircd_cmd_connect(int servernum);
+void inspircd_cmd_svshold(char *nick);
+void inspircd_cmd_release_svshold(char *nick);
+void inspircd_cmd_unsgline(char *mask);
+void inspircd_cmd_unszline(char *mask);
+void inspircd_cmd_szline(char *mask, char *reason, char *whom);
+void inspircd_cmd_sgline(char *mask, char *reason);
+void inspircd_cmd_unban(char *name, char *nick);
+void inspircd_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void inspircd_cmd_svid_umode(char *nick, time_t ts);
+void inspircd_cmd_nc_change(User * u);
+void inspircd_cmd_svid_umode2(User * u, char *ts);
+void inspircd_cmd_svid_umode3(User * u, char *ts);
+void inspircd_cmd_eob();
+int inspircd_flood_mode_check(char *value);
+void inspircd_cmd_jupe(char *jserver, char *who, char *reason);
+int inspircd_valid_nick(char *nick);
+void inspircd_cmd_ctcp(char *source, char *dest, char *buf);
+int anope_event_fjoin(char *source, int ac, char **av);
+int anope_event_fmode(char *source, int ac, char **av);
+int anope_event_ftopic(char *source, int ac, char **av);
+int anope_event_sanick(char *source, int ac, char **av);
+int anope_event_samode(char *source, int ac, char **av);
+int anope_event_sajoin(char *source, int ac, char **av);
+int anope_event_sapart(char *source, int ac, char **av);
+int anope_event_version(char *source, int ac, char **av);
+int anope_event_opertype(char *source, int ac, char **av);
+int anope_event_idle(char* source, int ac, char **av);
+int anope_event_rsquit(char *source, int ac, char **av);
diff --git a/src/protocol/plexus2.c b/src/protocol/plexus2.c
new file mode 100644
index 000000000..0a91194f4
--- /dev/null
+++ b/src/protocol/plexus2.c
@@ -0,0 +1,1880 @@
+/* PlexusIRCD IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "plexus2.h"
+
+IRCDVar myIrcd[] = {
+ {"PleXusIRCd 2.0+", /* ircd name */
+ "+oiSR", /* nickserv mode */
+ "+oiSR", /* chanserv mode */
+ "+oiSR", /* memoserv mode */
+ "+oiSR", /* hostserv mode */
+ "+oaiSR", /* operserv mode */
+ "+oiSR", /* botserv mode */
+ "+oiSR", /* helpserv mode */
+ "+oiSR", /* Dev/Null mode */
+ "+oiSR", /* Global mode */
+ "+oiSR", /* nickserv alias mode */
+ "+oiSR", /* chanserv alias mode */
+ "+oiSR", /* memoserv alias mode */
+ "+oiSR", /* hostserv alias mode */
+ "+oaiSR", /* operserv alias mode */
+ "+oiSR", /* botserv alias mode */
+ "+oiSR", /* helpserv alias mode */
+ "+oiSR", /* Dev/Null alias mode */
+ "+oiSR", /* Global alias mode */
+ "+iSR", /* Used by BotServ Bots */
+ 3, /* Chan Max Symbols */
+ "-acilmnpstMNORZ", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to unset for chan admin */
+ "+R", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-R", /* Mode on UnReg */
+ "-R", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 0, /* Chan Reg */
+ 0, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 1, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_h, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 0, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "h", /* vhost char */
+ 0, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ CAPAB_QS, /* QS */
+ CAPAB_UID, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+
+void
+plexus_set_umode (User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog ("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes)
+ {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++)
+ {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'h':
+ update_host (user);
+ break;
+ case 'o':
+ if (add)
+ {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global (s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news (user, NEWS_OPER);
+
+ }
+ else
+ {
+ opcnt--;
+ }
+ break;
+ case 'R':
+ if (add && !nick_identified (user))
+ {
+ common_svsmode (user, "-R", NULL);
+ user->mode &= ~UMODE_R;
+ }
+ break;
+
+ }
+ }
+}
+
+/*
+ * Local valid_op, and valid_halfop overrides.
+ * These are nessecary due to the way hybrid-based ircds handle halfops.
+ * hybrid-based ircds treat a -o as a -h as well. So if a user is set -o,
+ * the ircd will also set them -h if they have that mode. This breaks
+ * is_valid_op, as it always sends a -o. Breaking up the routines corrects this problem. - ThaPrince
+ */
+
+int
+plexus_check_valid_halfop (User * user, Channel * chan, int servermode)
+{
+ if (!chan || !chan->ci)
+ return 1;
+
+ /* They will be kicked; no need to deop, no need to update our internal struct too */
+ if (chan->ci->flags & CI_VERBOTEN)
+ return 0;
+
+ if (servermode && !check_access (user, chan->ci, CA_AUTOHALFOP))
+ {
+ notice_lang (s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
+ anope_cmd_mode (whosends (chan->ci), chan->name, "-h %s", user->nick);
+ return 0;
+ }
+
+ if (check_access (user, chan->ci, CA_AUTODEOP))
+ {
+ anope_cmd_mode (whosends (chan->ci), chan->name, "-h %s", user->nick);
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+plexus_check_valid_op (User * user, Channel * chan, int servermode)
+{
+ if (!chan || !chan->ci)
+ return 1;
+
+ /* They will be kicked; no need to deop, no need to update our internal struct too */
+ if (chan->ci->flags & CI_VERBOTEN)
+ return 0;
+
+ if (servermode && !check_access (user, chan->ci, CA_AUTOOP))
+ {
+ notice_lang (s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
+ if (check_access (user, chan->ci, CA_AUTOHALFOP))
+ {
+ anope_cmd_mode (whosends (chan->ci), chan->name,
+ "-o+h %s %s", user->nick, user->nick);
+ }
+ else
+ {
+ anope_cmd_mode (whosends (chan->ci), chan->name, "-o %s",
+ user->nick);
+ }
+ return 0;
+ }
+
+ if (check_access (user, chan->ci, CA_AUTODEOP))
+ {
+ anope_cmd_mode (whosends (chan->ci), chan->name, "-o %s", user->nick);
+ return 0;
+ }
+
+ return 1;
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ 0, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, 0, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ UMODE_S, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, 0, /* a b c */
+ UMODE_d, 0, 0, /* d e f */
+ 0, UMODE_h, UMODE_i, /* g h i */
+ 0, 0, UMODE_l, /* j k l */
+ UMODE_g, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, 0, /* p q r */
+ 0, 0, UMODE_u, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h',
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {CMODE_Z, 0, NULL, NULL}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {CMODE_a, 0, NULL, NULL},
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {0},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'a', CMODE_a, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'Z', CMODE_Z, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, plexus_check_valid_halfop},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, plexus_check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void
+plexus_cmd_notice (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG)
+ {
+ plexus_cmd_privmsg2 (source, dest, buf);
+ }
+ else
+ {
+ send_cmd (source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void
+plexus_cmd_notice2 (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "NOTICE %s :%s", dest, msg);
+}
+
+void
+plexus_cmd_privmsg (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void
+plexus_cmd_privmsg2 (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void
+plexus_cmd_serv_notice (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void
+plexus_cmd_serv_privmsg (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void
+plexus_cmd_global (char *source, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source ? source : ServerName, "OPERWALL :%s", buf);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void
+plexus_cmd_global_legacy (char *source, char *fmt)
+{
+ send_cmd (source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int
+anope_event_sjoin (char *source, int ac, char **av)
+{
+ do_sjoin (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_nick (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ {
+ User *user = do_nick (source, av[0], av[4], av[5], av[7], av[9],
+ strtoul (av[2], NULL, 10),
+ strtoul (av[8], NULL, 0), 0, av[6], NULL);
+ if (user)
+ anope_set_umode (user, 1, &av[3]);
+ }
+ else
+ {
+ do_nick (source, av[0], NULL, NULL, NULL, NULL,
+ strtoul (av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int
+anope_event_topic (char *source, int ac, char **av)
+{
+ if (ac == 4)
+ {
+ do_topic (source, ac, av);
+ }
+ else
+ {
+ Channel *c = findchan (av[0]);
+ time_t topic_time = time (NULL);
+
+ if (!c)
+ {
+ if (debug)
+ {
+ alog ("debug: TOPIC %s for nonexistent channel %s",
+ merge_args (ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock (c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic)
+ {
+ free (c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup (av[1]);
+
+ strscpy (c->topic_setter, source, sizeof (c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic (av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ }
+ return MOD_CONT;
+}
+
+int
+anope_event_tburst (char *source, int ac, char **av)
+{
+ if (ac != 5)
+ return MOD_CONT;
+
+ av[0] = av[1];
+ av[1] = av[3];
+ av[3] = av[4];
+ do_topic (source, 4, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_436 (char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll (av[0]);
+ return MOD_CONT;
+}
+
+
+void
+moduleAddIRCDMsgs (void)
+{
+ Message *m;
+
+ updateProtectDetails ("PROTECT", "PROTECTME", "protect", "deprotect",
+ "AUTOPROTECT", "+", "-");
+
+ m = createMessage ("401", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("402", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("436", anope_event_436);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("AWAY", anope_event_away);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("INVITE", anope_event_invite);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("JOIN", anope_event_join);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("KICK", anope_event_kick);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("KILL", anope_event_kill);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("MODE", anope_event_mode);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("MOTD", anope_event_motd);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("NICK", anope_event_nick);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("NOTICE", anope_event_notice);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PART", anope_event_part);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PASS", anope_event_pass);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PING", anope_event_ping);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PRIVMSG", anope_event_privmsg);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("QUIT", anope_event_quit);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SERVER", anope_event_server);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SQUIT", anope_event_squit);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("TOPIC", anope_event_topic);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("TBURST", anope_event_tburst);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("USER", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("WALLOPS", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("WHOIS", anope_event_whois);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SVSMODE", anope_event_mode);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SVSNICK", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("CAPAB", anope_event_capab);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SJOIN", anope_event_sjoin);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SVINFO", anope_event_svinfo);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("EOB", anope_event_eob);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("ADMIN", anope_event_admin);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("ERROR", anope_event_error);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SETHOST", anope_event_sethost);
+ addCoreMessage (IRCD, m);
+}
+
+void
+plexus_cmd_sqline (char *mask, char *reason)
+{
+ send_cmd (s_OperServ, "RESV * %s :%s", mask, reason);
+}
+
+void
+plexus_cmd_unsgline (char *mask)
+{
+ send_cmd (s_OperServ, "UNXLINE * %s", mask);
+}
+
+void
+plexus_cmd_unszline (char *mask)
+{
+ /* Does not support */
+}
+
+void
+plexus_cmd_szline (char *mask, char *reason, char *whom)
+{
+ /* Does not support */
+}
+
+void
+plexus_cmd_svsnoop (char *server, int set)
+{
+ /* does not support */
+}
+
+void
+plexus_cmd_svsadmin (char *server, int set)
+{
+ plexus_cmd_svsnoop (server, set);
+}
+
+void
+plexus_cmd_sgline (char *mask, char *reason)
+{
+ send_cmd (s_OperServ, "XLINE * %s :%s", mask, reason);
+}
+
+void
+plexus_cmd_remove_akill (char *user, char *host)
+{
+ send_cmd (s_OperServ, "UNKLINE * %s %s", user, host);
+}
+
+void
+plexus_cmd_topic (char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd (whosets, "SVSTOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void
+plexus_cmd_vhost_off (User * u)
+{
+ send_cmd (ServerName, "SVSMODE %s -h", u->nick);
+}
+
+void
+plexus_cmd_vhost_on (char *nick, char *vIdent, char *vhost)
+{
+ User *u;
+
+ if (!nick)
+ {
+ return;
+ }
+
+ u = finduser (nick);
+
+ if (u)
+ {
+ send_cmd (ServerName, "SVSHOST %s %s", nick, vhost);
+ u->mode |= UMODE_h;
+ }
+}
+
+void
+plexus_cmd_unsqline (char *user)
+{
+ send_cmd (s_OperServ, "UNRESV * %s", user);
+}
+
+void
+plexus_cmd_join (char *user, char *channel, time_t chantime)
+{
+ send_cmd (ServerName, "SJOIN %ld %s + :%s", (long int) chantime, channel,
+ user);
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void
+plexus_cmd_akill (char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd (s_OperServ, "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time (NULL)), user, host, reason);
+}
+
+void
+plexus_cmd_svskill (char *source, char *user, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ if (!source || !user)
+ {
+ return;
+ }
+
+ send_cmd (source, "KILL %s :%s", user, buf);
+}
+
+void
+plexus_cmd_svsmode (User * u, int ac, char **av)
+{
+ send_cmd (ServerName, "SVSMODE %s %s", u->nick, av[0]);
+
+ if ((ac == 2) && isdigit (*av[1]))
+ send_cmd (ServerName, "SVSID %s %s", u->nick, av[1]);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void
+plexus_cmd_svinfo ()
+{
+ send_cmd (NULL, "SVINFO 5 5 0 :%ld", (long int) time (NULL));
+}
+
+/* CAPAB */
+/*
+ QS - Can handle quit storm removal
+ EX - Can do channel +e exemptions
+ CHW - Can do channel wall @#
+ LL - Can do lazy links
+ IE - Can do invite exceptions
+ EOB - Can do EOB message
+ KLN - Can do KLINE message
+ GLN - Can do GLINE message
+ HOPS - can do half ops (+h)
+ HUB - This server is a HUB
+ AOPS - Can do anon ops (+a)
+ UID - Can do UIDs
+ ZIP - Can do ZIPlinks
+ ENC - Can do ENCrypted links
+ KNOCK - supports KNOCK
+ TBURST - supports TBURST
+ PARA - supports invite broadcasting for +p
+ ENCAP - ?
+*/
+void
+plexus_cmd_capab ()
+{
+ send_cmd (NULL,
+ "CAPAB :QS EX CHW IE EOB KLN GLN HOPS HUB KNOCK TBURST PARA");
+}
+
+/* PASS */
+void
+plexus_cmd_pass (char *pass)
+{
+ send_cmd (NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER name hop descript */
+void
+plexus_cmd_server (char *servname, int hop, char *descript)
+{
+ send_cmd (NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void
+plexus_cmd_connect (int servernum)
+{
+ me_server = new_server (NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1)
+ plexus_cmd_pass (RemotePassword);
+ else if (servernum == 2)
+ plexus_cmd_pass (RemotePassword2);
+ else if (servernum == 3)
+ plexus_cmd_pass (RemotePassword3);
+
+ plexus_cmd_capab ();
+ plexus_cmd_server (ServerName, 1, ServerDesc);
+ plexus_cmd_svinfo ();
+}
+
+void
+plexus_cmd_svsinfo ()
+{
+ /* not used */
+}
+
+
+
+void
+plexus_cmd_bot_nick (char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick (nick, NULL);
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s %s 0 :%s", nick,
+ (long int) time (NULL), modes, user, host, "*", ServerName, real);
+ plexus_cmd_sqline (nick, "Reserved for services");
+
+}
+
+void
+plexus_cmd_part (char *nick, char *chan, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (nick, "PART %s :%s", chan, buf);
+ }
+ else
+ {
+ send_cmd (nick, "PART %s", chan);
+ }
+}
+
+int
+anope_event_sethost (char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser (av[0]);
+ if (!u)
+ {
+ if (debug)
+ {
+ alog ("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host (u, av[1]);
+ return MOD_CONT;
+}
+
+int
+anope_event_ping (char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ plexus_cmd_pong (ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int
+anope_event_away (char *source, int ac, char **av)
+{
+ if (!source)
+ {
+ return MOD_CONT;
+ }
+ m_away (source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int
+anope_event_kill (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill (av[0], av[1]);
+ return MOD_CONT;
+}
+
+int
+anope_event_kick (char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_eob (char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver (servlist, source);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync (s, 1);
+
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_eob ()
+{
+ send_cmd (ServerName, "EOB");
+}
+
+
+int
+anope_event_join (char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_motd (char *source, int ac, char **av)
+{
+ if (!source)
+ {
+ return MOD_CONT;
+ }
+
+ m_motd (source);
+ return MOD_CONT;
+}
+
+int
+anope_event_privmsg (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg (source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int
+anope_event_part (char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_whois (char *source, int ac, char **av)
+{
+ if (source && ac >= 1)
+ {
+ m_whois (source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int
+anope_event_server (char *source, int ac, char **av)
+{
+ if (!stricmp (av[1], "1"))
+ {
+ uplink = sstrdup (av[0]);
+ }
+ do_server (source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+int
+anope_event_squit (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_quit (char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit (source, ac, av);
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_372 (char *source, char *msg)
+{
+ send_cmd (ServerName, "372 %s :- %s", source, msg);
+}
+
+void
+plexus_cmd_372_error (char *source)
+{
+ send_cmd (ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void
+plexus_cmd_375 (char *source)
+{
+ send_cmd (ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void
+plexus_cmd_376 (char *source)
+{
+ send_cmd (ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void
+plexus_cmd_391 (char *source, char *timestr)
+{
+ if (!timestr)
+ {
+ return;
+ }
+ send_cmd (ServerName, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void
+plexus_cmd_250 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "250 %s", buf);
+}
+
+/* 307 */
+void
+plexus_cmd_307 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void
+plexus_cmd_311 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void
+plexus_cmd_312 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void
+plexus_cmd_317 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void
+plexus_cmd_219 (char *source, char *letter)
+{
+ if (!source)
+ {
+ return;
+ }
+
+ if (letter)
+ {
+ send_cmd (ServerName, "219 %s %c :End of /STATS report.", source, *letter);
+ }
+ else
+ {
+ send_cmd (ServerName, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void
+plexus_cmd_401 (char *source, char *who)
+{
+ if (!source || !who)
+ {
+ return;
+ }
+ send_cmd (ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void
+plexus_cmd_318 (char *source, char *who)
+{
+ if (!source || !who)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void
+plexus_cmd_242 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "242 %s", buf);
+}
+
+/* 243 */
+void
+plexus_cmd_243 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "243 %s", buf);
+}
+
+/* 211 */
+void
+plexus_cmd_211 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "211 %s", buf);
+}
+
+void
+plexus_cmd_mode (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source, "MODE %s %s", dest, buf);
+}
+
+void
+plexus_cmd_nick (char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick (nick, NULL);
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s %s 0 :%s", nick,
+ (long int) time (NULL), mode, ServiceUser, ServiceHost,
+ "*", ServerName, (name));
+ send_cmd (nick, "RESV * %s :%s", nick, "Reserved for services");
+}
+
+void
+plexus_cmd_kick (char *source, char *chan, char *user, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (source, "KICK %s %s :%s", chan, user, buf);
+ }
+ else
+ {
+ send_cmd (source, "KICK %s %s", chan, user);
+ }
+}
+
+void
+plexus_cmd_notice_ops (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "NOTICE @%s :%s", dest, buf);
+}
+
+void
+plexus_cmd_bot_chan_mode (char *nick, char *chan)
+{
+ anope_cmd_mode (nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+/* QUIT */
+void
+plexus_cmd_quit (char *source, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (source, "QUIT :%s", buf);
+ }
+ else
+ {
+ send_cmd (source, "QUIT");
+ }
+}
+
+/* PONG */
+void
+plexus_cmd_pong (char *servname, char *who)
+{
+ send_cmd (servname, "PONG %s", who);
+}
+
+/* INVITE */
+void
+plexus_cmd_invite (char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick)
+ {
+ return;
+ }
+
+ send_cmd (source, "INVITE %s %s", nick, chan);
+}
+
+/* SQUIT */
+void
+plexus_cmd_squit (char *servname, char *message)
+{
+ if (!servname || !message)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "SQUIT %s :%s", servname, message);
+}
+
+int
+anope_event_mode (char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&')
+ {
+ do_cmode (source, ac, av);
+ }
+ else
+ {
+ Server *s;
+ s = findserver (servlist, source);
+
+ if (s && *av[0])
+ {
+ do_umode (av[0], ac, av);
+ }
+ else
+ {
+ do_umode (source, ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_351 (char *source)
+{
+ send_cmd (ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* Event: PROTOCTL */
+int
+anope_event_capab (char *source, int ac, char **av)
+{
+ int argvsize = 8;
+ int argc;
+ char **argv;
+ char *str;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ /* We get the params as one arg, we should split it for capab_parse */
+ argv = scalloc(argvsize, sizeof(char *));
+ argc = 0;
+ while ((str = myStrGetToken(av[0], ' ', argc))) {
+ if (argc == argvsize) {
+ argvsize += 8;
+ argv = srealloc(argv, argvsize * sizeof(char *));
+ }
+ argv[argc] = str;
+ argc++;
+ }
+
+ capab_parse(argc, argv);
+
+ /* Free our built ac/av */
+ for (argvsize = 0; argvsize < argc; argvsize++) {
+ free(argv[argvsize]);
+ }
+ free(argv);
+
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void
+plexus_cmd_svshold (char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void
+plexus_cmd_release_svshold (char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void
+plexus_cmd_svsnick (char *nick, char *newnick, time_t when)
+{
+ if (!nick || !newnick)
+ {
+ return;
+ }
+ send_cmd (ServerName, "SVSNICK %s %s", nick, newnick);
+}
+
+void
+plexus_cmd_guest_nick (char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s %s 0 :%s", nick,
+ (long int) time (NULL), modes, user, host, "*", ServerName, real);
+}
+
+void
+plexus_cmd_svso (char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void
+plexus_cmd_unban (char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void
+plexus_cmd_svsmode_chan (char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void
+plexus_cmd_svid_umode (char *nick, time_t ts)
+{
+ send_cmd (ServerName, "SVSID %s 1", nick);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void
+plexus_cmd_nc_change (User * u)
+{
+ common_svsmode (u, "-R", "1");
+}
+
+/* SVSMODE +d */
+void
+plexus_cmd_svid_umode2 (User * u, char *ts)
+{
+ if (u->svid != u->timestamp)
+ {
+ common_svsmode (u, "+R", ts);
+ }
+ else
+ {
+ common_svsmode (u, "+R", NULL);
+ }
+}
+
+void
+plexus_cmd_svid_umode3 (User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void
+plexus_cmd_chg_nick (char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick)
+ {
+ return;
+ }
+
+ send_cmd (oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int
+anope_event_svinfo (char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int
+anope_event_pass (char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_svsjoin (char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void
+plexus_cmd_svspart (char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void
+plexus_cmd_swhois (char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int
+anope_event_notice (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+anope_event_admin (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+anope_event_invite (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+plexus_flood_mode_check (char *value)
+{
+ return 0;
+}
+
+int
+anope_event_error (char *source, int ac, char **av)
+{
+ if (ac >= 1)
+ {
+ if (debug)
+ {
+ alog ("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_jupe (char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf (rbuf, sizeof (rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ plexus_cmd_squit (jserver, rbuf);
+ plexus_cmd_server (jserver, 2, rbuf);
+ new_server (me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int
+plexus_valid_nick (char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int
+plexus_valid_chan (char *chan)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void
+plexus_cmd_ctcp (char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf)
+ {
+ return;
+ }
+ else
+ {
+ s = normalizeBuffer (buf);
+ }
+
+ send_cmd (source, "NOTICE %s :\1%s \1", dest, s);
+ free (s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void
+moduleAddAnopeCmds ()
+{
+ pmodule_cmd_svsnoop (plexus_cmd_svsnoop);
+ pmodule_cmd_remove_akill (plexus_cmd_remove_akill);
+ pmodule_cmd_topic (plexus_cmd_topic);
+ pmodule_cmd_vhost_off (plexus_cmd_vhost_off);
+ pmodule_cmd_akill (plexus_cmd_akill);
+ pmodule_cmd_svskill (plexus_cmd_svskill);
+ pmodule_cmd_svsmode (plexus_cmd_svsmode);
+ pmodule_cmd_372 (plexus_cmd_372);
+ pmodule_cmd_372_error (plexus_cmd_372_error);
+ pmodule_cmd_375 (plexus_cmd_375);
+ pmodule_cmd_376 (plexus_cmd_376);
+ pmodule_cmd_nick (plexus_cmd_nick);
+ pmodule_cmd_guest_nick (plexus_cmd_guest_nick);
+ pmodule_cmd_mode (plexus_cmd_mode);
+ pmodule_cmd_bot_nick (plexus_cmd_bot_nick);
+ pmodule_cmd_kick (plexus_cmd_kick);
+ pmodule_cmd_notice_ops (plexus_cmd_notice_ops);
+ pmodule_cmd_notice (plexus_cmd_notice);
+ pmodule_cmd_notice2 (plexus_cmd_notice2);
+ pmodule_cmd_privmsg (plexus_cmd_privmsg);
+ pmodule_cmd_privmsg2 (plexus_cmd_privmsg2);
+ pmodule_cmd_serv_notice (plexus_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg (plexus_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode (plexus_cmd_bot_chan_mode);
+ pmodule_cmd_351 (plexus_cmd_351);
+ pmodule_cmd_quit (plexus_cmd_quit);
+ pmodule_cmd_pong (plexus_cmd_pong);
+ pmodule_cmd_join (plexus_cmd_join);
+ pmodule_cmd_unsqline (plexus_cmd_unsqline);
+ pmodule_cmd_invite (plexus_cmd_invite);
+ pmodule_cmd_part (plexus_cmd_part);
+ pmodule_cmd_391 (plexus_cmd_391);
+ pmodule_cmd_250 (plexus_cmd_250);
+ pmodule_cmd_307 (plexus_cmd_307);
+ pmodule_cmd_311 (plexus_cmd_311);
+ pmodule_cmd_312 (plexus_cmd_312);
+ pmodule_cmd_317 (plexus_cmd_317);
+ pmodule_cmd_219 (plexus_cmd_219);
+ pmodule_cmd_401 (plexus_cmd_401);
+ pmodule_cmd_318 (plexus_cmd_318);
+ pmodule_cmd_242 (plexus_cmd_242);
+ pmodule_cmd_243 (plexus_cmd_243);
+ pmodule_cmd_211 (plexus_cmd_211);
+ pmodule_cmd_global (plexus_cmd_global);
+ pmodule_cmd_global_legacy (plexus_cmd_global_legacy);
+ pmodule_cmd_sqline (plexus_cmd_sqline);
+ pmodule_cmd_squit (plexus_cmd_squit);
+ pmodule_cmd_svso (plexus_cmd_svso);
+ pmodule_cmd_chg_nick (plexus_cmd_chg_nick);
+ pmodule_cmd_svsnick (plexus_cmd_svsnick);
+ pmodule_cmd_vhost_on (plexus_cmd_vhost_on);
+ pmodule_cmd_connect (plexus_cmd_connect);
+ pmodule_cmd_svshold (plexus_cmd_svshold);
+ pmodule_cmd_release_svshold (plexus_cmd_release_svshold);
+ pmodule_cmd_unsgline (plexus_cmd_unsgline);
+ pmodule_cmd_unszline (plexus_cmd_unszline);
+ pmodule_cmd_szline (plexus_cmd_szline);
+ pmodule_cmd_sgline (plexus_cmd_sgline);
+ pmodule_cmd_unban (plexus_cmd_unban);
+ pmodule_cmd_svsmode_chan (plexus_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode (plexus_cmd_svid_umode);
+ pmodule_cmd_nc_change (plexus_cmd_nc_change);
+ pmodule_cmd_svid_umode2 (plexus_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3 (plexus_cmd_svid_umode3);
+ pmodule_cmd_svsjoin (plexus_cmd_svsjoin);
+ pmodule_cmd_svspart (plexus_cmd_svspart);
+ pmodule_cmd_swhois (plexus_cmd_swhois);
+ pmodule_cmd_eob (plexus_cmd_eob);
+ pmodule_flood_mode_check (plexus_flood_mode_check);
+ pmodule_cmd_jupe (plexus_cmd_jupe);
+ pmodule_valid_nick (plexus_valid_nick);
+ pmodule_valid_chan (plexus_valid_chan);
+ pmodule_cmd_ctcp (plexus_cmd_ctcp);
+ pmodule_set_umode (plexus_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int
+AnopeInit (int argc, char **argv)
+{
+
+ moduleAddAuthor ("Anope");
+ moduleAddVersion ("$Id$");
+ moduleSetType (PROTOCOL);
+
+ pmodule_ircd_version ("PleXusIRCd 2.0+");
+ pmodule_ircd_cap (myIrcdcap);
+ pmodule_ircd_var (myIrcd);
+ pmodule_ircd_cbmodeinfos (myCbmodeinfos);
+ pmodule_ircd_cumodes (myCumodes);
+ pmodule_ircd_flood_mode_char_set ("");
+ pmodule_ircd_flood_mode_char_remove ("");
+ pmodule_ircd_cbmodes (myCbmodes);
+ pmodule_ircd_cmmodes (myCmmodes);
+ pmodule_ircd_csmodes (myCsmodes);
+ pmodule_ircd_useTSMode (0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode (UMODE_i);
+ pmodule_oper_umode (UMODE_o);
+ pmodule_invite_cmode (CMODE_i);
+ pmodule_secret_cmode (CMODE_s);
+ pmodule_private_cmode (CMODE_p);
+ pmodule_key_mode (CMODE_k);
+ pmodule_limit_mode (CMODE_l);
+
+ moduleAddAnopeCmds ();
+ moduleAddIRCDMsgs ();
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/protocol/plexus2.h b/src/protocol/plexus2.h
new file mode 100644
index 000000000..366909b2b
--- /dev/null
+++ b/src/protocol/plexus2.h
@@ -0,0 +1,126 @@
+/* PlexusIRCD IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_R 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_s 0x00000040
+#define UMODE_c 0x00000080
+#define UMODE_r 0x00000100
+#define UMODE_k 0x00000200
+#define UMODE_f 0x00000400
+#define UMODE_y 0x00000800
+#define UMODE_d 0x00001000
+#define UMODE_n 0x00002000
+#define UMODE_x 0x00004000
+#define UMODE_u 0x00008000
+#define UMODE_b 0x00010000
+#define UMODE_l 0x00020000
+#define UMODE_g 0x00040000
+#define UMODE_S 0x00080000
+
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_a 0x00000400
+#define CMODE_Z 0x00000800
+#define CMODE_M 0x00001000
+#define CMODE_c 0x00002000
+#define CMODE_O 0x00004000
+#define CMODE_R 0x00008000
+#define CMODE_N 0x00010000
+
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t
+
+void plexus_set_umode(User * user, int ac, char **av);
+void plexus_cmd_svsnoop(char *server, int set);
+void plexus_cmd_remove_akill(char *user, char *host);
+void plexus_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void plexus_cmd_vhost_off(User * u);
+void plexus_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void plexus_cmd_svskill(char *source, char *user, char *buf);
+void plexus_cmd_svsmode(User * u, int ac, char **av);
+void plexus_cmd_372(char *source, char *msg);
+void plexus_cmd_372_error(char *source);
+void plexus_cmd_375(char *source);
+void plexus_cmd_376(char *source);
+void plexus_cmd_nick(char *nick, char *name, char *modes);
+void plexus_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void plexus_cmd_mode(char *source, char *dest, char *buf);
+void plexus_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void plexus_cmd_kick(char *source, char *chan, char *user, char *buf);
+void plexus_cmd_notice_ops(char *source, char *dest, char *buf);
+void plexus_cmd_notice(char *source, char *dest, char *buf);
+void plexus_cmd_notice2(char *source, char *dest, char *msg);
+void plexus_cmd_privmsg(char *source, char *dest, char *buf);
+void plexus_cmd_privmsg2(char *source, char *dest, char *msg);
+void plexus_cmd_serv_notice(char *source, char *dest, char *msg);
+void plexus_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void plexus_cmd_bot_chan_mode(char *nick, char *chan);
+void plexus_cmd_351(char *source);
+void plexus_cmd_quit(char *source, char *buf);
+void plexus_cmd_pong(char *servname, char *who);
+void plexus_cmd_join(char *user, char *channel, time_t chantime);
+void plexus_cmd_unsqline(char *user);
+void plexus_cmd_invite(char *source, char *chan, char *nick);
+void plexus_cmd_part(char *nick, char *chan, char *buf);
+void plexus_cmd_391(char *source, char *timestr);
+void plexus_cmd_250(char *buf);
+void plexus_cmd_307(char *buf);
+void plexus_cmd_311(char *buf);
+void plexus_cmd_312(char *buf);
+void plexus_cmd_317(char *buf);
+void plexus_cmd_219(char *source, char *letter);
+void plexus_cmd_401(char *source, char *who);
+void plexus_cmd_318(char *source, char *who);
+void plexus_cmd_242(char *buf);
+void plexus_cmd_243(char *buf);
+void plexus_cmd_211(char *buf);
+void plexus_cmd_global(char *source, char *buf);
+void plexus_cmd_global_legacy(char *source, char *fmt);
+void plexus_cmd_sqline(char *mask, char *reason);
+void plexus_cmd_squit(char *servname, char *message);
+void plexus_cmd_svso(char *source, char *nick, char *flag);
+void plexus_cmd_chg_nick(char *oldnick, char *newnick);
+void plexus_cmd_svsnick(char *source, char *guest, time_t when);
+void plexus_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void plexus_cmd_connect(int servernum);
+void plexus_cmd_svshold(char *nick);
+void plexus_cmd_release_svshold(char *nick);
+void plexus_cmd_unsgline(char *mask);
+void plexus_cmd_unszline(char *mask);
+void plexus_cmd_szline(char *mask, char *reason, char *whom);
+void plexus_cmd_sgline(char *mask, char *reason);
+void plexus_cmd_unban(char *name, char *nick);
+void plexus_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void plexus_cmd_svid_umode(char *nick, time_t ts);
+void plexus_cmd_nc_change(User * u);
+void plexus_cmd_svid_umode2(User * u, char *ts);
+void plexus_cmd_svid_umode3(User * u, char *ts);
+void plexus_cmd_eob();
+int plexus_flood_mode_check(char *value);
+void plexus_cmd_jupe(char *jserver, char *who, char *reason);
+int plexus_valid_nick(char *nick);
+void plexus_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/plexus3.c b/src/protocol/plexus3.c
new file mode 100644
index 000000000..2265e66b8
--- /dev/null
+++ b/src/protocol/plexus3.c
@@ -0,0 +1,1857 @@
+/* PlexusIRCD IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "plexus3.h"
+
+IRCDVar myIrcd[] = {
+ {"hybrid-7.2.1+plexus-3.0.0+",/* ircd name */
+ "+i", /* nickserv mode */
+ "+i", /* chanserv mode */
+ "+i", /* memoserv mode */
+ "+i", /* hostserv mode */
+ "+oai", /* operserv mode */
+ "+i", /* botserv mode */
+ "+i", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+i", /* Global mode */
+ "+i", /* nickserv alias mode */
+ "+i", /* chanserv alias mode */
+ "+i", /* memoserv alias mode */
+ "+i", /* hostserv alias mode */
+ "+oai", /* operserv alias mode */
+ "+i", /* botserv alias mode */
+ "+i", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+i", /* Global alias mode */
+ "+i", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-cilmnpstBMNORS", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for chan admin */
+ "-a", /* Mode to unset for chan admin */
+ "+rd", /* Mode On Reg */
+ "N", /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ UMODE_N, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 0, /* Reverse */
+ 0, /* Chan Reg */
+ 0, /* Channel Mode */
+ 0, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 1, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ CAPAB_QS, /* QS */
+ CAPAB_UID, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+
+void
+plexus_set_umode (User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog ("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes)
+ {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++)
+ {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0)
+ {
+ alog ("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul (*av, NULL, 0);
+ break;
+ case 'x':
+ update_host (user);
+ break;
+ case 'o':
+ if (add)
+ {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global (s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news (user, NEWS_OPER);
+
+ }
+ else
+ {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified (user))
+ {
+ common_svsmode (user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ 0, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, UMODE_N, 0, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ UMODE_S, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ 0, 0, 0, /* d e f */
+ 0, 0, UMODE_i, /* g h i */
+ 0, 0, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ 0, 0, 0, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 'a',
+ 0, 0, 0, 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'q', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {CMODE_B, CBM_NO_USER_MLOCK, NULL, NULL}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {0},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'B', CMODE_B, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void
+plexus_cmd_notice (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG)
+ {
+ plexus_cmd_privmsg2 (source, dest, buf);
+ }
+ else
+ {
+ send_cmd (source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void
+plexus_cmd_notice2 (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "NOTICE %s :%s", dest, msg);
+}
+
+void
+plexus_cmd_privmsg (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void
+plexus_cmd_privmsg2 (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void
+plexus_cmd_serv_notice (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void
+plexus_cmd_serv_privmsg (char *source, char *dest, char *msg)
+{
+ send_cmd (source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void
+plexus_cmd_global (char *source, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source ? source : ServerName, "OPERWALL :%s", buf);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void
+plexus_cmd_global_legacy (char *source, char *fmt)
+{
+ send_cmd (source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int
+anope_event_sjoin (char *source, int ac, char **av)
+{
+ do_sjoin (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_nick (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ {
+ User *user = do_nick (source, av[0], av[4], av[8], av[6], av[9],
+ strtoul (av[2], NULL, 10),
+ strtoul (av[7], NULL, 0), 0, av[5], NULL);
+ if (user)
+ anope_set_umode (user, 1, &av[3]);
+ }
+ else
+ {
+ do_nick (source, av[0], NULL, NULL, NULL, NULL,
+ strtoul (av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int
+anope_event_topic (char *source, int ac, char **av)
+{
+ if (ac == 4)
+ {
+ do_topic (source, ac, av);
+ }
+ else
+ {
+ Channel *c = findchan (av[0]);
+ time_t topic_time = time (NULL);
+
+ if (!c)
+ {
+ if (debug)
+ {
+ alog ("debug: TOPIC %s for nonexistent channel %s",
+ merge_args (ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock (c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic)
+ {
+ free (c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup (av[1]);
+
+ strscpy (c->topic_setter, source, sizeof (c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic (av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ }
+ return MOD_CONT;
+}
+
+int
+anope_event_tburst (char *source, int ac, char **av)
+{
+ if (ac != 5)
+ return MOD_CONT;
+
+ av[0] = av[1];
+ av[1] = av[3];
+ av[3] = av[4];
+ do_topic (source, 4, av);
+ return MOD_CONT;
+}
+
+/*
+ * ENCAP handler
+ * av[0] = servermask (not used)
+ * av[1] = command
+ * av[2] and beyond are dynamic.
+ */
+int
+anope_event_encap (char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (!stricmp (av[1], "CHGHOST"))
+ {
+ User *u;
+
+ if (ac != 4)
+ return MOD_CONT;
+
+ u = finduser (av[2]);
+ if (!u)
+ {
+ if (debug)
+ {
+ alog ("debug: CHGHOST for nonexistent user %s", av[2]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host (u, av[3]);
+ return MOD_CONT;
+ }
+ return MOD_CONT;
+}
+
+int
+anope_event_436 (char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll (av[0]);
+ return MOD_CONT;
+}
+
+
+void
+moduleAddIRCDMsgs (void)
+{
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage ("401", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("402", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("436", anope_event_436);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("AWAY", anope_event_away);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("INVITE", anope_event_invite);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("JOIN", anope_event_join);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("KICK", anope_event_kick);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("KILL", anope_event_kill);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("MODE", anope_event_mode);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("MOTD", anope_event_motd);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("NICK", anope_event_nick);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("NOTICE", anope_event_notice);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PART", anope_event_part);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PASS", anope_event_pass);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PING", anope_event_ping);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("PRIVMSG", anope_event_privmsg);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("QUIT", anope_event_quit);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SERVER", anope_event_server);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SQUIT", anope_event_squit);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("TOPIC", anope_event_topic);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("TBURST", anope_event_tburst);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("USER", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("WALLOPS", anope_event_null);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("WHOIS", anope_event_whois);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("CAPAB", anope_event_capab);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SJOIN", anope_event_sjoin);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SVINFO", anope_event_svinfo);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("EOB", anope_event_eob);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("ADMIN", anope_event_admin);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("ERROR", anope_event_error);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("ENCAP", anope_event_encap);
+ addCoreMessage (IRCD, m);
+ m = createMessage ("SVSMODE", anope_event_mode);
+ addCoreMessage (IRCD, m);
+}
+
+void
+plexus_cmd_sqline (char *mask, char *reason)
+{
+ send_cmd (s_OperServ, "RESV * %s :%s", mask, reason);
+}
+
+void
+plexus_cmd_unsgline (char *mask)
+{
+ send_cmd (s_OperServ, "UNXLINE * %s", mask);
+}
+
+void
+plexus_cmd_unszline (char *mask)
+{
+ /* Does not support */
+}
+
+void
+plexus_cmd_szline (char *mask, char *reason, char *whom)
+{
+ /* Does not support */
+}
+
+void
+plexus_cmd_svsnoop (char *server, int set)
+{
+ send_cmd(ServerName, "ENCAP %s SVSNOOP %s",
+ server, (set ? "+" : "-"));
+}
+
+void
+plexus_cmd_svsadmin (char *server, int set)
+{
+ plexus_cmd_svsnoop (server, set);
+}
+
+void
+plexus_cmd_sgline (char *mask, char *reason)
+{
+ send_cmd (s_OperServ, "XLINE * %s 0 :%s", mask, reason);
+}
+
+void
+plexus_cmd_remove_akill (char *user, char *host)
+{
+ send_cmd (s_OperServ, "UNKLINE * %s %s", user, host);
+}
+
+void
+plexus_cmd_topic (char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd (whosets, "ENCAP * TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void
+plexus_cmd_vhost_off (User * u)
+{
+ common_svsmode (u, "-x", NULL);
+}
+
+void
+plexus_cmd_vhost_on (char *nick, char *vIdent, char *vhost)
+{
+ User *u;
+
+ if (!nick)
+ {
+ return;
+ }
+
+ u = finduser (nick);
+
+ if (u)
+ {
+ send_cmd (ServerName, "ENCAP * CHGHOST %s %s", u->nick, vhost);
+ common_svsmode (u, "+x", NULL);
+ u->mode |= UMODE_x;
+ }
+}
+
+void
+plexus_cmd_unsqline (char *user)
+{
+ send_cmd (s_OperServ, "UNRESV * %s", user);
+}
+
+void
+plexus_cmd_join (char *user, char *channel, time_t chantime)
+{
+ send_cmd (ServerName, "SJOIN %ld %s + :%s", (long int) chantime, channel,
+ user);
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void
+plexus_cmd_akill (char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd (s_OperServ, "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time (NULL)), user, host, reason);
+}
+
+void
+plexus_cmd_svskill (char *source, char *user, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ if (!source || !user)
+ {
+ return;
+ }
+
+ send_cmd (source, "KILL %s :%s", user, buf);
+}
+
+void
+plexus_cmd_svsmode (User * u, int ac, char **av)
+{
+ send_cmd (ServerName, "ENCAP * SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void
+plexus_cmd_svinfo ()
+{
+ send_cmd (NULL, "SVINFO 5 5 0 :%ld", (long int) time (NULL));
+}
+
+/* CAPAB */
+/*
+ QS - Can handle quit storm removal
+ EX - Can do channel +e exemptions
+ CHW - Can do channel wall @#
+ LL - Can do lazy links
+ IE - Can do invite exceptions
+ EOB - Can do EOB message
+ KLN - Can do KLINE message
+ GLN - Can do GLINE message
+ HOPS - can do half ops (+h)
+ HUB - This server is a HUB
+ AOPS - Can do anon ops (+a)
+ UID - Can do UIDs
+ ZIP - Can do ZIPlinks
+ ENC - Can do ENCrypted links
+ KNOCK - supports KNOCK
+ TBURST - supports TBURST
+ PARA - supports invite broadcasting for +p
+ ENCAP - supports encapsulization of protocol messages
+ SVS - supports services protocol extensions
+*/
+void
+plexus_cmd_capab ()
+{
+ send_cmd (NULL,
+ "CAPAB :QS EX CHW IE EOB KLN UNKLN GLN HUB KNOCK TBURST PARA ENCAP SVS");
+}
+
+/* PASS */
+void
+plexus_cmd_pass (char *pass)
+{
+ send_cmd (NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER name hop descript */
+void
+plexus_cmd_server (char *servname, int hop, char *descript)
+{
+ send_cmd (NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void
+plexus_cmd_connect (int servernum)
+{
+ me_server = new_server (NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1)
+ plexus_cmd_pass (RemotePassword);
+ else if (servernum == 2)
+ plexus_cmd_pass (RemotePassword2);
+ else if (servernum == 3)
+ plexus_cmd_pass (RemotePassword3);
+
+ plexus_cmd_capab ();
+ plexus_cmd_server (ServerName, 1, ServerDesc);
+ plexus_cmd_svinfo ();
+}
+
+void
+plexus_cmd_svsinfo ()
+{
+ /* not used */
+}
+
+
+
+void
+plexus_cmd_bot_nick (char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick (nick, NULL);
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s 0 %s :%s", nick,
+ (long int) time (NULL), modes, user, host, ServerName, host,
+ real);
+ plexus_cmd_sqline (nick, "Reserved for services");
+
+}
+
+void
+plexus_cmd_part (char *nick, char *chan, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (nick, "PART %s :%s", chan, buf);
+ }
+ else
+ {
+ send_cmd (nick, "PART %s", chan);
+ }
+}
+
+int
+anope_event_ping (char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ plexus_cmd_pong (ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int
+anope_event_away (char *source, int ac, char **av)
+{
+ if (!source)
+ {
+ return MOD_CONT;
+ }
+ m_away (source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int
+anope_event_kill (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill (av[0], av[1]);
+ return MOD_CONT;
+}
+
+int
+anope_event_kick (char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_eob (char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver (servlist, source);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync (s, 1);
+
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_eob ()
+{
+ send_cmd (ServerName, "EOB");
+}
+
+
+int
+anope_event_join (char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_motd (char *source, int ac, char **av)
+{
+ if (!source)
+ {
+ return MOD_CONT;
+ }
+
+ m_motd (source);
+ return MOD_CONT;
+}
+
+int
+anope_event_privmsg (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg (source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int
+anope_event_part (char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_whois (char *source, int ac, char **av)
+{
+ if (source && ac >= 1)
+ {
+ m_whois (source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int
+anope_event_server (char *source, int ac, char **av)
+{
+ if (!stricmp (av[1], "1"))
+ {
+ uplink = sstrdup (av[0]);
+ }
+ do_server (source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+int
+anope_event_squit (char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit (source, ac, av);
+ return MOD_CONT;
+}
+
+int
+anope_event_quit (char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit (source, ac, av);
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_372 (char *source, char *msg)
+{
+ send_cmd (ServerName, "372 %s :- %s", source, msg);
+}
+
+void
+plexus_cmd_372_error (char *source)
+{
+ send_cmd (ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void
+plexus_cmd_375 (char *source)
+{
+ send_cmd (ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void
+plexus_cmd_376 (char *source)
+{
+ send_cmd (ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void
+plexus_cmd_391 (char *source, char *timestr)
+{
+ if (!timestr)
+ {
+ return;
+ }
+ send_cmd (ServerName, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void
+plexus_cmd_250 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "250 %s", buf);
+}
+
+/* 307 */
+void
+plexus_cmd_307 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void
+plexus_cmd_311 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void
+plexus_cmd_312 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void
+plexus_cmd_317 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void
+plexus_cmd_219 (char *source, char *letter)
+{
+ if (!source)
+ {
+ return;
+ }
+
+ if (letter)
+ {
+ send_cmd (ServerName, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ }
+ else
+ {
+ send_cmd (ServerName, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void
+plexus_cmd_401 (char *source, char *who)
+{
+ if (!source || !who)
+ {
+ return;
+ }
+ send_cmd (ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void
+plexus_cmd_318 (char *source, char *who)
+{
+ if (!source || !who)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void
+plexus_cmd_242 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "242 %s", buf);
+}
+
+/* 243 */
+void
+plexus_cmd_243 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "243 %s", buf);
+}
+
+/* 211 */
+void
+plexus_cmd_211 (char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "211 %s", buf);
+}
+
+void
+plexus_cmd_mode (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (source, "MODE %s %s", dest, buf);
+}
+
+void
+plexus_cmd_nick (char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick (nick, NULL);
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s 0 %s :%s", nick,
+ (long int) time (NULL), mode, ServiceUser, ServiceHost,
+ ServerName, ServiceHost, (name));
+ send_cmd (nick, "RESV * %s :%s", nick, "Reserved for services");
+}
+
+void
+plexus_cmd_kick (char *source, char *chan, char *user, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (source, "KICK %s %s :%s", chan, user, buf);
+ }
+ else
+ {
+ send_cmd (source, "KICK %s %s", chan, user);
+ }
+}
+
+void
+plexus_cmd_notice_ops (char *source, char *dest, char *buf)
+{
+ if (!buf)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "NOTICE @%s :%s", dest, buf);
+}
+
+void
+plexus_cmd_bot_chan_mode (char *nick, char *chan)
+{
+ anope_cmd_mode (nick, chan, "%s %s %s", myIrcd->botchanumode, nick, nick);
+}
+
+/* QUIT */
+void
+plexus_cmd_quit (char *source, char *buf)
+{
+ if (buf)
+ {
+ send_cmd (source, "QUIT :%s", buf);
+ }
+ else
+ {
+ send_cmd (source, "QUIT");
+ }
+}
+
+/* PONG */
+void
+plexus_cmd_pong (char *servname, char *who)
+{
+ send_cmd (servname, "PONG %s", who);
+}
+
+/* INVITE */
+void
+plexus_cmd_invite (char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick)
+ {
+ return;
+ }
+
+ send_cmd (source, "INVITE %s %s", nick, chan);
+}
+
+/* SQUIT */
+void
+plexus_cmd_squit (char *servname, char *message)
+{
+ if (!servname || !message)
+ {
+ return;
+ }
+
+ send_cmd (ServerName, "SQUIT %s :%s", servname, message);
+}
+
+int
+anope_event_mode (char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&')
+ {
+ do_cmode (source, ac, av);
+ }
+ else
+ {
+ Server *s;
+ s = findserver (servlist, source);
+
+ if (s && *av[0])
+ {
+ do_umode (av[0], ac, av);
+ }
+ else
+ {
+ do_umode (source, ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_351 (char *source)
+{
+ send_cmd (ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* Event: PROTOCTL */
+int
+anope_event_capab (char *source, int ac, char **av)
+{
+ int argvsize = 8;
+ int argc;
+ char **argv;
+ char *str;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ /* We get the params as one arg, we should split it for capab_parse */
+ argv = scalloc (argvsize, sizeof (char *));
+ argc = 0;
+ while ((str = myStrGetToken (av[0], ' ', argc)))
+ {
+ if (argc == argvsize)
+ {
+ argvsize += 8;
+ argv = srealloc (argv, argvsize * sizeof (char *));
+ }
+ argv[argc] = str;
+ argc++;
+ }
+
+ capab_parse (argc, argv);
+
+ /* Free our built ac/av */
+ for (argvsize = 0; argvsize < argc; argvsize++)
+ {
+ free (argv[argvsize]);
+ }
+ free (argv);
+
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void
+plexus_cmd_svshold (char *nick)
+{
+ send_cmd (s_OperServ, "ENCAP * RESV %d %s 0 :%s", NSReleaseTimeout, nick,
+ "This nick is being held for a registered user. "
+ "For help with regaining nicknames please see /nickserv help release");
+}
+
+/* SVSHOLD - release */
+void
+plexus_cmd_release_svshold (char *nick)
+{
+ send_cmd (s_OperServ, "UNRESV * %s", nick);
+}
+
+/* SVSNICK */
+void
+plexus_cmd_svsnick (char *nick, char *newnick, time_t when)
+{
+ User *u;
+
+ if (!nick || !newnick)
+ return;
+
+ if( (u = finduser (nick))) {
+ send_cmd (ServerName, "ENCAP * SVSNICK %s %ld %s %ld",
+ u->nick, (long int) u->timestamp, newnick, (long int) when);
+ }
+}
+
+void
+plexus_cmd_guest_nick (char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd (ServerName, "NICK %s 1 %ld %s %s %s %s 0 %s :%s", nick,
+ (long int) time (NULL), modes, user, host, ServerName, host,
+ real);
+}
+
+void
+plexus_cmd_svso (char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void
+plexus_cmd_unban (char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void
+plexus_cmd_svsmode_chan (char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void
+plexus_cmd_svid_umode (char *nick, time_t ts)
+{
+ send_cmd (ServerName, "ENCAP * SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void
+plexus_cmd_nc_change (User * u)
+{
+ common_svsmode (u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void
+plexus_cmd_svid_umode2 (User * u, char *ts)
+{
+ /* not used */
+}
+
+void
+plexus_cmd_svid_umode3 (User * u, char *ts)
+{
+ char modes[512];
+
+ strlcpy(modes, "+r", sizeof(modes));
+
+ if(ircd->rootmodeonid && is_services_root(u)) {
+ strlcat(modes, ircd->rootmodeonid, sizeof(modes));
+ } else if(ircd->adminmodeonid && is_services_admin(u)) {
+ strlcat(modes, ircd->adminmodeonid, sizeof(modes));
+ } else if(ircd->opermodeonid && is_services_oper(u)) {
+ strlcat(modes, ircd->opermodeonid, sizeof(modes));
+ }
+ if (u->svid != u->timestamp) {
+ strlcat(modes, "d", sizeof(modes));
+ common_svsmode (u, modes, ts);
+ } else {
+ common_svsmode (u, modes, NULL);
+ }
+}
+
+/* NICK <newnick> */
+void
+plexus_cmd_chg_nick (char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick)
+ {
+ return;
+ }
+
+ send_cmd (oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int
+anope_event_svinfo (char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int
+anope_event_pass (char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_svsjoin (char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(ServerName, "ENCAP * SVSJOIN %s %s", nick, chan);
+}
+
+void
+plexus_cmd_svspart (char *source, char *nick, char *chan)
+{
+ send_cmd(ServerName, "ENCAP * SVSPART %s %s", nick, chan);
+}
+
+void
+plexus_cmd_swhois (char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int
+anope_event_notice (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+anope_event_admin (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+anope_event_invite (char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int
+plexus_flood_mode_check (char *value)
+{
+ return 0;
+}
+
+int
+anope_event_error (char *source, int ac, char **av)
+{
+ if (ac >= 1)
+ {
+ if (debug)
+ {
+ alog ("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void
+plexus_cmd_jupe (char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf (rbuf, sizeof (rbuf), "(H) Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ plexus_cmd_squit (jserver, rbuf);
+ plexus_cmd_server (jserver, 2, rbuf);
+ new_server (me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int
+plexus_valid_nick (char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int
+plexus_valid_chan (char *chan)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void
+plexus_cmd_ctcp (char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf)
+ {
+ return;
+ }
+ else
+ {
+ s = normalizeBuffer (buf);
+ }
+
+ send_cmd (source, "NOTICE %s :\1%s \1", dest, s);
+ free (s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void
+moduleAddAnopeCmds ()
+{
+ pmodule_cmd_svsnoop (plexus_cmd_svsnoop);
+ pmodule_cmd_remove_akill (plexus_cmd_remove_akill);
+ pmodule_cmd_topic (plexus_cmd_topic);
+ pmodule_cmd_vhost_off (plexus_cmd_vhost_off);
+ pmodule_cmd_akill (plexus_cmd_akill);
+ pmodule_cmd_svskill (plexus_cmd_svskill);
+ pmodule_cmd_svsmode (plexus_cmd_svsmode);
+ pmodule_cmd_372 (plexus_cmd_372);
+ pmodule_cmd_372_error (plexus_cmd_372_error);
+ pmodule_cmd_375 (plexus_cmd_375);
+ pmodule_cmd_376 (plexus_cmd_376);
+ pmodule_cmd_nick (plexus_cmd_nick);
+ pmodule_cmd_guest_nick (plexus_cmd_guest_nick);
+ pmodule_cmd_mode (plexus_cmd_mode);
+ pmodule_cmd_bot_nick (plexus_cmd_bot_nick);
+ pmodule_cmd_kick (plexus_cmd_kick);
+ pmodule_cmd_notice_ops (plexus_cmd_notice_ops);
+ pmodule_cmd_notice (plexus_cmd_notice);
+ pmodule_cmd_notice2 (plexus_cmd_notice2);
+ pmodule_cmd_privmsg (plexus_cmd_privmsg);
+ pmodule_cmd_privmsg2 (plexus_cmd_privmsg2);
+ pmodule_cmd_serv_notice (plexus_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg (plexus_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode (plexus_cmd_bot_chan_mode);
+ pmodule_cmd_351 (plexus_cmd_351);
+ pmodule_cmd_quit (plexus_cmd_quit);
+ pmodule_cmd_pong (plexus_cmd_pong);
+ pmodule_cmd_join (plexus_cmd_join);
+ pmodule_cmd_unsqline (plexus_cmd_unsqline);
+ pmodule_cmd_invite (plexus_cmd_invite);
+ pmodule_cmd_part (plexus_cmd_part);
+ pmodule_cmd_391 (plexus_cmd_391);
+ pmodule_cmd_250 (plexus_cmd_250);
+ pmodule_cmd_307 (plexus_cmd_307);
+ pmodule_cmd_311 (plexus_cmd_311);
+ pmodule_cmd_312 (plexus_cmd_312);
+ pmodule_cmd_317 (plexus_cmd_317);
+ pmodule_cmd_219 (plexus_cmd_219);
+ pmodule_cmd_401 (plexus_cmd_401);
+ pmodule_cmd_318 (plexus_cmd_318);
+ pmodule_cmd_242 (plexus_cmd_242);
+ pmodule_cmd_243 (plexus_cmd_243);
+ pmodule_cmd_211 (plexus_cmd_211);
+ pmodule_cmd_global (plexus_cmd_global);
+ pmodule_cmd_global_legacy (plexus_cmd_global_legacy);
+ pmodule_cmd_sqline (plexus_cmd_sqline);
+ pmodule_cmd_squit (plexus_cmd_squit);
+ pmodule_cmd_svso (plexus_cmd_svso);
+ pmodule_cmd_chg_nick (plexus_cmd_chg_nick);
+ pmodule_cmd_svsnick (plexus_cmd_svsnick);
+ pmodule_cmd_vhost_on (plexus_cmd_vhost_on);
+ pmodule_cmd_connect (plexus_cmd_connect);
+ pmodule_cmd_svshold (plexus_cmd_svshold);
+ pmodule_cmd_release_svshold (plexus_cmd_release_svshold);
+ pmodule_cmd_unsgline (plexus_cmd_unsgline);
+ pmodule_cmd_unszline (plexus_cmd_unszline);
+ pmodule_cmd_szline (plexus_cmd_szline);
+ pmodule_cmd_sgline (plexus_cmd_sgline);
+ pmodule_cmd_unban (plexus_cmd_unban);
+ pmodule_cmd_svsmode_chan (plexus_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode (plexus_cmd_svid_umode);
+ pmodule_cmd_nc_change (plexus_cmd_nc_change);
+ pmodule_cmd_svid_umode2 (plexus_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3 (plexus_cmd_svid_umode3);
+ pmodule_cmd_svsjoin (plexus_cmd_svsjoin);
+ pmodule_cmd_svspart (plexus_cmd_svspart);
+ pmodule_cmd_swhois (plexus_cmd_swhois);
+ pmodule_cmd_eob (plexus_cmd_eob);
+ pmodule_flood_mode_check (plexus_flood_mode_check);
+ pmodule_cmd_jupe (plexus_cmd_jupe);
+ pmodule_valid_nick (plexus_valid_nick);
+ pmodule_valid_chan (plexus_valid_chan);
+ pmodule_cmd_ctcp (plexus_cmd_ctcp);
+ pmodule_set_umode (plexus_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int
+AnopeInit (int argc, char **argv)
+{
+
+ moduleAddAuthor ("Anope");
+ moduleAddVersion ("$Id$");
+ moduleSetType (PROTOCOL);
+
+ pmodule_ircd_version ("hybrid-7.2.1+plexus-3.0.0+");
+ pmodule_ircd_cap (myIrcdcap);
+ pmodule_ircd_var (myIrcd);
+ pmodule_ircd_cbmodeinfos (myCbmodeinfos);
+ pmodule_ircd_cumodes (myCumodes);
+ pmodule_ircd_flood_mode_char_set ("");
+ pmodule_ircd_flood_mode_char_remove ("");
+ pmodule_ircd_cbmodes (myCbmodes);
+ pmodule_ircd_cmmodes (myCmmodes);
+ pmodule_ircd_csmodes (myCsmodes);
+ pmodule_ircd_useTSMode (0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode (UMODE_i);
+ pmodule_oper_umode (UMODE_o);
+ pmodule_invite_cmode (CMODE_i);
+ pmodule_secret_cmode (CMODE_s);
+ pmodule_private_cmode (CMODE_p);
+ pmodule_key_mode (CMODE_k);
+ pmodule_limit_mode (CMODE_l);
+
+ moduleAddAnopeCmds ();
+ moduleAddIRCDMsgs ();
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/protocol/plexus3.h b/src/protocol/plexus3.h
new file mode 100644
index 000000000..eedd4a572
--- /dev/null
+++ b/src/protocol/plexus3.h
@@ -0,0 +1,113 @@
+/* PlexusIRCD IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_i 0x00000001
+#define UMODE_o 0x00000002
+#define UMODE_w 0x00000004
+#define UMODE_a 0x00000008
+#define UMODE_x 0x00000010
+#define UMODE_S 0x00000020
+#define UMODE_r 0x00000040
+#define UMODE_R 0x00000080
+#define UMODE_N 0x00000100
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_M 0x00001000
+#define CMODE_c 0x00002000
+#define CMODE_O 0x00004000
+#define CMODE_R 0x00008000
+#define CMODE_N 0x00010000
+#define CMODE_B 0x00020000
+#define CMODE_S 0x00040000
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t
+
+void plexus_set_umode(User * user, int ac, char **av);
+void plexus_cmd_svsnoop(char *server, int set);
+void plexus_cmd_remove_akill(char *user, char *host);
+void plexus_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void plexus_cmd_vhost_off(User * u);
+void plexus_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void plexus_cmd_svskill(char *source, char *user, char *buf);
+void plexus_cmd_svsmode(User * u, int ac, char **av);
+void plexus_cmd_372(char *source, char *msg);
+void plexus_cmd_372_error(char *source);
+void plexus_cmd_375(char *source);
+void plexus_cmd_376(char *source);
+void plexus_cmd_nick(char *nick, char *name, char *modes);
+void plexus_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void plexus_cmd_mode(char *source, char *dest, char *buf);
+void plexus_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void plexus_cmd_kick(char *source, char *chan, char *user, char *buf);
+void plexus_cmd_notice_ops(char *source, char *dest, char *buf);
+void plexus_cmd_notice(char *source, char *dest, char *buf);
+void plexus_cmd_notice2(char *source, char *dest, char *msg);
+void plexus_cmd_privmsg(char *source, char *dest, char *buf);
+void plexus_cmd_privmsg2(char *source, char *dest, char *msg);
+void plexus_cmd_serv_notice(char *source, char *dest, char *msg);
+void plexus_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void plexus_cmd_bot_chan_mode(char *nick, char *chan);
+void plexus_cmd_351(char *source);
+void plexus_cmd_quit(char *source, char *buf);
+void plexus_cmd_pong(char *servname, char *who);
+void plexus_cmd_join(char *user, char *channel, time_t chantime);
+void plexus_cmd_unsqline(char *user);
+void plexus_cmd_invite(char *source, char *chan, char *nick);
+void plexus_cmd_part(char *nick, char *chan, char *buf);
+void plexus_cmd_391(char *source, char *timestr);
+void plexus_cmd_250(char *buf);
+void plexus_cmd_307(char *buf);
+void plexus_cmd_311(char *buf);
+void plexus_cmd_312(char *buf);
+void plexus_cmd_317(char *buf);
+void plexus_cmd_219(char *source, char *letter);
+void plexus_cmd_401(char *source, char *who);
+void plexus_cmd_318(char *source, char *who);
+void plexus_cmd_242(char *buf);
+void plexus_cmd_243(char *buf);
+void plexus_cmd_211(char *buf);
+void plexus_cmd_global(char *source, char *buf);
+void plexus_cmd_global_legacy(char *source, char *fmt);
+void plexus_cmd_sqline(char *mask, char *reason);
+void plexus_cmd_squit(char *servname, char *message);
+void plexus_cmd_svso(char *source, char *nick, char *flag);
+void plexus_cmd_chg_nick(char *oldnick, char *newnick);
+void plexus_cmd_svsnick(char *source, char *guest, time_t when);
+void plexus_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void plexus_cmd_connect(int servernum);
+void plexus_cmd_svshold(char *nick);
+void plexus_cmd_release_svshold(char *nick);
+void plexus_cmd_unsgline(char *mask);
+void plexus_cmd_unszline(char *mask);
+void plexus_cmd_szline(char *mask, char *reason, char *whom);
+void plexus_cmd_sgline(char *mask, char *reason);
+void plexus_cmd_unban(char *name, char *nick);
+void plexus_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void plexus_cmd_svid_umode(char *nick, time_t ts);
+void plexus_cmd_nc_change(User * u);
+void plexus_cmd_svid_umode2(User * u, char *ts);
+void plexus_cmd_svid_umode3(User * u, char *ts);
+void plexus_cmd_eob();
+int plexus_flood_mode_check(char *value);
+void plexus_cmd_jupe(char *jserver, char *who, char *reason);
+int plexus_valid_nick(char *nick);
+void plexus_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/ptlink.c b/src/protocol/ptlink.c
new file mode 100644
index 000000000..9e6eb08b1
--- /dev/null
+++ b/src/protocol/ptlink.c
@@ -0,0 +1,1800 @@
+/* PTLink IRCD functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "ptlink.h"
+
+IRCDVar myIrcd[] = {
+ {"PTlink 6.15.*+", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ "+o", /* hostserv mode */
+ "+io", /* operserv mode */
+ "+o", /* botserv mode */
+ "+h", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+io", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-inpsmtCRKOASdcqBNl", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ "+a", /* Mode to set for chan admin */
+ "-a", /* Mode to unset for chan admin */
+ "+r", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r", /* Mode on UnReg */
+ NULL, /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 0, /* Supports Halfop +h */
+ 4, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_VH, /* Vhost Mode */
+ 1, /* +f */
+ 0, /* +L */
+ CMODE_f,
+ 0,
+ 1,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ CAPAB_PT4, /* PT4 */
+ CAPAB_SCS, /* SCS */
+ CAPAB_QS, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, UMODE_B, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, UMODE_H, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, UMODE_N, UMODE_O, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ UMODE_S, UMODE_T, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ 0, 0, 0, /* d e f */
+ 0, UMODE_h, UMODE_i, /* g h i */
+ 0, 0, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ UMODE_p, 0, UMODE_r, /* p q r */
+ UMODE_s, 0, 0, /* s t u */
+ UMODE_v, UMODE_w, 0, /* v w x */
+ UMODE_y, /* y */
+ UMODE_z, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 'a', 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, 0, NULL, NULL}, /* A */
+ {CMODE_B, 0, NULL, NULL}, /* B */
+ {CMODE_C, 0, NULL, NULL}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {0}, /* L */
+ {0}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, 0, NULL, NULL}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {CMODE_d, 0, NULL, NULL},
+ {0}, /* e */
+ {CMODE_f, 0, set_flood, cs_set_flood},
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {CMODE_q, 0, NULL, NULL},
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'d', CMODE_d, 0, NULL, NULL},
+ {'f', CMODE_f, 0, get_flood, cs_get_flood},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'q', CMODE_q, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'B', CMODE_B, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void ptlink_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(s_ChanServ, chan, "%s %s %s", ircd->botchanumode, nick,
+ nick);
+}
+
+/*
+ :%s SJOIN %lu %s %s %s :%s
+ parv[0] = sender
+ parv[1] = channel TS (channel creation time)
+ parv[2] = channel
+ parv[3] = modes + n arguments (key and/or limit)
+ ... [n] = if(key and/or limit) mode arguments
+ parv[4+n] = flags+nick list (all in one parameter)
+ NOTE: ignore channel modes if we already have the channel with a gr
+*/
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+ * Note: This function has no validation whatsoever. Also, as of PTlink6.15.1
+ * when you /deoper you get to keep your vindent, but you lose your vhost. In
+ * that case serives will *NOT* modify it's internal record for the vhost. We
+ * need to address this in the future.
+ */
+/*
+ :%s NEWMASK %s
+ parv[0] = sender
+ parv[1] = new mask (if no '@', hostname is assumed)
+*/
+int anope_event_newmask(char *source, int ac, char **av)
+{
+ User *u;
+ char *newhost = NULL, *newuser = NULL;
+ int tofree = 0;
+
+ if (ac != 1)
+ return MOD_CONT;
+ u = finduser(source);
+
+ if (!u) {
+ if (debug) {
+ alog("debug: NEWMASK for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if ((u->mode & (UMODE_NM | UMODE_VH)) == (UMODE_NM | UMODE_VH)) {
+ /* This NEWMASK should be discarded because it's sent due to a +r by
+ * someone with a ptlink-masked host. PTlink has our correct host, so
+ * we can just ignore this :) Or we'll get ptlink's old host which is
+ * not what we want. -GD
+ */
+ u->mode &= ~UMODE_NM;
+ if (debug)
+ alog("debug: Ignoring NEWMASK because it's send because of SVSMODE +r");
+ return MOD_CONT;
+ }
+
+ newuser = myStrGetOnlyToken(av[0], '@', 0);
+ if (newuser) {
+ newhost = myStrGetTokenRemainder(av[0], '@', 1);
+ tofree = 1;
+ change_user_username(u, newuser);
+ free(newuser);
+ } else {
+ newhost = av[0];
+ }
+
+ if (newhost && *newhost == '@')
+ newhost++;
+
+ u->mode |= UMODE_VH;
+
+ if (newhost)
+ change_user_host(u, newhost);
+
+ if (tofree)
+ free(newhost);
+
+ return MOD_CONT;
+}
+
+/*
+ NICK %s %d %lu %s %s %s %s %s :%s
+ parv[0] = nickname
+ parv[1] = hopcount
+ parv[2] = nick TS (nick introduction time)
+ parv[3] = umodes
+ parv[4] = username
+ parv[5] = hostname
+ parv[6] = spoofed hostname
+ parv[7] = server
+ parv[8] = nick info
+*/
+/*
+ Change NICK
+ parv[0] = old nick
+ parv[1] = new nick
+ parv[2] = TS (timestamp from user's server when nick changed was received)
+*/
+/*
+ NICK xpto 2 561264 +rw irc num.myisp.pt mask.myisp.pt uc.ptlink.net :Just me
+ 0 1 2 3 4 5 6 7 8
+
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[7], av[8],
+ strtoul(av[2], NULL, 10), 0, 0, av[6], NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+/*
+ :%s SERVER %s %d %s :%s
+ parv[0] = server from where the server was introduced to us
+ parv[1] = server name
+ parv[2] = hop count (1 wen are directly connected)
+ parv[3] = server version
+ parv[4] = server description
+*/
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[3], NULL);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+void moduleAddIRCDMsgs(void)
+{
+ Message *m;
+
+ updateProtectDetails("PROTECT", "PROTECTME", "protect", "deprotect",
+ "AUTOPROTECT", "+a", "-a");
+
+ m = createMessage("401", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("402", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("436", anope_event_436);
+ addCoreMessage(IRCD, m);
+ m = createMessage("461", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("AWAY", anope_event_away);
+ addCoreMessage(IRCD, m);
+ m = createMessage("INVITE", anope_event_invite);
+ addCoreMessage(IRCD, m);
+ m = createMessage("JOIN", anope_event_join);
+ addCoreMessage(IRCD, m);
+ m = createMessage("KICK", anope_event_kick);
+ addCoreMessage(IRCD, m);
+ m = createMessage("KILL", anope_event_kill);
+ addCoreMessage(IRCD, m);
+ m = createMessage("MODE", anope_event_mode);
+ addCoreMessage(IRCD, m);
+ m = createMessage("MOTD", anope_event_motd);
+ addCoreMessage(IRCD, m);
+ m = createMessage("NICK", anope_event_nick);
+ addCoreMessage(IRCD, m);
+ m = createMessage("NOTICE", anope_event_notice);
+ addCoreMessage(IRCD, m);
+ m = createMessage("PART", anope_event_part);
+ addCoreMessage(IRCD, m);
+ m = createMessage("PASS", anope_event_pass);
+ addCoreMessage(IRCD, m);
+ m = createMessage("PING", anope_event_ping);
+ addCoreMessage(IRCD, m);
+ m = createMessage("PRIVMSG", anope_event_privmsg);
+ addCoreMessage(IRCD, m);
+ m = createMessage("QUIT", anope_event_quit);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SERVER", anope_event_server);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SQUIT", anope_event_squit);
+ addCoreMessage(IRCD, m);
+ m = createMessage("TOPIC", anope_event_topic);
+ addCoreMessage(IRCD, m);
+ m = createMessage("USER", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("WALLOPS", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("WHOIS", anope_event_whois);
+ addCoreMessage(IRCD, m);
+ m = createMessage("AKILL", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("GLOBOPS", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("GNOTICE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("GOPER", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("RAKILL", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SILENCE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVSKILL", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVSMODE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVSNICK", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVSNOOP", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SQLINE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("UNSQLINE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("NEWMASK", anope_event_newmask);
+ addCoreMessage(IRCD, m);
+ m = createMessage("CAPAB", anope_event_capab);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVINFO", anope_event_svinfo);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SVSINFO", anope_event_svsinfo);
+ addCoreMessage(IRCD, m);
+ m = createMessage("SJOIN", anope_event_sjoin);
+ addCoreMessage(IRCD, m);
+ m = createMessage("REHASH", anope_event_rehash);
+ addCoreMessage(IRCD, m);
+ m = createMessage("ADMIN", anope_event_admin);
+ addCoreMessage(IRCD, m);
+ m = createMessage("CREDITS", anope_event_credits);
+ addCoreMessage(IRCD, m);
+ m = createMessage("ERROR", anope_event_error);
+ addCoreMessage(IRCD, m);
+ m = createMessage("NJOIN", anope_event_sjoin);
+ addCoreMessage(IRCD, m);
+ m = createMessage("NNICK", anope_event_nick);
+ addCoreMessage(IRCD, m);
+ m = createMessage("ZLINE", anope_event_null);
+ addCoreMessage(IRCD, m);
+ m = createMessage("UNZLINE", anope_event_null);
+ addCoreMessage(IRCD, m);
+}
+
+int anope_event_svsinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/*
+ :%s SQLINE %s :%s
+ parv[0] = sender
+ parv[1] = sqlined nick/mask
+ parv[2] = reason
+*/
+void ptlink_cmd_sqline(char *mask, char *reason)
+{
+ send_cmd(ServerName, "SQLINE %s :%s", mask, reason);
+}
+
+/*
+ :%s SVSADMIN %s :%s
+ parv[0] = sender (services client)
+ parv[1] = target server
+ parv[2] = operation
+ operations:
+ noopers - remove existing opers and disable o:lines
+*/
+void ptlink_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSADMIN %s :%s", server, set ? "noopers" : "rehash");
+}
+
+void ptlink_cmd_svsadmin(char *server, int set)
+{
+ ptlink_cmd_svsnoop(server, set);
+}
+
+/*
+ :%s UNGLINE %s
+ parv[0] = sender (server if on network synchronization)
+ parv[1] = glined usert@host mask or ALL to remove all glines
+*/
+void ptlink_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "UNGLINE %s@%s", user, host);
+}
+
+
+void anope_part(char *nick, char *chan)
+{
+ send_cmd(nick, "PART %s", chan);
+}
+void anope_topic(char *whosets, char *chan, char *whosetit, char *topic,
+ time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+/*
+ :%s UNSQLINE %s
+ parv[0] = sender
+ parv[1] = sqlined nick/mask
+*/
+void ptlink_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+void ptlink_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(ServerName, "SJOIN %ld %s + :%s", (long int) chantime,
+ channel, user);
+}
+
+/*
+ :%s GLINE %s %lu %s %s
+ parv[0] = sender (server if on network synchronization)
+ parv[1] = glined usert@host mask
+ parv[2] = gline duration time (seconds)
+ parv[3] = who added the gline
+ parv[4] = reason
+*/
+void ptlink_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(ServerName, "GLINE %s@%s %i %s :%s", user, host, 86400 * 2,
+ who, reason);
+}
+
+
+void ptlink_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+/*
+ :%s SVSMODE %s %s :%s
+ parv[0] = sender (services client)
+ parv[1] = target client nick
+ parv[2] = mode changes
+ parv[3] = extra parameter ( if news setting mode(+n) )
+ e.g.: :NickServ SVSMODE Lamego +rn 1991234
+*/
+void ptlink_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %s%s%s", u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+
+ /* If we set +r on someone +NRah (1 or more of those modes), PTlink will
+ * send us a NEWMASK with their ptlink-masked-host. If we want HostServ
+ * to work for them, we will need to send our NEWMASK after we receive
+ * theirs. Thus we make a hack and store in moduleData that we need to
+ * look out for that.
+ */
+ if ((strchr(av[0], 'r')
+ && ((u->mode & UMODE_N) || (u->mode & UMODE_R)
+ || (u->mode & UMODE_a) || (u->mode & UMODE_h))))
+ u->mode |= UMODE_NM;
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void ptlink_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* PONG */
+void ptlink_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/*
+ SVINFO %d %d
+ parv[0] = server name
+ parv[1] = current supported protocol version
+ parv[2] = minimum supported protocol version
+
+ See the ptlink.h for information on PTLINK_TS_CURRENT, and
+ PTLINK_TS_MIN
+*/
+void ptlink_cmd_svinfo()
+{
+#if defined(PTLINK_TS_CURRENT) && defined(PTLINK_TS_MIN)
+ send_cmd(NULL, "SVINFO %d %d %lu", PTLINK_TS_CURRENT, PTLINK_TS_MIN,
+ (unsigned long int) time(NULL));
+#else
+ /* hardwired if the defs some how go missing */
+ send_cmd(NULL, "SVINFO 6 3 %lu", (unsigned long int) time(NULL));
+#endif
+}
+
+/*
+ SVSINFO %lu %d
+ parv[0] = sender (server name)
+ parv[1] = local services data TS
+ parv[1] = max global users
+*/
+void ptlink_cmd_svsinfo()
+{
+ send_cmd(NULL, "SVSINFO %lu %d", (unsigned long int) time(NULL),
+ maxusercnt);
+}
+
+/*
+ PASS %s :TS
+ parv[1] = connection password
+ (TS indicates this is server uses TS protocol and SVINFO will be sent
+ for protocol compatibility checking)
+*/
+void ptlink_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/*
+ CAPAB :%s
+ parv[1] = capability list
+*/
+void ptlink_cmd_capab()
+{
+ send_cmd(NULL, "CAPAB :QS PTS4");
+}
+
+
+void ptlink_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d Anope.Services%s :%s", servname, hop,
+ version_number_dotted, descript);
+}
+void ptlink_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1)
+ ptlink_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ ptlink_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ ptlink_cmd_pass(RemotePassword3);
+
+ ptlink_cmd_capab();
+ ptlink_cmd_server(ServerName, 1, ServerDesc);
+ ptlink_cmd_svinfo();
+ ptlink_cmd_svsinfo();
+}
+
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/*
+ :%s TOPIC %s %s %lu :%s
+ parv[0] = sender prefix
+ parv[1] = channel
+ parv[2] = topic nick
+ parv[3] = topic time
+ parv[4] = topic text
+*/
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+ :%s MODE %s :%s
+ parv[0] = sender
+ parv[1] = target nick (==sender)
+ parv[2] = mode change string
+*/
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+void ptlink_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void ptlink_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ ptlink_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void ptlink_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void ptlink_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void ptlink_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void ptlink_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void ptlink_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+/* GLOBOPS */
+void ptlink_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* 391 */
+void ptlink_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void ptlink_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void ptlink_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void ptlink_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void ptlink_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void ptlink_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void ptlink_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void ptlink_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void ptlink_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void ptlink_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void ptlink_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void ptlink_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void ptlink_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+/*
+ NICK %s %d %lu %s %s %s %s %s :%s
+ parv[1] = nickname
+ parv[2] = hopcount
+ parv[3] = nick TS (nick introduction time)
+ parv[4] = umodes
+ parv[5] = username
+ parv[6] = hostname
+ parv[7] = spoofed hostname
+ parv[8] = server
+ parv[9] = nick info
+*/
+void ptlink_cmd_nick(char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %lu %s %s %s %s %s :%s", nick,
+ (unsigned long int) time(NULL), mode, ServiceUser,
+ ServiceHost, ServiceHost, ServerName, name);
+ ptlink_cmd_sqline(nick, "Reserved for services");
+}
+
+void ptlink_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+/* QUIT */
+void ptlink_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+void ptlink_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/*
+ :%s TOPIC %s %s %lu :%s
+ parv[0] = sender prefix
+ parv[1] = channel
+ parv[2] = topic nick
+ parv[3] = topic time
+ parv[4] = topic text
+*/
+void ptlink_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (long int) time(NULL), topic);
+}
+
+void ptlink_cmd_vhost_off(User * u)
+{
+ /* does not support vhosting */
+}
+
+void ptlink_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ User *u;
+
+ if (vIdent) {
+ send_cmd(s_HostServ, "NEWMASK %s@%s %s", vIdent, vhost, nick);
+ } else {
+ send_cmd(s_HostServ, "NEWMASK %s %s", vhost, nick);
+ }
+
+ if ((u = finduser(nick)))
+ u->mode |= UMODE_VH;
+}
+
+/* INVITE */
+void ptlink_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+void ptlink_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void ptlink_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void ptlink_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void ptlink_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+
+void ptlink_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+ if (is_services_admin(user)) {
+ common_svsmode(user, "+a", NULL);
+ user->mode |= UMODE_a;
+ }
+
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ }
+ }
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ ptlink_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+void ptlink_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %lu %s %s %s %s %s :%s", nick,
+ (unsigned long int) time(NULL), modes, user, host, host,
+ ServerName, real);
+ ptlink_cmd_sqline(nick, "Reserved for services");
+
+}
+
+void ptlink_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+
+
+}
+
+/* SVSHOLD - set */
+void ptlink_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void ptlink_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/*
+:%s UNZLINE %s
+ parv[0] = sender
+ parv[1] = zlined host
+*/
+void ptlink_cmd_unszline(char *mask)
+{
+ send_cmd(s_OperServ, "UNZLINE %s", mask);
+}
+
+/*
+:%s ZLINE %s :%s
+ parv[0] = sender
+ parv[1] = zlined host
+ parv[2] = time
+ parv[3] = reason
+*/
+void ptlink_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(s_OperServ, "ZLINE %s %ld :%s", mask,
+ (long int) time(NULL) + 86400 * 2, reason);
+}
+
+/*
+:%s UNSXLINE %s
+ parv[0] = sender
+ parv[1] = info ban mask
+*/
+void ptlink_cmd_unsgline(char *mask)
+{
+ send_cmd(ServerName, "UNSXLINE :%s", mask);
+}
+
+
+/*
+ * sxline - add info ban line
+ *
+ * parv[0] = sender prefix
+ * parv[1] = mask length
+ * parv[2] = real name banned mask:reason
+ */
+void ptlink_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(ServerName, "SXLINE %d :%s:%s", (int) strlen(mask), mask,
+ reason);
+}
+
+/* SVSNICK */
+/*
+ :%s SVSNICK %s %s
+ parv[0] = sender (services client)
+ parv[1] = target client nick
+ parv[2] = new nick
+ e.g.: :NickServ SVSNICK Smiler 67455223 _Smiler-
+*/
+void ptlink_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void ptlink_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %lu %s %s %s %s %s :%s", nick,
+ (unsigned long int) time(NULL), modes, user, host, host,
+ ServerName, real);
+}
+
+
+void ptlink_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void ptlink_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ptlink_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void ptlink_cmd_svid_umode(char *nick, time_t ts)
+{
+ /* Not Supported by this ircd */
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void ptlink_cmd_nc_change(User * u)
+{
+ /* Not Supported by this ircd */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void ptlink_cmd_svid_umode2(User * u, char *ts)
+{
+ common_svsmode(u, "+r", NULL);
+}
+
+void ptlink_cmd_svid_umode3(User * u, char *ts)
+{
+ /* Bahamuts have this extra one, since they can check on even nick changes */
+}
+
+/* NICK <newnick> */
+/*
+ :%s NICK %s %lu
+ parv[0] = old nick
+ parv[1] = new nick
+ parv[2] = TS (timestamp from user's server when nick changed was received)
+*/
+void ptlink_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s %ld", newnick, (long int) time(NULL));
+}
+
+/*
+ :%s SVSJOIN %s :%s
+ parv[0] = sender (services client)
+ parv[1] = target client nick
+ parv[2] = channels list
+ :OperServ SVSJOIN Trystan #Admin
+*/
+void ptlink_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(source, "SVSJOIN %s %s", nick, chan);
+}
+
+/*
+ :%s SVSPART %s :%s
+ parv[0] = sender (services client)
+ parv[1] = target client nick
+ parv[2] = channels list
+ e.g.: :ChanServ SVSPART mynick 4163321 #Chan1,#Chan2
+*/
+void ptlink_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SVSPART %s :%s", nick, chan);
+}
+
+void ptlink_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int ptlink_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void ptlink_cmd_eob()
+{
+ /* not supported */
+}
+
+void ptlink_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ ptlink_cmd_squit(jserver, rbuf);
+ ptlink_cmd_server(jserver, 1, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void ptlink_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int ptlink_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int ptlink_valid_chan(char *cahn)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void ptlink_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(ptlink_cmd_svsnoop);
+ pmodule_cmd_remove_akill(ptlink_cmd_remove_akill);
+ pmodule_cmd_topic(ptlink_cmd_topic);
+ pmodule_cmd_vhost_off(ptlink_cmd_vhost_off);
+ pmodule_cmd_akill(ptlink_cmd_akill);
+ pmodule_cmd_svskill(ptlink_cmd_svskill);
+ pmodule_cmd_svsmode(ptlink_cmd_svsmode);
+ pmodule_cmd_372(ptlink_cmd_372);
+ pmodule_cmd_372_error(ptlink_cmd_372_error);
+ pmodule_cmd_375(ptlink_cmd_375);
+ pmodule_cmd_376(ptlink_cmd_376);
+ pmodule_cmd_nick(ptlink_cmd_nick);
+ pmodule_cmd_guest_nick(ptlink_cmd_guest_nick);
+ pmodule_cmd_mode(ptlink_cmd_mode);
+ pmodule_cmd_bot_nick(ptlink_cmd_bot_nick);
+ pmodule_cmd_kick(ptlink_cmd_kick);
+ pmodule_cmd_notice_ops(ptlink_cmd_notice_ops);
+ pmodule_cmd_notice(ptlink_cmd_notice);
+ pmodule_cmd_notice2(ptlink_cmd_notice2);
+ pmodule_cmd_privmsg(ptlink_cmd_privmsg);
+ pmodule_cmd_privmsg2(ptlink_cmd_privmsg2);
+ pmodule_cmd_serv_notice(ptlink_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(ptlink_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(ptlink_cmd_bot_chan_mode);
+ pmodule_cmd_351(ptlink_cmd_351);
+ pmodule_cmd_quit(ptlink_cmd_quit);
+ pmodule_cmd_pong(ptlink_cmd_pong);
+ pmodule_cmd_join(ptlink_cmd_join);
+ pmodule_cmd_unsqline(ptlink_cmd_unsqline);
+ pmodule_cmd_invite(ptlink_cmd_invite);
+ pmodule_cmd_part(ptlink_cmd_part);
+ pmodule_cmd_391(ptlink_cmd_391);
+ pmodule_cmd_250(ptlink_cmd_250);
+ pmodule_cmd_307(ptlink_cmd_307);
+ pmodule_cmd_311(ptlink_cmd_311);
+ pmodule_cmd_312(ptlink_cmd_312);
+ pmodule_cmd_317(ptlink_cmd_317);
+ pmodule_cmd_219(ptlink_cmd_219);
+ pmodule_cmd_401(ptlink_cmd_401);
+ pmodule_cmd_318(ptlink_cmd_318);
+ pmodule_cmd_242(ptlink_cmd_242);
+ pmodule_cmd_243(ptlink_cmd_243);
+ pmodule_cmd_211(ptlink_cmd_211);
+ pmodule_cmd_global(ptlink_cmd_global);
+ pmodule_cmd_global_legacy(ptlink_cmd_global_legacy);
+ pmodule_cmd_sqline(ptlink_cmd_sqline);
+ pmodule_cmd_squit(ptlink_cmd_squit);
+ pmodule_cmd_svso(ptlink_cmd_svso);
+ pmodule_cmd_chg_nick(ptlink_cmd_chg_nick);
+ pmodule_cmd_svsnick(ptlink_cmd_svsnick);
+ pmodule_cmd_vhost_on(ptlink_cmd_vhost_on);
+ pmodule_cmd_connect(ptlink_cmd_connect);
+ pmodule_cmd_svshold(ptlink_cmd_svshold);
+ pmodule_cmd_release_svshold(ptlink_cmd_release_svshold);
+ pmodule_cmd_unsgline(ptlink_cmd_unsgline);
+ pmodule_cmd_unszline(ptlink_cmd_unszline);
+ pmodule_cmd_szline(ptlink_cmd_szline);
+ pmodule_cmd_sgline(ptlink_cmd_sgline);
+ pmodule_cmd_unban(ptlink_cmd_unban);
+ pmodule_cmd_svsmode_chan(ptlink_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(ptlink_cmd_svid_umode);
+ pmodule_cmd_nc_change(ptlink_cmd_nc_change);
+ pmodule_cmd_svid_umode2(ptlink_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(ptlink_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(ptlink_cmd_svsjoin);
+ pmodule_cmd_svspart(ptlink_cmd_svspart);
+ pmodule_cmd_swhois(ptlink_cmd_swhois);
+ pmodule_cmd_eob(ptlink_cmd_eob);
+ pmodule_flood_mode_check(ptlink_flood_mode_check);
+ pmodule_cmd_jupe(ptlink_cmd_jupe);
+ pmodule_valid_nick(ptlink_valid_nick);
+ pmodule_valid_chan(ptlink_valid_chan);
+ pmodule_cmd_ctcp(ptlink_cmd_ctcp);
+ pmodule_set_umode(ptlink_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+
+ pmodule_ircd_version("PTlink 6.15.*+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/protocol/ptlink.h b/src/protocol/ptlink.h
new file mode 100644
index 000000000..a7c1d2c3f
--- /dev/null
+++ b/src/protocol/ptlink.h
@@ -0,0 +1,152 @@
+/* PTLink IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_B 0x00000080
+#define UMODE_H 0x00000100
+#define UMODE_N 0x00000200
+#define UMODE_O 0x00000400
+#define UMODE_p 0x00000800
+#define UMODE_R 0x00001000
+#define UMODE_s 0x00002000
+#define UMODE_S 0x00004000
+#define UMODE_T 0x00008000
+#define UMODE_v 0x00001000
+#define UMODE_y 0x00002000
+#define UMODE_z 0x00004000
+
+#define UMODE_VH 0x00008000 /* Fake umode used for internal vhost things */
+#define UMODE_NM 0x00010000 /* Fake umode used for internal NEWMASK things */
+/* Let's hope for a better vhost-system with PTlink7 ;) */
+
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_A 0x00000400
+#define CMODE_B 0x00000800
+#define CMODE_c 0x00001000
+#define CMODE_d 0x00002000
+#define CMODE_f 0x00004000
+#define CMODE_K 0x00008000
+#define CMODE_O 0x00010000
+#define CMODE_q 0x00020000
+#define CMODE_S 0x00040000
+#define CMODE_N 0x00080000
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_C 0x00100000
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+/*
+ The following variables are set to define the TS protocol version
+ that we support.
+
+ PTLink 6.14 to 6.17 TS CURRENT is 6 and MIN is 3
+ PTlink 6.18 TS CURRENT is 9 and MIN is 3
+ PTLink 6.19 TS CURRENT is 10 and MIN is 9
+
+ If you are running 6.18 or 6.19 do not touch these values as they will
+ allow you to connect
+
+ If you are running an older version of PTLink, first think about updating
+ your ircd, or changing the TS_CURRENT to 6 to allow services to connect
+*/
+
+#define PTLINK_TS_CURRENT 9
+#define PTLINK_TS_MIN 3
+
+void ptlink_set_umode(User * user, int ac, char **av);
+void ptlink_cmd_svsnoop(char *server, int set);
+void ptlink_cmd_remove_akill(char *user, char *host);
+void ptlink_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void ptlink_cmd_vhost_off(User * u);
+void ptlink_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void ptlink_cmd_svskill(char *source, char *user, char *buf);
+void ptlink_cmd_svsmode(User * u, int ac, char **av);
+void ptlink_cmd_372(char *source, char *msg);
+void ptlink_cmd_372_error(char *source);
+void ptlink_cmd_375(char *source);
+void ptlink_cmd_376(char *source);
+void ptlink_cmd_nick(char *nick, char *name, char *modes);
+void ptlink_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ptlink_cmd_mode(char *source, char *dest, char *buf);
+void ptlink_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ptlink_cmd_kick(char *source, char *chan, char *user, char *buf);
+void ptlink_cmd_notice_ops(char *source, char *dest, char *buf);
+void ptlink_cmd_notice(char *source, char *dest, char *buf);
+void ptlink_cmd_notice2(char *source, char *dest, char *msg);
+void ptlink_cmd_privmsg(char *source, char *dest, char *buf);
+void ptlink_cmd_privmsg2(char *source, char *dest, char *msg);
+void ptlink_cmd_serv_notice(char *source, char *dest, char *msg);
+void ptlink_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void ptlink_cmd_bot_chan_mode(char *nick, char *chan);
+void ptlink_cmd_351(char *source);
+void ptlink_cmd_quit(char *source, char *buf);
+void ptlink_cmd_pong(char *servname, char *who);
+void ptlink_cmd_join(char *user, char *channel, time_t chantime);
+void ptlink_cmd_unsqline(char *user);
+void ptlink_cmd_invite(char *source, char *chan, char *nick);
+void ptlink_cmd_part(char *nick, char *chan, char *buf);
+void ptlink_cmd_391(char *source, char *timestr);
+void ptlink_cmd_250(char *buf);
+void ptlink_cmd_307(char *buf);
+void ptlink_cmd_311(char *buf);
+void ptlink_cmd_312(char *buf);
+void ptlink_cmd_317(char *buf);
+void ptlink_cmd_219(char *source, char *letter);
+void ptlink_cmd_401(char *source, char *who);
+void ptlink_cmd_318(char *source, char *who);
+void ptlink_cmd_242(char *buf);
+void ptlink_cmd_243(char *buf);
+void ptlink_cmd_211(char *buf);
+void ptlink_cmd_global(char *source, char *buf);
+void ptlink_cmd_global_legacy(char *source, char *fmt);
+void ptlink_cmd_sqline(char *mask, char *reason);
+void ptlink_cmd_squit(char *servname, char *message);
+void ptlink_cmd_svso(char *source, char *nick, char *flag);
+void ptlink_cmd_chg_nick(char *oldnick, char *newnick);
+void ptlink_cmd_svsnick(char *source, char *guest, time_t when);
+void ptlink_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void ptlink_cmd_connect(int servernum);
+void ptlink_cmd_svshold(char *nick);
+void ptlink_cmd_release_svshold(char *nick);
+void ptlink_cmd_unsgline(char *mask);
+void ptlink_cmd_unszline(char *mask);
+void ptlink_cmd_szline(char *mask, char *reason, char *whom);
+void ptlink_cmd_sgline(char *mask, char *reason);
+void ptlink_cmd_unban(char *name, char *nick);
+void ptlink_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void ptlink_cmd_svid_umode(char *nick, time_t ts);
+void ptlink_cmd_nc_change(User * u);
+void ptlink_cmd_svid_umode2(User * u, char *ts);
+void ptlink_cmd_svid_umode3(User * u, char *ts);
+void ptlink_cmd_eob();
+int ptlink_flood_mode_check(char *value);
+void ptlink_cmd_jupe(char *jserver, char *who, char *reason);
+int ptlink_valid_nick(char *nick);
+void ptlink_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/rageircd.c b/src/protocol/rageircd.c
new file mode 100644
index 000000000..94fc7824e
--- /dev/null
+++ b/src/protocol/rageircd.c
@@ -0,0 +1,1679 @@
+/* Rage IRCD functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "rageircd.h"
+
+IRCDVar myIrcd[] = {
+ {"RageIRCd 2.0.*", /* ircd name */
+ "+d", /* nickserv mode */
+ "+d", /* chanserv mode */
+ "+d", /* memoserv mode */
+ "+d", /* hostserv mode */
+ "+di", /* operserv mode */
+ "+d", /* botserv mode */
+ "+dh", /* helpserv mode */
+ "+di", /* Dev/Null mode */
+ "+di", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+io", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+o", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 3, /* Chan Max Symbols */
+ "-ilmnpRstcOACNM", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-rd", /* Mode on UnReg */
+ "-r+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topic Backward */
+ 0, /* Protected Umode */
+ 1, /* Has Admin */
+ 1, /* Chan SQlines */
+ 1, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0,
+ 0,
+ 1,
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ CAPAB_TSMODE, /* TSMODE */
+ CAPAB_UNCONNECT, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ CAPAB_BURST, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ CAPAB_DKEY, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ CAPAB_UID, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ CAPAB_SN2, /* SN2 */
+ CAPAB_TOKEN, /* TOKEN */
+ CAPAB_VHOST, /* VHOST */
+ CAPAB_SSJ3, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, 0, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ 0, 0, 0, /* d e f */
+ 0, UMODE_h, UMODE_i, /* g h i */
+ 0, 0, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ 0, 0, 0, /* s t u */
+ 0, UMODE_w, 0, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 0, 0, 0, 0,
+ 'a', /* * Channel Admins */
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {CMODE_C, 0, NULL, NULL},
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_admin},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void rageircd_cmd_bot_unban(ChannelInfo * ci, char *nick)
+{
+ send_cmd(ServerName, "SVSMODE %s -b %s", ci->name, nick);
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[7], NULL, 0),
+ strtoul(av[8], NULL, 0), "*", NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_vhost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: VHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+/*
+** SNICK
+** source = NULL
+** parv[0] = nickname Trystan
+** parv[1] = timestamp 1090113640
+** parv[2] = hops 1
+** parv[3] = username Trystan
+** parv[4] = host c-24-2-101-227.client.comcast.net
+** parv[5] = IP 402810339
+** parv[6] = vhost mynet-27CCA80D.client.comcast.net
+** parv[7] = server rage2.nomadirc.net
+** parv[8] = servicestamp 0
+** parv[9] = modes +ix
+** parv[10] = info Dreams are answers to questions not yet asked
+*/
+
+int anope_event_snick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[3], av[4], av[7], av[10],
+ strtoul(av[1], NULL, 10), strtoul(av[8], NULL, 0),
+ strtoul(av[5], NULL, 0), av[6], NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[9]);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("ADMIN","ADMINME","admin","deadmin","AUTOADMIN","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("482", anope_event_482); addCoreMessage(IRCD,m);
+ m = createMessage("461", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_globops); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m);
+ m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m);
+ m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m);
+ m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m);
+ m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m);
+ m = createMessage("RS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("SZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SNICK", anope_event_snick); addCoreMessage(IRCD,m);
+ m = createMessage("VHOST", anope_event_vhost); addCoreMessage(IRCD,m);
+ m = createMessage("MYID", anope_event_myid); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_burst(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ if (ac > 1) {
+ /* for future use - start burst */
+} else {
+
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+}
+
+return MOD_CONT;
+}
+
+void rageircd_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+void rageircd_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "UNSGLINE 0 :%s", mask);
+}
+
+void rageircd_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "UNSZLINE 0 %s", mask);
+}
+
+void rageircd_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "SZLINE %s :%s", mask, reason);
+}
+
+void rageircd_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void rageircd_cmd_svsadmin(char *server, int set)
+{
+ rageircd_cmd_svsnoop(server, set);
+}
+
+void rageircd_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
+
+}
+
+void rageircd_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+
+/* PART */
+void rageircd_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+void rageircd_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void rageircd_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "SVSMODE %s -x", u->nick);
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick, ircd->vhostchar);
+}
+
+void rageircd_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "VHOST %s %s", nick, vhost);
+}
+
+void rageircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ send_cmd(s_HostServ, "SVSMODE %s +x", nick);
+ rageircd_cmd_chghost(nick, vhost);
+}
+
+void rageircd_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+void rageircd_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "SJOIN %ld %s", (long int) chantime, channel);
+}
+
+void rageircd_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400 * 2, who,
+ (long int) time(NULL), reason);
+}
+
+void rageircd_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "SVSKILL %s :%s", user, buf);
+}
+
+void rageircd_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+void rageircd_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* PONG */
+void rageircd_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+void rageircd_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 5 3 0 %ld bluemoon 0", (long int) time(NULL));
+}
+
+void rageircd_cmd_capab()
+{
+ /* CAPAB BURST UNCONNECT ZIP SSJ3 SN2 VHOST SUID TOK1 TSMODE */
+ send_cmd(NULL, "CAPAB BURST UNCONNECT SSJ3 SN2 VHOST TSMODE");
+}
+
+void rageircd_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+/* PASS */
+void rageircd_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+void rageircd_cmd_burst()
+{
+ send_cmd(NULL, "BURST");
+}
+
+void rageircd_cmd_connect(int servernum)
+{
+ if (Numeric) {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, Numeric);
+ } else {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+ }
+
+ if (servernum == 1)
+ rageircd_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ rageircd_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ rageircd_cmd_pass(RemotePassword3);
+ rageircd_cmd_capab();
+ if (Numeric) {
+ send_cmd(NULL, "MYID !%s", Numeric);
+ }
+ rageircd_cmd_server(ServerName, 1, ServerDesc);
+ rageircd_cmd_svinfo();
+ rageircd_cmd_burst();
+}
+
+void rageircd_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+ if (is_services_oper(user)) {
+ common_svsmode(user, "+a", NULL);
+ user->mode |= UMODE_a;
+ }
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+/* GLOBOPS */
+void rageircd_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+void rageircd_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void rageircd_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ rageircd_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void rageircd_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void rageircd_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void rageircd_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void rageircd_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void rageircd_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ rageircd_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void rageircd_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+void rageircd_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (ircdcap->tsmode) {
+ if (uplink_capab & ircdcap->tsmode || UseTSMODE) {
+ send_cmd(source, "MODE %s 0 %s", dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+
+void rageircd_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void rageircd_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void rageircd_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void rageircd_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void rageircd_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* INVITE */
+void rageircd_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* 391 */
+void rageircd_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void rageircd_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void rageircd_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void rageircd_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void rageircd_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void rageircd_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void rageircd_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void rageircd_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void rageircd_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void rageircd_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void rageircd_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void rageircd_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void rageircd_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "SNICK %s %ld 1 %s %s 0 * %s 0 %s :%s", nick,
+ (long int) time(NULL), ServiceUser, ServiceHost, ServerName,
+ modes, name);
+ rageircd_cmd_sqline(nick, "Reserved for services");
+}
+
+/* EVENT : OS */
+int anope_event_os(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_OperServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : NS */
+int anope_event_ns(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_NickServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : MS */
+int anope_event_ms(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_MemoServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : HS */
+int anope_event_hs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_HostServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : CS */
+int anope_event_cs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_ChanServ, av[0]);
+ return MOD_CONT;
+}
+
+/* QUIT */
+void rageircd_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+void rageircd_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "SNICK %s %ld 1 %s %s 0 * %s 0 %s :%s", nick,
+ (long int) time(NULL), user, host, ServerName, modes, real);
+ rageircd_cmd_sqline(nick, "Reserved for services");
+}
+
+/* SVSMODE -b */
+void rageircd_cmd_unban(char *name, char *nick)
+{
+ rageircd_cmd_svsmode_chan(name, "-b", nick);
+}
+
+
+/* SVSMODE channel modes */
+
+void rageircd_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "SVSMODE %s %s %s", name, mode, nick);
+ } else {
+ send_cmd(ServerName, "SVSMODE %s %s", name, mode);
+ }
+}
+
+void rageircd_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_482(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void rageircd_cmd_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s %d :%s", nick, NSReleaseTimeout,
+ "Being held for registered user");
+}
+
+/* SVSHOLD - release */
+void rageircd_cmd_release_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s 0", nick);
+}
+
+void rageircd_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void rageircd_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(NULL, "SNICK %s %ld 1 %s %s 0 * %s 0 %s :%s", nick,
+ (long int) time(NULL), user, host, ServerName, modes, real);
+}
+
+
+void rageircd_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void rageircd_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void rageircd_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void rageircd_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used by bahamut ircds */
+}
+
+void rageircd_cmd_svid_umode3(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+/* NICK <newnick> */
+void rageircd_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+int anope_event_myid(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ *
+ * if (parc == 2)
+ * parv[1] = ZIP (compression initialisation)
+ *
+ * if (parc > 2)
+ * parv[1] = TS_CURRENT
+ * parv[2] = TS_MIN
+ * parv[3] = standalone or connected to non-TS (unused)
+ * parv[4] = UTC time
+ * parv[5] = ircd codename
+ * parv[6] = masking keys
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_gnotice(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+void rageircd_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Find no reference to it in the code and docs */
+}
+
+void rageircd_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Find no reference to it in the code and docs */
+}
+
+void rageircd_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_globops(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int rageircd_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+void rageircd_cmd_eob()
+{
+ send_cmd(NULL, "BURST 0");
+}
+
+void rageircd_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ rageircd_cmd_squit(jserver, rbuf);
+ rageircd_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void rageircd_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int rageircd_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int rageircd_valid_chan(char *chan)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+
+void rageircd_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(rageircd_cmd_svsnoop);
+ pmodule_cmd_remove_akill(rageircd_cmd_remove_akill);
+ pmodule_cmd_topic(rageircd_cmd_topic);
+ pmodule_cmd_vhost_off(rageircd_cmd_vhost_off);
+ pmodule_cmd_akill(rageircd_cmd_akill);
+ pmodule_cmd_svskill(rageircd_cmd_svskill);
+ pmodule_cmd_svsmode(rageircd_cmd_svsmode);
+ pmodule_cmd_372(rageircd_cmd_372);
+ pmodule_cmd_372_error(rageircd_cmd_372_error);
+ pmodule_cmd_375(rageircd_cmd_375);
+ pmodule_cmd_376(rageircd_cmd_376);
+ pmodule_cmd_nick(rageircd_cmd_nick);
+ pmodule_cmd_guest_nick(rageircd_cmd_guest_nick);
+ pmodule_cmd_mode(rageircd_cmd_mode);
+ pmodule_cmd_bot_nick(rageircd_cmd_bot_nick);
+ pmodule_cmd_kick(rageircd_cmd_kick);
+ pmodule_cmd_notice_ops(rageircd_cmd_notice_ops);
+ pmodule_cmd_notice(rageircd_cmd_notice);
+ pmodule_cmd_notice2(rageircd_cmd_notice2);
+ pmodule_cmd_privmsg(rageircd_cmd_privmsg);
+ pmodule_cmd_privmsg2(rageircd_cmd_privmsg2);
+ pmodule_cmd_serv_notice(rageircd_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(rageircd_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(rageircd_cmd_bot_chan_mode);
+ pmodule_cmd_351(rageircd_cmd_351);
+ pmodule_cmd_quit(rageircd_cmd_quit);
+ pmodule_cmd_pong(rageircd_cmd_pong);
+ pmodule_cmd_join(rageircd_cmd_join);
+ pmodule_cmd_unsqline(rageircd_cmd_unsqline);
+ pmodule_cmd_invite(rageircd_cmd_invite);
+ pmodule_cmd_part(rageircd_cmd_part);
+ pmodule_cmd_391(rageircd_cmd_391);
+ pmodule_cmd_250(rageircd_cmd_250);
+ pmodule_cmd_307(rageircd_cmd_307);
+ pmodule_cmd_311(rageircd_cmd_311);
+ pmodule_cmd_312(rageircd_cmd_312);
+ pmodule_cmd_317(rageircd_cmd_317);
+ pmodule_cmd_219(rageircd_cmd_219);
+ pmodule_cmd_401(rageircd_cmd_401);
+ pmodule_cmd_318(rageircd_cmd_318);
+ pmodule_cmd_242(rageircd_cmd_242);
+ pmodule_cmd_243(rageircd_cmd_243);
+ pmodule_cmd_211(rageircd_cmd_211);
+ pmodule_cmd_global(rageircd_cmd_global);
+ pmodule_cmd_global_legacy(rageircd_cmd_global_legacy);
+ pmodule_cmd_sqline(rageircd_cmd_sqline);
+ pmodule_cmd_squit(rageircd_cmd_squit);
+ pmodule_cmd_svso(rageircd_cmd_svso);
+ pmodule_cmd_chg_nick(rageircd_cmd_chg_nick);
+ pmodule_cmd_svsnick(rageircd_cmd_svsnick);
+ pmodule_cmd_vhost_on(rageircd_cmd_vhost_on);
+ pmodule_cmd_connect(rageircd_cmd_connect);
+ pmodule_cmd_svshold(rageircd_cmd_svshold);
+ pmodule_cmd_release_svshold(rageircd_cmd_release_svshold);
+ pmodule_cmd_unsgline(rageircd_cmd_unsgline);
+ pmodule_cmd_unszline(rageircd_cmd_unszline);
+ pmodule_cmd_szline(rageircd_cmd_szline);
+ pmodule_cmd_sgline(rageircd_cmd_sgline);
+ pmodule_cmd_unban(rageircd_cmd_unban);
+ pmodule_cmd_svsmode_chan(rageircd_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(rageircd_cmd_svid_umode);
+ pmodule_cmd_nc_change(rageircd_cmd_nc_change);
+ pmodule_cmd_svid_umode2(rageircd_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(rageircd_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(rageircd_cmd_svsjoin);
+ pmodule_cmd_svspart(rageircd_cmd_svspart);
+ pmodule_cmd_swhois(rageircd_cmd_swhois);
+ pmodule_cmd_eob(rageircd_cmd_eob);
+ pmodule_flood_mode_check(rageircd_flood_mode_check);
+ pmodule_cmd_jupe(rageircd_cmd_jupe);
+ pmodule_valid_nick(rageircd_valid_nick);
+ pmodule_valid_chan(rageircd_valid_chan);
+ pmodule_cmd_ctcp(rageircd_cmd_ctcp);
+ pmodule_set_umode(rageircd_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("RageIRCd 2.0.x");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(1);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
+
+/* EOF */
diff --git a/src/protocol/rageircd.h b/src/protocol/rageircd.h
new file mode 100644
index 000000000..c997a8f1c
--- /dev/null
+++ b/src/protocol/rageircd.h
@@ -0,0 +1,113 @@
+/* Rage IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_R 0x80000000
+#define UMODE_x 0x40000000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_c 0x00000400 /* Colors can't be used */
+#define CMODE_M 0x00000800 /* Non-regged nicks can't send messages */
+#define CMODE_N 0x00001000
+#define CMODE_S 0x00002000
+#define CMODE_C 0x00004000
+#define CMODE_A 0x00008000
+#define CMODE_O 0x00010000 /* Only opers can join */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void rageircd_set_umode(User * user, int ac, char **av);
+void rageircd_cmd_svsnoop(char *server, int set);
+void rageircd_cmd_remove_akill(char *user, char *host);
+void rageircd_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void rageircd_cmd_vhost_off(User * u);
+void rageircd_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void rageircd_cmd_svskill(char *source, char *user, char *buf);
+void rageircd_cmd_svsmode(User * u, int ac, char **av);
+void rageircd_cmd_372(char *source, char *msg);
+void rageircd_cmd_372_error(char *source);
+void rageircd_cmd_375(char *source);
+void rageircd_cmd_376(char *source);
+void rageircd_cmd_nick(char *nick, char *name, char *modes);
+void rageircd_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void rageircd_cmd_mode(char *source, char *dest, char *buf);
+void rageircd_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void rageircd_cmd_kick(char *source, char *chan, char *user, char *buf);
+void rageircd_cmd_notice_ops(char *source, char *dest, char *buf);
+void rageircd_cmd_notice(char *source, char *dest, char *buf);
+void rageircd_cmd_notice2(char *source, char *dest, char *msg);
+void rageircd_cmd_privmsg(char *source, char *dest, char *buf);
+void rageircd_cmd_privmsg2(char *source, char *dest, char *msg);
+void rageircd_cmd_serv_notice(char *source, char *dest, char *msg);
+void rageircd_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void rageircd_cmd_bot_chan_mode(char *nick, char *chan);
+void rageircd_cmd_351(char *source);
+void rageircd_cmd_quit(char *source, char *buf);
+void rageircd_cmd_pong(char *servname, char *who);
+void rageircd_cmd_join(char *user, char *channel, time_t chantime);
+void rageircd_cmd_unsqline(char *user);
+void rageircd_cmd_invite(char *source, char *chan, char *nick);
+void rageircd_cmd_part(char *nick, char *chan, char *buf);
+void rageircd_cmd_391(char *source, char *timestr);
+void rageircd_cmd_250(char *buf);
+void rageircd_cmd_307(char *buf);
+void rageircd_cmd_311(char *buf);
+void rageircd_cmd_312(char *buf);
+void rageircd_cmd_317(char *buf);
+void rageircd_cmd_219(char *source, char *letter);
+void rageircd_cmd_401(char *source, char *who);
+void rageircd_cmd_318(char *source, char *who);
+void rageircd_cmd_242(char *buf);
+void rageircd_cmd_243(char *buf);
+void rageircd_cmd_211(char *buf);
+void rageircd_cmd_global(char *source, char *buf);
+void rageircd_cmd_global_legacy(char *source, char *fmt);
+void rageircd_cmd_sqline(char *mask, char *reason);
+void rageircd_cmd_squit(char *servname, char *message);
+void rageircd_cmd_svso(char *source, char *nick, char *flag);
+void rageircd_cmd_chg_nick(char *oldnick, char *newnick);
+void rageircd_cmd_svsnick(char *source, char *guest, time_t when);
+void rageircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void rageircd_cmd_connect(int servernum);
+void rageircd_cmd_svshold(char *nick);
+void rageircd_cmd_release_svshold(char *nick);
+void rageircd_cmd_unsgline(char *mask);
+void rageircd_cmd_unszline(char *mask);
+void rageircd_cmd_szline(char *mask, char *reason, char *whom);
+void rageircd_cmd_sgline(char *mask, char *reason);
+void rageircd_cmd_unban(char *name, char *nick);
+void rageircd_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void rageircd_cmd_svid_umode(char *nick, time_t ts);
+void rageircd_cmd_nc_change(User * u);
+void rageircd_cmd_svid_umode2(User * u, char *ts);
+void rageircd_cmd_svid_umode3(User * u, char *ts);
+void rageircd_cmd_eob();
+int rageircd_flood_mode_check(char *value);
+void rageircd_cmd_jupe(char *jserver, char *who, char *reason);
+int rageircd_valid_nick(char *nick);
+void rageircd_cmd_ctcp(char *source, char *dest, char *buf);
diff --git a/src/protocol/ratbox.c b/src/protocol/ratbox.c
new file mode 100644
index 000000000..d8c33b4a3
--- /dev/null
+++ b/src/protocol/ratbox.c
@@ -0,0 +1,1882 @@
+/* Ratbox IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "ratbox.h"
+
+IRCDVar myIrcd[] = {
+ {"Ratbox 2.0+", /* ircd name */
+ "+oi", /* nickserv mode */
+ "+oi", /* chanserv mode */
+ "+oi", /* memoserv mode */
+ "+oi", /* hostserv mode */
+ "+oai", /* operserv mode */
+ "+oi", /* botserv mode */
+ "+oi", /* helpserv mode */
+ "+oi", /* Dev/Null mode */
+ "+oi", /* Global mode */
+ "+oi", /* nickserv alias mode */
+ "+oi", /* chanserv alias mode */
+ "+oi", /* memoserv alias mode */
+ "+oi", /* hostserv alias mode */
+ "+oai", /* operserv alias mode */
+ "+oi", /* botserv alias mode */
+ "+oi", /* helpserv alias mode */
+ "+oi", /* Dev/Null alias mode */
+ "+oi", /* Global alias mode */
+ "+oi", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-acilmnpst", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 0, /* SVSNICK */
+ 0, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to unset for chan admin */
+ NULL, /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ NULL, /* Mode on UnReg */
+ NULL, /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 0, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 1, /* Join 2 Set */
+ 1, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 0, /* Chan Reg */
+ 0, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* UMODE */
+ 0, /* O:LINE */
+ 0, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_p, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ 0, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 0, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ NULL, /* vhost char */
+ 1, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ CAPAB_QS, /* QS */
+ CAPAB_UID, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+void ratbox_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ 0, 0, 0, /* A B C */
+ 0, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, 0, /* M N O */
+ 0, 0, 0, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, 0, /* a b c */
+ UMODE_d, 0, 0, /* d e f */
+ UMODE_g, 0, UMODE_i, /* g h i */
+ 0, 0, UMODE_l, /* j k l */
+ 0, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, 0, /* p q r */
+ 0, 0, UMODE_u, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {0}, /* M */
+ {0}, /* N */
+ {0}, /* O */
+ {0}, /* P */
+ {0}, /* Q */
+ {0}, /* R */
+ {0}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {0},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void ratbox_cmd_notice(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ ratbox_cmd_privmsg2(source, dest, buf);
+ } else {
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source),
+ "NOTICE %s :%s", (UseTS6 ? (u ? u->uid : dest) : dest),
+ buf);
+ }
+}
+
+void ratbox_cmd_notice2(char *source, char *dest, char *msg)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "NOTICE %s :%s",
+ (UseTS6 ? (u ? u->uid : dest) : dest), msg);
+}
+
+void ratbox_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ Uid *ud, *ud2;
+
+ if (!buf) {
+ return;
+ }
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "PRIVMSG %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : dest) : dest), buf);
+}
+
+void ratbox_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ Uid *ud, *ud2;
+
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "PRIVMSG %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : dest) : dest), msg);
+}
+
+void ratbox_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void ratbox_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void ratbox_cmd_global(char *source, char *buf)
+{
+ Uid *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((UseTS6 ? u->uid : source), "OPERWALL :%s", buf);
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "OPERWALL :%s", buf);
+ }
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "OPERWALL :%s", buf);
+ }
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void ratbox_cmd_global_legacy(char *source, char *fmt)
+{
+ Uid *u;
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((UseTS6 ? u->uid : source), "OPERWALL :%s", fmt);
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "OPERWALL :%s", fmt);
+ }
+ } else {
+ send_cmd((UseTS6 ? TS6SID : ServerName), "OPERWALL :%s", fmt);
+ }
+
+ send_cmd(source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+ Non TS6
+
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = server
+ av[7] = info
+
+ TS6
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = IP
+ av[7] = UID
+ av[8] = info
+
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ Server *s;
+ User *user;
+
+ if (UseTS6 && ac == 9) {
+ s = findserver_uid(servlist, source);
+ /* Source is always the server */
+ *source = '\0';
+ user = do_nick(source, av[0], av[4], av[5], s->name, av[8],
+ strtoul(av[2], NULL, 10), 0, 0, "*", av[7]);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[7],
+ strtoul(av[2], NULL, 10), 0, 0, "*", NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac == 4) {
+ do_topic(source, ac, av);
+ } else {
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ if (UseTS6) {
+ u = find_byuid(source);
+ if (u) {
+ strscpy(c->topic_setter, u->nick, sizeof(c->topic_setter));
+ } else {
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ }
+ } else {
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ }
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tburst(char *source, int ac, char **av)
+{
+ char *setter;
+ Channel *c;
+ time_t topic_time;
+
+ if (ac != 4) {
+ return MOD_CONT;
+ }
+
+ setter = myStrGetToken(av[2], '!', 0);
+
+ c = findchan(av[0]);
+ topic_time = strtol(av[1], NULL, 10);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time)) {
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[3])
+ c->topic = sstrdup(av[3]);
+
+ strscpy(c->topic_setter, setter, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void)
+{
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ if (UseTS6) {
+ TS6SID = sstrdup(Numeric);
+ UseTSMODE = 1; /* TMODE */
+ }
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("TMODE", anope_event_tmode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("BMASK", anope_event_bmask); addCoreMessage(IRCD,m);
+ m = createMessage("UID", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("TB", anope_event_tburst); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("421", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ENCAP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SID", anope_event_sid); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+void ratbox_cmd_sqline(char *mask, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "RESV * %s :%s", mask, reason);
+}
+
+void ratbox_cmd_unsgline(char *mask)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNXLINE * %s", mask);
+}
+
+void ratbox_cmd_unszline(char *mask)
+{
+ /* Does not support */
+}
+
+void ratbox_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* Does not support */
+}
+
+void ratbox_cmd_svsnoop(char *server, int set)
+{
+ /* does not support */
+}
+
+void ratbox_cmd_svsadmin(char *server, int set)
+{
+ ratbox_cmd_svsnoop(server, set);
+}
+
+void ratbox_cmd_sgline(char *mask, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "XLINE * %s 0 :%s", mask, reason);
+}
+
+void ratbox_cmd_remove_akill(char *user, char *host)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNKLINE * %s %s", user, host);
+}
+
+void ratbox_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ Uid *ud;
+
+ ud = find_uid(whosets);
+ send_cmd((UseTS6 ? (ud ? ud->uid : whosets) : whosets), "TOPIC %s :%s",
+ chan, topic);
+}
+
+void ratbox_cmd_vhost_off(User * u)
+{
+ /* not supported */
+}
+
+void ratbox_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ /* not supported */
+}
+
+void ratbox_cmd_unsqline(char *user)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "UNRESV * %s", user);
+}
+
+void ratbox_cmd_join(char *user, char *channel, time_t chantime)
+{
+ Uid *ud;
+
+ ud = find_uid(user);
+ send_cmd(NULL, "SJOIN %ld %s + :%s", (long int) chantime,
+ channel, (UseTS6 ? (ud ? ud->uid : user) : user));
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void ratbox_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : s_OperServ) : s_OperServ),
+ "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time(NULL)), user, host, reason);
+}
+
+void ratbox_cmd_svskill(char *source, char *user, char *buf)
+{
+ Uid *ud, *ud2;
+
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ ud = find_uid(source);
+ ud2 = find_uid(user);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "KILL %s :%s",
+ (UseTS6 ? (ud2 ? ud2->uid : user) : user), buf);
+}
+
+void ratbox_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "SVSMODE %s %s", u->nick,
+ av[0]);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void ratbox_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 6 3 0 :%ld", (long int) time(NULL));
+}
+
+void ratbox_cmd_svsinfo()
+{
+
+}
+
+/* CAPAB */
+/*
+ QS - Can handle quit storm removal
+ EX - Can do channel +e exemptions
+ CHW - Can do channel wall @#
+ LL - Can do lazy links
+ IE - Can do invite exceptions
+ EOB - Can do EOB message
+ KLN - Can do KLINE message
+ GLN - Can do GLINE message
+ HUB - This server is a HUB
+ UID - Can do UIDs
+ ZIP - Can do ZIPlinks
+ ENC - Can do ENCrypted links
+ KNOCK - supports KNOCK
+ TBURST - supports TBURST
+ PARA - supports invite broadcasting for +p
+ ENCAP - ?
+*/
+void ratbox_cmd_capab()
+{
+ send_cmd(NULL,
+ "CAPAB :QS EX CHW IE KLN GLN KNOCK TB UNKLN CLUSTER ENCAP");
+}
+
+/* PASS */
+void ratbox_cmd_pass(char *pass)
+{
+ if (UseTS6) {
+ send_cmd(NULL, "PASS %s TS 6 :%s", pass, TS6SID);
+ } else {
+ send_cmd(NULL, "PASS %s :TS", pass);
+ }
+}
+
+/* SERVER name hop descript */
+void ratbox_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void ratbox_cmd_connect(int servernum)
+{
+ /* Make myself known to myself in the serverlist */
+ if (UseTS6) {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, TS6SID);
+ } else {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+ }
+ if (servernum == 1)
+ ratbox_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ ratbox_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ ratbox_cmd_pass(RemotePassword3);
+
+ ratbox_cmd_capab();
+ ratbox_cmd_server(ServerName, 1, ServerDesc);
+ ratbox_cmd_svinfo();
+}
+
+void ratbox_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ if (UseTS6) {
+ char *uidbuf = ts6_uid_retrieve();
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick,
+ (long int) time(NULL), modes, user, host, uidbuf,
+ real);
+ new_uid(nick, uidbuf);
+ } else {
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName,
+ real);
+ }
+ ratbox_cmd_sqline(nick, "Reserved for services");
+}
+
+void ratbox_cmd_part(char *nick, char *chan, char *buf)
+{
+ Uid *ud;
+
+ ud = find_uid(nick);
+
+ if (buf) {
+ send_cmd((UseTS6 ? ud->uid : nick), "PART %s :%s", chan, buf);
+ } else {
+ send_cmd((UseTS6 ? ud->uid : nick), "PART %s", chan);
+ }
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ ratbox_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ User *u = NULL;
+
+ if (UseTS6) {
+ u = find_byuid(source);
+ }
+
+ m_away((UseTS6 ? (u ? u->nick : source) : source),
+ (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+void ratbox_cmd_eob()
+{
+ /* doesn't support EOB */
+}
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1) {
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+ } else {
+ do_join(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ User *u;
+ Uid *ud;
+
+ if (ac != 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ ud = find_nickuid(av[0]);
+ m_privmsg((UseTS6 ? (u ? u->nick : source) : source),
+ (UseTS6 ? (ud ? ud->nick : av[0]) : av[0]), av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac < 1 || ac > 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ do_part((UseTS6 ? (u ? u->nick : source) : source), ac, av);
+
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ Uid *ud;
+
+ if (source && ac >= 1) {
+ ud = find_nickuid(av[0]);
+ m_whois(source, (UseTS6 ? (ud ? ud->nick : av[0]) : av[0]));
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ if (UseTS6 && TS6UPLINK) {
+ do_server(source, av[0], av[1], av[2], TS6UPLINK);
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_sid(char *source, int ac, char **av)
+{
+ Server *s;
+
+ /* :42X SID trystan.nomadirc.net 2 43X :ircd-ratbox test server */
+
+ s = findserver_uid(servlist, source);
+
+ do_server(s->name, av[0], av[1], av[3], av[2]);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+
+ do_quit((UseTS6 ? (u ? u->nick : source) : source), ac, av);
+ return MOD_CONT;
+}
+
+void ratbox_cmd_372(char *source, char *msg)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName), "372 %s :- %s", source, msg);
+}
+
+void ratbox_cmd_372_error(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void ratbox_cmd_375(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "375 %s :- %s Message of the Day", source, ServerName);
+}
+
+void ratbox_cmd_376(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void ratbox_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void ratbox_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void ratbox_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "307 %s", buf);
+}
+
+/* 311 */
+void ratbox_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "311 %s", buf);
+}
+
+/* 312 */
+void ratbox_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "312 %s", buf);
+}
+
+/* 317 */
+void ratbox_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName), "317 %s", buf);
+}
+
+/* 219 */
+void ratbox_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void ratbox_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd((UseTS6 ? TS6SID : ServerName), "401 %s %s :No such service.",
+ source, who);
+}
+
+/* 318 */
+void ratbox_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void ratbox_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void ratbox_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void ratbox_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void ratbox_cmd_mode(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ ud = find_uid(source);
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "MODE %s %s",
+ dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+void ratbox_cmd_tmode(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+ if (!*buf) {
+ return;
+ }
+
+ send_cmd(NULL, "MODE %s %s", dest, buf);
+}
+
+void ratbox_cmd_nick(char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick(nick, NULL);
+ if (UseTS6) {
+ char *uidbuf = ts6_uid_retrieve();
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ uidbuf, name);
+ new_uid(nick, uidbuf);
+ } else {
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ ServerName, name);
+ }
+ ratbox_cmd_sqline(nick, "Reserved for services");
+}
+
+void ratbox_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(user);
+
+ if (buf) {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source),
+ "KICK %s %s :%s", chan,
+ (UseTS6 ? (u ? u->uid : user) : user), buf);
+ } else {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "KICK %s %s",
+ chan, (UseTS6 ? (u ? u->uid : user) : user));
+ }
+}
+
+void ratbox_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+void ratbox_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ Uid *u;
+
+ if (UseTS6) {
+ u = find_uid(nick);
+ ratbox_cmd_tmode(nick, chan, "%s %s", ircd->botchanumode,
+ (u ? u->uid : nick));
+ } else {
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+ }
+}
+
+/* QUIT */
+void ratbox_cmd_quit(char *source, char *buf)
+{
+ Uid *ud;
+ ud = find_uid(source);
+
+ if (buf) {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "QUIT :%s",
+ buf);
+ } else {
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "QUIT");
+ }
+}
+
+/* PONG */
+void ratbox_cmd_pong(char *servname, char *who)
+{
+ if (UseTS6) {
+ send_cmd(TS6SID, "PONG %s", who);
+ } else {
+ send_cmd(servname, "PONG %s", who);
+ }
+}
+
+/* INVITE */
+void ratbox_cmd_invite(char *source, char *chan, char *nick)
+{
+ Uid *ud;
+ User *u;
+
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ ud = find_uid(source);
+ u = finduser(nick);
+
+ send_cmd((UseTS6 ? (ud ? ud->uid : source) : source), "INVITE %s %s",
+ (UseTS6 ? (u ? u->uid : nick) : nick), chan);
+}
+
+/* SQUIT */
+void ratbox_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ User *u, *u2;
+
+ if (ac < 2) {
+ return MOD_CONT;
+ }
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ if (UseTS6) {
+ u = find_byuid(source);
+ u2 = find_byuid(av[0]);
+ av[0] = u2->nick;
+ do_umode(u->nick, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tmode(char *source, int ac, char **av)
+{
+ if (*av[1] == '#' || *av[1] == '&') {
+ do_cmode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+void ratbox_cmd_351(char *source)
+{
+ send_cmd((UseTS6 ? TS6SID : ServerName),
+ "351 %s Anope-%s %s :%s - %s (%s) -- %s", source, version_number,
+ ServerName, ircd->name, version_flags, EncModule, version_build);
+
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ int argvsize = 8;
+ int argc;
+ char **argv;
+ char *str;
+
+ if (ac < 1)
+ return MOD_CONT;
+
+ /* We get the params as one arg, we should split it for capab_parse */
+ argv = scalloc(argvsize, sizeof(char *));
+ argc = 0;
+ while ((str = myStrGetToken(av[0], ' ', argc))) {
+ if (argc == argvsize) {
+ argvsize += 8;
+ argv = srealloc(argv, argvsize * sizeof(char *));
+ }
+ argv[argc] = str;
+ argc++;
+ }
+
+ capab_parse(argc, argv);
+
+ /* Free our built ac/av */
+ for (argvsize = 0; argvsize < argc; argvsize++) {
+ free(argv[argvsize]);
+ }
+ free(argv);
+
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void ratbox_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void ratbox_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void ratbox_cmd_svsnick(char *nick, char *newnick, time_t when)
+{
+ /* not supported */
+}
+
+void ratbox_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ /* not supported */
+}
+
+void ratbox_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ratbox_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void ratbox_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void ratbox_cmd_svid_umode(char *nick, time_t ts)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void ratbox_cmd_nc_change(User * u)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+void ratbox_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not supported */
+}
+
+void ratbox_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void ratbox_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ if (UseTS6) {
+ TS6UPLINK = sstrdup(av[3]);
+ }
+ return MOD_CONT;
+}
+
+void ratbox_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ratbox_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ratbox_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_bmask(char *source, int ac, char **av)
+{
+ Channel *c;
+ char *bans;
+ char *b;
+ int count, i;
+
+ /* :42X BMASK 1106409026 #ircops b :*!*@*.aol.com */
+ /* 0 1 2 3 */
+ c = findchan(av[1]);
+
+ if (c) {
+ bans = sstrdup(av[3]);
+ count = myNumToken(bans, ' ');
+ for (i = 0; i <= count - 1; i++) {
+ b = myStrGetToken(bans, ' ', i);
+ if (!stricmp(av[2], "b")) {
+ add_ban(c, b);
+ }
+ if (!stricmp(av[2], "e")) {
+ add_exception(c, b);
+ }
+ if (!stricmp(av[2], "I")) {
+ add_invite(c, b);
+ }
+ if (b)
+ free(b);
+ }
+ free(bans);
+ }
+ return MOD_CONT;
+}
+
+int ratbox_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void ratbox_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ ratbox_cmd_squit(jserver, rbuf);
+ ratbox_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int ratbox_valid_nick(char *nick)
+{
+ /* TS6 Save extension -Certus */
+ if (isdigit(*nick))
+ return 0;
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int ratbox_valid_chan(char *chan)
+{
+ /* no hard coded invalid chans */
+ return 1;
+}
+
+
+void ratbox_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(ratbox_cmd_svsnoop);
+ pmodule_cmd_remove_akill(ratbox_cmd_remove_akill);
+ pmodule_cmd_topic(ratbox_cmd_topic);
+ pmodule_cmd_vhost_off(ratbox_cmd_vhost_off);
+ pmodule_cmd_akill(ratbox_cmd_akill);
+ pmodule_cmd_svskill(ratbox_cmd_svskill);
+ pmodule_cmd_svsmode(ratbox_cmd_svsmode);
+ pmodule_cmd_372(ratbox_cmd_372);
+ pmodule_cmd_372_error(ratbox_cmd_372_error);
+ pmodule_cmd_375(ratbox_cmd_375);
+ pmodule_cmd_376(ratbox_cmd_376);
+ pmodule_cmd_nick(ratbox_cmd_nick);
+ pmodule_cmd_guest_nick(ratbox_cmd_guest_nick);
+ pmodule_cmd_mode(ratbox_cmd_mode);
+ pmodule_cmd_bot_nick(ratbox_cmd_bot_nick);
+ pmodule_cmd_kick(ratbox_cmd_kick);
+ pmodule_cmd_notice_ops(ratbox_cmd_notice_ops);
+ pmodule_cmd_notice(ratbox_cmd_notice);
+ pmodule_cmd_notice2(ratbox_cmd_notice2);
+ pmodule_cmd_privmsg(ratbox_cmd_privmsg);
+ pmodule_cmd_privmsg2(ratbox_cmd_privmsg2);
+ pmodule_cmd_serv_notice(ratbox_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(ratbox_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(ratbox_cmd_bot_chan_mode);
+ pmodule_cmd_351(ratbox_cmd_351);
+ pmodule_cmd_quit(ratbox_cmd_quit);
+ pmodule_cmd_pong(ratbox_cmd_pong);
+ pmodule_cmd_join(ratbox_cmd_join);
+ pmodule_cmd_unsqline(ratbox_cmd_unsqline);
+ pmodule_cmd_invite(ratbox_cmd_invite);
+ pmodule_cmd_part(ratbox_cmd_part);
+ pmodule_cmd_391(ratbox_cmd_391);
+ pmodule_cmd_250(ratbox_cmd_250);
+ pmodule_cmd_307(ratbox_cmd_307);
+ pmodule_cmd_311(ratbox_cmd_311);
+ pmodule_cmd_312(ratbox_cmd_312);
+ pmodule_cmd_317(ratbox_cmd_317);
+ pmodule_cmd_219(ratbox_cmd_219);
+ pmodule_cmd_401(ratbox_cmd_401);
+ pmodule_cmd_318(ratbox_cmd_318);
+ pmodule_cmd_242(ratbox_cmd_242);
+ pmodule_cmd_243(ratbox_cmd_243);
+ pmodule_cmd_211(ratbox_cmd_211);
+ pmodule_cmd_global(ratbox_cmd_global);
+ pmodule_cmd_global_legacy(ratbox_cmd_global_legacy);
+ pmodule_cmd_sqline(ratbox_cmd_sqline);
+ pmodule_cmd_squit(ratbox_cmd_squit);
+ pmodule_cmd_svso(ratbox_cmd_svso);
+ pmodule_cmd_chg_nick(ratbox_cmd_chg_nick);
+ pmodule_cmd_svsnick(ratbox_cmd_svsnick);
+ pmodule_cmd_vhost_on(ratbox_cmd_vhost_on);
+ pmodule_cmd_connect(ratbox_cmd_connect);
+ pmodule_cmd_svshold(ratbox_cmd_svshold);
+ pmodule_cmd_release_svshold(ratbox_cmd_release_svshold);
+ pmodule_cmd_unsgline(ratbox_cmd_unsgline);
+ pmodule_cmd_unszline(ratbox_cmd_unszline);
+ pmodule_cmd_szline(ratbox_cmd_szline);
+ pmodule_cmd_sgline(ratbox_cmd_sgline);
+ pmodule_cmd_unban(ratbox_cmd_unban);
+ pmodule_cmd_svsmode_chan(ratbox_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(ratbox_cmd_svid_umode);
+ pmodule_cmd_nc_change(ratbox_cmd_nc_change);
+ pmodule_cmd_svid_umode2(ratbox_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(ratbox_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(ratbox_cmd_svsjoin);
+ pmodule_cmd_svspart(ratbox_cmd_svspart);
+ pmodule_cmd_swhois(ratbox_cmd_swhois);
+ pmodule_cmd_eob(ratbox_cmd_eob);
+ pmodule_flood_mode_check(ratbox_flood_mode_check);
+ pmodule_cmd_jupe(ratbox_cmd_jupe);
+ pmodule_valid_nick(ratbox_valid_nick);
+ pmodule_valid_chan(ratbox_valid_chan);
+ pmodule_cmd_ctcp(ratbox_cmd_ctcp);
+ pmodule_set_umode(ratbox_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("Ratbox IRCD 2.0+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(1);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/ratbox.h b/src/protocol/ratbox.h
new file mode 100644
index 000000000..4088bd7be
--- /dev/null
+++ b/src/protocol/ratbox.h
@@ -0,0 +1,119 @@
+/* Ratbox IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_C 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_z 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_s 0x00000040
+#define UMODE_c 0x00000080
+#define UMODE_r 0x00000100
+#define UMODE_k 0x00000200
+#define UMODE_f 0x00000400
+#define UMODE_y 0x00000800
+#define UMODE_d 0x00001000
+#define UMODE_n 0x00002000
+#define UMODE_x 0x00004000
+#define UMODE_u 0x00008000
+#define UMODE_b 0x00010000
+#define UMODE_l 0x00020000
+#define UMODE_g 0x00040000
+#define UMODE_Z 0x00080000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040
+#define CMODE_l 0x00000080
+
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t
+
+
+void ratbox_set_umode(User * user, int ac, char **av);
+void ratbox_cmd_svsnoop(char *server, int set);
+void ratbox_cmd_remove_akill(char *user, char *host);
+void ratbox_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void ratbox_cmd_vhost_off(User * u);
+void ratbox_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void ratbox_cmd_svskill(char *source, char *user, char *buf);
+void ratbox_cmd_svsmode(User * u, int ac, char **av);
+void ratbox_cmd_372(char *source, char *msg);
+void ratbox_cmd_372_error(char *source);
+void ratbox_cmd_375(char *source);
+void ratbox_cmd_376(char *source);
+void ratbox_cmd_nick(char *nick, char *name, char *modes);
+void ratbox_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ratbox_cmd_mode(char *source, char *dest, char *buf);
+void ratbox_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ratbox_cmd_kick(char *source, char *chan, char *user, char *buf);
+void ratbox_cmd_notice_ops(char *source, char *dest, char *buf);
+void ratbox_cmd_notice(char *source, char *dest, char *buf);
+void ratbox_cmd_notice2(char *source, char *dest, char *msg);
+void ratbox_cmd_privmsg(char *source, char *dest, char *buf);
+void ratbox_cmd_privmsg2(char *source, char *dest, char *msg);
+void ratbox_cmd_serv_notice(char *source, char *dest, char *msg);
+void ratbox_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void ratbox_cmd_bot_chan_mode(char *nick, char *chan);
+void ratbox_cmd_351(char *source);
+void ratbox_cmd_quit(char *source, char *buf);
+void ratbox_cmd_pong(char *servname, char *who);
+void ratbox_cmd_join(char *user, char *channel, time_t chantime);
+void ratbox_cmd_unsqline(char *user);
+void ratbox_cmd_invite(char *source, char *chan, char *nick);
+void ratbox_cmd_part(char *nick, char *chan, char *buf);
+void ratbox_cmd_391(char *source, char *timestr);
+void ratbox_cmd_250(char *buf);
+void ratbox_cmd_307(char *buf);
+void ratbox_cmd_311(char *buf);
+void ratbox_cmd_312(char *buf);
+void ratbox_cmd_317(char *buf);
+void ratbox_cmd_219(char *source, char *letter);
+void ratbox_cmd_401(char *source, char *who);
+void ratbox_cmd_318(char *source, char *who);
+void ratbox_cmd_242(char *buf);
+void ratbox_cmd_243(char *buf);
+void ratbox_cmd_211(char *buf);
+void ratbox_cmd_global(char *source, char *buf);
+void ratbox_cmd_global_legacy(char *source, char *fmt);
+void ratbox_cmd_sqline(char *mask, char *reason);
+void ratbox_cmd_squit(char *servname, char *message);
+void ratbox_cmd_svso(char *source, char *nick, char *flag);
+void ratbox_cmd_chg_nick(char *oldnick, char *newnick);
+void ratbox_cmd_svsnick(char *source, char *guest, time_t when);
+void ratbox_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void ratbox_cmd_connect(int servernum);
+void ratbox_cmd_svshold(char *nick);
+void ratbox_cmd_release_svshold(char *nick);
+void ratbox_cmd_unsgline(char *mask);
+void ratbox_cmd_unszline(char *mask);
+void ratbox_cmd_szline(char *mask, char *reason, char *whom);
+void ratbox_cmd_sgline(char *mask, char *reason);
+void ratbox_cmd_unban(char *name, char *nick);
+void ratbox_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void ratbox_cmd_svid_umode(char *nick, time_t ts);
+void ratbox_cmd_nc_change(User * u);
+void ratbox_cmd_svid_umode2(User * u, char *ts);
+void ratbox_cmd_svid_umode3(User * u, char *ts);
+void ratbox_cmd_eob();
+int ratbox_flood_mode_check(char *value);
+void ratbox_cmd_jupe(char *jserver, char *who, char *reason);
+int ratbox_valid_nick(char *nick);
+void ratbox_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/shadowircd.c b/src/protocol/shadowircd.c
new file mode 100644
index 000000000..0061a538b
--- /dev/null
+++ b/src/protocol/shadowircd.c
@@ -0,0 +1,1833 @@
+/* ShadowIRCd functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ * Provided by the ShadowIRCd development group. See
+ * http://www.shadowircd.net for details.
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "shadowircd.h"
+
+IRCDVar myIrcd[] = {
+ {"ShadowIRCd 4.0+", /* ircd name */
+ "+oiqSK", /* nickserv mode */
+ "+oiqSK", /* chanserv mode */
+ "+oiqSK", /* memoserv mode */
+ "+oiqSK", /* hostserv mode */
+ "+oiqSK", /* operserv mode */
+ "+oiqSK", /* botserv mode */
+ "+oiqSK", /* helpserv mode */
+ "+oiqSK", /* Dev/Null mode */
+ "+oiqSK", /* Global mode */
+ "+oiqSK", /* nickserv alias mode */
+ "+oiqSK", /* chanserv alias mode */
+ "+oiqSK", /* memoserv alias mode */
+ "+oiqSK", /* hostserv alias mode */
+ "+oiqSK", /* operserv alias mode */
+ "+oiqSK", /* botserv alias mode */
+ "+oiqSK", /* helpserv alias mode */
+ "+oiqSK", /* Dev/Null alias mode */
+ "+oiqSK", /* Global alias mode */
+ "+oiqSK", /* Used by BotServ Bots */
+ 4, /* Chan Max Symbols */
+ "-cimnprstvzAEFGKLNOPRSTV", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+e", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-e", /* Mode on UnReg */
+ "-e", /* Mode on Nick Change */
+ 0, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 4, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 1, /* Has Admin */
+ 1, /* Chan SQlines */
+ 1, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ 1, /* Channel Mode */
+ 1, /* vidents */
+ 0, /* svshold */
+ 0, /* time stamp on mode */
+ 0, /* NICKIP */
+ 1, /* UMODE */
+ 0, /* O:LINE */
+ 1, /* VHOST ON NICK */
+ 1, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_v, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 1, /* On nick change check if they could be identified */
+ 0, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "v", /* vhost char */
+ 1, /* ts6 */
+ 0, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+/* ShadowIRCd does not use CAPAB */
+IRCDCAPAB myIrcdcap[] = {
+ {
+ 0, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0, 0, 0}
+};
+
+void shadowircd_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, 0, /* A B C */
+ 0, UMODE_E, 0, /* D E F */
+ UMODE_G, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, UMODE_O, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, 0, /* a b c */
+ UMODE_d, UMODE_e, 0, /* d e f */
+ UMODE_g, 0, UMODE_i, /* g h i */
+ 0, 0, UMODE_l, /* j k l */
+ 0, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, 0, /* p q r */
+ 0, 0, UMODE_u, /* s t u */
+ UMODE_v, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 'a',
+ 0, 0, 0,
+ 'h',
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, 0, NULL, NULL}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {CMODE_E, 0, NULL, NULL}, /* E */
+ {CMODE_F, 0, NULL, NULL}, /* F */
+ {CMODE_G, 0, NULL, NULL}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, NULL, NULL}, /* L */
+ {0}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, 0, NULL, NULL}, /* O */
+ {CMODE_P, 0, NULL, NULL}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {CMODE_T, 0, NULL, NULL}, /* T */
+ {0}, /* U */
+ {CMODE_V, 0, NULL, NULL}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, 0, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'E', CMODE_E, 0, NULL, NULL},
+ {'F', CMODE_F, 0, NULL, NULL},
+ {'G', CMODE_G, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'P', CMODE_P, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {'T', CMODE_T, 0, NULL, NULL},
+ {'V', CMODE_V, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_admin}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+
+void shadowircd_cmd_notice(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ shadowircd_cmd_privmsg2(source, dest, buf);
+ } else {
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((ud ? ud->uid : source), "NOTICE %s :%s",
+ (u ? u->uid : dest), buf);
+ }
+}
+
+void shadowircd_cmd_notice2(char *source, char *dest, char *msg)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(dest);
+ send_cmd((ud ? ud->uid : source), "NOTICE %s :%s", (u ? u->uid : dest),
+ msg);
+}
+
+void shadowircd_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ Uid *ud, *ud2;
+
+ if (!buf) {
+ return;
+ }
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((ud ? ud->uid : source), "PRIVMSG %s :%s",
+ (ud2 ? ud2->uid : dest), buf);
+}
+
+void shadowircd_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ Uid *ud, *ud2;
+
+ ud = find_uid(source);
+ ud2 = find_uid(dest);
+
+ send_cmd((ud ? ud->uid : source), "PRIVMSG %s :%s",
+ (ud2 ? ud2->uid : dest), msg);
+}
+
+void shadowircd_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $$%s :%s", dest, msg);
+}
+
+void shadowircd_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $$%s :%s", dest, msg);
+}
+
+
+void shadowircd_cmd_global(char *source, char *buf)
+{
+ Uid *u;
+
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((u ? u->uid : source), "OPERWALL :%s", buf);
+ } else {
+ send_cmd(TS6SID, "OPERWALL :%s", buf);
+ }
+ } else {
+ send_cmd(TS6SID, "OPERWALL :%s", buf);
+ }
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void shadowircd_cmd_global_legacy(char *source, char *fmt)
+{
+ Uid *u;
+
+ if (source) {
+ u = find_uid(source);
+ if (u) {
+ send_cmd((u ? u->uid : source), "OPERWALL :%s", fmt);
+ } else {
+ send_cmd(TS6SID, "OPERWALL :%s", fmt);
+ }
+ } else {
+ send_cmd(TS6SID, "OPERWALL :%s", fmt);
+ }
+
+ send_cmd(source ? source : ServerName, "OPERWALL :%s", fmt);
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+ Non TS6
+
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = server
+ av[7] = info
+
+ TS6
+ av[0] = nick
+ av[1] = hop
+ av[2] = ts
+ av[3] = modes
+ av[4] = user
+ av[5] = host
+ av[6] = IP
+ av[7] = UID
+ av[8] = vhost
+ av[9] = info
+
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ Server *s = NULL;
+ User *user, *u2;
+
+ if (ac == 10) {
+ s = findserver_uid(servlist, source);
+ /* Source is always the server */
+ *source = '\0';
+ user = do_nick(source, av[0], av[4], av[5], s->name, av[9],
+ strtoul(av[2], NULL, 10), 0, 0, av[8], av[7]);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else if (ac == 8) {
+ /* Changed use of s->name to av[6], as s will be NULL
+ * if i can believe the above comments, this should be fine
+ * if anyone from shadowircd see's this, and its wrong, let
+ * me know? :)
+ */
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[7],
+ strtoul(av[2], NULL, 10), 0, 0, NULL, NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ u2 = find_byuid(source);
+ do_nick((u2 ? u2->nick : source), av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = find_byuid(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac == 4) {
+ do_topic(source, ac, av);
+ } else {
+ Channel *c = findchan(av[0]);
+ time_t topic_time = time(NULL);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time))
+ return MOD_CONT;
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[1])
+ c->topic = sstrdup(av[1]);
+
+ u = find_byuid(source);
+ if (u) {
+ strscpy(c->topic_setter, u->nick, sizeof(c->topic_setter));
+ } else {
+ strscpy(c->topic_setter, source, sizeof(c->topic_setter));
+ }
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[1])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[1]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tburst(char *source, int ac, char **av)
+{
+ char *setter;
+ Channel *c;
+ time_t topic_time;
+
+ if (ac != 4) {
+ return MOD_CONT;
+ }
+
+ setter = myStrGetToken(av[2], '!', 0);
+
+ c = findchan(av[0]);
+ topic_time = strtol(av[1], NULL, 10);
+
+ if (!c) {
+ if (debug) {
+ alog("debug: TOPIC %s for nonexistent channel %s",
+ merge_args(ac - 1, av + 1), av[0]);
+ }
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (check_topiclock(c, topic_time)) {
+ if (setter)
+ free(setter);
+ return MOD_CONT;
+ }
+
+ if (c->topic) {
+ free(c->topic);
+ c->topic = NULL;
+ }
+ if (ac > 1 && *av[3])
+ c->topic = sstrdup(av[3]);
+
+ strscpy(c->topic_setter, setter, sizeof(c->topic_setter));
+ c->topic_time = topic_time;
+
+ record_topic(av[0]);
+
+ if (ac > 1 && *av[3])
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], av[3]);
+ else
+ send_event(EVENT_TOPIC_UPDATED, 2, av[0], "");
+
+ if (setter)
+ free(setter);
+
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void)
+{
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ TS6SID = sstrdup(Numeric);
+ UseTS6 = 1;
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("TMODE", anope_event_tmode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("BMASK", anope_event_bmask); addCoreMessage(IRCD,m);
+ m = createMessage("UID", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("TBURST", anope_event_tburst); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("421", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ENCAP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SID", anope_event_sid); addCoreMessage(IRCD,m);
+ m = createMessage("EOB", anope_event_eos); addCoreMessage(IRCD,m);
+ m = createMessage("TSSYNC", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSCLOAK", anope_event_chghost); addCoreMessage(IRCD,m);
+
+}
+
+/* *INDENT-ON* */
+
+
+void shadowircd_cmd_sqline(char *mask, char *reason)
+{
+ send_cmd(NULL, "RESV * %s :%s", mask, reason);
+}
+
+void shadowircd_cmd_unsgline(char *mask)
+{
+ /* Does not support */
+}
+
+void shadowircd_cmd_unszline(char *mask)
+{
+ /* Does not support */
+}
+
+void shadowircd_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* Does not support */
+}
+
+void shadowircd_cmd_svsnoop(char *server, int set)
+{
+ /* does not support */
+}
+
+void shadowircd_cmd_svsadmin(char *server, int set)
+{
+ shadowircd_cmd_svsnoop(server, set);
+}
+
+void shadowircd_cmd_sgline(char *mask, char *reason)
+{
+ /* does not support */
+}
+
+void shadowircd_cmd_remove_akill(char *user, char *host)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+ send_cmd((ud ? ud->uid : s_OperServ), "UNKLINE * %s %s", user, host);
+}
+
+void shadowircd_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ Uid *ud;
+
+ ud = find_uid(whosets);
+ send_cmd((ud ? ud->uid : whosets), "TOPIC %s %s %ld :%s", chan,
+ whosetit, (long int) when, topic);
+}
+
+void shadowircd_cmd_vhost_off(User * u)
+{
+ send_cmd(NULL, "MODE %s -v", (u->uid ? u->uid : u->nick));
+}
+
+void shadowircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ send_cmd(NULL, "SVSCLOAK %s %s", nick, vhost);
+
+ if (vIdent)
+ send_cmd(NULL, "SVSIDENT %s %s", nick, vIdent);
+}
+
+void shadowircd_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNRESV * %s", user);
+}
+
+void shadowircd_cmd_join(char *user, char *channel, time_t chantime)
+{
+ Uid *ud;
+
+ ud = find_uid(user);
+ send_cmd(NULL, "SJOIN %ld %s + :%s", (long int) chantime,
+ channel, (ud ? ud->uid : user));
+}
+
+/*
+oper: the nick of the oper performing the kline
+target.server: the server(s) this kline is destined for
+duration: the duration if a tkline, 0 if permanent.
+user: the 'user' portion of the kline
+host: the 'host' portion of the kline
+reason: the reason for the kline.
+*/
+
+void shadowircd_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ Uid *ud;
+
+ ud = find_uid(s_OperServ);
+
+ send_cmd((ud ? ud->uid : s_OperServ), "KLINE * %ld %s %s :%s",
+ (long int) (expires - (long) time(NULL)), user, host, reason);
+}
+
+void shadowircd_cmd_svskill(char *source, char *user, char *buf)
+{
+ Uid *ud;
+
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ ud = find_uid(user);
+ send_cmd(NULL, "SVSKILL %s :%s", (ud ? ud->uid : user), buf);
+}
+
+void shadowircd_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(TS6SID, "MODE %s %s", u->uid, av[0]);
+}
+
+void shadowircd_cmd_svsinfo()
+{
+ /* not used */
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void shadowircd_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 6 3 0 :%ld", (long int) time(NULL));
+}
+
+void shadowircd_cmd_capab()
+{
+ /* ShadowIRCd does not use CAPAB */
+}
+
+/* PASS */
+void shadowircd_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s TS 6 %s", pass, TS6SID);
+}
+
+/* SERVER name protocol hop descript */
+void shadowircd_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d %d :%s", servname, hop, PROTOCOL_REVISION,
+ descript);
+}
+
+
+void shadowircd_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, TS6SID);
+ if (servernum == 1)
+ shadowircd_cmd_pass(RemotePassword);
+ else if (servernum == 2)
+ shadowircd_cmd_pass(RemotePassword2);
+ else if (servernum == 3)
+ shadowircd_cmd_pass(RemotePassword3);
+
+ shadowircd_cmd_capab();
+ shadowircd_cmd_server(ServerName, 1, ServerDesc);
+ shadowircd_cmd_svinfo();
+}
+
+void shadowircd_cmd_bot_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ char *uidbuf = ts6_uid_retrieve();
+
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0.0.0.0 %s %s :%s", nick,
+ (long int) time(NULL), modes, user, host, uidbuf, host,
+ real);
+ new_uid(nick, uidbuf);
+ shadowircd_cmd_sqline(nick, "Reserved for services");
+}
+
+void shadowircd_cmd_part(char *nick, char *chan, char *buf)
+{
+ Uid *ud;
+
+ ud = find_uid(nick);
+
+ if (buf) {
+ send_cmd((ud ? ud->uid : nick), "PART %s :%s", chan, buf);
+ } else {
+ send_cmd((ud ? ud->uid : nick), "PART %s", chan);
+ }
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ shadowircd_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ User *u = NULL;
+
+ u = find_byuid(source);
+
+ m_away(u->nick, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+void shadowircd_cmd_eob()
+{
+ send_cmd(TS6SID, "EOB");
+}
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1) {
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+ } else {
+ do_join(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ User *u;
+ Uid *ud;
+
+ if (ac != 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ ud = find_nickuid(av[0]);
+
+ m_privmsg((u ? u->nick : source), (ud ? ud->nick : av[0]), av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac < 1 || ac > 2) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+ do_part(u->nick, ac, av);
+
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ Uid *ud;
+
+ if (source && ac >= 1) {
+ ud = find_nickuid(av[0]);
+ m_whois(source, (ud ? ud->nick : source));
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ if (TS6UPLINK) {
+ do_server(source, av[0], av[1], av[2], TS6UPLINK);
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_sid(char *source, int ac, char **av)
+{
+ Server *s;
+
+ /* :42X SID trystan.nomadirc.net 2 43X :ircd-ratbox test server */
+
+ s = findserver_uid(servlist, source);
+ do_server(s->name, av[0], av[1], av[3], av[2]);
+ return MOD_CONT;
+}
+
+int anope_event_eos(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver_uid(servlist, source);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1) {
+ return MOD_CONT;
+ }
+
+ u = find_byuid(source);
+
+ do_quit(u->nick, ac, av);
+ return MOD_CONT;
+}
+
+void shadowircd_cmd_372(char *source, char *msg)
+{
+ send_cmd(TS6SID, "372 %s :- %s", source, msg);
+}
+
+void shadowircd_cmd_372_error(char *source)
+{
+ send_cmd(TS6SID,
+ "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void shadowircd_cmd_375(char *source)
+{
+ send_cmd(TS6SID,
+ "375 %s :- %s Message of the Day", source, ServerName);
+}
+
+void shadowircd_cmd_376(char *source)
+{
+ send_cmd(TS6SID, "376 %s :End of /MOTD command.", source);
+}
+
+/* 391 */
+void shadowircd_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void shadowircd_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void shadowircd_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(TS6SID, "307 %s", buf);
+}
+
+/* 311 */
+void shadowircd_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(TS6SID, "311 %s", buf);
+}
+
+/* 312 */
+void shadowircd_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(TS6SID, "312 %s", buf);
+}
+
+/* 317 */
+void shadowircd_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(TS6SID, "317 %s", buf);
+}
+
+/* 219 */
+void shadowircd_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void shadowircd_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(TS6SID, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void shadowircd_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(TS6SID, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void shadowircd_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void shadowircd_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void shadowircd_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void shadowircd_cmd_mode(char *source, char *dest, char *buf)
+{
+ Uid *ud;
+ if (!buf) {
+ return;
+ }
+
+ if (source) {
+ ud = find_uid(source);
+ send_cmd((ud ? ud->uid : source), "MODE %s %s", dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+void shadowircd_cmd_tmode(char *source, char *dest, char *buf)
+{
+
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "MODE %s %s", dest, buf);
+}
+
+void shadowircd_cmd_nick(char *nick, char *name, char *mode)
+{
+ char *uidbuf = ts6_uid_retrieve();
+
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0.0.0.0 %s %s :%s", nick,
+ (long int) time(NULL), mode, ServiceUser, ServiceHost,
+ uidbuf, ServiceHost, name);
+ new_uid(nick, uidbuf);
+ shadowircd_cmd_sqline(nick, "Reserved for services");
+}
+
+void shadowircd_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ Uid *ud;
+ User *u;
+
+ ud = find_uid(source);
+ u = finduser(user);
+
+ if (buf) {
+ send_cmd((ud ? ud->uid : source), "KICK %s %s :%s", chan,
+ (u ? u->uid : user), buf);
+ } else {
+ send_cmd((ud ? ud->uid : source), "KICK %s %s", chan,
+ (u ? u->uid : user));
+ }
+}
+
+void shadowircd_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+void shadowircd_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ Uid *u;
+
+ u = find_uid(nick);
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode,
+ (u ? u->uid : nick));
+}
+
+/* QUIT */
+void shadowircd_cmd_quit(char *source, char *buf)
+{
+ Uid *ud;
+
+ ud = find_uid(source);
+
+ if (buf) {
+ send_cmd((ud ? ud->uid : source), "QUIT :%s", buf);
+ } else {
+ send_cmd((ud ? ud->uid : source), "QUIT");
+ }
+}
+
+/* PONG */
+void shadowircd_cmd_pong(char *servname, char *who)
+{
+ send_cmd(TS6SID, "PONG %s", who);
+}
+
+/* INVITE */
+void shadowircd_cmd_invite(char *source, char *chan, char *nick)
+{
+ Uid *ud;
+ User *u;
+
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ ud = find_uid(source);
+ u = finduser(nick);
+
+ send_cmd((ud ? ud->uid : source), "INVITE %s %s",
+ (u ? u->uid : nick), chan);
+}
+
+/* SQUIT */
+void shadowircd_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ User *u, *u2;
+
+ if (ac < 2 || *av[0] == '&') {
+ return MOD_CONT;
+ }
+
+ if (*av[0] == '#') {
+ do_cmode(source, ac, av);
+ } else {
+ u = find_byuid(source);
+ u2 = find_byuid(av[0]);
+ av[0] = u2->nick;
+ do_umode2((u ? u->nick : source), ac, av);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tmode(char *source, int ac, char **av)
+{
+ if (*av[1] == '#' || *av[1] == '&') {
+ do_cmode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+void shadowircd_cmd_351(char *source)
+{
+ send_cmd(TS6SID,
+ "351 %s Anope-%s %s :%s (ShadowProtocol %d) - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name,
+ PROTOCOL_REVISION, version_flags, EncModule, version_build);
+}
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ /* Not supported by ShadowIRCd. */
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void shadowircd_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void shadowircd_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void shadowircd_cmd_svsnick(char *nick, char *newnick, time_t when)
+{
+ if (!nick || !newnick) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s %ld", nick, newnick, (long int) when);
+}
+
+void shadowircd_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ /* not supported */
+}
+
+void shadowircd_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void shadowircd_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void shadowircd_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void shadowircd_cmd_svid_umode(char *nick, time_t ts)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void shadowircd_cmd_nc_change(User * u)
+{
+ /* not supported */
+}
+
+/* SVSMODE +d */
+void shadowircd_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not supported */
+}
+
+void shadowircd_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* NICK <newnick> */
+void shadowircd_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ TS6UPLINK = sstrdup(av[3]);
+ return MOD_CONT;
+}
+
+void shadowircd_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void shadowircd_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void shadowircd_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_bmask(char *source, int ac, char **av)
+{
+ Channel *c;
+ char *bans;
+ char *b;
+ int count, i;
+
+ /* :42X BMASK 1106409026 #ircops b :*!*@*.aol.com */
+ /* 0 1 2 3 */
+ c = findchan(av[1]);
+
+ if (c) {
+ bans = sstrdup(av[3]);
+ count = myNumToken(bans, ' ');
+ for (i = 0; i <= count - 1; i++) {
+ b = myStrGetToken(bans, ' ', i);
+ if (!stricmp(av[2], "b")) {
+ add_ban(c, b);
+ }
+ if (!stricmp(av[2], "e")) {
+ add_exception(c, b);
+ }
+ if (!stricmp(av[2], "I")) {
+ add_invite(c, b);
+ }
+ if (b)
+ free(b);
+ }
+ free(bans);
+ }
+ return MOD_CONT;
+}
+
+int shadowircd_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void shadowircd_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ shadowircd_cmd_squit(jserver, rbuf);
+ shadowircd_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int shadowircd_valid_nick(char *nick)
+{
+ /* TS6 Save extension -Certus */
+ if (isdigit(*nick))
+ return 0;
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int shadowircd_valid_chan(char *chan)
+{
+ /* no hard coded invalid chan */
+ return 1;
+}
+
+
+void shadowircd_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(shadowircd_cmd_svsnoop);
+ pmodule_cmd_remove_akill(shadowircd_cmd_remove_akill);
+ pmodule_cmd_topic(shadowircd_cmd_topic);
+ pmodule_cmd_vhost_off(shadowircd_cmd_vhost_off);
+ pmodule_cmd_akill(shadowircd_cmd_akill);
+ pmodule_cmd_svskill(shadowircd_cmd_svskill);
+ pmodule_cmd_svsmode(shadowircd_cmd_svsmode);
+ pmodule_cmd_372(shadowircd_cmd_372);
+ pmodule_cmd_372_error(shadowircd_cmd_372_error);
+ pmodule_cmd_375(shadowircd_cmd_375);
+ pmodule_cmd_376(shadowircd_cmd_376);
+ pmodule_cmd_nick(shadowircd_cmd_nick);
+ pmodule_cmd_guest_nick(shadowircd_cmd_guest_nick);
+ pmodule_cmd_mode(shadowircd_cmd_mode);
+ pmodule_cmd_bot_nick(shadowircd_cmd_bot_nick);
+ pmodule_cmd_kick(shadowircd_cmd_kick);
+ pmodule_cmd_notice_ops(shadowircd_cmd_notice_ops);
+ pmodule_cmd_notice(shadowircd_cmd_notice);
+ pmodule_cmd_notice2(shadowircd_cmd_notice2);
+ pmodule_cmd_privmsg(shadowircd_cmd_privmsg);
+ pmodule_cmd_privmsg2(shadowircd_cmd_privmsg2);
+ pmodule_cmd_serv_notice(shadowircd_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(shadowircd_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(shadowircd_cmd_bot_chan_mode);
+ pmodule_cmd_351(shadowircd_cmd_351);
+ pmodule_cmd_quit(shadowircd_cmd_quit);
+ pmodule_cmd_pong(shadowircd_cmd_pong);
+ pmodule_cmd_join(shadowircd_cmd_join);
+ pmodule_cmd_unsqline(shadowircd_cmd_unsqline);
+ pmodule_cmd_invite(shadowircd_cmd_invite);
+ pmodule_cmd_part(shadowircd_cmd_part);
+ pmodule_cmd_391(shadowircd_cmd_391);
+ pmodule_cmd_250(shadowircd_cmd_250);
+ pmodule_cmd_307(shadowircd_cmd_307);
+ pmodule_cmd_311(shadowircd_cmd_311);
+ pmodule_cmd_312(shadowircd_cmd_312);
+ pmodule_cmd_317(shadowircd_cmd_317);
+ pmodule_cmd_219(shadowircd_cmd_219);
+ pmodule_cmd_401(shadowircd_cmd_401);
+ pmodule_cmd_318(shadowircd_cmd_318);
+ pmodule_cmd_242(shadowircd_cmd_242);
+ pmodule_cmd_243(shadowircd_cmd_243);
+ pmodule_cmd_211(shadowircd_cmd_211);
+ pmodule_cmd_global(shadowircd_cmd_global);
+ pmodule_cmd_global_legacy(shadowircd_cmd_global_legacy);
+ pmodule_cmd_sqline(shadowircd_cmd_sqline);
+ pmodule_cmd_squit(shadowircd_cmd_squit);
+ pmodule_cmd_svso(shadowircd_cmd_svso);
+ pmodule_cmd_chg_nick(shadowircd_cmd_chg_nick);
+ pmodule_cmd_svsnick(shadowircd_cmd_svsnick);
+ pmodule_cmd_vhost_on(shadowircd_cmd_vhost_on);
+ pmodule_cmd_connect(shadowircd_cmd_connect);
+ pmodule_cmd_svshold(shadowircd_cmd_svshold);
+ pmodule_cmd_release_svshold(shadowircd_cmd_release_svshold);
+ pmodule_cmd_unsgline(shadowircd_cmd_unsgline);
+ pmodule_cmd_unszline(shadowircd_cmd_unszline);
+ pmodule_cmd_szline(shadowircd_cmd_szline);
+ pmodule_cmd_sgline(shadowircd_cmd_sgline);
+ pmodule_cmd_unban(shadowircd_cmd_unban);
+ pmodule_cmd_svsmode_chan(shadowircd_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(shadowircd_cmd_svid_umode);
+ pmodule_cmd_nc_change(shadowircd_cmd_nc_change);
+ pmodule_cmd_svid_umode2(shadowircd_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(shadowircd_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(shadowircd_cmd_svsjoin);
+ pmodule_cmd_svspart(shadowircd_cmd_svspart);
+ pmodule_cmd_swhois(shadowircd_cmd_swhois);
+ pmodule_cmd_eob(shadowircd_cmd_eob);
+ pmodule_flood_mode_check(shadowircd_flood_mode_check);
+ pmodule_cmd_jupe(shadowircd_cmd_jupe);
+ pmodule_valid_nick(shadowircd_valid_nick);
+ pmodule_valid_chan(shadowircd_valid_chan);
+ pmodule_cmd_ctcp(shadowircd_cmd_ctcp);
+ pmodule_set_umode(shadowircd_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("ShadowIRCd 4.0+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(1);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/shadowircd.h b/src/protocol/shadowircd.h
new file mode 100644
index 000000000..67f5188fd
--- /dev/null
+++ b/src/protocol/shadowircd.h
@@ -0,0 +1,142 @@
+/* ShadowIRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/* The protocol revision. */
+#define PROTOCOL_REVISION 3402
+
+
+#define UMODE_a 0x00000001
+#define UMODE_C 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_z 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_s 0x00000040
+#define UMODE_c 0x00000080
+#define UMODE_r 0x00000100
+#define UMODE_k 0x00000200
+#define UMODE_f 0x00000400
+#define UMODE_y 0x00000800
+#define UMODE_d 0x00001000
+#define UMODE_n 0x00002000
+#define UMODE_x 0x00004000
+#define UMODE_u 0x00008000
+#define UMODE_b 0x00010000
+#define UMODE_l 0x00020000
+#define UMODE_g 0x00040000
+#define UMODE_v 0x00080000
+#define UMODE_A 0x00100000
+#define UMODE_E 0x00200000
+#define UMODE_G 0x00400000
+#define UMODE_R 0x00800000
+#define UMODE_e 0x01000000
+#define UMODE_O 0x02000000
+#define UMODE_H 0x04000000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040
+#define CMODE_l 0x00000080
+#define CMODE_K 0x00000100
+#define CMODE_A 0x00000200
+#define CMODE_r 0x00000400
+#define CMODE_z 0x00000800
+#define CMODE_S 0x00001000
+#define CMODE_c 0x00002000
+#define CMODE_E 0x00004000
+#define CMODE_F 0x00008000
+#define CMODE_G 0x00010000
+#define CMODE_L 0x00020000
+#define CMODE_N 0x00040000
+#define CMODE_O 0x00080000
+#define CMODE_P 0x00100000
+#define CMODE_R 0x00200000
+#define CMODE_T 0x00400000
+#define CMODE_V 0x00800000
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void shadowircd_set_umode(User * user, int ac, char **av);
+void shadowircd_cmd_svsnoop(char *server, int set);
+void shadowircd_cmd_remove_akill(char *user, char *host);
+void shadowircd_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void shadowircd_cmd_vhost_off(User * u);
+void shadowircd_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void shadowircd_cmd_svskill(char *source, char *user, char *buf);
+void shadowircd_cmd_svsmode(User * u, int ac, char **av);
+void shadowircd_cmd_372(char *source, char *msg);
+void shadowircd_cmd_372_error(char *source);
+void shadowircd_cmd_375(char *source);
+void shadowircd_cmd_376(char *source);
+void shadowircd_cmd_nick(char *nick, char *name, char *modes);
+void shadowircd_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void shadowircd_cmd_mode(char *source, char *dest, char *buf);
+void shadowircd_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void shadowircd_cmd_kick(char *source, char *chan, char *user, char *buf);
+void shadowircd_cmd_notice_ops(char *source, char *dest, char *buf);
+void shadowircd_cmd_notice(char *source, char *dest, char *buf);
+void shadowircd_cmd_notice2(char *source, char *dest, char *msg);
+void shadowircd_cmd_privmsg(char *source, char *dest, char *buf);
+void shadowircd_cmd_privmsg2(char *source, char *dest, char *msg);
+void shadowircd_cmd_serv_notice(char *source, char *dest, char *msg);
+void shadowircd_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void shadowircd_cmd_bot_chan_mode(char *nick, char *chan);
+void shadowircd_cmd_351(char *source);
+void shadowircd_cmd_quit(char *source, char *buf);
+void shadowircd_cmd_pong(char *servname, char *who);
+void shadowircd_cmd_join(char *user, char *channel, time_t chantime);
+void shadowircd_cmd_unsqline(char *user);
+void shadowircd_cmd_invite(char *source, char *chan, char *nick);
+void shadowircd_cmd_part(char *nick, char *chan, char *buf);
+void shadowircd_cmd_391(char *source, char *timestr);
+void shadowircd_cmd_250(char *buf);
+void shadowircd_cmd_307(char *buf);
+void shadowircd_cmd_311(char *buf);
+void shadowircd_cmd_312(char *buf);
+void shadowircd_cmd_317(char *buf);
+void shadowircd_cmd_219(char *source, char *letter);
+void shadowircd_cmd_401(char *source, char *who);
+void shadowircd_cmd_318(char *source, char *who);
+void shadowircd_cmd_242(char *buf);
+void shadowircd_cmd_243(char *buf);
+void shadowircd_cmd_211(char *buf);
+void shadowircd_cmd_global(char *source, char *buf);
+void shadowircd_cmd_global_legacy(char *source, char *fmt);
+void shadowircd_cmd_sqline(char *mask, char *reason);
+void shadowircd_cmd_squit(char *servname, char *message);
+void shadowircd_cmd_svso(char *source, char *nick, char *flag);
+void shadowircd_cmd_chg_nick(char *oldnick, char *newnick);
+void shadowircd_cmd_svsnick(char *source, char *guest, time_t when);
+void shadowircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void shadowircd_cmd_connect(int servernum);
+void shadowircd_cmd_svshold(char *nick);
+void shadowircd_cmd_release_svshold(char *nick);
+void shadowircd_cmd_unsgline(char *mask);
+void shadowircd_cmd_unszline(char *mask);
+void shadowircd_cmd_szline(char *mask, char *reason, char *whom);
+void shadowircd_cmd_sgline(char *mask, char *reason);
+void shadowircd_cmd_unban(char *name, char *nick);
+void shadowircd_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void shadowircd_cmd_svid_umode(char *nick, time_t ts);
+void shadowircd_cmd_nc_change(User * u);
+void shadowircd_cmd_svid_umode2(User * u, char *ts);
+void shadowircd_cmd_svid_umode3(User * u, char *ts);
+void shadowircd_cmd_eob();
+int shadowircd_flood_mode_check(char *value);
+void shadowircd_cmd_jupe(char *jserver, char *who, char *reason);
+int shadowircd_valid_nick(char *nick);
+void shadowircd_cmd_ctcp(char *source, char *dest, char *buf);
diff --git a/src/protocol/solidircd.c b/src/protocol/solidircd.c
new file mode 100644
index 000000000..b0f948794
--- /dev/null
+++ b/src/protocol/solidircd.c
@@ -0,0 +1,1710 @@
+/* Solid-IRCD functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "solidircd.h"
+
+IRCDVar myIrcd[] = {
+ {"Solid-IRCd 3.4.*", /* ircd name */
+ "+o", /* nickserv mode */
+ "+o", /* chanserv mode */
+ "+o", /* memoserv mode */
+ "+o", /* hostserv mode */
+ "+io", /* operserv mode */
+ "+o", /* botserv mode */
+ "+h", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+io", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+io", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+", /* Used by BotServ Bots */
+ 2, /* Chan Max Symbols */
+ "-cilmnpstOR", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to unset for chan admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 1, /* Chan SQlines */
+ 1, /* Quit on Kill */
+ 1, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 0, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ 0, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_v, /* Vhost Mode */
+ 1, /* +f */
+ 0, /* +L */
+ CMODE_j, /* Mode */
+ 0, /* Mode */
+ 1,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "v", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ CAPAB_TSMODE, /* TSMODE */
+ CAPAB_UNCONNECT, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ CAPAB_BURST, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ CAPAB_DKEY, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ CAPAB_DOZIP, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+void solidircd_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'a':
+ if (UnRestrictSAdmin) {
+ break;
+ }
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+
+ if (WallOper)
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ display_news(user, NEWS_OPER);
+
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'v':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, UMODE_C, /* A B C */
+ UMODE_D, 0, UMODE_F, /* D E F */
+ 0, UMODE_H, UMODE_I, /* G H I */
+ 0, UMODE_K, 0, /* J K L */
+ 0, 0, UMODE_O, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ 0, 0, 0, /* S T U */
+ 0, 0, UMODE_X, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, UMODE_b, UMODE_c, /* a b c */
+ UMODE_d, UMODE_e, UMODE_f, /* d e f */
+ UMODE_g, UMODE_h, UMODE_i, /* g h i */
+ UMODE_j, UMODE_k, 0, /* j k l */
+ UMODE_m, UMODE_n, UMODE_o, /* m n o */
+ 0, 0, UMODE_r, /* p q r */
+ UMODE_s, 0, 0, /* s t u */
+ UMODE_v, UMODE_w, UMODE_x, /* v w x */
+ UMODE_y, /* y */
+ UMODE_z, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h',
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite},
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {CMODE_j, 0, set_flood, cs_set_flood}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'j', CMODE_j, 0, get_flood, cs_get_flood},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+void solidircd_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (ircdcap->tsmode) {
+ if (uplink_capab & ircdcap->tsmode) {
+ send_cmd(source, "MODE %s 0 %s", dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+/* SVSHOLD - set */
+void solidircd_cmd_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s %d :%s", nick, NSReleaseTimeout,
+ "Being held for registered user");
+}
+
+/* SVSHOLD - release */
+void solidircd_cmd_release_svshold(char *nick)
+{
+ send_cmd(ServerName, "SVSHOLD %s 0", nick);
+}
+
+/* SVSMODE -b */
+void solidircd_cmd_unban(char *name, char *nick)
+{
+ solidircd_cmd_svsmode_chan(name, "-b", nick);
+}
+
+
+/* SVSMODE channel modes */
+
+void solidircd_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "SVSMODE %s %s %s", name, mode, nick);
+ } else {
+ send_cmd(ServerName, "SVSMODE %s %s", name, mode);
+ }
+}
+
+void solidircd_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+/* EVENT: SJOIN */
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+/*
+** NICK - new
+** source = NULL
+** parv[0] = nickname
+** parv[1] = hopcount
+** parv[2] = timestamp
+** parv[3] = modes
+** parv[4] = username
+** parv[5] = hostname
+** parv[6] = server
+** parv[7] = servicestamp
+** parv[8] = IP
+** parv[9] = info
+** NICK - change
+** source = oldnick
+** parv[0] = new nickname
+** parv[1] = hopcount
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[7], NULL, 0),
+ strtoul(av[8], NULL, 0), NULL, NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT : CAPAB */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT : OS */
+int anope_event_os(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_OperServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : NS */
+int anope_event_ns(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_NickServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : MS */
+int anope_event_ms(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_MemoServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : HS */
+int anope_event_hs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_HostServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : CS */
+int anope_event_cs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_ChanServ, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+","-");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_gnotice); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m);
+ m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m);
+ m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m);
+ m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m);
+ m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m);
+ m = createMessage("RS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("SZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("LUSERSLOCK",anope_event_luserslock); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("SVHOST", anope_event_vs); addCoreMessage(IRCD,m);
+ m = createMessage("ELMER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILLY", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SHUN", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("NORMAL", anope_event_null); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+int anope_event_vs(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: SVHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+
+}
+
+/* SQLINE */
+void solidircd_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+/* UNSGLINE */
+void solidircd_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "UNSGLINE 0 :%s", mask);
+}
+
+/* UNSZLINE */
+void solidircd_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "UNSZLINE 0 %s", mask);
+}
+
+/* SZLINE */
+void solidircd_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "SZLINE %s :%s", mask, reason);
+}
+
+/* SVSNOOP */
+void solidircd_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void solidircd_cmd_svsadmin(char *server, int set)
+{
+ solidircd_cmd_svsnoop(server, set);
+}
+
+/* SGLINE */
+void solidircd_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
+}
+
+/* RAKILL */
+void solidircd_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+/* PART */
+void solidircd_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/* TOPIC */
+void solidircd_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+/* UNSQLINE */
+void solidircd_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+/* JOIN - SJOIN */
+void solidircd_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "SJOIN %ld %s", (long int) chantime, channel);
+}
+
+/* AKILL */
+/* parv[1]=host
+ * parv[2]=user
+ * parv[3]=length
+ * parv[4]=akiller
+ * parv[5]=time set
+ * parv[6]=reason
+ */
+void solidircd_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400 * 2, who,
+ (long int) time(NULL), reason);
+}
+
+/* SVSKILL */
+/* parv[0] = servername
+ * parv[1] = client
+ * parv[2] = nick stamp
+ * parv[3] = kill message
+ */
+/*
+ Note: if the stamp is null 0, the below usage is correct of Bahamut
+*/
+void solidircd_cmd_svskill(char *source, char *user, char *buf)
+{
+
+ if (!source || !user || !buf) {
+ return;
+ }
+
+ send_cmd(source, "SVSKILL %s :%s", user, buf);
+}
+
+/* SVSMODE */
+/* parv[0] - sender
+ * parv[1] - nick
+ * parv[2] - TS (or mode, depending on svs version)
+ * parv[3] - mode (or services id if old svs version)
+ * parv[4] - optional arguement (services id)
+ */
+void solidircd_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+/* SQUIT */
+/*
+ * parv[0] = sender prefix
+ * parv[1] = server name
+ * parv[2] = comment
+*/
+void solidircd_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* PONG */
+void solidircd_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+void solidircd_cmd_burst()
+{
+ send_cmd(NULL, "BURST");
+}
+
+
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void solidircd_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 5 3 0 :%ld", (long int) time(NULL));
+}
+
+/* PASS */
+void solidircd_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER */
+void solidircd_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, ServerDesc);
+}
+
+/* CAPAB */
+void solidircd_cmd_capab()
+{
+ /* CAPAB SSJOIN NOQUIT BURST UNCONNECT ZIP NICKIP TSMODE */
+ send_cmd(NULL, "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE");
+}
+
+void solidircd_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1) {
+ solidircd_cmd_pass(RemotePassword);
+ } else if (servernum == 2) {
+ solidircd_cmd_pass(RemotePassword2);
+ } else if (servernum == 3) {
+ solidircd_cmd_pass(RemotePassword3);
+ }
+ solidircd_cmd_capab();
+ solidircd_cmd_server(ServerName, 1, ServerDesc);
+ solidircd_cmd_svinfo();
+ solidircd_cmd_burst();
+}
+
+/* EVENT : SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ char *uplink;
+
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+/* EVENT : PRIVMSG */
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT : SVINFO */
+/*
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: MODE */
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT: KILL */
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT: KICK */
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: JOIN */
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+/* EVENT: MOTD */
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+void solidircd_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+
+ if (!buf) {
+ return;
+ }
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+/* NOTICE */
+void solidircd_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ solidircd_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void solidircd_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void solidircd_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void solidircd_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void solidircd_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void solidircd_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+/* GLOBOPS */
+void solidircd_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* 391 */
+void solidircd_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void solidircd_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void solidircd_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void solidircd_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void solidircd_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void solidircd_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void solidircd_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void solidircd_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void solidircd_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void solidircd_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void solidircd_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void solidircd_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void solidircd_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, ServiceUser, ServiceHost,
+ ServerName, name);
+ solidircd_cmd_sqline(nick, "Reserved for services");
+}
+
+void solidircd_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void solidircd_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void solidircd_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void solidircd_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void solidircd_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* INVITE */
+void solidircd_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* QUIT */
+void solidircd_cmd_quit(char *source, char *buf)
+{
+
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ solidircd_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void solidircd_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s)-- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+
+
+}
+
+void solidircd_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+ solidircd_cmd_sqline(nick, "Reserved for services");
+}
+
+/* SVSNICK */
+/* parv[0] = sender
+ * parv[1] = old nickname
+ * parv[2] = new nickname
+ * parv[3] = timestamp
+ */
+void solidircd_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void solidircd_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+}
+
+void solidircd_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+void solidircd_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "SVHOST %s %s", nick, vhost);
+}
+
+
+void solidircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ send_cmd(s_HostServ, "SVSMODE %s +v", nick);
+ solidircd_cmd_chghost(nick, vhost);
+}
+
+void solidircd_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "SVSMODE %s -v", u->nick);
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick, ircd->vhostchar);
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void solidircd_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void solidircd_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void solidircd_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used by bahamut ircds */
+}
+
+
+void solidircd_cmd_svid_umode3(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+/* NICK <newnick> */
+void solidircd_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s :%ld", newnick, (long int) time(NULL));
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+
+int anope_event_gnotice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+void solidircd_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Can not find any reference to these in Bahamut */
+}
+
+void solidircd_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Can not find any reference to these in Bahamut */
+}
+
+void solidircd_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+void solidircd_cmd_eob()
+{
+ send_cmd(NULL, "BURST 0");
+}
+
+int anope_event_burst(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ if (!ac) {
+ /* for future use - start burst */
+ } else {
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_luserslock(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int solidircd_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void solidircd_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ solidircd_cmd_squit(jserver, rbuf);
+ solidircd_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void solidircd_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int solidircd_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int solidircd_valid_chan(char *chan)
+{
+ /* no hard coded invalid chan*/
+ return 1;
+}
+
+
+void solidircd_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "%s NOTICE :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(solidircd_cmd_svsnoop);
+ pmodule_cmd_remove_akill(solidircd_cmd_remove_akill);
+ pmodule_cmd_topic(solidircd_cmd_topic);
+ pmodule_cmd_vhost_off(solidircd_cmd_vhost_off);
+ pmodule_cmd_akill(solidircd_cmd_akill);
+ pmodule_cmd_svskill(solidircd_cmd_svskill);
+ pmodule_cmd_svsmode(solidircd_cmd_svsmode);
+ pmodule_cmd_372(solidircd_cmd_372);
+ pmodule_cmd_372_error(solidircd_cmd_372_error);
+ pmodule_cmd_375(solidircd_cmd_375);
+ pmodule_cmd_376(solidircd_cmd_376);
+ pmodule_cmd_nick(solidircd_cmd_nick);
+ pmodule_cmd_guest_nick(solidircd_cmd_guest_nick);
+ pmodule_cmd_mode(solidircd_cmd_mode);
+ pmodule_cmd_bot_nick(solidircd_cmd_bot_nick);
+ pmodule_cmd_kick(solidircd_cmd_kick);
+ pmodule_cmd_notice_ops(solidircd_cmd_notice_ops);
+ pmodule_cmd_notice(solidircd_cmd_notice);
+ pmodule_cmd_notice2(solidircd_cmd_notice2);
+ pmodule_cmd_privmsg(solidircd_cmd_privmsg);
+ pmodule_cmd_privmsg2(solidircd_cmd_privmsg2);
+ pmodule_cmd_serv_notice(solidircd_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(solidircd_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(solidircd_cmd_bot_chan_mode);
+ pmodule_cmd_351(solidircd_cmd_351);
+ pmodule_cmd_quit(solidircd_cmd_quit);
+ pmodule_cmd_pong(solidircd_cmd_pong);
+ pmodule_cmd_join(solidircd_cmd_join);
+ pmodule_cmd_unsqline(solidircd_cmd_unsqline);
+ pmodule_cmd_invite(solidircd_cmd_invite);
+ pmodule_cmd_part(solidircd_cmd_part);
+ pmodule_cmd_391(solidircd_cmd_391);
+ pmodule_cmd_250(solidircd_cmd_250);
+ pmodule_cmd_307(solidircd_cmd_307);
+ pmodule_cmd_311(solidircd_cmd_311);
+ pmodule_cmd_312(solidircd_cmd_312);
+ pmodule_cmd_317(solidircd_cmd_317);
+ pmodule_cmd_219(solidircd_cmd_219);
+ pmodule_cmd_401(solidircd_cmd_401);
+ pmodule_cmd_318(solidircd_cmd_318);
+ pmodule_cmd_242(solidircd_cmd_242);
+ pmodule_cmd_243(solidircd_cmd_243);
+ pmodule_cmd_211(solidircd_cmd_211);
+ pmodule_cmd_global(solidircd_cmd_global);
+ pmodule_cmd_global_legacy(solidircd_cmd_global_legacy);
+ pmodule_cmd_sqline(solidircd_cmd_sqline);
+ pmodule_cmd_squit(solidircd_cmd_squit);
+ pmodule_cmd_svso(solidircd_cmd_svso);
+ pmodule_cmd_chg_nick(solidircd_cmd_chg_nick);
+ pmodule_cmd_svsnick(solidircd_cmd_svsnick);
+ pmodule_cmd_vhost_on(solidircd_cmd_vhost_on);
+ pmodule_cmd_connect(solidircd_cmd_connect);
+ pmodule_cmd_svshold(solidircd_cmd_svshold);
+ pmodule_cmd_release_svshold(solidircd_cmd_release_svshold);
+ pmodule_cmd_unsgline(solidircd_cmd_unsgline);
+ pmodule_cmd_unszline(solidircd_cmd_unszline);
+ pmodule_cmd_szline(solidircd_cmd_szline);
+ pmodule_cmd_sgline(solidircd_cmd_sgline);
+ pmodule_cmd_unban(solidircd_cmd_unban);
+ pmodule_cmd_svsmode_chan(solidircd_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(solidircd_cmd_svid_umode);
+ pmodule_cmd_nc_change(solidircd_cmd_nc_change);
+ pmodule_cmd_svid_umode2(solidircd_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(solidircd_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(solidircd_cmd_svsjoin);
+ pmodule_cmd_svspart(solidircd_cmd_svspart);
+ pmodule_cmd_swhois(solidircd_cmd_swhois);
+ pmodule_cmd_eob(solidircd_cmd_eob);
+ pmodule_flood_mode_check(solidircd_flood_mode_check);
+ pmodule_cmd_jupe(solidircd_cmd_jupe);
+ pmodule_valid_nick(solidircd_valid_nick);
+ pmodule_valid_chan(solidircd_valid_chan);
+ pmodule_cmd_ctcp(solidircd_cmd_ctcp);
+ pmodule_set_umode(solidircd_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("Solid-IRCd 3.4.*");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+j");
+ pmodule_ircd_flood_mode_char_remove("-j");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/solidircd.h b/src/protocol/solidircd.h
new file mode 100644
index 000000000..9bf5d3b02
--- /dev/null
+++ b/src/protocol/solidircd.h
@@ -0,0 +1,137 @@
+/* SolidIRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+#define UMODE_a 0x00000001 /* umode +a - Services Admin */
+#define UMODE_h 0x00000002 /* umode +h - Helper */
+#define UMODE_i 0x00000004 /* umode +i - Invisible */
+#define UMODE_o 0x00000008 /* umode +o - Oper */
+#define UMODE_r 0x00000010 /* umode +r - registered nick */
+#define UMODE_w 0x00000020 /* umode +w - Get wallops */
+#define UMODE_A 0x00000040 /* umode +A - Server Admin */
+#define UMODE_x 0x00000080 /* umode +x - Squelch with notice */
+#define UMODE_X 0x00000100 /* umode +X - Squelch without notice */
+#define UMODE_F 0x00000200 /* umode +F - no cptr->since message rate throttle */
+#define UMODE_j 0x00000400 /* umode +j - client rejection notices */
+#define UMODE_K 0x00000800 /* umode +K - U: lined server kill messages */
+#define UMODE_O 0x00001000 /* umode +O - Local Oper */
+#define UMODE_s 0x00002000 /* umode +s - Server notices */
+#define UMODE_c 0x00004000 /* umode +c - Client connections/exits */
+#define UMODE_k 0x00008000 /* umode +k - Server kill messages */
+#define UMODE_f 0x00010000 /* umode +f - Server flood messages */
+#define UMODE_y 0x00020000 /* umode +y - Stats/links */
+#define UMODE_d 0x00040000 /* umode +d - Debug info */
+#define UMODE_g 0x00080000 /* umode +g - Globops */
+#define UMODE_b 0x00100000 /* umode +b - Chatops */
+#define UMODE_n 0x00200000 /* umode +n - Routing Notices */
+#define UMODE_m 0x00400000 /* umode +m - spambot notices */
+#define UMODE_e 0x00800000 /* umode +e - oper notices for the above +D */
+#define UMODE_D 0x01000000 /* umode +D - Hidden dccallow umode */
+#define UMODE_I 0x02000000 /* umode +I - invisible oper (masked) */
+#define UMODE_C 0x04000000 /* umode +C - conops */
+#define UMODE_v 0x10000000 /* umode +v - hostmasking */
+#define UMODE_H 0x20000000 /* umode +H - Oper Hiding */
+#define UMODE_z 0x40000000 /* umode +z - SSL */
+#define UMODE_R 0x80000000 /* umode +R - No non registered msgs */
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_c 0x00000400 /* Colors can't be used */
+#define CMODE_M 0x00000800 /* Non-regged nicks can't send messages */
+#define CMODE_j 0x00001000 /* join throttle */
+#define CMODE_S 0x00002000 /* SSL only */
+#define CMODE_N 0x00004000 /* No Nickname change */
+#define CMODE_O 0x00008000 /* Only opers can join */
+
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void solidircd_set_umode(User * user, int ac, char **av);
+void solidircd_cmd_svsnoop(char *server, int set);
+void solidircd_cmd_remove_akill(char *user, char *host);
+void solidircd_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void solidircd_cmd_vhost_off(User * u);
+void solidircd_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void solidircd_cmd_svskill(char *source, char *user, char *buf);
+void solidircd_cmd_svsmode(User * u, int ac, char **av);
+void solidircd_cmd_372(char *source, char *msg);
+void solidircd_cmd_372_error(char *source);
+void solidircd_cmd_375(char *source);
+void solidircd_cmd_376(char *source);
+void solidircd_cmd_nick(char *nick, char *name, char *modes);
+void solidircd_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void solidircd_cmd_mode(char *source, char *dest, char *buf);
+void solidircd_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void solidircd_cmd_kick(char *source, char *chan, char *user, char *buf);
+void solidircd_cmd_notice_ops(char *source, char *dest, char *buf);
+void solidircd_cmd_notice(char *source, char *dest, char *buf);
+void solidircd_cmd_notice2(char *source, char *dest, char *msg);
+void solidircd_cmd_privmsg(char *source, char *dest, char *buf);
+void solidircd_cmd_privmsg2(char *source, char *dest, char *msg);
+void solidircd_cmd_serv_notice(char *source, char *dest, char *msg);
+void solidircd_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void solidircd_cmd_bot_chan_mode(char *nick, char *chan);
+void solidircd_cmd_351(char *source);
+void solidircd_cmd_quit(char *source, char *buf);
+void solidircd_cmd_pong(char *servname, char *who);
+void solidircd_cmd_join(char *user, char *channel, time_t chantime);
+void solidircd_cmd_unsqline(char *user);
+void solidircd_cmd_invite(char *source, char *chan, char *nick);
+void solidircd_cmd_part(char *nick, char *chan, char *buf);
+void solidircd_cmd_391(char *source, char *timestr);
+void solidircd_cmd_250(char *buf);
+void solidircd_cmd_307(char *buf);
+void solidircd_cmd_311(char *buf);
+void solidircd_cmd_312(char *buf);
+void solidircd_cmd_317(char *buf);
+void solidircd_cmd_219(char *source, char *letter);
+void solidircd_cmd_401(char *source, char *who);
+void solidircd_cmd_318(char *source, char *who);
+void solidircd_cmd_242(char *buf);
+void solidircd_cmd_243(char *buf);
+void solidircd_cmd_211(char *buf);
+void solidircd_cmd_global(char *source, char *buf);
+void solidircd_cmd_global_legacy(char *source, char *fmt);
+void solidircd_cmd_sqline(char *mask, char *reason);
+void solidircd_cmd_squit(char *servname, char *message);
+void solidircd_cmd_svso(char *source, char *nick, char *flag);
+void solidircd_cmd_chg_nick(char *oldnick, char *newnick);
+void solidircd_cmd_svsnick(char *source, char *guest, time_t when);
+void solidircd_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void solidircd_cmd_connect(int servernum);
+void solidircd_cmd_svshold(char *nick);
+void solidircd_cmd_release_svshold(char *nick);
+void solidircd_cmd_unsgline(char *mask);
+void solidircd_cmd_unszline(char *mask);
+void solidircd_cmd_szline(char *mask, char *reason, char *whom);
+void solidircd_cmd_sgline(char *mask, char *reason);
+void solidircd_cmd_unban(char *name, char *nick);
+void solidircd_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void solidircd_cmd_svid_umode(char *nick, time_t ts);
+void solidircd_cmd_nc_change(User * u);
+void solidircd_cmd_svid_umode2(User * u, char *ts);
+void solidircd_cmd_svid_umode3(User * u, char *ts);
+void solidircd_cmd_eob();
+int solidircd_flood_mode_check(char *value);
+void solidircd_cmd_jupe(char *jserver, char *who, char *reason);
+int solidircd_valid_nick(char *nick);
+void solidircd_cmd_ctcp(char *source, char *dest, char *buf);
diff --git a/src/protocol/ultimate2.c b/src/protocol/ultimate2.c
new file mode 100644
index 000000000..2e6125861
--- /dev/null
+++ b/src/protocol/ultimate2.c
@@ -0,0 +1,1734 @@
+/* Ultimate IRCD 2 functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "ultimate2.h"
+
+IRCDVar myIrcd[] = {
+ {"UltimateIRCd 2.8.*", /* ircd name */
+ "+S", /* nickserv mode */
+ "+S", /* chanserv mode */
+ "+S", /* memoserv mode */
+ "+oS", /* hostserv mode */
+ "+iS", /* operserv mode */
+ "+S", /* botserv mode */
+ "+Sh", /* helpserv mode */
+ "+iS", /* Dev/Null mode */
+ "+iS", /* Global mode */
+ "+oS", /* nickserv alias mode */
+ "+oS", /* chanserv alias mode */
+ "+oS", /* memoserv alias mode */
+ "+ioS", /* hostserv alias mode */
+ "+ioS", /* operserv alias mode */
+ "+oS", /* botserv alias mode */
+ "+oS", /* helpserv alias mode */
+ "+iS", /* Dev/Null alias mode */
+ "+ioS", /* Global alias mode */
+ "+pS", /* Used by BotServ Bots */
+ 3, /* Chan Max Symbols */
+ "-ilmnpstxAIKORS", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ NULL, /* Mode to set for chan admin */
+ NULL, /* Mode to remove for chan admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "-r+d", /* Mode on Nick Change */
+ 0, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 0, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ UMODE_p, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 0, /* svshold */
+ 1, /* time stamp on mode */
+ 0, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 0, /* VHOST ON NICK */
+ 1, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 1, /* +f */
+ 1, /* +L */
+ CMODE_f,
+ CMODE_L,
+ 0,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 1, /* We support TOKENS */
+ 0, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ 0, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ CAPAB_KNOCK, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ CAPAB_TOKEN, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ CAPAB_CHANMODE, /* CHANMODE */
+ 0, 0}
+};
+
+void ultiamte2_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'a':
+ if (add && !is_services_oper(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'P':
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-P", NULL);
+ user->mode &= ~UMODE_P;
+ }
+ break;
+ case 'R':
+ if (add && !is_services_root(user)) {
+ common_svsmode(user, "-R", NULL);
+ user->mode &= ~UMODE_R;
+ }
+ break;
+ case 'd':
+ if (ac == 0) {
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ if (is_services_oper(user)) {
+ common_svsmode(user, "+a", NULL);
+ user->mode |= UMODE_a;
+ }
+ if (is_services_admin(user)) {
+ common_svsmode(user, "+P", NULL);
+ user->mode |= UMODE_P;
+ }
+ if (is_services_root(user)) {
+ common_svsmode(user, "+R", NULL);
+ user->mode |= UMODE_R;
+ }
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, UMODE_A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ UMODE_P,
+ 0,
+ UMODE_R,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0, UMODE_a, 0, 0, 0, 0, 0,
+ UMODE_g,
+ UMODE_h, UMODE_i, 0, 0, 0, 0, 0, UMODE_o,
+ UMODE_p,
+ 0, UMODE_r, 0, 0, 0, 0, UMODE_w,
+ UMODE_x,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {CMODE_I, 0, NULL, NULL}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, set_redirect, cs_set_redirect},
+ {0}, /* M */
+ {0}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {CMODE_f, 0, set_flood, cs_set_flood},
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL}, /* i */
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL}, /* m */
+ {CMODE_n, 0, NULL, NULL}, /* n */
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL}, /* p */
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL}, /* s */
+ {CMODE_t, 0, NULL, NULL}, /* t */
+ {0}, /* u */
+ {0}, /* v */
+ {0}, /* w */
+ {CMODE_x, 0, NULL, NULL}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'f', CMODE_f, 0, get_flood, cs_get_flood},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'x', CMODE_x, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'I', CMODE_I, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, get_redirect, cs_get_redirect},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {0}, /* a */
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGNAME for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ if (ac != 2) {
+ if (ac == 7) {
+ do_nick(source, av[0], av[3], av[4], av[5], av[6],
+ strtoul(av[2], NULL, 10), 0, 0, NULL, NULL);
+ } else {
+ do_nick(source, av[0], av[3], av[4], av[5], av[7],
+ strtoul(av[2], NULL, 10), strtoul(av[6], NULL, 0), 0,
+ NULL, NULL);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("6", anope_event_away); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("*", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("C", anope_event_join); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("H", anope_event_kick); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(".", anope_event_kill); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("G", anope_event_mode); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("F", anope_event_motd); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("&", anope_event_nick); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("B", anope_event_notice); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("D", anope_event_part); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("<", anope_event_pass); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("9", anope_event_ping); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!", anope_event_privmsg); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(",", anope_event_quit); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("'", anope_event_server); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("-", anope_event_squit); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(")", anope_event_topic); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("%", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("=", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("#", anope_event_whois); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("V", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("]", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GNOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("Z", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("[", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("Y", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("U", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("h", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("n", anope_event_mode); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("e", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("f", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("c", anope_event_sqline); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("d", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PROTOCTL", anope_event_capab); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("_", anope_event_capab); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CHGHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!<", anope_event_chghost); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!=", anope_event_chgident); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NETINFO", anope_event_netinfo); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("u", anope_event_netinfo); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SNETINFO", anope_event_snetinfo); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!1", anope_event_snetinfo); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!8", anope_event_sethost); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!9", anope_event_setident); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!;", anope_event_setname); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("VCTRL", anope_event_vctrl); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!I", anope_event_vctrl); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+
+
+}
+
+/* *INDENT-ON* */
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+void ultimate2_cmd_sqline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+void ultimate2_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void ultimate2_cmd_svsadmin(char *server, int set)
+{
+ ultimate2_cmd_svsnoop(server, set);
+}
+
+void ultimate2_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+
+void ultimate2_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void ultimate2_cmd_vhost_off(User * u)
+{
+ /* does not support removing vhosting */
+}
+
+void ultimate2_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (vIdent) {
+ send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+ }
+ send_cmd(s_HostServ, "SVSMODE %s +x", nick);
+ send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+}
+
+void ultimate2_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+void ultimate2_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "JOIN %s", channel);
+}
+
+void ultimate2_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s :%s", host, user, reason);
+}
+
+void ultimate2_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "KILL %s :%s", user, buf);
+}
+
+void ultimate2_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %s%s%s", u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+}
+
+void ultimate2_cmd_capab()
+{
+ if (UseTokens) {
+ send_cmd(NULL, "PROTOCTL NOQUIT TOKEN SILENCE KNOCK");
+ } else {
+ send_cmd(NULL, "PROTOCTL NOQUIT SILENCE KNOCK");
+ }
+}
+
+
+/* PASS */
+void ultimate2_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS :%s", pass);
+}
+
+/* SERVER name hop descript */
+void ultimate2_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+/* PONG */
+void ultimate2_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+void ultimate2_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ ultimate2_cmd_capab();
+ if (servernum == 1)
+ ultimate2_cmd_pass(RemotePassword);
+ if (servernum == 2)
+ ultimate2_cmd_pass(RemotePassword2);
+ if (servernum == 3)
+ ultimate2_cmd_pass(RemotePassword3);
+ ultimate2_cmd_server(ServerName, 1, ServerDesc);
+}
+
+/* CHGHOST */
+void ultimate2_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+}
+
+/* CHGIDENT */
+void ultimate2_cmd_chgident(char *nick, char *vIdent)
+{
+ if (!nick || !vIdent) {
+ return;
+ }
+ send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+}
+
+/* INVITE */
+void ultimate2_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PART */
+void ultimate2_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/* 391 */
+void ultimate2_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void ultimate2_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void ultimate2_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void ultimate2_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void ultimate2_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void ultimate2_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void ultimate2_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void ultimate2_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void ultimate2_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void ultimate2_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void ultimate2_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void ultimate2_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void ultimate2_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* SQUIT */
+void ultimate2_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* SVSO */
+void ultimate2_cmd_svso(char *source, char *nick, char *flag)
+{
+ if (!source || !nick || !flag) {
+ return;
+ }
+
+ send_cmd(source, "SVSO %s %s", nick, flag);
+}
+
+/* NICK <newnick> */
+void ultimate2_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/* SVSNICK */
+void ultimate2_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ ultimate2_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+void ultimate2_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void ultimate2_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void ultimate2_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ ultimate2_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void ultimate2_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void ultimate2_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void ultimate2_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void ultimate2_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void ultimate2_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+void ultimate2_cmd_nick(char *nick, char *name, char *mode)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), ServiceUser, ServiceHost, ServerName,
+ name);
+ anope_cmd_mode(nick, nick, "%s", mode);
+ ultimate2_cmd_sqline(nick, "Reserved for services");
+}
+
+void ultimate2_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* QUIT */
+void ultimate2_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+void ultimate2_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+void ultimate2_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), user, host, ServerName, real);
+ anope_cmd_mode(nick, nick, "%s", modes);
+ ultimate2_cmd_sqline(nick, "Reserved for services");
+}
+
+void ultimate2_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void ultimate2_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void ultimate2_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void ultimate2_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void ultimate2_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+/* SVSHOLD - set */
+void ultimate2_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void ultimate2_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSGLINE */
+void ultimate2_cmd_unsgline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSZLINE */
+void ultimate2_cmd_unszline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SZLINE */
+void ultimate2_cmd_szline(char *mask, char *reason, char *whom)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SGLINE */
+void ultimate2_cmd_sgline(char *mask, char *reason)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ultimate2_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 :%s", nick,
+ (long int) time(NULL), user, host, ServerName, real);
+ anope_cmd_mode(nick, nick, "MODE %s %s", modes);
+}
+
+
+void ultimate2_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void ultimate2_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void ultimate2_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s +d 1", nick);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void ultimate2_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "-r+d", "1");
+}
+
+/* SVSMODE +r */
+void ultimate2_cmd_svid_umode2(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+void ultimate2_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_vctrl(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_netinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_snetinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/*
+** svsjoin
+**
+** parv[0] - sender
+** parv[1] - nick to make join
+** parv[2] - channel(s) to join
+*/
+void ultimate2_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(source, "SVSJOIN %s %s", nick, chan);
+}
+
+/*
+** svspart
+**
+** parv[0] - sender
+** parv[1] - nick to make part
+** parv[2] - channel(s) to part
+*/
+void ultimate2_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SVSPART %s %s", nick, chan);
+}
+
+void ultimate2_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+void ultimate2_cmd_eob()
+{
+ /* not supported */
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int ultiamte2_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (av[0]) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+void ultimate2_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ ultimate2_cmd_squit(jserver, rbuf);
+ ultimate2_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void ultimate2_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int ultiamte2_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int ultiamte2_valid_chan(char *chan)
+{
+ /* no hard coded invalid chans */
+ return 1;
+}
+
+
+void ultimate2_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(ultimate2_cmd_svsnoop);
+ pmodule_cmd_remove_akill(ultimate2_cmd_remove_akill);
+ pmodule_cmd_topic(ultimate2_cmd_topic);
+ pmodule_cmd_vhost_off(ultimate2_cmd_vhost_off);
+ pmodule_cmd_akill(ultimate2_cmd_akill);
+ pmodule_cmd_svskill(ultimate2_cmd_svskill);
+ pmodule_cmd_svsmode(ultimate2_cmd_svsmode);
+ pmodule_cmd_372(ultimate2_cmd_372);
+ pmodule_cmd_372_error(ultimate2_cmd_372_error);
+ pmodule_cmd_375(ultimate2_cmd_375);
+ pmodule_cmd_376(ultimate2_cmd_376);
+ pmodule_cmd_nick(ultimate2_cmd_nick);
+ pmodule_cmd_guest_nick(ultimate2_cmd_guest_nick);
+ pmodule_cmd_mode(ultimate2_cmd_mode);
+ pmodule_cmd_bot_nick(ultimate2_cmd_bot_nick);
+ pmodule_cmd_kick(ultimate2_cmd_kick);
+ pmodule_cmd_notice_ops(ultimate2_cmd_notice_ops);
+ pmodule_cmd_notice(ultimate2_cmd_notice);
+ pmodule_cmd_notice2(ultimate2_cmd_notice2);
+ pmodule_cmd_privmsg(ultimate2_cmd_privmsg);
+ pmodule_cmd_privmsg2(ultimate2_cmd_privmsg2);
+ pmodule_cmd_serv_notice(ultimate2_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(ultimate2_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(ultimate2_cmd_bot_chan_mode);
+ pmodule_cmd_351(ultimate2_cmd_351);
+ pmodule_cmd_quit(ultimate2_cmd_quit);
+ pmodule_cmd_pong(ultimate2_cmd_pong);
+ pmodule_cmd_join(ultimate2_cmd_join);
+ pmodule_cmd_unsqline(ultimate2_cmd_unsqline);
+ pmodule_cmd_invite(ultimate2_cmd_invite);
+ pmodule_cmd_part(ultimate2_cmd_part);
+ pmodule_cmd_391(ultimate2_cmd_391);
+ pmodule_cmd_250(ultimate2_cmd_250);
+ pmodule_cmd_307(ultimate2_cmd_307);
+ pmodule_cmd_311(ultimate2_cmd_311);
+ pmodule_cmd_312(ultimate2_cmd_312);
+ pmodule_cmd_317(ultimate2_cmd_317);
+ pmodule_cmd_219(ultimate2_cmd_219);
+ pmodule_cmd_401(ultimate2_cmd_401);
+ pmodule_cmd_318(ultimate2_cmd_318);
+ pmodule_cmd_242(ultimate2_cmd_242);
+ pmodule_cmd_243(ultimate2_cmd_243);
+ pmodule_cmd_211(ultimate2_cmd_211);
+ pmodule_cmd_global(ultimate2_cmd_global);
+ pmodule_cmd_global_legacy(ultimate2_cmd_global_legacy);
+ pmodule_cmd_sqline(ultimate2_cmd_sqline);
+ pmodule_cmd_squit(ultimate2_cmd_squit);
+ pmodule_cmd_svso(ultimate2_cmd_svso);
+ pmodule_cmd_chg_nick(ultimate2_cmd_chg_nick);
+ pmodule_cmd_svsnick(ultimate2_cmd_svsnick);
+ pmodule_cmd_vhost_on(ultimate2_cmd_vhost_on);
+ pmodule_cmd_connect(ultimate2_cmd_connect);
+ pmodule_cmd_svshold(ultimate2_cmd_svshold);
+ pmodule_cmd_release_svshold(ultimate2_cmd_release_svshold);
+ pmodule_cmd_unsgline(ultimate2_cmd_unsgline);
+ pmodule_cmd_unszline(ultimate2_cmd_unszline);
+ pmodule_cmd_szline(ultimate2_cmd_szline);
+ pmodule_cmd_sgline(ultimate2_cmd_sgline);
+ pmodule_cmd_unban(ultimate2_cmd_unban);
+ pmodule_cmd_svsmode_chan(ultimate2_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(ultimate2_cmd_svid_umode);
+ pmodule_cmd_nc_change(ultimate2_cmd_nc_change);
+ pmodule_cmd_svid_umode2(ultimate2_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(ultimate2_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(ultimate2_cmd_svsjoin);
+ pmodule_cmd_svspart(ultimate2_cmd_svspart);
+ pmodule_cmd_swhois(ultimate2_cmd_swhois);
+ pmodule_cmd_eob(ultimate2_cmd_eob);
+ pmodule_flood_mode_check(ultiamte2_flood_mode_check);
+ pmodule_cmd_jupe(ultimate2_cmd_jupe);
+ pmodule_valid_nick(ultiamte2_valid_nick);
+ pmodule_valid_chan(ultiamte2_valid_chan);
+ pmodule_cmd_ctcp(ultimate2_cmd_ctcp);
+ pmodule_set_umode(ultiamte2_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("UltimateIRCd 2.8.2+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/ultimate2.h b/src/protocol/ultimate2.h
new file mode 100644
index 000000000..221e69911
--- /dev/null
+++ b/src/protocol/ultimate2.h
@@ -0,0 +1,120 @@
+/* Ultimate IRCD 2 functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_p 0x04000000
+#define UMODE_R 0x08000000
+#define UMODE_P 0x20000000
+#define UMODE_g 0x80000000
+#define UMODE_x 0x40000000
+
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_f 0x00000400
+#define CMODE_x 0x00000800
+#define CMODE_A 0x00001000
+#define CMODE_I 0x00002000
+#define CMODE_K 0x00004000
+#define CMODE_L 0x00008000
+#define CMODE_O 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void ultimate2_set_umode(User * user, int ac, char **av);
+void ultimate2_cmd_svsnoop(char *server, int set);
+void ultimate2_cmd_remove_akill(char *user, char *host);
+void ultimate2_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void ultimate2_cmd_vhost_off(User * u);
+void ultimate2_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void ultimate2_cmd_svskill(char *source, char *user, char *buf);
+void ultimate2_cmd_svsmode(User * u, int ac, char **av);
+void ultimate2_cmd_372(char *source, char *msg);
+void ultimate2_cmd_372_error(char *source);
+void ultimate2_cmd_375(char *source);
+void ultimate2_cmd_376(char *source);
+void ultimate2_cmd_nick(char *nick, char *name, char *modes);
+void ultimate2_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ultimate2_cmd_mode(char *source, char *dest, char *buf);
+void ultimate2_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ultimate2_cmd_kick(char *source, char *chan, char *user, char *buf);
+void ultimate2_cmd_notice_ops(char *source, char *dest, char *buf);
+void ultimate2_cmd_notice(char *source, char *dest, char *buf);
+void ultimate2_cmd_notice2(char *source, char *dest, char *msg);
+void ultimate2_cmd_privmsg(char *source, char *dest, char *buf);
+void ultimate2_cmd_privmsg2(char *source, char *dest, char *msg);
+void ultimate2_cmd_serv_notice(char *source, char *dest, char *msg);
+void ultimate2_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void ultimate2_cmd_bot_chan_mode(char *nick, char *chan);
+void ultimate2_cmd_351(char *source);
+void ultimate2_cmd_quit(char *source, char *buf);
+void ultimate2_cmd_pong(char *servname, char *who);
+void ultimate2_cmd_join(char *user, char *channel, time_t chantime);
+void ultimate2_cmd_unsqline(char *user);
+void ultimate2_cmd_invite(char *source, char *chan, char *nick);
+void ultimate2_cmd_part(char *nick, char *chan, char *buf);
+void ultimate2_cmd_391(char *source, char *timestr);
+void ultimate2_cmd_250(char *buf);
+void ultimate2_cmd_307(char *buf);
+void ultimate2_cmd_311(char *buf);
+void ultimate2_cmd_312(char *buf);
+void ultimate2_cmd_317(char *buf);
+void ultimate2_cmd_219(char *source, char *letter);
+void ultimate2_cmd_401(char *source, char *who);
+void ultimate2_cmd_318(char *source, char *who);
+void ultimate2_cmd_242(char *buf);
+void ultimate2_cmd_243(char *buf);
+void ultimate2_cmd_211(char *buf);
+void ultimate2_cmd_global(char *source, char *buf);
+void ultimate2_cmd_global_legacy(char *source, char *fmt);
+void ultimate2_cmd_sqline(char *mask, char *reason);
+void ultimate2_cmd_squit(char *servname, char *message);
+void ultimate2_cmd_svso(char *source, char *nick, char *flag);
+void ultimate2_cmd_chg_nick(char *oldnick, char *newnick);
+void ultimate2_cmd_svsnick(char *source, char *guest, time_t when);
+void ultimate2_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void ultimate2_cmd_connect(int servernum);
+void ultimate2_cmd_svshold(char *nick);
+void ultimate2_cmd_release_svshold(char *nick);
+void ultimate2_cmd_unsgline(char *mask);
+void ultimate2_cmd_unszline(char *mask);
+void ultimate2_cmd_szline(char *mask, char *reason, char *whom);
+void ultimate2_cmd_sgline(char *mask, char *reason);
+void ultimate2_cmd_unban(char *name, char *nick);
+void ultimate2_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void ultimate2_cmd_svid_umode(char *nick, time_t ts);
+void ultimate2_cmd_nc_change(User * u);
+void ultimate2_cmd_svid_umode2(User * u, char *ts);
+void ultimate2_cmd_svid_umode3(User * u, char *ts);
+void ultimate2_cmd_eob();
+int ultimate2_flood_mode_check(char *value);
+void ultimate2_cmd_jupe(char *jserver, char *who, char *reason);
+int ultimate2_valid_nick(char *nick);
+void ultimate2_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/ultimate3.c b/src/protocol/ultimate3.c
new file mode 100644
index 000000000..16186481a
--- /dev/null
+++ b/src/protocol/ultimate3.c
@@ -0,0 +1,1818 @@
+/* Ultimate IRCD 3 functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "ultimate3.h"
+
+IRCDVar myIrcd[] = {
+ {"UltimateIRCd 3.0.*", /* ircd name */
+ "+S", /* nickserv mode */
+ "+S", /* chanserv mode */
+ "+S", /* memoserv mode */
+ "+o", /* hostserv mode */
+ "+iS", /* operserv mode */
+ "+S", /* botserv mode */
+ "+Sh", /* helpserv mode */
+ "+iS", /* Dev/Null mode */
+ "+iS", /* Global mode */
+ "+o", /* nickserv alias mode */
+ "+o", /* chanserv alias mode */
+ "+o", /* memoserv alias mode */
+ "+io", /* hostserv alias mode */
+ "+io", /* operserv alias mode */
+ "+o", /* botserv alias mode */
+ "+h", /* helpserv alias mode */
+ "+i", /* Dev/Null alias mode */
+ "+io", /* Global alias mode */
+ "+S", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-ilmnpqstRKAO", /* Modes to Remove */
+ "+o", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 0, /* Has Owner */
+ NULL, /* Mode to set for an owner */
+ NULL, /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ UMODE_p, /* Protected Umode */
+ 1, /* Has Admin */
+ 1, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 1, /* SVSMODE unban */
+ 0, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 0, /* vidents */
+ 0, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 0, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0, /* +f Mode */
+ 0, /* +L Mode */
+ 1, /* On nick change check if they could be identified */
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 1, /* Sglines are enforced */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ CAPAB_TSMODE, /* TSMODE */
+ CAPAB_UNCONNECT, /* UNCONNECT */
+ 0, /* NICKIP */
+ CAPAB_NSJOIN, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ CAPAB_BURST, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ 0, /* TS3 */
+ CAPAB_DKEY, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ CAPAB_CLIENT, /* CLIENT */
+ CAPAB_IPV6, /* IPV6 */
+ CAPAB_SSJ5, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ CAPAB_DODKEY, /* DODKEY */
+ CAPAB_DOZIP, /* DOZIP */
+ 0, 0, 0}
+};
+
+void ultimate3_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'a':
+ if (add && !is_services_oper(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'P':
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-P", NULL);
+ user->mode &= ~UMODE_P;
+ }
+ break;
+ case 'Z':
+ if (add && !is_services_root(user)) {
+ common_svsmode(user, "-Z", NULL);
+ user->mode &= ~UMODE_Z;
+ }
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ if (is_services_oper(user)) {
+ common_svsmode(user, "+a", NULL);
+ user->mode |= UMODE_a;
+ }
+ if (is_services_admin(user)) {
+ common_svsmode(user, "+P", NULL);
+ user->mode |= UMODE_P;
+ }
+ if (is_services_root(user)) {
+ common_svsmode(user, "+Z", NULL);
+ user->mode |= UMODE_Z;
+ }
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, 0, 0, /* A B C */
+ UMODE_D, 0, 0, /* D E F */
+ 0, 0, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, 0, UMODE_0, /* M N O */
+ UMODE_P, 0, UMODE_R, /* P Q R */
+ UMODE_S, 0, 0, /* S T U */
+ 0, UMODE_W, 0, /* V W X */
+ 0, /* Y */
+ UMODE_Z, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ UMODE_d, 0, 0, /* d e f */
+ 0, UMODE_h, UMODE_i, /* g h i */
+ 0, 0, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ UMODE_p, 0, UMODE_r, /* p q r */
+ 0, 0, 0, /* s t u */
+ 0, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ 0, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 'a', /* (33) ! Channel Admins */
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 0, 0, 0, 0,
+ 0,
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL}, /* i */
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL}, /* m */
+ {CMODE_n, 0, NULL, NULL}, /* n */
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL}, /* p */
+ {CMODE_q, 0, NULL, NULL}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL}, /* s */
+ {CMODE_t, 0, NULL, NULL}, /* t */
+ {0}, /* u */
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'q', CMODE_q, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_admin},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {0}, /* q */
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+/* SVSMODE -b */
+void ultimate3_cmd_unban(char *name, char *nick)
+{
+ ultimate3_cmd_svsmode_chan(name, "-b", nick);
+}
+
+
+/* SVSMODE channel modes */
+
+void ultimate3_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "SVSMODE %s %s %s", name, mode, nick);
+ } else {
+ send_cmd(ServerName, "SVSMODE %s %s", name, mode);
+ }
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+
+/*
+** NICK - new
+** source = NULL
+** parv[0] = nickname
+** parv[1] = hopcount
+** parv[2] = timestamp
+** parv[3] = modes
+** parv[4] = username
+** parv[5] = hostname
+** parv[6] = server
+** parv[7] = servicestamp
+** parv[8] = IP
+** parv[9] = info
+** NICK - change
+** source = oldnick
+** parv[0] = new nickname
+** parv[1] = hopcount
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ if (ac != 2) {
+ User *user = do_nick(source, av[0], av[4], av[5], av[6], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[7], NULL,
+ 0),
+ strtoul(av[8], NULL, 0), "*", NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[3]);
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/*
+** CLIENT
+** source = NULL
+** parv[0] = nickname Trystan
+** parv[1] = hopcount 1
+** parv[2] = timestamp 1090083810
+** parv[3] = modes +ix
+** parv[4] = modes ? +
+** parv[5] = username Trystan
+** parv[6] = hostname c-24-2-101-227.client.comcast.net
+** parv[7] = vhost 3223f75b.2b32ee69.client.comcast.net
+** parv[8] = server WhiteRose.No.Eu.Shadow-Realm.org
+** parv[9] = svid 0
+** parv[10] = ip 402810339
+** parv[11] = info Dreams are answers to questions not yet asked
+*/
+int anope_event_client(char *source, int ac, char **av)
+{
+ if (ac != 2) {
+ User *user = do_nick(source, av[0], av[5], av[6], av[8], av[11],
+ strtoul(av[2], NULL, 10), strtoul(av[9], NULL,
+ 0),
+ strtoul(av[10], NULL, 0), av[7], NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ }
+ return MOD_CONT;
+}
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("ADMIN","ADMINME","admin","deadmin","AUTOADMIN","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_gnotice); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m);
+ m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m);
+ m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m);
+ m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m);
+ m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m);
+ m = createMessage("RS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("SZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ m = createMessage("NETINFO", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GCONNECT", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("NETGLOBAL", anope_event_netglobal); addCoreMessage(IRCD,m);
+ m = createMessage("CHATOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("NETCTRL", anope_event_netctrl); addCoreMessage(IRCD,m);
+ m = createMessage("CLIENT", anope_event_client); addCoreMessage(IRCD,m);
+ m = createMessage("SMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+ m = createMessage("SMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("EOBURST", anope_event_eob); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+void ultimate3_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+void ultimate3_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "UNSGLINE 0 :%s", mask);
+}
+
+void ultimate3_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "UNSZLINE 0 %s", mask);
+}
+
+/* As of alpha27 (one after our offical support szline was removed */
+/* quote the changelog ---
+ Complete rewrite of the kline/akill/zline system. (s)zlines no longer exist.
+ K: lines set on IP addresses without username portions (or *) are treated as Z: lines used to be.
+*/
+void ultimate3_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "AKILL %s * %d %s %ld :%s", mask, 86400 * 2, whom,
+ (long int) time(NULL), reason);
+ /* leaving this in here in case some legacy user asks for it */
+ /* send_cmd(NULL, "SZLINE %s :%s", mask, reason); */
+}
+
+void ultimate3_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void ultimate3_cmd_svsadmin(char *server, int set)
+{
+ ultimate3_cmd_svsnoop(server, set);
+}
+
+void ultimate3_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
+}
+
+void ultimate3_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+void ultimate3_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "SVSMODE %s -x", u->nick);
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick, ircd->vhostchar);
+}
+
+void ultimate3_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ send_cmd(s_HostServ, "SVSMODE %s +x", nick);
+ send_cmd(ServerName, "SETHOST %s %s", nick, vhost);
+}
+
+void ultimate3_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "SJOIN %ld %s", (long int) chantime, channel);
+}
+
+void ultimate3_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400 * 2, who,
+ (long int) time(NULL), reason);
+}
+
+void ultimate3_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "SVSKILL %s :%s", user, buf);
+}
+
+
+void ultimate3_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+void anope_squit(char *servname, char *message)
+{
+ send_cmd(servname, "SQUIT %s :%s", servname, message);
+}
+
+void anope_pong(char *servname)
+{
+ send_cmd(servname, "PONG %s", servname);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ ultimate3_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+/* EVENT : OS */
+int anope_event_os(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_OperServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : NS */
+int anope_event_ns(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_NickServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : MS */
+int anope_event_ms(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_MemoServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : HS */
+int anope_event_hs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_HostServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : CS */
+int anope_event_cs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_ChanServ, av[0]);
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGNAME for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+void ultimate3_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void ultimate3_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void ultimate3_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void ultimate3_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void ultimate3_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void ultimate3_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "CLIENT %s 1 %ld %s + %s %s * %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, ServiceUser, ServiceHost,
+ ServerName, name);
+ ultimate3_cmd_sqline(nick, "Reserved for services");
+}
+
+void ultimate3_cmd_guest_nick(char *nick, char *user, char *host,
+ char *real, char *modes)
+{
+ send_cmd(NULL, "CLIENT %s 1 %ld %s + %s %s * %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+}
+
+void ultimate3_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+void ultimate3_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "CLIENT %s 1 %ld %s + %s %s * %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+ ultimate3_cmd_sqline(nick, "Reserved for services");
+}
+
+void ultimate3_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void ultimate3_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void ultimate3_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ ultimate3_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void ultimate3_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void ultimate3_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void ultimate3_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void ultimate3_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void ultimate3_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+void ultimate3_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+void ultimate3_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule,version_build);
+
+}
+
+/* QUIT */
+void ultimate3_cmd_quit(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+/* PROTOCTL */
+void ultimate3_cmd_capab()
+{
+ send_cmd(NULL,
+ "CAPAB TS5 NOQUIT SSJ5 BURST UNCONNECT TSMODE NICKIP CLIENT");
+}
+
+/* PASS */
+void ultimate3_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER name hop descript */
+/* Unreal 3.2 actually sends some info about itself in the descript area */
+void ultimate3_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+/* PONG */
+void ultimate3_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/* UNSQLINE */
+void ultimate3_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+/* CHGHOST */
+void ultimate3_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+}
+
+/* CHGIDENT */
+void ultimate3_cmd_chgident(char *nick, char *vIdent)
+{
+ if (!nick || !vIdent) {
+ return;
+ }
+ send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+}
+
+/* INVITE */
+void ultimate3_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PART */
+void ultimate3_cmd_part(char *nick, char *chan, char *buf)
+{
+
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/* 391 */
+void ultimate3_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void ultimate3_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void ultimate3_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void ultimate3_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void ultimate3_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void ultimate3_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void ultimate3_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void ultimate3_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void ultimate3_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void ultimate3_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void ultimate3_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void ultimate3_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void ultimate3_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* SQUIT */
+void ultimate3_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* SVSO */
+void ultimate3_cmd_svso(char *source, char *nick, char *flag)
+{
+ if (!source || !nick || !flag) {
+ return;
+ }
+
+ send_cmd(source, "SVSO %s %s", nick, flag);
+}
+
+/* NICK <newnick> */
+void ultimate3_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/* SVSNICK */
+void ultimate3_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+/* Functions that use serval cmd functions */
+/*
+ * SVINFO
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void ultimate3_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 5 3 0 :%ld", (long int) time(NULL));
+}
+
+void ultimate3_cmd_burst()
+{
+ send_cmd(NULL, "BURST");
+}
+
+
+void ultimate3_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1) {
+ ultimate3_cmd_pass(RemotePassword);
+ }
+ if (servernum == 2) {
+ ultimate3_cmd_pass(RemotePassword2);
+ }
+ if (servernum == 3) {
+ ultimate3_cmd_pass(RemotePassword3);
+ }
+ ultimate3_cmd_capab();
+ ultimate3_cmd_server(ServerName, 1, ServerDesc);
+ ultimate3_cmd_svinfo();
+ ultimate3_cmd_burst();
+}
+
+/* SVSHOLD - set */
+void ultimate3_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void ultimate3_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void ultimate3_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void ultimate3_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void ultimate3_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used by bahamut ircds */
+}
+
+void ultimate3_cmd_svid_umode3(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+
+}
+
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_gnotice(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_netctrl(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ /* currently not used but removes the message : unknown message from server */
+ return MOD_CONT;
+}
+
+void ultimate3_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ultimate3_cmd_svspart(char *source, char *nick, char *chan)
+{
+ /* Not Supported by this IRCD */
+}
+
+void ultimate3_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+
+void ultimate3_cmd_eob()
+{
+ send_cmd(NULL, "BURST 0");
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_eob(char *source, int ac, char **av)
+{
+ Server *s;
+
+ if (ac == 1) {
+ s = findserver(servlist, av[0]);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_burst(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ if (!ac) {
+ /* for future use - start burst */
+ } else {
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_netglobal(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int ultiamte3_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+void ultimate3_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ ultimate3_cmd_squit(jserver, rbuf);
+ ultimate3_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void ultimate3_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int ultiamte3_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int ultiamte3_valid_chan(char *chan)
+{
+ /* no hard coded invalid chans */
+ return 1;
+}
+
+
+void ultimate3_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(ultimate3_cmd_svsnoop);
+ pmodule_cmd_remove_akill(ultimate3_cmd_remove_akill);
+ pmodule_cmd_topic(ultimate3_cmd_topic);
+ pmodule_cmd_vhost_off(ultimate3_cmd_vhost_off);
+ pmodule_cmd_akill(ultimate3_cmd_akill);
+ pmodule_cmd_svskill(ultimate3_cmd_svskill);
+ pmodule_cmd_svsmode(ultimate3_cmd_svsmode);
+ pmodule_cmd_372(ultimate3_cmd_372);
+ pmodule_cmd_372_error(ultimate3_cmd_372_error);
+ pmodule_cmd_375(ultimate3_cmd_375);
+ pmodule_cmd_376(ultimate3_cmd_376);
+ pmodule_cmd_nick(ultimate3_cmd_nick);
+ pmodule_cmd_guest_nick(ultimate3_cmd_guest_nick);
+ pmodule_cmd_mode(ultimate3_cmd_mode);
+ pmodule_cmd_bot_nick(ultimate3_cmd_bot_nick);
+ pmodule_cmd_kick(ultimate3_cmd_kick);
+ pmodule_cmd_notice_ops(ultimate3_cmd_notice_ops);
+ pmodule_cmd_notice(ultimate3_cmd_notice);
+ pmodule_cmd_notice2(ultimate3_cmd_notice2);
+ pmodule_cmd_privmsg(ultimate3_cmd_privmsg);
+ pmodule_cmd_privmsg2(ultimate3_cmd_privmsg2);
+ pmodule_cmd_serv_notice(ultimate3_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(ultimate3_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(ultimate3_cmd_bot_chan_mode);
+ pmodule_cmd_351(ultimate3_cmd_351);
+ pmodule_cmd_quit(ultimate3_cmd_quit);
+ pmodule_cmd_pong(ultimate3_cmd_pong);
+ pmodule_cmd_join(ultimate3_cmd_join);
+ pmodule_cmd_unsqline(ultimate3_cmd_unsqline);
+ pmodule_cmd_invite(ultimate3_cmd_invite);
+ pmodule_cmd_part(ultimate3_cmd_part);
+ pmodule_cmd_391(ultimate3_cmd_391);
+ pmodule_cmd_250(ultimate3_cmd_250);
+ pmodule_cmd_307(ultimate3_cmd_307);
+ pmodule_cmd_311(ultimate3_cmd_311);
+ pmodule_cmd_312(ultimate3_cmd_312);
+ pmodule_cmd_317(ultimate3_cmd_317);
+ pmodule_cmd_219(ultimate3_cmd_219);
+ pmodule_cmd_401(ultimate3_cmd_401);
+ pmodule_cmd_318(ultimate3_cmd_318);
+ pmodule_cmd_242(ultimate3_cmd_242);
+ pmodule_cmd_243(ultimate3_cmd_243);
+ pmodule_cmd_211(ultimate3_cmd_211);
+ pmodule_cmd_global(ultimate3_cmd_global);
+ pmodule_cmd_global_legacy(ultimate3_cmd_global_legacy);
+ pmodule_cmd_sqline(ultimate3_cmd_sqline);
+ pmodule_cmd_squit(ultimate3_cmd_squit);
+ pmodule_cmd_svso(ultimate3_cmd_svso);
+ pmodule_cmd_chg_nick(ultimate3_cmd_chg_nick);
+ pmodule_cmd_svsnick(ultimate3_cmd_svsnick);
+ pmodule_cmd_vhost_on(ultimate3_cmd_vhost_on);
+ pmodule_cmd_connect(ultimate3_cmd_connect);
+ pmodule_cmd_svshold(ultimate3_cmd_svshold);
+ pmodule_cmd_release_svshold(ultimate3_cmd_release_svshold);
+ pmodule_cmd_unsgline(ultimate3_cmd_unsgline);
+ pmodule_cmd_unszline(ultimate3_cmd_unszline);
+ pmodule_cmd_szline(ultimate3_cmd_szline);
+ pmodule_cmd_sgline(ultimate3_cmd_sgline);
+ pmodule_cmd_unban(ultimate3_cmd_unban);
+ pmodule_cmd_svsmode_chan(ultimate3_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(ultimate3_cmd_svid_umode);
+ pmodule_cmd_nc_change(ultimate3_cmd_nc_change);
+ pmodule_cmd_svid_umode2(ultimate3_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(ultimate3_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(ultimate3_cmd_svsjoin);
+ pmodule_cmd_svspart(ultimate3_cmd_svspart);
+ pmodule_cmd_swhois(ultimate3_cmd_swhois);
+ pmodule_cmd_eob(ultimate3_cmd_eob);
+ pmodule_flood_mode_check(ultiamte3_flood_mode_check);
+ pmodule_cmd_jupe(ultimate3_cmd_jupe);
+ pmodule_valid_nick(ultiamte3_valid_nick);
+ pmodule_valid_chan(ultiamte3_valid_chan);
+ pmodule_cmd_ctcp(ultimate3_cmd_ctcp);
+ pmodule_set_umode(ultimate3_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion
+ ("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("UltimateIRCd 3.0.0.a26+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/ultimate3.h b/src/protocol/ultimate3.h
new file mode 100644
index 000000000..cdff880c1
--- /dev/null
+++ b/src/protocol/ultimate3.h
@@ -0,0 +1,125 @@
+/* Ultimate IRCD 3.0 functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_0 0x00000080
+#define UMODE_Z 0x00000100 /* umode +Z - Services Root Admin */
+#define UMODE_S 0x00000200 /* umode +S - Services Client */
+#define UMODE_D 0x00000400 /* umode +D - has seen dcc warning message */
+#define UMODE_d 0x00000800 /* umode +d - user is deaf to channel messages */
+#define UMODE_W 0x00001000 /* umode +d - user is deaf to channel messages */
+#define UMODE_p 0x04000000
+#define UMODE_P 0x20000000 /* umode +P - Services Admin */
+#define UMODE_x 0x40000000
+#define UMODE_R 0x80000000
+
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_c 0x00000400 /* Colors can't be used */
+#define CMODE_A 0x00000800
+#define CMODE_N 0x00001000
+#define CMODE_S 0x00002000
+#define CMODE_K 0x00004000
+#define CMODE_O 0x00008000 /* Only opers can join */
+#define CMODE_q 0x00010000 /* No Quit Reason */
+#define CMODE_M 0x00020000 /* Non-regged nicks can't send messages */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void ultimate3_set_umode(User * user, int ac, char **av);
+void ultimate3_cmd_svsnoop(char *server, int set);
+void ultimate3_cmd_remove_akill(char *user, char *host);
+void ultimate3_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void ultimate3_cmd_vhost_off(User * u);
+void ultimate3_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void ultimate3_cmd_svskill(char *source, char *user, char *buf);
+void ultimate3_cmd_svsmode(User * u, int ac, char **av);
+void ultimate3_cmd_372(char *source, char *msg);
+void ultimate3_cmd_372_error(char *source);
+void ultimate3_cmd_375(char *source);
+void ultimate3_cmd_376(char *source);
+void ultimate3_cmd_nick(char *nick, char *name, char *modes);
+void ultimate3_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ultimate3_cmd_mode(char *source, char *dest, char *buf);
+void ultimate3_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void ultimate3_cmd_kick(char *source, char *chan, char *user, char *buf);
+void ultimate3_cmd_notice_ops(char *source, char *dest, char *buf);
+void ultimate3_cmd_notice(char *source, char *dest, char *buf);
+void ultimate3_cmd_notice2(char *source, char *dest, char *msg);
+void ultimate3_cmd_privmsg(char *source, char *dest, char *buf);
+void ultimate3_cmd_privmsg2(char *source, char *dest, char *msg);
+void ultimate3_cmd_serv_notice(char *source, char *dest, char *msg);
+void ultimate3_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void ultimate3_cmd_bot_chan_mode(char *nick, char *chan);
+void ultimate3_cmd_351(char *source);
+void ultimate3_cmd_quit(char *source, char *buf);
+void ultimate3_cmd_pong(char *servname, char *who);
+void ultimate3_cmd_join(char *user, char *channel, time_t chantime);
+void ultimate3_cmd_unsqline(char *user);
+void ultimate3_cmd_invite(char *source, char *chan, char *nick);
+void ultimate3_cmd_part(char *nick, char *chan, char *buf);
+void ultimate3_cmd_391(char *source, char *timestr);
+void ultimate3_cmd_250(char *buf);
+void ultimate3_cmd_307(char *buf);
+void ultimate3_cmd_311(char *buf);
+void ultimate3_cmd_312(char *buf);
+void ultimate3_cmd_317(char *buf);
+void ultimate3_cmd_219(char *source, char *letter);
+void ultimate3_cmd_401(char *source, char *who);
+void ultimate3_cmd_318(char *source, char *who);
+void ultimate3_cmd_242(char *buf);
+void ultimate3_cmd_243(char *buf);
+void ultimate3_cmd_211(char *buf);
+void ultimate3_cmd_global(char *source, char *buf);
+void ultimate3_cmd_global_legacy(char *source, char *fmt);
+void ultimate3_cmd_sqline(char *mask, char *reason);
+void ultimate3_cmd_squit(char *servname, char *message);
+void ultimate3_cmd_svso(char *source, char *nick, char *flag);
+void ultimate3_cmd_chg_nick(char *oldnick, char *newnick);
+void ultimate3_cmd_svsnick(char *source, char *guest, time_t when);
+void ultimate3_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void ultimate3_cmd_connect(int servernum);
+void ultimate3_cmd_svshold(char *nick);
+void ultimate3_cmd_release_svshold(char *nick);
+void ultimate3_cmd_unsgline(char *mask);
+void ultimate3_cmd_unszline(char *mask);
+void ultimate3_cmd_szline(char *mask, char *reason, char *whom);
+void ultimate3_cmd_sgline(char *mask, char *reason);
+void ultimate3_cmd_unban(char *name, char *nick);
+void ultimate3_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void ultimate3_cmd_svid_umode(char *nick, time_t ts);
+void ultimate3_cmd_nc_change(User * u);
+void ultimate3_cmd_svid_umode2(User * u, char *ts);
+void ultimate3_cmd_svid_umode3(User * u, char *ts);
+void ultimate3_cmd_eob();
+int ultimate3_flood_mode_check(char *value);
+void ultimate3_cmd_jupe(char *jserver, char *who, char *reason);
+int ultimate3_valid_nick(char *nick);
+void ultimate3_cmd_ctcp(char *source, char *dest, char *buf);
+
+
diff --git a/src/protocol/unreal31.c b/src/protocol/unreal31.c
new file mode 100644
index 000000000..08781ca0f
--- /dev/null
+++ b/src/protocol/unreal31.c
@@ -0,0 +1,1592 @@
+/* Unreal IRCD 3.1.x functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "unreal31.h"
+
+IRCDVar myIrcd[] = {
+ {"UnrealIRCd 3.1.x", /* ircd name */
+ "+oS", /* nickserv mode */
+ "+oS", /* chanserv mode */
+ "+oS", /* memoserv mode */
+ "+oS", /* hostserv mode */
+ "+ioS", /* operserv mode */
+ "+oS", /* botserv mode */
+ "+oS", /* helpserv mode */
+ "+iS", /* Dev/Null mode */
+ "+ioS", /* Global mode */
+ "+oS", /* nickserv alias mode */
+ "+oS", /* chanserv alias mode */
+ "+oS", /* memoserv alias mode */
+ "+ioS", /* hostserv alias mode */
+ "+ioS", /* operserv alias mode */
+ "+oS", /* botserv alias mode */
+ "+oS", /* helpserv alias mode */
+ "+iS", /* Dev/Null alias mode */
+ "+ioS", /* Global alias mode */
+ "+qS", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-cilmnpstuzACGHKNOQRSV", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "-r+d", /* Mode on Nick Change */
+ 0, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 1, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 0, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 0, /* NICKIP */
+ 1, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 1, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 1, /* +f */
+ 1, /* +L */
+ CMODE_f,
+ CMODE_L,
+ 0,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support Unreal TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 0, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ 0, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ CAPAB_TOKEN, /* TOKEN */
+ 0, /* VHOST */
+ CAPAB_SSJ3, /* SSJ3 */
+ CAPAB_NICK2, /* NICK2 */
+ CAPAB_UMODE2, /* UMODE2 */
+ CAPAB_VL, /* VL */
+ CAPAB_TLKEXT, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ 0,
+ 0, 0}
+};
+
+unsigned long umodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, UMODE_A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0, UMODE_a, 0, 0, 0, 0, 0,
+ UMODE_g,
+ UMODE_h, UMODE_i, 0, 0, 0, 0, 0, UMODE_o,
+ 0,
+ 0, UMODE_r, 0, 0, 0, 0, UMODE_w,
+ UMODE_x,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 0,
+ 0, 0, 0,
+ 'q',
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'a', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {CMODE_C, 0, NULL, NULL}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {CMODE_G, 0, NULL, NULL}, /* G */
+ {CMODE_H, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, set_redirect, cs_set_redirect},
+ {0}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {CMODE_Q, 0, NULL, NULL}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {CMODE_V, 0, NULL, NULL}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {CMODE_f, 0, set_flood, cs_set_flood},
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {CMODE_u, 0, NULL, NULL},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL},
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'f', CMODE_f, 0, get_flood, cs_get_flood},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'u', CMODE_u, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'G', CMODE_G, 0, NULL, NULL},
+ {'H', CMODE_H, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, get_redirect, cs_get_redirect},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'Q', CMODE_Q, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {'V', CMODE_V, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op},
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+void unreal_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("PROTOCTL", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CHGHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ m = createMessage("CHGNAME", anope_event_chgname); addCoreMessage(IRCD,m);
+ m = createMessage("NETINFO", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+void unreal_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void unreal_cmd_svsadmin(char *server, int set)
+{
+ unreal_cmd_svsnoop(server, set);
+}
+
+void unreal_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "TKL - G %s %s %s", user, host, s_OperServ);
+}
+
+void unreal_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void unreal_cmd_vhost_off(User * u)
+{
+ send_cmd(s_HostServ, "SVSMODE %s -xt", u->nick);
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick, ircd->vhostchar);
+}
+
+void unreal_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "TKL + G %s %s %s %ld %ld :%s", user, host, who,
+ (long int) time(NULL) + 86400 * 2, (long int) when, reason);
+}
+
+void unreal_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (!source || !user) {
+ return;
+ }
+
+ send_cmd(source, "SVSKILL %s :%s", user, buf);
+}
+
+void unreal_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %s%s%s", u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+}
+
+
+void unreal_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void unreal_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void unreal_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void unreal_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void unreal_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 %s * :%s", nick,
+ (long int) time(NULL), ServiceUser, ServiceHost, ServerName,
+ modes, name);
+ unreal_cmd_sqline(nick, "Reserved for services");
+}
+
+void unreal_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 %s * :%s", nick,
+ (long int) time(NULL), user, host, ServerName, modes, real);
+}
+
+void unreal_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "MODE %s %s", dest, buf);
+}
+
+void unreal_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s 0 %s * :%s", nick,
+ (long int) time(NULL), user, host, ServerName, modes, real);
+ unreal_cmd_sqline(nick, "Reserved for services");
+}
+
+void unreal_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void unreal_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+}
+
+
+void unreal_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ unreal_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void unreal_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void unreal_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void unreal_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void unreal_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void unreal_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+
+void unreal_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", ircd->botchanumode, nick, nick);
+}
+
+void unreal_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+/* QUIT */
+void unreal_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+/* PROTOCTL */
+void unreal_cmd_protoctl()
+{
+ /*
+ See Unreal's protoctl.txt for reference
+ VHP - Send hostnames in NICKv2 even if not sethosted
+ */
+ send_cmd(NULL, "PROTOCTL NICKv2 VHP");
+}
+
+/* PASS */
+void unreal_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS :%s", pass);
+}
+
+/* SERVER name hop descript */
+/* Unreal 3.2 actually sends some info about itself in the descript area */
+void unreal_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+/* PONG */
+void unreal_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/* JOIN */
+/* Althought Unreal 3.2 does not need the timestamp others do so
+ we get it in the common function call */
+void unreal_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "JOIN %s", channel);
+}
+
+/* UNSQLINE */
+void unreal_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+/* CHGHOST */
+void unreal_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "CHGHOST %s %s", nick, vhost);
+}
+
+/* CHGIDENT */
+void unreal_cmd_chgident(char *nick, char *vIdent)
+{
+ if (!nick || !vIdent) {
+ return;
+ }
+ send_cmd(ServerName, "CHGIDENT %s %s", nick, vIdent);
+}
+
+/* INVITE */
+void unreal_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+/* PART */
+void unreal_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+/* 391 */
+void unreal_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void unreal_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void unreal_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void unreal_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void unreal_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void unreal_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void unreal_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void unreal_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void unreal_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void unreal_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void unreal_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void unreal_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void unreal_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* SQLINE */
+void unreal_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+/* SQUIT */
+void unreal_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* SVSO */
+void unreal_cmd_svso(char *source, char *nick, char *flag)
+{
+ if (!source || !nick || !flag) {
+ return;
+ }
+
+ send_cmd(source, "SVSO %s %s", nick, flag);
+}
+
+/* NICK <newnick> */
+void unreal_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/* SVSNICK */
+void unreal_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+/* Functions that use serval cmd functions */
+
+void unreal_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (!nick) {
+ return;
+ }
+ if (vIdent) {
+ unreal_cmd_chgident(nick, vIdent);
+ }
+ unreal_cmd_chghost(nick, vhost);
+}
+
+void unreal_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ unreal_cmd_protoctl();
+ if (servernum == 1) {
+ unreal_cmd_pass(RemotePassword);
+ }
+ if (servernum == 2) {
+ unreal_cmd_pass(RemotePassword2);
+ }
+ if (servernum == 3) {
+ unreal_cmd_pass(RemotePassword3);
+ }
+ unreal_cmd_server(ServerName, 1, ServerDesc);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ unreal_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGNAME for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ if (ac == 7) {
+ /*
+ <codemastr> that was a bug that is now fixed in 3.2.1
+ <codemastr> in some instances it would use the non-nickv2 format
+ <codemastr> it's sent when a nick collision occurs
+ - so we have to leave it around for now -TSL
+ */
+ do_nick(source, av[0], av[3], av[4], av[5], av[6],
+ strtoul(av[2], NULL, 10), 0, 0, "*", NULL);
+ } else {
+ user = do_nick(source, av[0], av[3], av[4], av[5], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[6], NULL,
+ 0), 0, av[8],
+ NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[7]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void unreal_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void unreal_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSGLINE */
+void unreal_cmd_unsgline(char *mask)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* UNSZLINE */
+void unreal_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "%s - Z * %s %s", send_token("TKL", "BD"), mask,
+ s_OperServ);
+}
+
+/* SZLINE */
+void unreal_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "%s + Z * %s %s %ld %ld :%s", send_token("TKL", "BD"),
+ mask, whom, (long int) time(NULL) + 86400 * 2,
+ (long int) time(NULL), reason);
+}
+
+/* SGLINE */
+void unreal_cmd_sgline(char *mask, char *reason)
+{
+ /* Not Supported by this IRCD */
+}
+
+void unreal_cmd_unban(char *name, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSMODE channel modes */
+
+void unreal_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void unreal_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s +d 1", nick);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void unreal_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "-r+d", "1");
+}
+
+/* SVSMODE +r */
+void unreal_cmd_svid_umode2(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+void unreal_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+/* svsjoin
+ parv[0] - sender
+ parv[1] - nick to make join
+ parv[2] - channel(s) to join
+ parv[3] - (optional) channel key(s)
+*/
+void unreal_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ if (param) {
+ send_cmd(source, "SVSJOIN %s %s :%s", nick, chan, param);
+ } else {
+ send_cmd(source, "SVSJOIN %s :%s", nick, chan);
+ }
+}
+
+/* svspart
+ parv[0] - sender
+ parv[1] - nick to make part
+ parv[2] - channel(s) to part
+*/
+void unreal_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SVSPART %s :%s", nick, chan);
+}
+
+void unreal_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* Can anyone tell me if 3.1 has this? */
+}
+
+void unreal_cmd_eob()
+{
+ /* Can anyone tell me if 3.1 has this? */
+}
+
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int unreal_flood_mode_check(char *value)
+{
+ char *dp, *end;
+
+ if (value && *value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void unreal_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ unreal_cmd_squit(jserver, rbuf);
+ unreal_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void unreal_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "%s :%s",
+ send_token("GLOBOPS", "]"), fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int unreal_valid_nick(char *nick)
+{
+ if (!stricmp("ircd", nick)) {
+ return 0;
+ }
+ if (!stricmp("irc", nick)) {
+ return 0;
+ }
+ return 1;
+}
+
+int unreal_valid_chan(char *chan) {
+ if (strchr(chan, ':')) {
+ return 0;
+ }
+ return 1;
+}
+
+void unreal_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(unreal_cmd_svsnoop);
+ pmodule_cmd_remove_akill(unreal_cmd_remove_akill);
+ pmodule_cmd_topic(unreal_cmd_topic);
+ pmodule_cmd_vhost_off(unreal_cmd_vhost_off);
+ pmodule_cmd_akill(unreal_cmd_akill);
+ pmodule_cmd_svskill(unreal_cmd_svskill);
+ pmodule_cmd_svsmode(unreal_cmd_svsmode);
+ pmodule_cmd_372(unreal_cmd_372);
+ pmodule_cmd_372_error(unreal_cmd_372_error);
+ pmodule_cmd_375(unreal_cmd_375);
+ pmodule_cmd_376(unreal_cmd_376);
+ pmodule_cmd_nick(unreal_cmd_nick);
+ pmodule_cmd_guest_nick(unreal_cmd_guest_nick);
+ pmodule_cmd_mode(unreal_cmd_mode);
+ pmodule_cmd_bot_nick(unreal_cmd_bot_nick);
+ pmodule_cmd_kick(unreal_cmd_kick);
+ pmodule_cmd_notice_ops(unreal_cmd_notice_ops);
+ pmodule_cmd_notice(unreal_cmd_notice);
+ pmodule_cmd_notice2(unreal_cmd_notice2);
+ pmodule_cmd_privmsg(unreal_cmd_privmsg);
+ pmodule_cmd_privmsg2(unreal_cmd_privmsg2);
+ pmodule_cmd_serv_notice(unreal_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(unreal_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(unreal_cmd_bot_chan_mode);
+ pmodule_cmd_351(unreal_cmd_351);
+ pmodule_cmd_quit(unreal_cmd_quit);
+ pmodule_cmd_pong(unreal_cmd_pong);
+ pmodule_cmd_join(unreal_cmd_join);
+ pmodule_cmd_unsqline(unreal_cmd_unsqline);
+ pmodule_cmd_invite(unreal_cmd_invite);
+ pmodule_cmd_part(unreal_cmd_part);
+ pmodule_cmd_391(unreal_cmd_391);
+ pmodule_cmd_250(unreal_cmd_250);
+ pmodule_cmd_307(unreal_cmd_307);
+ pmodule_cmd_311(unreal_cmd_311);
+ pmodule_cmd_312(unreal_cmd_312);
+ pmodule_cmd_317(unreal_cmd_317);
+ pmodule_cmd_219(unreal_cmd_219);
+ pmodule_cmd_401(unreal_cmd_401);
+ pmodule_cmd_318(unreal_cmd_318);
+ pmodule_cmd_242(unreal_cmd_242);
+ pmodule_cmd_243(unreal_cmd_243);
+ pmodule_cmd_211(unreal_cmd_211);
+ pmodule_cmd_global(unreal_cmd_global);
+ pmodule_cmd_global_legacy(unreal_cmd_global_legacy);
+ pmodule_cmd_sqline(unreal_cmd_sqline);
+ pmodule_cmd_squit(unreal_cmd_squit);
+ pmodule_cmd_svso(unreal_cmd_svso);
+ pmodule_cmd_chg_nick(unreal_cmd_chg_nick);
+ pmodule_cmd_svsnick(unreal_cmd_svsnick);
+ pmodule_cmd_vhost_on(unreal_cmd_vhost_on);
+ pmodule_cmd_connect(unreal_cmd_connect);
+ pmodule_cmd_svshold(unreal_cmd_svshold);
+ pmodule_cmd_release_svshold(unreal_cmd_release_svshold);
+ pmodule_cmd_unsgline(unreal_cmd_unsgline);
+ pmodule_cmd_unszline(unreal_cmd_unszline);
+ pmodule_cmd_szline(unreal_cmd_szline);
+ pmodule_cmd_sgline(unreal_cmd_sgline);
+ pmodule_cmd_unban(unreal_cmd_unban);
+ pmodule_cmd_svsmode_chan(unreal_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(unreal_cmd_svid_umode);
+ pmodule_cmd_nc_change(unreal_cmd_nc_change);
+ pmodule_cmd_svid_umode2(unreal_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(unreal_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(unreal_cmd_svsjoin);
+ pmodule_cmd_svspart(unreal_cmd_svspart);
+ pmodule_cmd_swhois(unreal_cmd_swhois);
+ pmodule_cmd_eob(unreal_cmd_eob);
+ pmodule_flood_mode_check(unreal_flood_mode_check);
+ pmodule_cmd_jupe(unreal_cmd_jupe);
+ pmodule_valid_nick(unreal_valid_nick);
+ pmodule_valid_chan(unreal_valid_chan);
+ pmodule_cmd_ctcp(unreal_cmd_ctcp);
+ pmodule_set_umode(unreal_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("UnrealIRCd 3.1.1+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/unreal31.h b/src/protocol/unreal31.h
new file mode 100644
index 000000000..21ace9b86
--- /dev/null
+++ b/src/protocol/unreal31.h
@@ -0,0 +1,124 @@
+/* Unreal IRCD 3.1.x functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+#define UMODE_a 0x00000001
+#define UMODE_h 0x00000002
+#define UMODE_i 0x00000004
+#define UMODE_o 0x00000008
+#define UMODE_r 0x00000010
+#define UMODE_w 0x00000020
+#define UMODE_A 0x00000040
+#define UMODE_g 0x80000000
+#define UMODE_x 0x40000000
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_c 0x00000400
+#define CMODE_A 0x00000800
+#define CMODE_H 0x00001000
+#define CMODE_K 0x00002000
+#define CMODE_L 0x00004000
+#define CMODE_O 0x00008000
+#define CMODE_Q 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_V 0x00040000
+#define CMODE_f 0x00080000
+#define CMODE_G 0x00100000
+#define CMODE_C 0x00200000
+#define CMODE_u 0x00400000
+#define CMODE_z 0x00800000
+#define CMODE_N 0x01000000
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void unreal_set_umode(User * user, int ac, char **av);
+void unreal_cmd_svsnoop(char *server, int set);
+void unreal_cmd_remove_akill(char *user, char *host);
+void unreal_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void unreal_cmd_vhost_off(User * u);
+void unreal_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void unreal_cmd_svskill(char *source, char *user, char *buf);
+void unreal_cmd_svsmode(User * u, int ac, char **av);
+void unreal_cmd_372(char *source, char *msg);
+void unreal_cmd_372_error(char *source);
+void unreal_cmd_375(char *source);
+void unreal_cmd_376(char *source);
+void unreal_cmd_nick(char *nick, char *name, char *modes);
+void unreal_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void unreal_cmd_mode(char *source, char *dest, char *buf);
+void unreal_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void unreal_cmd_kick(char *source, char *chan, char *user, char *buf);
+void unreal_cmd_notice_ops(char *source, char *dest, char *buf);
+void unreal_cmd_notice(char *source, char *dest, char *buf);
+void unreal_cmd_notice2(char *source, char *dest, char *msg);
+void unreal_cmd_privmsg(char *source, char *dest, char *buf);
+void unreal_cmd_privmsg2(char *source, char *dest, char *msg);
+void unreal_cmd_serv_notice(char *source, char *dest, char *msg);
+void unreal_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void unreal_cmd_bot_chan_mode(char *nick, char *chan);
+void unreal_cmd_351(char *source);
+void unreal_cmd_quit(char *source, char *buf);
+void unreal_cmd_pong(char *servname, char *who);
+void unreal_cmd_join(char *user, char *channel, time_t chantime);
+void unreal_cmd_unsqline(char *user);
+void unreal_cmd_invite(char *source, char *chan, char *nick);
+void unreal_cmd_part(char *nick, char *chan, char *buf);
+void unreal_cmd_391(char *source, char *timestr);
+void unreal_cmd_250(char *buf);
+void unreal_cmd_307(char *buf);
+void unreal_cmd_311(char *buf);
+void unreal_cmd_312(char *buf);
+void unreal_cmd_317(char *buf);
+void unreal_cmd_219(char *source, char *letter);
+void unreal_cmd_401(char *source, char *who);
+void unreal_cmd_318(char *source, char *who);
+void unreal_cmd_242(char *buf);
+void unreal_cmd_243(char *buf);
+void unreal_cmd_211(char *buf);
+void unreal_cmd_global(char *source, char *buf);
+void unreal_cmd_global_legacy(char *source, char *fmt);
+void unreal_cmd_sqline(char *mask, char *reason);
+void unreal_cmd_squit(char *servname, char *message);
+void unreal_cmd_svso(char *source, char *nick, char *flag);
+void unreal_cmd_chg_nick(char *oldnick, char *newnick);
+void unreal_cmd_svsnick(char *source, char *guest, time_t when);
+void unreal_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void unreal_cmd_connect(int servernum);
+void unreal_cmd_svshold(char *nick);
+void unreal_cmd_release_svshold(char *nick);
+void unreal_cmd_unsgline(char *mask);
+void unreal_cmd_unszline(char *mask);
+void unreal_cmd_szline(char *mask, char *reason, char *whom);
+void unreal_cmd_sgline(char *mask, char *reason);
+void unreal_cmd_unban(char *name, char *nick);
+void unreal_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void unreal_cmd_svid_umode(char *nick, time_t ts);
+void unreal_cmd_nc_change(User * u);
+void unreal_cmd_svid_umode2(User * u, char *ts);
+void unreal_cmd_svid_umode3(User * u, char *ts);
+void unreal_cmd_eob();
+int unreal_flood_mode_check(char *value);
+void unreal_cmd_jupe(char *jserver, char *who, char *reason);
+int unreal_valid_nick(char *nick);
+void unreal_cmd_ctcp(char *source, char *dest, char *buf);
+
diff --git a/src/protocol/unreal32.c b/src/protocol/unreal32.c
new file mode 100644
index 000000000..a3b1c04ce
--- /dev/null
+++ b/src/protocol/unreal32.c
@@ -0,0 +1,2232 @@
+/* Unreal IRCD 3.2.x functions
+ *
+ * (C) 2003-2008 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 "services.h"
+#include "pseudo.h"
+#include "unreal32.h"
+
+IRCDVar myIrcd[] = {
+ {"UnrealIRCd 3.2.x", /* ircd name */
+ "+oS", /* nickserv mode */
+ "+oS", /* chanserv mode */
+ "+oS", /* memoserv mode */
+ "+oS", /* hostserv mode */
+ "+ioS", /* operserv mode */
+ "+oS", /* botserv mode */
+ "+oS", /* helpserv mode */
+ "+iS", /* Dev/Null mode */
+ "+ioS", /* Global mode */
+ "+oS", /* nickserv alias mode */
+ "+oS", /* chanserv alias mode */
+ "+oS", /* memoserv alias mode */
+ "+ioS", /* hostserv alias mode */
+ "+ioS", /* operserv alias mode */
+ "+oS", /* botserv alias mode */
+ "+oS", /* helpserv alias mode */
+ "+iS", /* Dev/Null alias mode */
+ "+ioS", /* Global alias mode */
+ "+qS", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-cilmnpstuzACGHKMNOQRSTV", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "-r+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 1, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ UMODE_S, /* Protected Umode */
+ 0, /* Has Admin */
+ 0, /* Chan SQlines */
+ 0, /* Quit on Kill */
+ 1, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 1, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 1, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 1, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 1, /* Change RealName */
+ CMODE_K, /* No Knock */
+ CMODE_A, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 1, /* +f */
+ 1, /* +L */
+ CMODE_f, /* +f Mode */
+ CMODE_L, /* +L Mode */
+ 0, /* On nick change check if they could be identified */
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 1, /* We support Unreal TOKENS */
+ 0, /* TOKENS are CASE Sensitive */
+ 1, /* TIME STAMPS are BASE64 */
+ 1, /* +I support */
+ '&', /* SJOIN ban char */
+ '\"', /* SJOIN except char */
+ '\'', /* SJOIN invite char */
+ 1, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ 0, /* TSMODE */
+ 0, /* UNCONNECT */
+ CAPAB_NICKIP, /* NICKIP */
+ 0, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ 0, /* BURST */
+ 0, /* TS5 */
+ 0, /* TS3 */
+ 0, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ CAPAB_TOKEN, /* TOKEN */
+ 0, /* VHOST */
+ CAPAB_SSJ3, /* SSJ3 */
+ CAPAB_NICK2, /* NICK2 */
+ CAPAB_UMODE2, /* UMODE2 */
+ CAPAB_VL, /* VL */
+ CAPAB_TLKEXT, /* TLKEXT */
+ 0, /* DODKEY */
+ 0, /* DOZIP */
+ CAPAB_CHANMODE, /* CHANMODE */
+ CAPAB_SJB64,
+ CAPAB_NICKCHARS,
+ }
+};
+
+
+unsigned long umodes[128] = {
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Horzontal Tab */
+ 0, 0, 0, /* Line Feed, Unused, Unused */
+ 0, 0, 0, /* Carriage Return, Unused, Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused */
+ 0, 0, 0, /* Unused, Unused, Space */
+ 0, 0, 0, /* ! " # */
+ 0, 0, 0, /* $ % & */
+ 0, 0, 0, /* ! ( ) */
+ 0, 0, 0, /* * + , */
+ 0, 0, 0, /* - . / */
+ 0, 0, /* 0 1 */
+ 0, 0, /* 2 3 */
+ 0, 0, /* 4 5 */
+ 0, 0, /* 6 7 */
+ 0, 0, /* 8 9 */
+ 0, 0, /* : ; */
+ 0, 0, 0, /* < = > */
+ 0, 0, /* ? @ */
+ UMODE_A, UMODE_B, UMODE_C, /* A B C */
+ 0, 0, 0, /* D E F */
+ UMODE_G, UMODE_H, 0, /* G H I */
+ 0, 0, 0, /* J K L */
+ 0, UMODE_N, UMODE_O, /* M N O */
+ 0, 0, UMODE_R, /* P Q R */
+ UMODE_S, UMODE_T, 0, /* S T U */
+ UMODE_V, UMODE_W, 0, /* V W X */
+ 0, /* Y */
+ 0, /* Z */
+ 0, 0, 0, /* [ \ ] */
+ 0, 0, 0, /* ^ _ ` */
+ UMODE_a, 0, 0, /* a b c */
+ UMODE_d, 0, 0, /* d e f */
+ UMODE_g, UMODE_h, UMODE_i, /* g h i */
+ 0, 0, 0, /* j k l */
+ 0, 0, UMODE_o, /* m n o */
+ UMODE_p, UMODE_q, UMODE_r, /* p q r */
+ UMODE_s, UMODE_t, 0, /* s t u */
+ UMODE_v, UMODE_w, UMODE_x, /* v w x */
+ 0, /* y */
+ UMODE_z, /* z */
+ 0, 0, 0, /* { | } */
+ 0, 0 /* ~ � */
+};
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 'b', /* (38) & bans */
+ 0, 0, 0,
+ 'q',
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'a', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, /* BCD */
+ {NULL}, {NULL}, {NULL}, /* EFG */
+ {NULL}, /* H */
+ {add_invite, del_invite}, /* I */
+ {NULL}, /* J */
+ {NULL}, {NULL}, {NULL}, /* KLM */
+ {NULL}, {NULL}, {NULL}, /* NOP */
+ {NULL}, {NULL}, {NULL}, /* QRS */
+ {NULL}, {NULL}, {NULL}, /* TUV */
+ {NULL}, {NULL}, {NULL}, /* WXY */
+ {NULL}, /* Z */
+ {NULL}, {NULL}, /* (char 91 - 92) */
+ {NULL}, {NULL}, {NULL}, /* (char 93 - 95) */
+ {NULL}, /* ` (char 96) */
+ {NULL}, /* a (char 97) */
+ {add_ban, del_ban}, /* b */
+ {NULL}, {NULL}, /* cd */
+ {add_exception, del_exception},
+ {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {CMODE_A, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* B */
+ {CMODE_C, 0, NULL, NULL}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {CMODE_G, 0, NULL, NULL}, /* G */
+ {0}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {CMODE_K, 0, NULL, NULL}, /* K */
+ {CMODE_L, 0, set_redirect, cs_set_redirect},
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {0}, /* P */
+ {CMODE_Q, 0, NULL, NULL}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {CMODE_T, 0, NULL, NULL}, /* T */
+ {0}, /* U */
+ {CMODE_V, 0, NULL, NULL}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {CMODE_f, 0, set_flood, cs_set_flood},
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {CMODE_u, 0, NULL, NULL},
+ {0}, /* v */
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {CMODE_z, 0, NULL, NULL},
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'f', CMODE_f, 0, get_flood, cs_get_flood},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'u', CMODE_u, 0, NULL, NULL},
+ {'z', CMODE_z, 0, NULL, NULL},
+ {'A', CMODE_A, 0, NULL, NULL},
+ {'C', CMODE_C, 0, NULL, NULL},
+ {'G', CMODE_G, 0, NULL, NULL},
+ {'K', CMODE_K, 0, NULL, NULL},
+ {'L', CMODE_L, 0, get_redirect, cs_get_redirect},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'Q', CMODE_Q, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {'T', CMODE_T, 0, NULL, NULL},
+ {'V', CMODE_V, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op},
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+void unreal_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (!user || !modes) {
+ /* Prevent NULLs from doing bad things */
+ return;
+ }
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+ uint32 backup = user->mode;
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac <= 0) {
+ break;
+ }
+ if (isdigit(*av[1])) {
+ user->svid = strtoul(av[1], NULL, 0);
+ user->mode = backup; /* Ugly fix, but should do the job ~ Viper */
+ }
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'a':
+ if (UnRestrictSAdmin) {
+ break;
+ }
+ if (add && !is_services_admin(user)) {
+ common_svsmode(user, "-a", NULL);
+ user->mode &= ~UMODE_a;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+
+
+
+/* Event: PROTOCTL */
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/* SVSNOOP */
+void unreal_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "%s %s %s", send_token("SVSNOOP", "f"), server,
+ (set ? "+" : "-"));
+}
+
+void unreal_cmd_svsadmin(char *server, int set)
+{
+ unreal_cmd_svsnoop(server, set);
+}
+
+void unreal_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "%s - G %s %s %s", send_token("TKL", "BD"), user, host,
+ s_OperServ);
+}
+
+void unreal_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "%s %s %s %lu :%s", send_token("TOPIC", ")"), chan,
+ whosetit, (unsigned long int) when, topic);
+}
+
+void unreal_cmd_vhost_off(User * u)
+{
+ if (UseSVS2MODE) {
+ send_cmd(s_HostServ, "%s %s -xt", send_token("SVS2MODE", "v"),
+ u->nick);
+ } else {
+ send_cmd(s_HostServ, "%s %s -xt", send_token("SVSMODE", "n"),
+ u->nick);
+ }
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick,
+ myIrcd->vhostchar);
+}
+
+void unreal_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "%s + G %s %s %s %ld %ld :%s", send_token("TKL", "BD"),
+ user, host, who, (long int) time(NULL) + 86400 * 2,
+ (long int) when, reason);
+}
+
+/*
+** svskill
+** parv[0] = servername
+** parv[1] = client
+** parv[2] = kill message
+*/
+void unreal_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (!source || !user || !buf) {
+ return;
+ }
+ send_cmd(source, "%s %s :%s", send_token("SVSKILL", "h"), user, buf);
+}
+
+/*
+ * m_svsmode() added by taz
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ * parv[3] - Service Stamp (if mode == d)
+ */
+void unreal_cmd_svsmode(User * u, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (!u || !av[0]) {
+ return;
+ }
+ if (UseSVS2MODE) {
+ send_cmd(ServerName, "%s %s %s%s%s",
+ send_token("SVS2MODE", "v"), u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+ } else {
+ send_cmd(ServerName, "%s %s %s%s%s",
+ send_token("SVSMODE", "n"), u->nick, av[0],
+ (ac == 2 ? " " : ""), (ac == 2 ? av[1] : ""));
+ }
+ }
+}
+
+/* 372 */
+void unreal_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void unreal_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void unreal_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void unreal_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+void unreal_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "%s %s 1 %ld %s %s %s 0 %s %s%s :%s",
+ send_token("NICK", "&"), nick, (long int) time(NULL),
+ ServiceUser, ServiceHost, ServerName, modes, ServiceHost,
+ (myIrcd->nickip ? " *" : " "), name);
+ unreal_cmd_sqline(nick, "Reserved for services");
+}
+
+void unreal_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "%s %s 1 %ld %s %s %s 0 %s %s%s :%s",
+ send_token("NICK", "&"), nick, (long int) time(NULL), user,
+ host, ServerName, modes, host, (myIrcd->nickip ? " *" : " "),
+ real);
+}
+
+void unreal_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "%s %s %s", send_token("MODE", "G"), dest, buf);
+}
+
+void unreal_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "%s %s 1 %ld %s %s %s 0 %s %s%s :%s",
+ send_token("NICK", "&"), nick, (long int) time(NULL), user,
+ host, ServerName, modes, host, (myIrcd->nickip ? " *" : " "),
+ real);
+ unreal_cmd_sqline(nick, "Reserved for services");
+}
+
+void unreal_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "%s %s %s :%s", send_token("KICK", "H"), chan,
+ user, buf);
+ } else {
+ send_cmd(source, "%s %s %s", send_token("KICK", "H"), chan, user);
+ }
+}
+
+void unreal_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "%s @%s :%s", send_token("NOTICE", "B"), dest, buf);
+}
+
+
+void unreal_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ unreal_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "%s %s :%s", send_token("NOTICE", "B"), dest,
+ buf);
+ }
+}
+
+void unreal_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "%s %s :%s", send_token("NOTICE", "B"), dest, msg);
+}
+
+void unreal_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "%s %s :%s", send_token("PRIVMSG", "!"), dest, buf);
+}
+
+void unreal_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "%s %s :%s", send_token("PRIVMSG", "!"), dest, msg);
+}
+
+void unreal_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "%s $%s :%s", send_token("NOTICE", "B"), dest, msg);
+}
+
+void unreal_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "%s $%s :%s", send_token("PRIVMSG", "!"), dest, msg);
+}
+
+void unreal_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s %s", myIrcd->botchanumode, nick,
+ nick);
+}
+
+void unreal_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, myIrcd->name,
+ version_flags, EncModule, version_build);
+}
+
+/* QUIT */
+void unreal_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "%s :%s", send_token("QUIT", ","), buf);
+ } else {
+ send_cmd(source, "%s", send_token("QUIT", ","));
+ }
+}
+
+/* PROTOCTL */
+/*
+ NICKv2 = Nick Version 2
+ VHP = Sends hidden host
+ UMODE2 = sends UMODE2 on user modes
+ NICKIP = Sends IP on NICK
+ TOKEN = Use tokens to talk
+ SJ3 = Supports SJOIN
+ NOQUIT = No Quit
+ TKLEXT = Extended TKL we don't use it but best to have it
+ SJB64 = Base64 encoded time stamps
+ VL = Version Info
+ NS = Numeric Server
+
+*/
+void unreal_cmd_capab()
+{
+ if (UseTokens) {
+ if (Numeric) {
+ send_cmd(NULL,
+ "PROTOCTL NICKv2 VHP UMODE2 NICKIP TOKEN SJOIN SJOIN2 SJ3 NOQUIT TKLEXT SJB64 VL");
+ } else {
+ send_cmd(NULL,
+ "PROTOCTL NICKv2 VHP UMODE2 NICKIP TOKEN SJOIN SJOIN2 SJ3 NOQUIT TKLEXT SJB64");
+ }
+ } else {
+ if (Numeric) {
+ send_cmd(NULL,
+ "PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT SJB64 VL");
+ } else {
+ send_cmd(NULL,
+ "PROTOCTL NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT SJB64");
+ }
+ }
+}
+
+/* PASS */
+void unreal_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS :%s", pass);
+}
+
+/* SERVER name hop descript */
+/* Unreal 3.2 actually sends some info about itself in the descript area */
+void unreal_cmd_server(char *servname, int hop, char *descript)
+{
+ if (Numeric) {
+ send_cmd(NULL, "SERVER %s %d :U0-*-%s %s", servname, hop, Numeric,
+ descript);
+ } else {
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+ }
+}
+
+/* PONG */
+void unreal_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "%s %s", send_token("PONG", "9"), who);
+}
+
+/* JOIN */
+void unreal_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(ServerName, "%s !%s %s :%s",
+ send_token("SJOIN", "~"), base64enc((long int) chantime),
+ channel, user);
+ /* send_cmd(user, "%s %s", send_token("JOIN", "C"), channel); */
+}
+
+/* unsqline
+** parv[0] = sender
+** parv[1] = nickmask
+*/
+void unreal_cmd_unsqline(char *user)
+{
+ if (!user) {
+ return;
+ }
+ send_cmd(NULL, "%s %s", send_token("UNSQLINE", "d"), user);
+}
+
+/* CHGHOST */
+void unreal_cmd_chghost(char *nick, char *vhost)
+{
+ if (!nick || !vhost) {
+ return;
+ }
+ send_cmd(ServerName, "%s %s %s", send_token("CHGHOST", "AL"), nick,
+ vhost);
+}
+
+/* CHGIDENT */
+void unreal_cmd_chgident(char *nick, char *vIdent)
+{
+ if (!nick || !vIdent) {
+ return;
+ }
+ send_cmd(ServerName, "%s %s %s", send_token("CHGIDENT", "AZ"), nick,
+ vIdent);
+}
+
+/* INVITE */
+void unreal_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "%s %s %s", send_token("INVITE", "*"), nick, chan);
+}
+
+/* PART */
+void unreal_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "%s %s :%s", send_token("PART", "D"), chan, buf);
+ } else {
+ send_cmd(nick, "%s %s", send_token("PART", "D"), chan);
+ }
+}
+
+/* 391 RPL_TIME ":%s 391 %s %s :%s" */
+void unreal_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(ServerName, "391 %s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void unreal_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void unreal_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void unreal_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void unreal_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void unreal_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void unreal_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void unreal_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void unreal_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void unreal_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void unreal_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void unreal_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+/* GLOBOPS */
+void unreal_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "%s :%s",
+ send_token("GLOBOPS", "]"), buf);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void unreal_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "%s :%s",
+ send_token("GLOBOPS", "]"), fmt);
+}
+
+/* SQLINE */
+/*
+** parv[0] = sender
+** parv[1] = nickmask
+** parv[2] = reason
+**
+** - Unreal will translate this to TKL for us
+**
+*/
+void unreal_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "%s %s :%s", send_token("SQLINE", "c"), mask, reason);
+}
+
+/* SQUIT */
+void unreal_cmd_squit(char *servname, char *message)
+{
+ if (!servname || !message) {
+ return;
+ }
+
+ send_cmd(NULL, "%s %s :%s", send_token("SQUIT", "-"), servname,
+ message);
+}
+
+/*
+** svso
+** parv[0] = sender prefix
+** parv[1] = nick
+** parv[2] = options
+*/
+void unreal_cmd_svso(char *source, char *nick, char *flag)
+{
+ if (!source || !nick || !flag) {
+ return;
+ }
+
+ send_cmd(source, "%s %s %s", send_token("SVSO", "BB"), nick, flag);
+}
+
+/* NICK <newnick> */
+void unreal_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "%s %s %ld", send_token("NICK", "&"), newnick,
+ (long int) time(NULL));
+}
+
+/* SVSNICK */
+/*
+** parv[0] = sender
+** parv[1] = old nickname
+** parv[2] = new nickname
+** parv[3] = timestamp
+*/
+void unreal_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "%s %s %s :%ld", send_token("SVSNICK", "e"), source,
+ guest, (long int) when);
+}
+
+/* Functions that use serval cmd functions */
+
+void unreal_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (!nick) {
+ return;
+ }
+ if (vIdent) {
+ unreal_cmd_chgident(nick, vIdent);
+ }
+ unreal_cmd_chghost(nick, vhost);
+}
+
+void unreal_cmd_connect(int servernum)
+{
+ if (Numeric) {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, Numeric);
+ } else {
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+ }
+
+ unreal_cmd_capab();
+ if (servernum == 1) {
+ unreal_cmd_pass(RemotePassword);
+ }
+ if (servernum == 2) {
+ unreal_cmd_pass(RemotePassword2);
+ }
+ if (servernum == 3) {
+ unreal_cmd_pass(RemotePassword3);
+ }
+ unreal_cmd_server(ServerName, 1, ServerDesc);
+}
+
+/* Events */
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ unreal_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void unreal_cmd_netinfo(int ac, char **av)
+{
+ send_cmd(NULL, "%s %ld %ld %d %s 0 0 0 :%s",
+ send_token("NETINFO", "AO"), (long int) maxusercnt,
+ (long int) time(NULL), atoi(av[2]), av[3], av[7]);
+}
+
+/* netinfo
+ * argv[0] = max global count
+ * argv[1] = time of end sync
+ * argv[2] = unreal protocol using (numeric)
+ * argv[3] = cloak-crc (> u2302)
+ * argv[4] = free(**)
+ * argv[5] = free(**)
+ * argv[6] = free(**)
+ * argv[7] = ircnet
+ */
+int anope_event_netinfo(char *source, int ac, char **av)
+{
+ unreal_cmd_netinfo(ac, av);
+ return MOD_CONT;
+}
+
+
+/* TKL
+ * add: remove: spamfilter: spamfilter+TKLEXT sqline:
+ * parv[ 1]: + - +/- + +/-
+ * parv[ 2]: type type type type type
+ * parv[ 3]: user user target target hold
+ * parv[ 4]: host host action action host
+ * parv[ 5]: setby removedby (un)setby setby setby
+ * parv[ 6]: expire_at expire_at (0) expire_at (0) expire_at
+ * parv[ 7]: set_at set_at set_at set_at
+ * parv[ 8]: reason regex tkl duration reason
+ * parv[ 9]: tkl reason [A]
+ * parv[10]: regex
+ *
+*/
+int anope_event_tkl(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_eos(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+/*
+** away
+** parv[0] = sender prefix
+** parv[1] = away message
+*/
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+/*
+** m_topic
+** parv[0] = sender prefix
+** parv[1] = topic text
+**
+** For servers using TS:
+** parv[0] = sender prefix
+** parv[1] = channel name
+** parv[2] = topic nickname
+** parv[3] = topic time
+** parv[4] = topic text
+*/
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+/* Unreal sends USER modes with this */
+/*
+ umode2
+ parv[0] - sender
+ parv[1] - modes to change
+*/
+int anope_event_umode2(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ do_umode2(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGNAME for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+/*
+** NICK - new
+** source = NULL
+** parv[0] = nickname
+** parv[1] = hopcount
+** parv[2] = timestamp
+** parv[3] = username
+** parv[4] = hostname
+** parv[5] = servername
+** if NICK version 1:
+** parv[6] = servicestamp
+** parv[7] = info
+** if NICK version 2:
+** parv[6] = servicestamp
+** parv[7] = umodes
+** parv[8] = virthost, * if none
+** parv[9] = info
+** if NICKIP:
+** parv[9] = ip
+** parv[10] = info
+**
+** NICK - change
+** source = oldnick
+** parv[0] = new nickname
+** parv[1] = hopcount
+*/
+/*
+ do_nick(const char *source, char *nick, char *username, char *host,
+ char *server, char *realname, time_t ts, uint32 svid,
+ uint32 ip, char *vhost, char *uid)
+*/
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ if (ac == 7) {
+ /*
+ <codemastr> that was a bug that is now fixed in 3.2.1
+ <codemastr> in some instances it would use the non-nickv2 format
+ <codemastr> it's sent when a nick collision occurs
+ - so we have to leave it around for now -TSL
+ */
+ do_nick(source, av[0], av[3], av[4], av[5], av[6],
+ strtoul(av[2], NULL, 10), 0, 0, "*", NULL);
+
+ } else if (ac == 11) {
+ user = do_nick(source, av[0], av[3], av[4], av[5], av[10],
+ strtoul(av[2], NULL, 10), strtoul(av[6], NULL,
+ 0),
+ ntohl(decode_ip(av[9])), av[8], NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[7]);
+
+ } else {
+ /* NON NICKIP */
+ user = do_nick(source, av[0], av[3], av[4], av[5], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[6], NULL,
+ 0), 0, av[8],
+ NULL);
+ if (user)
+ anope_set_umode(user, 1, &av[7]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+/* EVENT: SERVER */
+int anope_event_server(char *source, int ac, char **av)
+{
+ char *desc;
+ char *vl;
+ char *upnumeric;
+
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ vl = myStrGetToken(av[2], ' ', 0);
+ upnumeric = myStrGetToken(vl, '-', 2);
+ desc = myStrGetTokenRemainder(av[2], ' ', 1);
+ do_server(source, av[0], av[1], desc, upnumeric);
+ Anope_Free(vl);
+ Anope_Free(desc);
+ Anope_Free(upnumeric);
+ } else {
+ do_server(source, av[0], av[1], av[2], NULL);
+ }
+
+ return MOD_CONT;
+}
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void unreal_cmd_svshold(char *nick)
+{
+ send_cmd(NULL, "%s + Q H %s %s %ld %ld :%s", send_token("TKL", "BD"),
+ nick, ServerName, (long int) time(NULL) + NSReleaseTimeout,
+ (long int) time(NULL), "Being held for registered user");
+}
+
+/* SVSHOLD - release */
+void unreal_cmd_release_svshold(char *nick)
+{
+ send_cmd(NULL, "%s - Q * %s %s", send_token("TKL", "BD"), nick,
+ ServerName);
+}
+
+/* UNSGLINE */
+/*
+ * SVSNLINE - :realname mask
+*/
+void unreal_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "%s - :%s", send_token("SVSNLINE", "BR"), mask);
+}
+
+/* UNSZLINE */
+void unreal_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "%s - Z * %s %s", send_token("TKL", "BD"), mask,
+ s_OperServ);
+}
+
+/* SZLINE */
+void unreal_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "%s + Z * %s %s %ld %ld :%s", send_token("TKL", "BD"),
+ mask, whom, (long int) time(NULL) + 86400 * 2,
+ (long int) time(NULL), reason);
+}
+
+/* SGLINE */
+/*
+ * SVSNLINE + reason_where_is_space :realname mask with spaces
+*/
+void unreal_cmd_sgline(char *mask, char *reason)
+{
+ strnrepl(reason, BUFSIZE, " ", "_");
+ send_cmd(NULL, "%s + %s :%s", send_token("SVSNLINE", "BR"), reason,
+ mask);
+}
+
+/* SVSMODE -b */
+void unreal_cmd_unban(char *name, char *nick)
+{
+ unreal_cmd_svsmode_chan(name, "-b", nick);
+}
+
+
+/* SVSMODE channel modes */
+
+void unreal_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "%s %s %s %s", send_token("SVSMODE", "n"),
+ name, mode, nick);
+ } else {
+ send_cmd(ServerName, "%s %s %s", send_token("SVSMODE", "n"), name,
+ mode);
+ }
+}
+
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void unreal_cmd_svid_umode(char *nick, time_t ts)
+{
+ if (UseSVS2MODE) {
+ send_cmd(ServerName, "%s %s +d 1", send_token("SVS2MODE", "v"),
+ nick);
+ } else {
+ send_cmd(ServerName, "%s %s +d 1", send_token("SVSMODE", "n"),
+ nick);
+ }
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void unreal_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "-r+d", "1");
+}
+
+/* SVSMODE +r */
+void unreal_cmd_svid_umode2(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+void unreal_cmd_svid_umode3(User * u, char *ts)
+{
+ /* not used */
+}
+
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (av[0]) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ if(strstr(av[0],"No matching link configuration")!=0) {
+ alog("Error: Your IRCD's link block may not setup correctly, please check unrealircd.conf");
+ }
+ }
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_smo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/* svsjoin
+ parv[0] - sender
+ parv[1] - nick to make join
+ parv[2] - channel to join
+ parv[3] - (optional) channel key(s)
+*/
+/* In older Unreal SVSJOIN and SVSNLINE tokens were mixed so SVSJOIN and SVSNLINE are broken
+ when coming from a none TOKEN'd server
+*/
+void unreal_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ if (param) {
+ send_cmd(source, "%s %s %s :%s", send_token("SVSJOIN", "BX"), nick, chan, param);
+ } else {
+ send_cmd(source, "%s %s :%s", send_token("SVSJOIN", "BX"), nick, chan);
+ }
+}
+
+/* svspart
+ parv[0] - sender
+ parv[1] - nick to make part
+ parv[2] - channel(s) to part
+*/
+void unreal_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "%s %s :%s", send_token("SVSPART", "BT"), nick, chan);
+}
+
+int anope_event_globops(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_swhois(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_credits(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_sdesc(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+
+ if (s) {
+ s->desc = av[0];
+ }
+
+ return MOD_CONT;
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+void unreal_cmd_swhois(char *source, char *who, char *mask)
+{
+ send_cmd(source, "%s %s :%s", send_token("SWHOIS", "BA"), who, mask);
+}
+
+void unreal_cmd_eob()
+{
+ send_cmd(ServerName, "%s", send_token("EOS", "ES"));
+}
+
+/* svswatch
+ * parv[0] - sender
+ * parv[1] - target nick
+ * parv[2] - parameters
+ */
+void unreal_cmd_svswatch(char *sender, char *nick, char *parm)
+{
+ send_cmd(sender, "%s %s :%s", send_token("SVSWATCH", "Bw"), nick,
+ parm);
+}
+
+/* check if +f mode is valid for the ircd */
+/* borrowed part of the new check from channels.c in Unreal */
+int unreal_flood_mode_check(char *value)
+{
+ char *dp, *end;
+ /* NEW +F */
+ char xbuf[256], *p, *p2, *x = xbuf + 1;
+ int v;
+
+ if (!value) {
+ return 0;
+ }
+
+ if (*value != ':'
+ && (strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0)
+ && (*dp == ':') && (*(++dp) != 0) && (strtoul(dp, &end, 10) > 0)
+ && (*end == 0)) {
+ return 1;
+ } else {
+ /* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */
+ strncpy(xbuf, value, sizeof(xbuf));
+ p2 = strchr(xbuf + 1, ']');
+ if (!p2) {
+ return 0;
+ }
+ *p2 = '\0';
+ if (*(p2 + 1) != ':') {
+ return 0;
+ }
+ for (x = strtok(xbuf + 1, ","); x; x = strtok(NULL, ",")) {
+ /* <number><1 letter>[optional: '#'+1 letter] */
+ p = x;
+ while (isdigit(*p)) {
+ p++;
+ }
+ if ((*p == '\0')
+ || !((*p == 'c') || (*p == 'j') || (*p == 'k')
+ || (*p == 'm') || (*p == 'n') || (*p == 't'))) {
+ continue; /* continue instead of break for forward compatability. */
+ }
+ *p = '\0';
+ v = atoi(x);
+ if ((v < 1) || (v > 999)) {
+ return 0;
+ }
+ p++;
+ }
+ return 1;
+ }
+}
+
+void unreal_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ unreal_cmd_squit(jserver, rbuf);
+ unreal_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int unreal_valid_nick(char *nick)
+{
+ if (!stricmp("ircd", nick)) {
+ return 0;
+ }
+ if (!stricmp("irc", nick)) {
+ return 0;
+ }
+ return 1;
+}
+
+int unreal_valid_chan(char *chan) {
+ if (strchr(chan, ':')) {
+ return 0;
+ }
+ return 1;
+}
+
+void unreal_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "%s %s :\1%s \1", send_token("NOTICE", "B"), dest, s);
+ free(s);
+}
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("451", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("461", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("6", anope_event_away); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("INVITE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("*", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("C", anope_event_join); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("H", anope_event_kick); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(".", anope_event_kill); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("G", anope_event_mode); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("F", anope_event_motd); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("&", anope_event_nick); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("B", anope_event_notice); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("D", anope_event_part); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("8", anope_event_ping); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("!", anope_event_privmsg); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(",", anope_event_quit); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("'", anope_event_server); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("-", anope_event_squit); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage(")", anope_event_topic); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("n", anope_event_mode); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVS2MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("v", anope_event_mode); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("USER", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("%", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("=", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("#", anope_event_whois); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("V", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GLOBOPS", anope_event_globops); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("]", anope_event_globops); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GNOTICE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("Z", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("[", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("Y", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("U", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("h", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("e", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("f", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("c", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("d", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PROTOCTL", anope_event_capab); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("_", anope_event_capab); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CHGHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AL", anope_event_chghost); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AZ", anope_event_chgident); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CHGNAME", anope_event_chgname); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("BK", anope_event_chgname); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("NETINFO", anope_event_netinfo); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AO", anope_event_netinfo); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AA", anope_event_sethost); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AD", anope_event_setident); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AE", anope_event_setname); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("TKL", anope_event_tkl); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("BD", anope_event_tkl); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("EOS", anope_event_eos); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("ES", anope_event_eos); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("<", anope_event_pass); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("5", anope_event_error); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SMO", anope_event_smo); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AU", anope_event_smo); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("UMODE2", anope_event_umode2); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("|", anope_event_umode2); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SWHOIS", anope_event_swhois); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("BA", anope_event_swhois); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("~", anope_event_sjoin); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("O", anope_event_rehash); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("@", anope_event_admin); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("CREDITS", anope_event_credits); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AJ", anope_event_credits); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SDESC", anope_event_sdesc); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AG", anope_event_sdesc); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("HTM", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("BH", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("HELP", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("4", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("TRACE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("b", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("LAG", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AF", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("RPING", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AM", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SENDSNO", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("Ss", anope_event_null); addCoreMessage(IRCD,m);
+ }
+ m = createMessage("SENDUMODE", anope_event_null); addCoreMessage(IRCD,m);
+ if (UseTokens) {
+ m = createMessage("AP", anope_event_null); addCoreMessage(IRCD,m);
+ }
+
+ /* The none token version of these is in messages.c */
+ if (UseTokens) {
+ m = createMessage("2", m_stats); addCoreMessage(IRCD,m);
+ m = createMessage(">", m_time); addCoreMessage(IRCD,m);
+ m = createMessage("+", m_version); addCoreMessage(IRCD,m);
+ }
+}
+
+/* *INDENT-ON* */
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(unreal_cmd_svsnoop);
+ pmodule_cmd_remove_akill(unreal_cmd_remove_akill);
+ pmodule_cmd_topic(unreal_cmd_topic);
+ pmodule_cmd_vhost_off(unreal_cmd_vhost_off);
+ pmodule_cmd_akill(unreal_cmd_akill);
+ pmodule_cmd_svskill(unreal_cmd_svskill);
+ pmodule_cmd_svsmode(unreal_cmd_svsmode);
+ pmodule_cmd_372(unreal_cmd_372);
+ pmodule_cmd_372_error(unreal_cmd_372_error);
+ pmodule_cmd_375(unreal_cmd_375);
+ pmodule_cmd_376(unreal_cmd_376);
+ pmodule_cmd_nick(unreal_cmd_nick);
+ pmodule_cmd_guest_nick(unreal_cmd_guest_nick);
+ pmodule_cmd_mode(unreal_cmd_mode);
+ pmodule_cmd_bot_nick(unreal_cmd_bot_nick);
+ pmodule_cmd_kick(unreal_cmd_kick);
+ pmodule_cmd_notice_ops(unreal_cmd_notice_ops);
+ pmodule_cmd_notice(unreal_cmd_notice);
+ pmodule_cmd_notice2(unreal_cmd_notice2);
+ pmodule_cmd_privmsg(unreal_cmd_privmsg);
+ pmodule_cmd_privmsg2(unreal_cmd_privmsg2);
+ pmodule_cmd_serv_notice(unreal_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(unreal_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(unreal_cmd_bot_chan_mode);
+ pmodule_cmd_351(unreal_cmd_351);
+ pmodule_cmd_quit(unreal_cmd_quit);
+ pmodule_cmd_pong(unreal_cmd_pong);
+ pmodule_cmd_join(unreal_cmd_join);
+ pmodule_cmd_unsqline(unreal_cmd_unsqline);
+ pmodule_cmd_invite(unreal_cmd_invite);
+ pmodule_cmd_part(unreal_cmd_part);
+ pmodule_cmd_391(unreal_cmd_391);
+ pmodule_cmd_250(unreal_cmd_250);
+ pmodule_cmd_307(unreal_cmd_307);
+ pmodule_cmd_311(unreal_cmd_311);
+ pmodule_cmd_312(unreal_cmd_312);
+ pmodule_cmd_317(unreal_cmd_317);
+ pmodule_cmd_219(unreal_cmd_219);
+ pmodule_cmd_401(unreal_cmd_401);
+ pmodule_cmd_318(unreal_cmd_318);
+ pmodule_cmd_242(unreal_cmd_242);
+ pmodule_cmd_243(unreal_cmd_243);
+ pmodule_cmd_211(unreal_cmd_211);
+ pmodule_cmd_global(unreal_cmd_global);
+ pmodule_cmd_global_legacy(unreal_cmd_global_legacy);
+ pmodule_cmd_sqline(unreal_cmd_sqline);
+ pmodule_cmd_squit(unreal_cmd_squit);
+ pmodule_cmd_svso(unreal_cmd_svso);
+ pmodule_cmd_chg_nick(unreal_cmd_chg_nick);
+ pmodule_cmd_svsnick(unreal_cmd_svsnick);
+ pmodule_cmd_vhost_on(unreal_cmd_vhost_on);
+ pmodule_cmd_connect(unreal_cmd_connect);
+ pmodule_cmd_svshold(unreal_cmd_svshold);
+ pmodule_cmd_release_svshold(unreal_cmd_release_svshold);
+ pmodule_cmd_unsgline(unreal_cmd_unsgline);
+ pmodule_cmd_unszline(unreal_cmd_unszline);
+ pmodule_cmd_szline(unreal_cmd_szline);
+ pmodule_cmd_sgline(unreal_cmd_sgline);
+ pmodule_cmd_unban(unreal_cmd_unban);
+ pmodule_cmd_svsmode_chan(unreal_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(unreal_cmd_svid_umode);
+ pmodule_cmd_nc_change(unreal_cmd_nc_change);
+ pmodule_cmd_svid_umode2(unreal_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(unreal_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(unreal_cmd_svsjoin);
+ pmodule_cmd_svspart(unreal_cmd_svspart);
+ pmodule_cmd_swhois(unreal_cmd_swhois);
+ pmodule_cmd_eob(unreal_cmd_eob);
+ pmodule_flood_mode_check(unreal_flood_mode_check);
+ pmodule_cmd_jupe(unreal_cmd_jupe);
+ pmodule_valid_nick(unreal_valid_nick);
+ pmodule_valid_chan(unreal_valid_chan);
+ pmodule_cmd_ctcp(unreal_cmd_ctcp);
+ pmodule_set_umode(unreal_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("UnrealIRCd 3.2+");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("+f");
+ pmodule_ircd_flood_mode_char_remove("-f");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/unreal32.h b/src/protocol/unreal32.h
new file mode 100644
index 000000000..4f8a9adf6
--- /dev/null
+++ b/src/protocol/unreal32.h
@@ -0,0 +1,153 @@
+/* Unreal IRCD 3.2.x functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@unreal.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/*************************************************************************/
+
+/* User Modes */
+#define UMODE_a 0x00000001 /* a Services Admin */
+#define UMODE_h 0x00000002 /* h Available for help (HelpOp) */
+#define UMODE_i 0x00000004 /* i Invisible (not shown in /who) */
+#define UMODE_o 0x00000008 /* o Global IRC Operator */
+#define UMODE_r 0x00000010 /* r Identifies the nick as being registered */
+#define UMODE_w 0x00000020 /* w Can listen to wallop messages */
+#define UMODE_A 0x00000040 /* A Server Admin */
+#define UMODE_N 0x00000080 /* N Network Administrator */
+#define UMODE_O 0x00000100 /* O Local IRC Operator */
+#define UMODE_C 0x00000200 /* C Co-Admin */
+#define UMODE_d 0x00000400 /* d Makes it so you can not receive channel PRIVMSGs */
+#define UMODE_p 0x00000800 /* Hides the channels you are in in a /whois reply */
+#define UMODE_q 0x00001000 /* q Only U:Lines can kick you (Services Admins Only) */
+#define UMODE_s 0x00002000 /* s Can listen to server notices */
+#define UMODE_t 0x00004000 /* t Says you are using a /vhost */
+#define UMODE_v 0x00008000 /* v Receives infected DCC Send Rejection notices */
+#define UMODE_z 0x00010000 /* z Indicates that you are an SSL client */
+#define UMODE_B 0x00020000 /* B Marks you as being a Bot */
+#define UMODE_G 0x00040000 /* G Filters out all the bad words per configuration */
+#define UMODE_H 0x00080000 /* H Hide IRCop Status (IRCop Only) */
+#define UMODE_S 0x00100000 /* S services client */
+#define UMODE_V 0x00200000 /* V Marks you as a WebTV user */
+#define UMODE_W 0x00400000 /* W Lets you see when people do a /whois on you */
+#define UMODE_T 0x00800000 /* T Prevents you from receiving CTCPs */
+#define UMODE_g 0x20000000 /* g Can send & read globops and locops */
+#define UMODE_x 0x40000000 /* x Gives user a hidden hostname */
+#define UMODE_R 0x80000000 /* Allows you to only receive PRIVMSGs/NOTICEs from registered (+r) users */
+
+
+/*************************************************************************/
+
+/* Channel Modes */
+
+#define CMODE_i 0x00000001
+#define CMODE_m 0x00000002
+#define CMODE_n 0x00000004
+#define CMODE_p 0x00000008
+#define CMODE_s 0x00000010
+#define CMODE_t 0x00000020
+#define CMODE_k 0x00000040 /* These two used only by ChanServ */
+#define CMODE_l 0x00000080
+#define CMODE_R 0x00000100 /* Only identified users can join */
+#define CMODE_r 0x00000200 /* Set for all registered channels */
+#define CMODE_c 0x00000400
+#define CMODE_A 0x00000800
+/* #define CMODE_H 0x00001000 Was now +I may not join, but Unreal Removed it and it will not set in 3.2 */
+#define CMODE_K 0x00002000
+#define CMODE_L 0x00004000
+#define CMODE_O 0x00008000
+#define CMODE_Q 0x00010000
+#define CMODE_S 0x00020000
+#define CMODE_V 0x00040000
+#define CMODE_f 0x00080000
+#define CMODE_G 0x00100000
+#define CMODE_C 0x00200000
+#define CMODE_u 0x00400000
+#define CMODE_z 0x00800000
+#define CMODE_N 0x01000000
+#define CMODE_T 0x02000000
+#define CMODE_M 0x04000000
+
+
+/* Default Modes with MLOCK */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void unreal_set_umode(User * user, int ac, char **av);
+void unreal_cmd_svsnoop(char *server, int set);
+void unreal_cmd_remove_akill(char *user, char *host);
+void unreal_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void unreal_cmd_vhost_off(User * u);
+void unreal_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void unreal_cmd_svskill(char *source, char *user, char *buf);
+void unreal_cmd_svsmode(User * u, int ac, char **av);
+void unreal_cmd_372(char *source, char *msg);
+void unreal_cmd_372_error(char *source);
+void unreal_cmd_375(char *source);
+void unreal_cmd_376(char *source);
+void unreal_cmd_nick(char *nick, char *name, char *modes);
+void unreal_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void unreal_cmd_mode(char *source, char *dest, char *buf);
+void unreal_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void unreal_cmd_kick(char *source, char *chan, char *user, char *buf);
+void unreal_cmd_notice_ops(char *source, char *dest, char *buf);
+void unreal_cmd_notice(char *source, char *dest, char *buf);
+void unreal_cmd_notice2(char *source, char *dest, char *msg);
+void unreal_cmd_privmsg(char *source, char *dest, char *buf);
+void unreal_cmd_privmsg2(char *source, char *dest, char *msg);
+void unreal_cmd_serv_notice(char *source, char *dest, char *msg);
+void unreal_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void unreal_cmd_bot_chan_mode(char *nick, char *chan);
+void unreal_cmd_351(char *source);
+void unreal_cmd_quit(char *source, char *buf);
+void unreal_cmd_pong(char *servname, char *who);
+void unreal_cmd_join(char *user, char *channel, time_t chantime);
+void unreal_cmd_unsqline(char *user);
+void unreal_cmd_invite(char *source, char *chan, char *nick);
+void unreal_cmd_part(char *nick, char *chan, char *buf);
+void unreal_cmd_391(char *source, char *timestr);
+void unreal_cmd_250(char *buf);
+void unreal_cmd_307(char *buf);
+void unreal_cmd_311(char *buf);
+void unreal_cmd_312(char *buf);
+void unreal_cmd_317(char *buf);
+void unreal_cmd_219(char *source, char *letter);
+void unreal_cmd_401(char *source, char *who);
+void unreal_cmd_318(char *source, char *who);
+void unreal_cmd_242(char *buf);
+void unreal_cmd_243(char *buf);
+void unreal_cmd_211(char *buf);
+void unreal_cmd_global(char *source, char *buf);
+void unreal_cmd_global_legacy(char *source, char *fmt);
+void unreal_cmd_sqline(char *mask, char *reason);
+void unreal_cmd_squit(char *servname, char *message);
+void unreal_cmd_svso(char *source, char *nick, char *flag);
+void unreal_cmd_chg_nick(char *oldnick, char *newnick);
+void unreal_cmd_svsnick(char *source, char *guest, time_t when);
+void unreal_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void unreal_cmd_connect(int servernum);
+void unreal_cmd_svshold(char *nick);
+void unreal_cmd_release_svshold(char *nick);
+void unreal_cmd_unsgline(char *mask);
+void unreal_cmd_unszline(char *mask);
+void unreal_cmd_szline(char *mask, char *reason, char *whom);
+void unreal_cmd_sgline(char *mask, char *reason);
+void unreal_cmd_unban(char *name, char *nick);
+void unreal_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void unreal_cmd_svid_umode(char *nick, time_t ts);
+void unreal_cmd_nc_change(User * u);
+void unreal_cmd_svid_umode2(User * u, char *ts);
+void unreal_cmd_svid_umode3(User * u, char *ts);
+void unreal_cmd_eob();
+int unreal_flood_mode_check(char *value);
+void unreal_cmd_jupe(char *jserver, char *who, char *reason);
+int unreal_valid_nick(char *nick);
+void unreal_cmd_ctcp(char *source, char *dest, char *buf);
+
diff --git a/src/protocol/viagra.c b/src/protocol/viagra.c
new file mode 100644
index 000000000..8638204b7
--- /dev/null
+++ b/src/protocol/viagra.c
@@ -0,0 +1,1716 @@
+/* Viagra IRCD functions
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+#include "viagra.h"
+
+IRCDVar myIrcd[] = {
+ {"ViagraIRCd 1.3.*", /* ircd name */
+ "+oS", /* nickserv mode */
+ "+oS", /* chanserv mode */
+ "+oS", /* memoserv mode */
+ "+oS", /* hostserv mode */
+ "+ioS", /* operserv mode */
+ "+oS", /* botserv mode */
+ "+oS", /* helpserv mode */
+ "+i", /* Dev/Null mode */
+ "+ioS", /* Global mode */
+ "+oS", /* nickserv alias mode */
+ "+oS", /* chanserv alias mode */
+ "+oS", /* memoserv alias mode */
+ "+ioS", /* hostserv alias mode */
+ "+ioS", /* operserv alias mode */
+ "+oS", /* botserv alias mode */
+ "+oS", /* helpserv alias mode */
+ "+iS", /* Dev/Null alias mode */
+ "+ioS", /* Global alias mode */
+ "+qS", /* Used by BotServ Bots */
+ 5, /* Chan Max Symbols */
+ "-ciklmnpstOR", /* Modes to Remove */
+ "+ao", /* Channel Umode used by Botserv bots */
+ 1, /* SVSNICK */
+ 1, /* Vhost */
+ 1, /* Has Owner */
+ "+q", /* Mode to set for an owner */
+ "-q", /* Mode to unset for an owner */
+ "+a", /* Mode to set for channel admin */
+ "-a", /* Mode to unset for channel admin */
+ "+rd", /* Mode On Reg */
+ NULL, /* Mode on ID for Roots */
+ NULL, /* Mode on ID for Admins */
+ NULL, /* Mode on ID for Opers */
+ "-r+d", /* Mode on UnReg */
+ "-r+d", /* Mode on Nick Change */
+ 1, /* Supports SGlines */
+ 1, /* Supports SQlines */
+ 1, /* Supports SZlines */
+ 1, /* Supports Halfop +h */
+ 3, /* Number of server args */
+ 0, /* Join 2 Set */
+ 0, /* Join 2 Message */
+ 1, /* Has exceptions +e */
+ 0, /* TS Topic Forward */
+ 0, /* TS Topci Backward */
+ 0, /* Protected Umode */
+ 1, /* Has Admin */
+ 0, /* Chan SQlines */
+ 1, /* Quit on Kill */
+ 1, /* SVSMODE unban */
+ 1, /* Has Protect */
+ 0, /* Reverse */
+ 1, /* Chan Reg */
+ CMODE_r, /* Channel Mode */
+ 1, /* vidents */
+ 0, /* svshold */
+ 1, /* time stamp on mode */
+ 1, /* NICKIP */
+ 0, /* O:LINE */
+ 1, /* UMODE */
+ 1, /* VHOST ON NICK */
+ 1, /* Change RealName */
+ 0, /* No Knock */
+ 0, /* Admin Only */
+ DEFAULT_MLOCK, /* Default MLOCK */
+ UMODE_x, /* Vhost Mode */
+ 0, /* +f */
+ 0, /* +L */
+ 0,
+ 0,
+ 1,
+ 1, /* No Knock requires +i */
+ NULL, /* CAPAB Chan Modes */
+ 0, /* We support TOKENS */
+ 1, /* TOKENS are CASE inSensitive */
+ 0, /* TIME STAMPS are BASE64 */
+ 0, /* +I support */
+ 0, /* SJOIN ban char */
+ 0, /* SJOIN except char */
+ 0, /* SJOIN invite char */
+ 0, /* Can remove User Channel Modes with SVSMODE */
+ 0, /* Sglines are not enforced until user reconnects */
+ "x", /* vhost char */
+ 0, /* ts6 */
+ 1, /* support helper umode */
+ 0, /* p10 */
+ NULL, /* character set */
+ 1, /* reports sync state */
+ 0, /* CIDR channelbans */
+ }
+ ,
+ {NULL}
+};
+
+
+IRCDCAPAB myIrcdcap[] = {
+ {
+ CAPAB_NOQUIT, /* NOQUIT */
+ CAPAB_TSMODE, /* TSMODE */
+ CAPAB_UNCONNECT, /* UNCONNECT */
+ CAPAB_NICKIP, /* NICKIP */
+ CAPAB_NSJOIN, /* SJOIN */
+ CAPAB_ZIP, /* ZIP */
+ CAPAB_BURST, /* BURST */
+ CAPAB_TS5, /* TS5 */
+ CAPAB_TS3, /* TS3 */
+ CAPAB_DKEY, /* DKEY */
+ 0, /* PT4 */
+ 0, /* SCS */
+ 0, /* QS */
+ 0, /* UID */
+ 0, /* KNOCK */
+ 0, /* CLIENT */
+ 0, /* IPV6 */
+ 0, /* SSJ5 */
+ 0, /* SN2 */
+ 0, /* TOKEN */
+ 0, /* VHOST */
+ 0, /* SSJ3 */
+ 0, /* NICK2 */
+ 0, /* UMODE2 */
+ 0, /* VL */
+ 0, /* TLKEXT */
+ CAPAB_DODKEY, /* DODKEY */
+ CAPAB_DOZIP, /* DOZIP */
+ 0, 0, 0}
+};
+
+
+
+
+void viagra_set_umode(User * user, int ac, char **av)
+{
+ int add = 1; /* 1 if adding modes, 0 if deleting */
+ char *modes = av[0];
+
+ ac--;
+
+ if (debug)
+ alog("debug: Changing mode for %s to %s", user->nick, modes);
+
+ while (*modes) {
+
+ /* This looks better, much better than "add ? (do_add) : (do_remove)".
+ * At least this is readable without paying much attention :) -GD
+ */
+ if (add)
+ user->mode |= umodes[(int) *modes];
+ else
+ user->mode &= ~umodes[(int) *modes];
+
+ switch (*modes++) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 'd':
+ if (ac == 0) {
+ alog("user: umode +d with no parameter (?) for user %s",
+ user->nick);
+ break;
+ }
+
+ ac--;
+ av++;
+ user->svid = strtoul(*av, NULL, 0);
+ break;
+ case 'o':
+ if (add) {
+ opcnt++;
+ if (WallOper) {
+ anope_cmd_global(s_OperServ,
+ "\2%s\2 is now an IRC operator.",
+ user->nick);
+ }
+ display_news(user, NEWS_OPER);
+ } else {
+ opcnt--;
+ }
+ break;
+ case 'r':
+ if (add && !nick_identified(user)) {
+ common_svsmode(user, "-r", NULL);
+ user->mode &= ~UMODE_r;
+ }
+ break;
+ case 'x':
+ update_host(user);
+ break;
+ }
+ }
+}
+
+unsigned long umodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, UMODE_A, 0, UMODE_C, 0, 0, 0, 0, 0, UMODE_I, 0, 0, 0, 0, UMODE_N,
+ UMODE_O,
+ 0,
+ UMODE_Q,
+ UMODE_R,
+ UMODE_S, UMODE_T, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0,
+ 0, UMODE_a, UMODE_b, UMODE_c, UMODE_d, UMODE_e, UMODE_f,
+ UMODE_g,
+ UMODE_h, UMODE_i, 0, 0, 0, 0, UMODE_n, UMODE_o,
+ 0,
+ 0, UMODE_r, UMODE_s, 0, 0, 0, UMODE_w,
+ UMODE_x,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0
+};
+
+
+char myCsmodes[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0,
+ 0,
+ 0, 0, 0,
+ 'h', /* (37) % Channel halfops */
+ 0, /* (38) & bans */
+ 0, 0, 0,
+ 'q',
+
+ 'v', 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'a', 0
+};
+
+CMMode myCmmodes[128] = {
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL},
+ {NULL},
+ {add_ban, del_ban},
+ {NULL},
+ {NULL},
+ {add_exception, del_exception},
+ {NULL},
+ {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL},
+ {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}, {NULL}
+};
+
+
+
+CBMode myCbmodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0},
+ {0}, /* A */
+ {0}, /* B */
+ {0}, /* C */
+ {0}, /* D */
+ {0}, /* E */
+ {0}, /* F */
+ {0}, /* G */
+ {CMODE_H, 0, NULL, NULL}, /* H */
+ {0}, /* I */
+ {0}, /* J */
+ {0}, /* K */
+ {0}, /* L */
+ {CMODE_M, 0, NULL, NULL}, /* M */
+ {CMODE_N, 0, NULL, NULL}, /* N */
+ {CMODE_O, CBM_NO_USER_MLOCK, NULL, NULL},
+ {CMODE_P, 0, NULL, NULL}, /* P */
+ {0}, /* Q */
+ {CMODE_R, 0, NULL, NULL}, /* R */
+ {CMODE_S, 0, NULL, NULL}, /* S */
+ {0}, /* T */
+ {0}, /* U */
+ {0}, /* V */
+ {0}, /* W */
+ {0}, /* X */
+ {0}, /* Y */
+ {0}, /* Z */
+ {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, /* a */
+ {0}, /* b */
+ {CMODE_c, 0, NULL, NULL},
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {0}, /* h */
+ {CMODE_i, 0, NULL, NULL},
+ {0}, /* j */
+ {CMODE_k, 0, chan_set_key, cs_set_key},
+ {CMODE_l, CBM_MINUS_NO_ARG, set_limit, cs_set_limit},
+ {CMODE_m, 0, NULL, NULL},
+ {CMODE_n, 0, NULL, NULL},
+ {0}, /* o */
+ {CMODE_p, 0, NULL, NULL},
+ {0}, /* q */
+ {CMODE_r, CBM_NO_MLOCK, NULL, NULL},
+ {CMODE_s, 0, NULL, NULL},
+ {CMODE_t, 0, NULL, NULL},
+ {0},
+ {0}, /* v */
+ {0}, /* w */
+ {CMODE_x, 0, NULL, NULL}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}
+};
+
+CBModeInfo myCbmodeinfos[] = {
+ {'c', CMODE_c, 0, NULL, NULL},
+ {'i', CMODE_i, 0, NULL, NULL},
+ {'k', CMODE_k, 0, get_key, cs_get_key},
+ {'l', CMODE_l, CBM_MINUS_NO_ARG, get_limit, cs_get_limit},
+ {'m', CMODE_m, 0, NULL, NULL},
+ {'n', CMODE_n, 0, NULL, NULL},
+ {'p', CMODE_p, 0, NULL, NULL},
+ {'r', CMODE_r, 0, NULL, NULL},
+ {'s', CMODE_s, 0, NULL, NULL},
+ {'t', CMODE_t, 0, NULL, NULL},
+ {'x', CMODE_x, 0, NULL, NULL},
+ {'H', CMODE_H, 0, NULL, NULL},
+ {'M', CMODE_M, 0, NULL, NULL},
+ {'N', CMODE_N, 0, NULL, NULL},
+ {'O', CMODE_O, 0, NULL, NULL},
+ {'P', CMODE_P, 0, NULL, NULL},
+ {'R', CMODE_R, 0, NULL, NULL},
+ {'S', CMODE_S, 0, NULL, NULL},
+ {0}
+};
+
+CUMode myCumodes[128] = {
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+ {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
+
+ {0},
+
+ {CUS_PROTECT, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* b */
+ {0}, /* c */
+ {0}, /* d */
+ {0}, /* e */
+ {0}, /* f */
+ {0}, /* g */
+ {CUS_HALFOP, 0, check_valid_op},
+ {0}, /* i */
+ {0}, /* j */
+ {0}, /* k */
+ {0}, /* l */
+ {0}, /* m */
+ {0}, /* n */
+ {CUS_OP, CUF_PROTECT_BOTSERV, check_valid_op},
+ {0}, /* p */
+ {CUS_OWNER, 0, check_valid_op},
+ {0}, /* r */
+ {0}, /* s */
+ {0}, /* t */
+ {0}, /* u */
+ {CUS_VOICE, 0, NULL},
+ {0}, /* w */
+ {0}, /* x */
+ {0}, /* y */
+ {0}, /* z */
+ {0}, {0}, {0}, {0}, {0}
+};
+
+
+void viagra_cmd_bot_unban(ChannelInfo * ci, char *nick)
+{
+ send_cmd(ServerName, "SVSMODE %s -b %s", ci->name, nick);
+}
+
+int anope_event_setname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETNAME for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_sjoin(char *source, int ac, char **av)
+{
+ do_sjoin(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_chgname(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGNAME for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_realname(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_setident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETIDENT for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_chgident(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGIDENT for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_username(u, av[1]);
+ return MOD_CONT;
+}
+
+/*
+ * sethost
+ * parv[0] = sender
+ * parv[1] = newhost
+ */
+int anope_event_sethost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 1)
+ return MOD_CONT;
+
+ u = finduser(source);
+ if (!u) {
+ if (debug) {
+ alog("debug: SETHOST for nonexistent user %s", source);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_nick(char *source, int ac, char **av)
+{
+ User *user;
+
+ if (ac != 2) {
+ user = do_nick(source, av[0], av[4], av[5], av[6], av[9],
+ strtoul(av[2], NULL, 10), strtoul(av[7], NULL, 0),
+ strtoul(av[8], NULL, 0), "*", NULL);
+ if (user) {
+ anope_set_umode(user, 1, &av[3]);
+ }
+ } else {
+ do_nick(source, av[0], NULL, NULL, NULL, NULL,
+ strtoul(av[1], NULL, 10), 0, 0, NULL, NULL);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_vs(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: VS for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+
+}
+
+int anope_event_chghost(char *source, int ac, char **av)
+{
+ User *u;
+
+ if (ac != 2)
+ return MOD_CONT;
+
+ u = finduser(av[0]);
+ if (!u) {
+ if (debug) {
+ alog("debug: CHGHOST for nonexistent user %s", av[0]);
+ }
+ return MOD_CONT;
+ }
+
+ change_user_host(u, av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_436(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+
+ m_nickcoll(av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_notice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_pass(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_svinfo(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/*
+ * gnotice
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+int anope_event_gnotice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_sqline(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_burst(char *source, int ac, char **av)
+{
+ Server *s;
+ s = findserver(servlist, source);
+ if (!ac) {
+ /* for future use - start burst */
+ } else {
+ /* If we found a server with the given source, that one just
+ * finished bursting. If there was no source, then our uplink
+ * server finished bursting. -GD
+ */
+ if (!s && serv_uplink)
+ s = serv_uplink;
+ finish_sync(s, 1);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_tctrl(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+/*
+ * error
+ * parv[0] = sender prefix
+ * parv[*] = parameters
+ */
+int anope_event_error(char *source, int ac, char **av)
+{
+ if (ac >= 1) {
+ if (debug) {
+ alog("debug: %s", av[0]);
+ }
+ }
+ return MOD_CONT;
+}
+
+/* *INDENT-OFF* */
+void moduleAddIRCDMsgs(void) {
+ Message *m;
+
+ updateProtectDetails("PROTECT","PROTECTME","protect","deprotect","AUTOPROTECT","+a","-a");
+
+ m = createMessage("401", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("402", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m);
+ m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m);
+ m = createMessage("INVITE", anope_event_invite); addCoreMessage(IRCD,m);
+ m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m);
+ m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m);
+ m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m);
+ m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m);
+ m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m);
+ m = createMessage("NOTICE", anope_event_notice); addCoreMessage(IRCD,m);
+ m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m);
+ m = createMessage("PASS", anope_event_pass); addCoreMessage(IRCD,m);
+ m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m);
+ m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m);
+ m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m);
+ m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m);
+ m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m);
+ m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m);
+ m = createMessage("WALLOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m);
+ m = createMessage("AKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GLOBOPS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("GNOTICE", anope_event_gnotice); addCoreMessage(IRCD,m);
+ m = createMessage("GOPER", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("RAKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SILENCE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSKILL", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNICK", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVSNOOP", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SQLINE", anope_event_sqline); addCoreMessage(IRCD,m);
+ m = createMessage("UNSQLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m);
+ m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m);
+ m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m);
+ m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m);
+ m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m);
+ m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m);
+ m = createMessage("RS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m);
+ m = createMessage("SS", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("SVINFO", anope_event_svinfo); addCoreMessage(IRCD,m);
+ m = createMessage("SZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSGLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("UNSZLINE", anope_event_null); addCoreMessage(IRCD,m);
+ m = createMessage("CHGHOST", anope_event_chghost); addCoreMessage(IRCD,m);
+ m = createMessage("CHGIDENT", anope_event_chgident); addCoreMessage(IRCD,m);
+ m = createMessage("CHGNAME", anope_event_chgname); addCoreMessage(IRCD,m);
+ m = createMessage("SETHOST", anope_event_sethost); addCoreMessage(IRCD,m);
+ m = createMessage("SETIDENT", anope_event_setident); addCoreMessage(IRCD,m);
+ m = createMessage("SETNAME", anope_event_setname); addCoreMessage(IRCD,m);
+ m = createMessage("VS", anope_event_vs); addCoreMessage(IRCD,m);
+ m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m);
+ m = createMessage("TCTRL", anope_event_tctrl); addCoreMessage(IRCD,m);
+ m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m);
+ m = createMessage("REHASH", anope_event_rehash); addCoreMessage(IRCD,m);
+ m = createMessage("ADMIN", anope_event_admin); addCoreMessage(IRCD,m);
+ m = createMessage("SNOTICE", anope_event_snotice); addCoreMessage(IRCD,m);
+}
+
+/* *INDENT-ON* */
+
+
+/* SQLINE */
+void viagra_cmd_sqline(char *mask, char *reason)
+{
+ if (!mask || !reason) {
+ return;
+ }
+
+ send_cmd(NULL, "SQLINE %s :%s", mask, reason);
+}
+
+void viagra_cmd_unsgline(char *mask)
+{
+ send_cmd(NULL, "UNSGLINE 0 :%s", mask);
+}
+
+void viagra_cmd_unszline(char *mask)
+{
+ send_cmd(NULL, "UNSZLINE 0 %s", mask);
+}
+
+void viagra_cmd_szline(char *mask, char *reason, char *whom)
+{
+ send_cmd(NULL, "SZLINE %s :%s", mask, reason);
+}
+
+void viagra_cmd_svsnoop(char *server, int set)
+{
+ send_cmd(NULL, "SVSNOOP %s %s", server, (set ? "+" : "-"));
+}
+
+void viagra_cmd_svsadmin(char *server, int set)
+{
+ viagra_cmd_svsnoop(server, set);
+}
+
+void viagra_cmd_sgline(char *mask, char *reason)
+{
+ send_cmd(NULL, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
+}
+
+void viagra_cmd_remove_akill(char *user, char *host)
+{
+ send_cmd(NULL, "RAKILL %s %s", host, user);
+}
+
+/* PART */
+void viagra_cmd_part(char *nick, char *chan, char *buf)
+{
+ if (!nick || !chan) {
+ return;
+ }
+
+ if (buf) {
+ send_cmd(nick, "PART %s :%s", chan, buf);
+ } else {
+ send_cmd(nick, "PART %s", chan);
+ }
+}
+
+void viagra_cmd_topic(char *whosets, char *chan, char *whosetit,
+ char *topic, time_t when)
+{
+ send_cmd(whosets, "TOPIC %s %s %lu :%s", chan, whosetit,
+ (unsigned long int) when, topic);
+}
+
+void viagra_cmd_vhost_off(User * u)
+{
+ send_cmd(NULL, "SVSMODE %s -x", u->nick);
+ notice_lang(s_HostServ, u, HOST_OFF_UNREAL, u->nick, ircd->vhostchar);
+}
+
+void viagra_cmd_vhost_on(char *nick, char *vIdent, char *vhost)
+{
+ if (vIdent) {
+ send_cmd(NULL, "CHGIDENT %s %s", nick, vIdent);
+ }
+ send_cmd(NULL, "SVSMODE %s +x", nick);
+ send_cmd(NULL, "SVSCHGHOST %s %s", nick, vhost);
+}
+
+void viagra_cmd_unsqline(char *user)
+{
+ send_cmd(NULL, "UNSQLINE %s", user);
+}
+
+void viagra_cmd_join(char *user, char *channel, time_t chantime)
+{
+ send_cmd(user, "SJOIN %ld %s", (long int) chantime, channel);
+}
+
+
+/*
+ * m_akill()
+ * parv[1]=host
+ * parv[2]=user
+ * parv[3]=length
+ * parv[4]=akiller
+ * parv[5]=time set
+ * parv[6]=reason
+ */
+void viagra_cmd_akill(char *user, char *host, char *who, time_t when,
+ time_t expires, char *reason)
+{
+ send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", host, user, 86400 * 2, who,
+ (long int) time(NULL), reason);
+}
+
+
+/*
+ * svskill
+ * parv[0] = servername
+ * parv[1] = client
+ * parv[2] = nick stamp
+ * parv[3] = kill message
+ */
+void viagra_cmd_svskill(char *source, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "SVSKILL %s :%s", user, buf);
+ }
+ return;
+}
+
+void viagra_cmd_mode(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (ircdcap->tsmode) {
+ if (uplink_capab & ircdcap->tsmode) {
+ send_cmd(source, "MODE %s 0 %s", dest, buf);
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+ } else {
+ send_cmd(source, "MODE %s %s", dest, buf);
+ }
+}
+
+/* QUIT */
+void viagra_cmd_quit(char *source, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "QUIT :%s", buf);
+ } else {
+ send_cmd(source, "QUIT");
+ }
+}
+
+int anope_event_away(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+ m_away(source, (ac ? av[0] : NULL));
+ return MOD_CONT;
+}
+
+int anope_event_ping(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ viagra_cmd_pong(ac > 1 ? av[1] : ServerName, av[0]);
+ return MOD_CONT;
+}
+
+void viagra_cmd_svsmode(User * u, int ac, char **av)
+{
+ send_cmd(ServerName, "SVSMODE %s %ld %s%s%s", u->nick,
+ (long int) u->timestamp, av[0], (ac == 2 ? " " : ""),
+ (ac == 2 ? av[1] : ""));
+}
+
+void viagra_cmd_squit(char *servname, char *message)
+{
+ send_cmd(NULL, "SQUIT %s :%s", servname, message);
+}
+
+/* PONG */
+void viagra_cmd_pong(char *servname, char *who)
+{
+ send_cmd(servname, "PONG %s", who);
+}
+
+/*
+ * svinfo
+ * parv[0] = sender prefix
+ * parv[1] = TS_CURRENT for the server
+ * parv[2] = TS_MIN for the server
+ * parv[3] = server is standalone or connected to non-TS only
+ * parv[4] = server's idea of UTC time
+ */
+void viagra_cmd_svinfo()
+{
+ send_cmd(NULL, "SVINFO 5 3 0 :%ld", (long int) time(NULL));
+}
+
+/* CAPAB */
+void viagra_cmd_capab()
+{
+ send_cmd(NULL, "CAPAB TS5 NOQUIT SSJOIN BURST UNCONNECT NICKIP");
+}
+
+/* PASS */
+void viagra_cmd_pass(char *pass)
+{
+ send_cmd(NULL, "PASS %s :TS", pass);
+}
+
+/* SERVER */
+void viagra_cmd_server(char *servname, int hop, char *descript)
+{
+ send_cmd(NULL, "SERVER %s %d :%s", servname, hop, descript);
+}
+
+void viagra_cmd_burst()
+{
+ send_cmd(NULL, "BURST");
+}
+
+void viagra_cmd_connect(int servernum)
+{
+ me_server =
+ new_server(NULL, ServerName, ServerDesc, SERVER_ISME, NULL);
+
+ if (servernum == 1) {
+ viagra_cmd_pass(RemotePassword);
+ } else if (servernum == 2) {
+ viagra_cmd_pass(RemotePassword2);
+ } else if (servernum == 3) {
+ viagra_cmd_pass(RemotePassword3);
+ }
+ viagra_cmd_capab();
+ viagra_cmd_server(ServerName, 1, ServerDesc);
+ viagra_cmd_svinfo();
+ viagra_cmd_burst();
+}
+
+/* EVENT : OS */
+int anope_event_os(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_OperServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : NS */
+int anope_event_ns(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_NickServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : MS */
+int anope_event_ms(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_MemoServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : HS */
+int anope_event_hs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_HostServ, av[0]);
+ return MOD_CONT;
+}
+
+/* EVENT : CS */
+int anope_event_cs(char *source, int ac, char **av)
+{
+ if (ac < 1)
+ return MOD_CONT;
+ m_privmsg(source, s_ChanServ, av[0]);
+ return MOD_CONT;
+}
+
+int anope_event_server(char *source, int ac, char **av)
+{
+ if (!stricmp(av[1], "1")) {
+ uplink = sstrdup(av[0]);
+ }
+ do_server(source, av[0], av[1], av[2], NULL);
+ return MOD_CONT;
+}
+
+
+int anope_event_privmsg(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ m_privmsg(source, av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_part(char *source, int ac, char **av)
+{
+ if (ac < 1 || ac > 2)
+ return MOD_CONT;
+ do_part(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_whois(char *source, int ac, char **av)
+{
+ if (source && ac >= 1) {
+ m_whois(source, av[0]);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_topic(char *source, int ac, char **av)
+{
+ if (ac != 4)
+ return MOD_CONT;
+ do_topic(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_squit(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+ do_squit(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_quit(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_quit(source, ac, av);
+ return MOD_CONT;
+}
+
+
+int anope_event_mode(char *source, int ac, char **av)
+{
+ if (ac < 2)
+ return MOD_CONT;
+
+ if (*av[0] == '#' || *av[0] == '&') {
+ do_cmode(source, ac, av);
+ } else {
+ do_umode(source, ac, av);
+ }
+ return MOD_CONT;
+}
+
+int anope_event_kill(char *source, int ac, char **av)
+{
+ if (ac != 2)
+ return MOD_CONT;
+
+ m_kill(av[0], av[1]);
+ return MOD_CONT;
+}
+
+int anope_event_kick(char *source, int ac, char **av)
+{
+ if (ac != 3)
+ return MOD_CONT;
+ do_kick(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_join(char *source, int ac, char **av)
+{
+ if (ac != 1)
+ return MOD_CONT;
+ do_join(source, ac, av);
+ return MOD_CONT;
+}
+
+int anope_event_motd(char *source, int ac, char **av)
+{
+ if (!source) {
+ return MOD_CONT;
+ }
+
+ m_motd(source);
+ return MOD_CONT;
+}
+
+void viagra_cmd_notice_ops(char *source, char *dest, char *buf)
+{
+ if (buf) {
+ send_cmd(NULL, "NOTICE @%s :%s", dest, buf);
+ }
+ return;
+}
+
+void viagra_cmd_notice(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ if (NSDefFlags & NI_MSG) {
+ viagra_cmd_privmsg2(source, dest, buf);
+ } else {
+ send_cmd(source, "NOTICE %s :%s", dest, buf);
+ }
+}
+
+void viagra_cmd_notice2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE %s :%s", dest, msg);
+}
+
+void viagra_cmd_privmsg(char *source, char *dest, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source, "PRIVMSG %s :%s", dest, buf);
+}
+
+void viagra_cmd_privmsg2(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG %s :%s", dest, msg);
+}
+
+void viagra_cmd_serv_notice(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "NOTICE $%s :%s", dest, msg);
+}
+
+void viagra_cmd_serv_privmsg(char *source, char *dest, char *msg)
+{
+ send_cmd(source, "PRIVMSG $%s :%s", dest, msg);
+}
+
+/* GLOBOPS */
+void viagra_cmd_global(char *source, char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
+}
+
+/* 391 */
+void viagra_cmd_391(char *source, char *timestr)
+{
+ if (!timestr) {
+ return;
+ }
+ send_cmd(NULL, "391 :%s %s :%s", source, ServerName, timestr);
+}
+
+/* 250 */
+void viagra_cmd_250(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "250 %s", buf);
+}
+
+/* 307 */
+void viagra_cmd_307(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "307 %s", buf);
+}
+
+/* 311 */
+void viagra_cmd_311(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "311 %s", buf);
+}
+
+/* 312 */
+void viagra_cmd_312(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "312 %s", buf);
+}
+
+/* 317 */
+void viagra_cmd_317(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(ServerName, "317 %s", buf);
+}
+
+/* 219 */
+void viagra_cmd_219(char *source, char *letter)
+{
+ if (!source) {
+ return;
+ }
+
+ if (letter) {
+ send_cmd(NULL, "219 %s %c :End of /STATS report.", source,
+ *letter);
+ } else {
+ send_cmd(NULL, "219 %s l :End of /STATS report.", source);
+ }
+}
+
+/* 401 */
+void viagra_cmd_401(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+ send_cmd(ServerName, "401 %s %s :No such service.", source, who);
+}
+
+/* 318 */
+void viagra_cmd_318(char *source, char *who)
+{
+ if (!source || !who) {
+ return;
+ }
+
+ send_cmd(ServerName, "318 %s %s :End of /WHOIS list.", source, who);
+}
+
+/* 242 */
+void viagra_cmd_242(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "242 %s", buf);
+}
+
+/* 243 */
+void viagra_cmd_243(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "243 %s", buf);
+}
+
+/* 211 */
+void viagra_cmd_211(char *buf)
+{
+ if (!buf) {
+ return;
+ }
+
+ send_cmd(NULL, "211 %s", buf);
+}
+
+void viagra_cmd_351(char *source)
+{
+ send_cmd(ServerName, "351 %s Anope-%s %s :%s - %s (%s) -- %s",
+ source, version_number, ServerName, ircd->name, version_flags,
+ EncModule, version_build);
+}
+
+void viagra_cmd_bot_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ EnforceQlinedNick(nick, s_BotServ);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+ viagra_cmd_sqline(nick, "Reserved for services");
+}
+
+void viagra_cmd_kick(char *source, char *chan, char *user, char *buf)
+{
+ if (buf) {
+ send_cmd(source, "KICK %s %s :%s", chan, user, buf);
+ } else {
+ send_cmd(source, "KICK %s %s", chan, user);
+ }
+}
+
+void viagra_cmd_nick(char *nick, char *name, char *modes)
+{
+ EnforceQlinedNick(nick, NULL);
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, ServiceUser, ServiceHost,
+ ServerName, name);
+ viagra_cmd_sqline(nick, "Reserved for services");
+}
+
+void viagra_cmd_372(char *source, char *msg)
+{
+ send_cmd(ServerName, "372 %s :- %s", source, msg);
+}
+
+void viagra_cmd_372_error(char *source)
+{
+ send_cmd(ServerName, "422 %s :- MOTD file not found! Please "
+ "contact your IRC administrator.", source);
+}
+
+void viagra_cmd_375(char *source)
+{
+ send_cmd(ServerName, "375 %s :- %s Message of the Day",
+ source, ServerName);
+}
+
+void viagra_cmd_376(char *source)
+{
+ send_cmd(ServerName, "376 %s :End of /MOTD command.", source);
+}
+
+/* INVITE */
+void viagra_cmd_invite(char *source, char *chan, char *nick)
+{
+ if (!source || !chan || !nick) {
+ return;
+ }
+
+ send_cmd(source, "INVITE %s %s", nick, chan);
+}
+
+void viagra_cmd_bot_chan_mode(char *nick, char *chan)
+{
+ anope_cmd_mode(nick, chan, "%s %s", ircd->botchanumode, nick);
+}
+
+int anope_event_capab(char *source, int ac, char **av)
+{
+ capab_parse(ac, av);
+ return MOD_CONT;
+}
+
+/* SVSHOLD - set */
+void viagra_cmd_svshold(char *nick)
+{
+ /* Not supported by this IRCD */
+}
+
+/* SVSHOLD - release */
+void viagra_cmd_release_svshold(char *nick)
+{
+ /* Not Supported by this IRCD */
+}
+
+/* SVSNICK */
+void viagra_cmd_svsnick(char *source, char *guest, time_t when)
+{
+ if (!source || !guest) {
+ return;
+ }
+ send_cmd(NULL, "SVSNICK %s %s :%ld", source, guest, (long int) when);
+}
+
+void viagra_cmd_guest_nick(char *nick, char *user, char *host, char *real,
+ char *modes)
+{
+ send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick,
+ (long int) time(NULL), modes, user, host, ServerName, real);
+}
+
+void viagra_cmd_svso(char *source, char *nick, char *flag)
+{
+ /* Not Supported by this IRCD */
+}
+
+
+/* SVSMODE -b */
+void viagra_cmd_unban(char *name, char *nick)
+{
+ viagra_cmd_svsmode_chan(name, "-b", nick);
+}
+
+/* SVSMODE channel modes */
+
+void viagra_cmd_svsmode_chan(char *name, char *mode, char *nick)
+{
+ if (nick) {
+ send_cmd(ServerName, "SVSMODE %s %s %s", name, mode, nick);
+ } else {
+ send_cmd(ServerName, "SVSMODE %s %s", name, mode);
+ }
+}
+
+/* SVSMODE +d */
+/* sent if svid is something weird */
+void viagra_cmd_svid_umode(char *nick, time_t ts)
+{
+ send_cmd(ServerName, "SVSMODE %s %lu +d 1", nick,
+ (unsigned long int) ts);
+}
+
+/* SVSMODE +d */
+/* nc_change was = 1, and there is no na->status */
+void viagra_cmd_nc_change(User * u)
+{
+ common_svsmode(u, "+d", "1");
+}
+
+/* SVSMODE +d */
+void viagra_cmd_svid_umode2(User * u, char *ts)
+{
+ /* not used by bahamut ircds */
+}
+
+void viagra_cmd_svid_umode3(User * u, char *ts)
+{
+ if (u->svid != u->timestamp) {
+ common_svsmode(u, "+rd", ts);
+ } else {
+ common_svsmode(u, "+r", NULL);
+ }
+}
+
+/* NICK <newnick> */
+void viagra_cmd_chg_nick(char *oldnick, char *newnick)
+{
+ if (!oldnick || !newnick) {
+ return;
+ }
+
+ send_cmd(oldnick, "NICK %s", newnick);
+}
+
+/*
+ * svsjoin
+ * parv[0] = sender
+ * parv[1] = nick to make join
+ * parv[2] = channel(s) to join
+ */
+void viagra_cmd_svsjoin(char *source, char *nick, char *chan, char *param)
+{
+ send_cmd(source, "SVSJOIN %s :%s", nick, chan);
+}
+
+/*
+ * svspart
+ * parv[0] = sender
+ * parv[1] = nick to make part
+ * parv[2] = channel(s) to part
+ */
+void viagra_cmd_svspart(char *source, char *nick, char *chan)
+{
+ send_cmd(source, "SVSPART %s :%s", nick, chan);
+}
+
+void viagra_cmd_swhois(char *source, char *who, char *mask)
+{
+ /* not supported */
+}
+
+int viagra_flood_mode_check(char *value)
+{
+ return 0;
+}
+
+int anope_event_rehash(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_admin(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_snotice(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+int anope_event_invite(char *source, int ac, char **av)
+{
+ return MOD_CONT;
+}
+
+void viagra_cmd_eob()
+{
+ send_cmd(NULL, "BURST 0");
+}
+
+void viagra_cmd_jupe(char *jserver, char *who, char *reason)
+{
+ char rbuf[256];
+
+ snprintf(rbuf, sizeof(rbuf), "Juped by %s%s%s", who,
+ reason ? ": " : "", reason ? reason : "");
+
+ if (findserver(servlist, jserver))
+ viagra_cmd_squit(jserver, rbuf);
+ viagra_cmd_server(jserver, 2, rbuf);
+ new_server(me_server, jserver, rbuf, SERVER_JUPED, NULL);
+}
+
+/* GLOBOPS - to handle old WALLOPS */
+void viagra_cmd_global_legacy(char *source, char *fmt)
+{
+ send_cmd(source ? source : ServerName, "GLOBOPS :%s", fmt);
+}
+
+/*
+ 1 = valid nick
+ 0 = nick is in valid
+*/
+int viagra_valid_nick(char *nick)
+{
+ /* no hard coded invalid nicks */
+ return 1;
+}
+
+/*
+ 1 = valid chan
+ 0 = chan is in valid
+*/
+int viagra_valid_chan(char *chan)
+{
+ /* no hard coded invalid chans */
+ return 1;
+}
+
+
+void viagra_cmd_ctcp(char *source, char *dest, char *buf)
+{
+ char *s;
+
+ if (!buf) {
+ return;
+ } else {
+ s = normalizeBuffer(buf);
+ }
+
+ send_cmd(source, "NOTICE %s :\1%s \1", dest, s);
+ free(s);
+}
+
+
+/**
+ * Tell anope which function we want to perform each task inside of anope.
+ * These prototypes must match what anope expects.
+ **/
+void moduleAddAnopeCmds()
+{
+ pmodule_cmd_svsnoop(viagra_cmd_svsnoop);
+ pmodule_cmd_remove_akill(viagra_cmd_remove_akill);
+ pmodule_cmd_topic(viagra_cmd_topic);
+ pmodule_cmd_vhost_off(viagra_cmd_vhost_off);
+ pmodule_cmd_akill(viagra_cmd_akill);
+ pmodule_cmd_svskill(viagra_cmd_svskill);
+ pmodule_cmd_svsmode(viagra_cmd_svsmode);
+ pmodule_cmd_372(viagra_cmd_372);
+ pmodule_cmd_372_error(viagra_cmd_372_error);
+ pmodule_cmd_375(viagra_cmd_375);
+ pmodule_cmd_376(viagra_cmd_376);
+ pmodule_cmd_nick(viagra_cmd_nick);
+ pmodule_cmd_guest_nick(viagra_cmd_guest_nick);
+ pmodule_cmd_mode(viagra_cmd_mode);
+ pmodule_cmd_bot_nick(viagra_cmd_bot_nick);
+ pmodule_cmd_kick(viagra_cmd_kick);
+ pmodule_cmd_notice_ops(viagra_cmd_notice_ops);
+ pmodule_cmd_notice(viagra_cmd_notice);
+ pmodule_cmd_notice2(viagra_cmd_notice2);
+ pmodule_cmd_privmsg(viagra_cmd_privmsg);
+ pmodule_cmd_privmsg2(viagra_cmd_privmsg2);
+ pmodule_cmd_serv_notice(viagra_cmd_serv_notice);
+ pmodule_cmd_serv_privmsg(viagra_cmd_serv_privmsg);
+ pmodule_cmd_bot_chan_mode(viagra_cmd_bot_chan_mode);
+ pmodule_cmd_351(viagra_cmd_351);
+ pmodule_cmd_quit(viagra_cmd_quit);
+ pmodule_cmd_pong(viagra_cmd_pong);
+ pmodule_cmd_join(viagra_cmd_join);
+ pmodule_cmd_unsqline(viagra_cmd_unsqline);
+ pmodule_cmd_invite(viagra_cmd_invite);
+ pmodule_cmd_part(viagra_cmd_part);
+ pmodule_cmd_391(viagra_cmd_391);
+ pmodule_cmd_250(viagra_cmd_250);
+ pmodule_cmd_307(viagra_cmd_307);
+ pmodule_cmd_311(viagra_cmd_311);
+ pmodule_cmd_312(viagra_cmd_312);
+ pmodule_cmd_317(viagra_cmd_317);
+ pmodule_cmd_219(viagra_cmd_219);
+ pmodule_cmd_401(viagra_cmd_401);
+ pmodule_cmd_318(viagra_cmd_318);
+ pmodule_cmd_242(viagra_cmd_242);
+ pmodule_cmd_243(viagra_cmd_243);
+ pmodule_cmd_211(viagra_cmd_211);
+ pmodule_cmd_global(viagra_cmd_global);
+ pmodule_cmd_global_legacy(viagra_cmd_global_legacy);
+ pmodule_cmd_sqline(viagra_cmd_sqline);
+ pmodule_cmd_squit(viagra_cmd_squit);
+ pmodule_cmd_svso(viagra_cmd_svso);
+ pmodule_cmd_chg_nick(viagra_cmd_chg_nick);
+ pmodule_cmd_svsnick(viagra_cmd_svsnick);
+ pmodule_cmd_vhost_on(viagra_cmd_vhost_on);
+ pmodule_cmd_connect(viagra_cmd_connect);
+ pmodule_cmd_svshold(viagra_cmd_svshold);
+ pmodule_cmd_release_svshold(viagra_cmd_release_svshold);
+ pmodule_cmd_unsgline(viagra_cmd_unsgline);
+ pmodule_cmd_unszline(viagra_cmd_unszline);
+ pmodule_cmd_szline(viagra_cmd_szline);
+ pmodule_cmd_sgline(viagra_cmd_sgline);
+ pmodule_cmd_unban(viagra_cmd_unban);
+ pmodule_cmd_svsmode_chan(viagra_cmd_svsmode_chan);
+ pmodule_cmd_svid_umode(viagra_cmd_svid_umode);
+ pmodule_cmd_nc_change(viagra_cmd_nc_change);
+ pmodule_cmd_svid_umode2(viagra_cmd_svid_umode2);
+ pmodule_cmd_svid_umode3(viagra_cmd_svid_umode3);
+ pmodule_cmd_svsjoin(viagra_cmd_svsjoin);
+ pmodule_cmd_svspart(viagra_cmd_svspart);
+ pmodule_cmd_swhois(viagra_cmd_swhois);
+ pmodule_cmd_eob(viagra_cmd_eob);
+ pmodule_flood_mode_check(viagra_flood_mode_check);
+ pmodule_cmd_jupe(viagra_cmd_jupe);
+ pmodule_valid_nick(viagra_valid_nick);
+ pmodule_valid_chan(viagra_valid_chan);
+ pmodule_cmd_ctcp(viagra_cmd_ctcp);
+ pmodule_set_umode(viagra_set_umode);
+}
+
+/**
+ * Now tell anope how to use us.
+ **/
+int AnopeInit(int argc, char **argv)
+{
+
+ moduleAddAuthor("Anope");
+ moduleAddVersion("$Id$");
+ moduleSetType(PROTOCOL);
+
+ pmodule_ircd_version("ViagraIRCd 1.3.x");
+ pmodule_ircd_cap(myIrcdcap);
+ pmodule_ircd_var(myIrcd);
+ pmodule_ircd_cbmodeinfos(myCbmodeinfos);
+ pmodule_ircd_cumodes(myCumodes);
+ pmodule_ircd_flood_mode_char_set("");
+ pmodule_ircd_flood_mode_char_remove("");
+ pmodule_ircd_cbmodes(myCbmodes);
+ pmodule_ircd_cmmodes(myCmmodes);
+ pmodule_ircd_csmodes(myCsmodes);
+ pmodule_ircd_useTSMode(0);
+
+ /** Deal with modes anope _needs_ to know **/
+ pmodule_invis_umode(UMODE_i);
+ pmodule_oper_umode(UMODE_o);
+ pmodule_invite_cmode(CMODE_i);
+ pmodule_secret_cmode(CMODE_s);
+ pmodule_private_cmode(CMODE_p);
+ pmodule_key_mode(CMODE_k);
+ pmodule_limit_mode(CMODE_l);
+
+ moduleAddAnopeCmds();
+ moduleAddIRCDMsgs();
+
+ return MOD_CONT;
+}
diff --git a/src/protocol/viagra.h b/src/protocol/viagra.h
new file mode 100644
index 000000000..1aa687eca
--- /dev/null
+++ b/src/protocol/viagra.h
@@ -0,0 +1,132 @@
+/* Viagra IRCD functions
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+/* User Modes */
+#define UMODE_A 0x00000040 /* Is a Server Administrator. */
+#define UMODE_C 0x00002000 /* Is a Server Co Administrator. */
+#define UMODE_I 0x00008000 /* Stealth mode, makes you beeing hidden at channel. invisible joins/parts. */
+#define UMODE_N 0x00000400 /* Is a Network Administrator. */
+#define UMODE_O 0x00004000 /* Local IRC Operator. */
+#define UMODE_Q 0x00001000 /* Is an Abuse Administrator. */
+#define UMODE_R 0x08000000 /* Cant receive messages from non registered user. */
+#define UMODE_S 0x00000080 /* Is a Network Service. For Services only. */
+#define UMODE_T 0x00000800 /* Is a Technical Administrator. */
+#define UMODE_a 0x00000001 /* Is a Services Administrator. */
+#define UMODE_b 0x00040000 /* Can listen to generic bot warnings. */
+#define UMODE_c 0x00010000 /* See's all connects/disconnects on local server. */
+#define UMODE_d 0x00000100 /* Can listen to debug and channel cration notices. */
+#define UMODE_e 0x00080000 /* Can see client connections/exits on remote servers. */
+#define UMODE_f 0x00100000 /* Listen to flood/spam alerts from server. */
+#define UMODE_g 0x00000200 /* Can read & send to globops, and locops. */
+#define UMODE_h 0x00000002 /* Is a Help Operator. */
+#define UMODE_i 0x00000004 /* Invisible (Not shown in /who and /names searches). */
+#define UMODE_n 0x00020000 /* Can see client nick change notices. */
+#define UMODE_o 0x00000008 /* Global IRC Operator. */
+#define UMODE_r 0x00000010 /* Identifies the nick as being registered. */
+#define UMODE_s 0x00200000 /* Can listen to generic server messages. */
+#define UMODE_w 0x00000020 /* Can listen to wallop messages. */
+#define UMODE_x 0x40000000 /* Gives the user hidden hostname. */
+
+
+/* Channel Modes */
+#define CMODE_i 0x00000001 /* Invite-only allowed. */
+#define CMODE_m 0x00000002 /* Moderated channel, noone can speak and changing nick except users with mode +vho */
+#define CMODE_n 0x00000004 /* No messages from outside channel */
+#define CMODE_p 0x00000008 /* Private channel. */
+#define CMODE_s 0x00000010 /* Secret channel. */
+#define CMODE_t 0x00000020 /* Only channel operators may set the topic */
+#define CMODE_k 0x00000040 /* Needs the channel key to join the channel */
+#define CMODE_l 0x00000080 /* Channel may hold at most <number> of users */
+#define CMODE_R 0x00000100 /* Requires a registered nickname to join the channel. */
+#define CMODE_r 0x00000200 /* Channel is registered. */
+#define CMODE_c 0x00000400 /* No ANSI color can be sent to the channel */
+#define CMODE_M 0x00000800 /* Requires a registered nickname to speak at the channel. */
+#define CMODE_H 0x00001000 /* HelpOps only channel. */
+#define CMODE_O 0x00008000 /* IRCOps only channel. */
+#define CMODE_S 0x00020000 /* Strips all mesages out of colors. */
+#define CMODE_N 0x01000000 /* No nickchanges allowed. */
+#define CMODE_P 0x02000000 /* "Peace mode" No kicks allowed unless by u:lines */
+#define CMODE_x 0x04000000 /* No bold/underlined or reversed text can be sent to the channel */
+
+#define DEFAULT_MLOCK CMODE_n | CMODE_t | CMODE_r
+
+void viagra_set_umode(User * user, int ac, char **av);
+void viagra_cmd_svsnoop(char *server, int set);
+void viagra_cmd_remove_akill(char *user, char *host);
+void viagra_cmd_topic(char *whosets, char *chan, char *whosetit, char *topic, time_t when);
+void viagra_cmd_vhost_off(User * u);
+void viagra_cmd_akill(char *user, char *host, char *who, time_t when,time_t expires, char *reason);
+void viagra_cmd_svskill(char *source, char *user, char *buf);
+void viagra_cmd_svsmode(User * u, int ac, char **av);
+void viagra_cmd_372(char *source, char *msg);
+void viagra_cmd_372_error(char *source);
+void viagra_cmd_375(char *source);
+void viagra_cmd_376(char *source);
+void viagra_cmd_nick(char *nick, char *name, char *modes);
+void viagra_cmd_guest_nick(char *nick, char *user, char *host, char *real, char *modes);
+void viagra_cmd_mode(char *source, char *dest, char *buf);
+void viagra_cmd_bot_nick(char *nick, char *user, char *host, char *real, char *modes);
+void viagra_cmd_kick(char *source, char *chan, char *user, char *buf);
+void viagra_cmd_notice_ops(char *source, char *dest, char *buf);
+void viagra_cmd_notice(char *source, char *dest, char *buf);
+void viagra_cmd_notice2(char *source, char *dest, char *msg);
+void viagra_cmd_privmsg(char *source, char *dest, char *buf);
+void viagra_cmd_privmsg2(char *source, char *dest, char *msg);
+void viagra_cmd_serv_notice(char *source, char *dest, char *msg);
+void viagra_cmd_serv_privmsg(char *source, char *dest, char *msg);
+void viagra_cmd_bot_chan_mode(char *nick, char *chan);
+void viagra_cmd_351(char *source);
+void viagra_cmd_quit(char *source, char *buf);
+void viagra_cmd_pong(char *servname, char *who);
+void viagra_cmd_join(char *user, char *channel, time_t chantime);
+void viagra_cmd_unsqline(char *user);
+void viagra_cmd_invite(char *source, char *chan, char *nick);
+void viagra_cmd_part(char *nick, char *chan, char *buf);
+void viagra_cmd_391(char *source, char *timestr);
+void viagra_cmd_250(char *buf);
+void viagra_cmd_307(char *buf);
+void viagra_cmd_311(char *buf);
+void viagra_cmd_312(char *buf);
+void viagra_cmd_317(char *buf);
+void viagra_cmd_219(char *source, char *letter);
+void viagra_cmd_401(char *source, char *who);
+void viagra_cmd_318(char *source, char *who);
+void viagra_cmd_242(char *buf);
+void viagra_cmd_243(char *buf);
+void viagra_cmd_211(char *buf);
+void viagra_cmd_global(char *source, char *buf);
+void viagra_cmd_global_legacy(char *source, char *fmt);
+void viagra_cmd_sqline(char *mask, char *reason);
+void viagra_cmd_squit(char *servname, char *message);
+void viagra_cmd_svso(char *source, char *nick, char *flag);
+void viagra_cmd_chg_nick(char *oldnick, char *newnick);
+void viagra_cmd_svsnick(char *source, char *guest, time_t when);
+void viagra_cmd_vhost_on(char *nick, char *vIdent, char *vhost);
+void viagra_cmd_connect(int servernum);
+void viagra_cmd_svshold(char *nick);
+void viagra_cmd_release_svshold(char *nick);
+void viagra_cmd_unsgline(char *mask);
+void viagra_cmd_unszline(char *mask);
+void viagra_cmd_szline(char *mask, char *reason, char *whom);
+void viagra_cmd_sgline(char *mask, char *reason);
+void viagra_cmd_unban(char *name, char *nick);
+void viagra_cmd_svsmode_chan(char *name, char *mode, char *nick);
+void viagra_cmd_svid_umode(char *nick, time_t ts);
+void viagra_cmd_nc_change(User * u);
+void viagra_cmd_svid_umode2(User * u, char *ts);
+void viagra_cmd_svid_umode3(User * u, char *ts);
+void viagra_cmd_eob();
+int viagra_flood_mode_check(char *value);
+void viagra_cmd_jupe(char *jserver, char *who, char *reason);
+int viagra_valid_nick(char *nick);
+void viagra_cmd_ctcp(char *source, char *dest, char *buf);
diff --git a/src/rdb.c b/src/rdb.c
new file mode 100644
index 000000000..91e4e8480
--- /dev/null
+++ b/src/rdb.c
@@ -0,0 +1,499 @@
+/* RDB functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+#include "services.h"
+
+/*************************************************************************/
+
+/* Initialize the current RDB database engine */
+int rdb_init()
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_init();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Check if RDB can be used to load/save data */
+int rdb_open()
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_open(); /* db_mysql_open(); */
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Strictly spoken this should close the database. However, it's not too
+ * efficient to close it every time after a write or so, so we just
+ * pretend we closed it while in reality it's still open.
+ */
+int rdb_close()
+{
+
+#ifdef USE_MYSQL
+ return 1; /* db_mysql_close(); */
+#endif
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Quote the string to be used in inclused for the current RDB database */
+char *rdb_quote(char *str)
+{
+#ifdef USE_MYSQL
+ return db_mysql_quote(str);
+#endif
+
+ return sstrdup(str);
+}
+
+/*************************************************************************/
+
+/* Tag a table by setting the 'active' field to 0 for all rows. After an
+ * update, all rows with active still 0 will be deleted; this is done to
+ * easily delete old entries from the database.
+ */
+int rdb_tag_table(char *table)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("UPDATE %s SET active = 0", table);
+#endif
+
+ return 0;
+
+}
+
+/* Be sure to quote all user input in the clause! */
+int rdb_tag_table_where(char *table, char *clause)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("UPDATE %s SET active = 0 WHERE %s", table,
+ clause);
+#endif
+
+ return 0;
+
+}
+
+/*************************************************************************/
+
+/* Empty an entire database table */
+int rdb_empty_table(char *table)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("TRUNCATE TABLE %s", table);
+#endif
+
+ return 0;
+
+}
+
+/*************************************************************************/
+
+/* Clean up a table with 'dirty' records (active = 0) */
+int rdb_clean_table(char *table)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("DELETE FROM %s WHERE active = 0", table);
+#endif
+
+ return 0;
+}
+
+/* Be sure to quote user input in the clause! */
+int rdb_clean_table_where(char *table, char *clause)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("DELETE FROM %s WHERE active = 0 AND (%s)", table,
+ clause);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Delete specific records from a table. The clause is MySQL syntax, and
+ * should be all quoted up nicely in the calling code.
+ */
+int rdb_scrub_table(char *table, char *clause)
+{
+#ifdef USE_MYSQL
+ return db_mysql_try("DELETE FROM %s WHERE %s", table, clause);
+#endif
+
+ return 0;
+
+}
+
+/*************************************************************************/
+
+/* Execute a direct MySQL query. Do NOT forget to quote all user input!
+ * NOTE: this ideally shouldn't be used, but that's probably a phase3 utopia
+ */
+int rdb_direct_query(char *query)
+{
+
+#ifdef USE_MYSQL
+ alog("Direct Query: %s", query);
+ return db_mysql_query(query);
+#endif
+
+ return 0;
+
+}
+
+/*************************************************************************/
+
+/* Update the needed tables when someone changes their display.
+ * The original author didn't even like this (claimed it should be in
+ * mysql.c), and i do agree muchly.
+ */
+int rdb_ns_set_display(char *newnick, char *oldnick)
+{
+ int ret = 0;
+ char *q_newnick;
+ char *q_oldnick;
+
+ q_newnick = rdb_quote(newnick);
+ q_oldnick = rdb_quote(oldnick);
+
+#ifdef USE_MYSQL
+ /* Change the display on NS_CORE */
+ ret =
+ db_mysql_try
+ ("UPDATE anope_ns_core SET display = '%s' WHERE display = '%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the display on NS_ALIAS for all grouped nicks */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_ns_alias SET display='%s' WHERE display='%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the display on ChanServ ACCESS list */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_cs_access SET display='%s' WHERE display='%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the display on ChanServ AKICK list */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_cs_akicks SET creator='%s' WHERE creator='%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the display on MemoServ sent memos -- is it required? */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_ms_info SET sender='%s' WHERE sender='%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the display on MemoServ received memos -- is it required? */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_ms_info SET receiver='%s' WHERE receiver='%s'",
+ q_newnick, q_oldnick);
+
+ /* Change the akills set on the person's nick */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_cs_akicks SET dmask='%s' WHERE dmask='%s' AND flags & %d",
+ q_newnick, q_oldnick, AK_ISNICK);
+
+ /* Change the display on NickServ ACCESS list */
+ if (ret)
+ ret =
+ db_mysql_try
+ ("UPDATE anope_ns_access SET display='%s' WHERE display='%s'",
+ q_newnick, q_oldnick);
+
+ /* No need to update anope_cs_info here as it is updated when we
+ * save the database.
+ *
+ * anope_hs_core is per nick, not per display; a changed display
+ * won't change anything there
+ */
+
+#endif
+
+ free(q_newnick);
+ free(q_oldnick);
+
+ return ret;
+}
+
+/*************************************************************************/
+
+int rdb_save_ns_core(NickCore * nc)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_ns_core(nc);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_ns_alias(NickAlias * na)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_ns_alias(na);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_ns_req(NickRequest * nr)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_ns_req(nr);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_cs_info(ChannelInfo * ci)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_cs_info(ci);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_bs_core(BotInfo * bi)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_bs_core(bi);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_hs_core(HostCore * hc)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_hs_core(hc);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_os_db(unsigned int maxucnt, unsigned int maxutime,
+ SList * ak, SList * sgl, SList * sql, SList * szl)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_os_db(maxusercnt, maxusertime, ak, sgl, sql, szl);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_news(NewsItem * ni)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_news(ni);
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_bs_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_bs_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_hs_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_hs_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_ns_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_ns_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_news(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_news();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_exceptions(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_exceptions();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_cs_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_cs_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_os_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_os_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_load_ns_req_dbase(void)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_load_ns_req_dbase();
+#endif
+
+ return 0;
+}
+
+/*************************************************************************/
+
+#define LOAD_DBASE(num, name, func) {\
+ if (!func) {\
+ alog("RDB unable to load %s database (%d/8) !!!", name, num);\
+ return 0;\
+ }\
+ if (debug)\
+ alog("debug: RDB Loaded %s DataBase (%d/8)", name, num);\
+}
+
+int rdb_load_dbases(void)
+{
+ if (!skeleton) {
+ LOAD_DBASE(1, "NickServ", rdb_load_ns_dbase());
+
+ if (s_HostServ) {
+ LOAD_DBASE(2, "HostServ", rdb_load_hs_dbase());
+ }
+
+ if (s_BotServ) {
+ LOAD_DBASE(3, "BotServ", rdb_load_bs_dbase());
+ }
+
+ LOAD_DBASE(4, "ChanServ", rdb_load_cs_dbase());
+ }
+
+ LOAD_DBASE(5, "OperServ", rdb_load_os_dbase());
+ LOAD_DBASE(6, "News", rdb_load_news());
+ LOAD_DBASE(7, "Exception", rdb_load_exceptions());
+
+ if (PreNickDBName) {
+ LOAD_DBASE(8, "PreNick", rdb_load_ns_req_dbase());
+ } else if (debug) {
+ alog("debug: RDB No need to load PreNickDB (8/8)");
+ }
+
+ alog("RDB: All DataBases loaded.");
+
+ return 0;
+}
+
+/*************************************************************************/
+
+int rdb_save_exceptions(Exception * e)
+{
+
+#ifdef USE_MYSQL
+ return db_mysql_save_exceptions(e);
+#endif
+
+ return 0;
+}
+
+/* EOF */
diff --git a/src/send.c b/src/send.c
new file mode 100644
index 000000000..6d57a9823
--- /dev/null
+++ b/src/send.c
@@ -0,0 +1,341 @@
+/* Routines for sending stuff to the network.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+/**
+ * Send a command to the server. The two forms here are like
+ * printf()/vprintf() and friends.
+ * @param source Orgin of the Message (some times NULL)
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void send_cmd(const char *source, const char *fmt, ...)
+{
+ va_list args;
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsend_cmd(source, fmt, args);
+ va_end(args);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * actually Send a command to the server.
+ * @param source Orgin of the Message (some times NULL)
+ * @param fmt Format of the Message
+ * @param args List of the arguments
+ * @return void
+ */
+void vsend_cmd(const char *source, const char *fmt, va_list args)
+{
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ vsnprintf(buf, BUFSIZE - 1, fmt, 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);
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Send a server notice
+ * @param source Orgin of the Message
+ * @param s Server Struct
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void notice_server(char *source, Server * s, char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+
+ if (NSDefFlags & NI_MSG) {
+ anope_cmd_serv_privmsg(source, s->name, buf);
+ } else {
+ anope_cmd_serv_notice(source, s->name, buf);
+ }
+ va_end(args);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Send a notice to a user
+ * @param source Orgin of the Message
+ * @param u User Struct
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void notice_user(char *source, User * u, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+
+ /* Send privmsg instead of notice if:
+ * - UsePrivmsg is enabled
+ * - The user is not registered and NSDefMsg is enabled
+ * - The user is registered and has set /ns set msg on
+ */
+ if (UsePrivmsg && ((!u->na && (NSDefFlags & NI_MSG))
+ || (u->na && (u->na->nc->flags & NI_MSG)))) {
+ anope_cmd_privmsg2(source, u->nick, buf);
+ } else {
+ anope_cmd_notice2(source, u->nick, buf);
+ }
+ va_end(args);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Send a NULL-terminated array of text as NOTICEs.
+ * @param source Orgin of the Message
+ * @param dest Destination of the Notice
+ * @param text Array of text to send
+ * @return void
+ */
+void notice_list(char *source, char *dest, char **text)
+{
+ while (*text) {
+ /* Have to kludge around an ircII bug here: if a notice includes
+ * no text, it is ignored, so we replace blank lines by lines
+ * with a single space.
+ */
+ if (**text) {
+ anope_cmd_notice2(source, dest, *text);
+ } else {
+ anope_cmd_notice2(source, dest, " ");
+ }
+ text++;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Send a message in the user's selected language to the user using NOTICE.
+ * @param source Orgin of the Message
+ * @param u User Struct
+ * @param int Index of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void notice_lang(char *source, User * dest, int message, ...)
+{
+ va_list args;
+ char buf[4096]; /* because messages can be really big */
+ char *s, *t;
+ const char *fmt;
+
+ if (!dest || !message) {
+ return;
+ }
+ va_start(args, message);
+ fmt = getstring(dest->na, message);
+
+ if (!fmt)
+ return;
+ memset(buf, 0, 4096);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ s = buf;
+ while (*s) {
+ t = s;
+ s += strcspn(s, "\n");
+ if (*s)
+ *s++ = 0;
+ /* Send privmsg instead of notice if:
+ * - UsePrivmsg is enabled
+ * - The user is not registered and NSDefMsg is enabled
+ * - The user is registered and has set /ns set msg on
+ */
+ if (UsePrivmsg && ((!dest->na && (NSDefFlags & NI_MSG))
+ || (dest->na
+ && (dest->na->nc->flags & NI_MSG)))) {
+ anope_cmd_privmsg2(source, dest->nick, *t ? t : " ");
+ } else {
+ anope_cmd_notice2(source, dest->nick, *t ? t : " ");
+ }
+ }
+ va_end(args);
+}
+
+/*************************************************************************/
+
+/**
+ * Like notice_lang(), but replace %S by the source. This is an ugly hack
+ * to simplify letting help messages display the name of the pseudoclient
+ * that's sending them.
+ * @param source Orgin of the Message
+ * @param u User Struct
+ * @param int Index of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void notice_help(char *source, User * dest, int message, ...)
+{
+ va_list args;
+ char buf[4096], buf2[4096], outbuf[BUFSIZE];
+ char *s, *t;
+ const char *fmt;
+
+ if (!dest || !message) {
+ return;
+ }
+ va_start(args, message);
+ fmt = getstring(dest->na, message);
+ if (!fmt)
+ return;
+ /* Some sprintf()'s eat %S or turn it into just S, so change all %S's
+ * into \1\1... we assume this doesn't occur anywhere else in the
+ * string. */
+ strscpy(buf2, fmt, sizeof(buf2));
+ strnrepl(buf2, sizeof(buf2), "%S", "\1\1");
+ vsnprintf(buf, sizeof(buf), buf2, args);
+ s = buf;
+ while (*s) {
+ t = s;
+ s += strcspn(s, "\n");
+ if (*s)
+ *s++ = 0;
+ strscpy(outbuf, t, sizeof(outbuf));
+ strnrepl(outbuf, sizeof(outbuf), "\1\1", source);
+ /* Send privmsg instead of notice if:
+ * - UsePrivmsg is enabled
+ * - The user is not registered and NSDefMsg is enabled
+ * - The user is registered and has set /ns set msg on
+ */
+ if (UsePrivmsg && ((!dest->na && (NSDefFlags & NI_MSG))
+ || (dest->na
+ && (dest->na->nc->flags & NI_MSG)))) {
+ anope_cmd_privmsg2(source, dest->nick, *outbuf ? outbuf : " ");
+ } else {
+ anope_cmd_notice2(source, dest->nick, *outbuf ? outbuf : " ");
+ }
+ }
+ va_end(args);
+}
+
+/*************************************************************************/
+
+/**
+ * Send a NOTICE from the given source to the given nick.
+ * @param source Orgin of the Message
+ * @param dest Destination of the Message
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void notice(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+
+ if (NSDefFlags & NI_MSG) {
+ anope_cmd_privmsg2(source, dest, buf);
+ } else {
+ anope_cmd_notice2(source, dest, buf);
+ }
+ va_end(args);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Send a PRIVMSG from the given source to the given nick.
+ * @param source Orgin of the Message
+ * @param dest Destination of the Message
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void privmsg(char *source, char *dest, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+
+ anope_cmd_privmsg2(source, dest, buf);
+}
+
+/*************************************************************************/
+
+/**
+ * Send out a WALLOP, this is here for legacy only, same day we will pull it out
+ * @param source Orgin of the Message
+ * @param fmt Format of the Message
+ * @param ... any number of parameters
+ * @return void
+ */
+void wallops(char *source, const char *fmt, ...)
+{
+ va_list args;
+ char buf[BUFSIZE];
+ *buf = '\0';
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(buf, BUFSIZE - 1, fmt, args);
+ va_end(args);
+ }
+
+ anope_cmd_global_legacy(source, buf);
+}
diff --git a/src/servers.c b/src/servers.c
new file mode 100644
index 000000000..dc87826ce
--- /dev/null
+++ b/src/servers.c
@@ -0,0 +1,618 @@
+/* Routines to maintain a list of connected servers
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+Server *servlist = NULL;
+Server *me_server = NULL; /* This are we */
+Server *serv_uplink = NULL; /* This is our uplink */
+uint32 uplink_capab;
+char *uplink;
+char *TS6UPLINK;
+char *TS6SID;
+
+/* For first_server / next_server */
+static Server *server_cur;
+
+CapabInfo capab_info[] = {
+ {"NOQUIT", CAPAB_NOQUIT},
+ {"TSMODE", CAPAB_TSMODE},
+ {"UNCONNECT", CAPAB_UNCONNECT},
+ {"NICKIP", CAPAB_NICKIP},
+ {"SSJOIN", CAPAB_NSJOIN},
+ {"ZIP", CAPAB_ZIP},
+ {"BURST", CAPAB_BURST},
+ {"TS5", CAPAB_TS5},
+ {"TS3", CAPAB_TS3},
+ {"DKEY", CAPAB_DKEY},
+ {"PT4", CAPAB_PT4},
+ {"SCS", CAPAB_SCS},
+ {"QS", CAPAB_QS},
+ {"UID", CAPAB_UID},
+ {"KNOCK", CAPAB_KNOCK},
+ {"CLIENT", CAPAB_CLIENT},
+ {"IPV6", CAPAB_IPV6},
+ {"SSJ5", CAPAB_SSJ5},
+ {"SN2", CAPAB_SN2},
+ {"TOK1", CAPAB_TOKEN},
+ {"TOKEN", CAPAB_TOKEN},
+ {"VHOST", CAPAB_VHOST},
+ {"SSJ3", CAPAB_SSJ3},
+ {"SJB64", CAPAB_SJB64},
+ {"CHANMODES", CAPAB_CHANMODE},
+ {"NICKCHARS", CAPAB_NICKCHARS},
+ {NULL, 0}
+};
+
+/*************************************************************************/
+
+/**
+ * Return the first server in the server struct
+ * @param flags Server Flags, see services.h
+ * @return Server Struct
+ */
+Server *first_server(int flags)
+{
+ server_cur = servlist;
+ if (flags > -1) {
+ while (server_cur && (server_cur->flags != flags))
+ server_cur = next_server(flags);
+ }
+ return server_cur;
+}
+
+/*************************************************************************/
+
+/**
+ * Return the next server in the server struct
+ * @param flags Server Flags, see services.h
+ * @return Server Struct
+ */
+Server *next_server(int flags)
+{
+ if (!server_cur)
+ return NULL;
+
+ do {
+ if (server_cur->links) {
+ server_cur = server_cur->links;
+ } else if (server_cur->next) {
+ server_cur = server_cur->next;
+ } else {
+ do {
+ server_cur = server_cur->uplink;
+ if (server_cur && server_cur->next) {
+ server_cur = server_cur->next;
+ break;
+ }
+ } while (server_cur);
+ }
+ } while (server_cur && ((flags > -1) && (server_cur->flags != flags)));
+
+ return server_cur;
+}
+
+/*************************************************************************/
+
+/**
+ * This function makes a new Server structure and links it in the right
+ * places in the linked list if a Server struct to it's uplink if provided.
+ * It can also be NULL to indicate it's the uplink and should be first in
+ * the server list.
+ * @param uplink Server struct
+ * @param name Server Name
+ * @param desc Server Description
+ * @param flags Server Flags, see services.h
+ * @param suid Server Universal ID
+ * @return Server Struct
+ */
+Server *new_server(Server * uplink, const char *name, const char *desc,
+ uint16 flags, char *suid)
+{
+ Server *serv;
+
+ serv = scalloc(sizeof(Server), 1);
+ if (!name)
+ name = "";
+ serv->name = sstrdup(name);
+ serv->desc = sstrdup(desc);
+ serv->flags = flags;
+ serv->uplink = uplink;
+ if (suid) {
+ serv->suid = sstrdup(suid);
+ } else {
+ serv->suid = NULL;
+ }
+ if (ircd->sync)
+ serv->sync = SSYNC_IN_PROGRESS;
+ else
+ serv->sync = SSYNC_UNKNOWN;
+ serv->links = NULL;
+ serv->prev = NULL;
+
+ if (!uplink) {
+ serv->hops = 0;
+ serv->next = servlist;
+ if (servlist)
+ servlist->prev = serv;
+ servlist = serv;
+ } else {
+ serv->hops = uplink->hops + 1;
+ serv->next = uplink->links;
+ if (uplink->links)
+ uplink->links->prev = serv;
+ uplink->links = serv;
+ }
+ /* Check if this is our uplink server */
+ if ((uplink == me_server) && !(flags & SERVER_JUPED))
+ serv_uplink = serv;
+
+ /* Write the StartGlobal (to non-juped servers) */
+ if (GlobalOnCycle && GlobalOnCycleUP && !(flags & SERVER_JUPED))
+ notice_server(s_GlobalNoticer, serv, "%s", GlobalOnCycleUP);
+
+ return serv;
+}
+
+/*************************************************************************/
+
+/**
+ * Remove and free a Server structure. This function is the most complete
+ * remove treatment a server can get, as it first quits all clients which
+ * still pretend to be on this server, then it walks through all connected
+ * servers and disconnects them too. If all mess is cleared, the server
+ * itself will be too.
+ * @param Server struct
+ * @param reason the server quit
+ * @return void
+ */
+static void delete_server(Server * serv, const char *quitreason)
+{
+ Server *s, *snext;
+ User *u, *unext;
+ NickAlias *na;
+
+ if (!serv) {
+ if (debug) {
+ alog("debug: delete_server() called with NULL arg!");
+ }
+ return;
+ }
+
+ if (debug)
+ alog("debug: delete_server() called for %s", serv->name);
+
+ if (ircdcap->noquit || ircdcap->qs) {
+ if ((uplink_capab & ircdcap->noquit)
+ || (uplink_capab & ircdcap->qs)) {
+ u = firstuser();
+ while (u) {
+ unext = nextuser();
+ if (u->server == serv) {
+ if ((na = u->na) && !(na->status & NS_VERBOTEN)
+ && (!(na->nc->flags & NI_SUSPENDED))
+ && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
+ na->last_seen = time(NULL);
+ if (na->last_quit)
+ free(na->last_quit);
+ na->last_quit =
+ (quitreason ? sstrdup(quitreason) : NULL);
+ }
+ if (LimitSessions) {
+ del_session(u->host);
+ }
+ delete_user(u);
+ }
+ u = unext;
+ }
+ if (debug)
+ alog("debug: delete_server() cleared all users");
+ }
+ }
+
+ s = serv->links;
+ while (s) {
+ snext = s->next;
+ delete_server(s, quitreason);
+ s = snext;
+ }
+
+ if (debug)
+ alog("debug: delete_server() cleared all servers");
+
+ free(serv->name);
+ free(serv->desc);
+ if (serv->prev)
+ serv->prev->next = serv->next;
+ if (serv->next)
+ serv->next->prev = serv->prev;
+ if (serv->uplink->links == serv)
+ serv->uplink->links = serv->next;
+
+ if (debug)
+ alog("debug: delete_server() completed");
+}
+
+/*************************************************************************/
+
+/**
+ * Find a server by name, returns NULL if not found
+ * @param s Server struct
+ * @param name Server Name
+ * @return Server struct
+ */
+Server *findserver(Server * s, const char *name)
+{
+ Server *sl;
+
+ if (!name || !*name) {
+ return NULL;
+ }
+
+ if (debug >= 3) {
+ alog("debug: findserver(%p)", name);
+ }
+ while (s && (stricmp(s->name, name) != 0)) {
+ if (s->links) {
+ sl = findserver(s->links, name);
+ if (sl) {
+ s = sl;
+ } else {
+ s = s->next;
+ }
+ } else {
+ s = s->next;
+ }
+ }
+ if (debug >= 3) {
+ alog("debug: findserver(%s) -> %p", name, (void *) s);
+ }
+ return s;
+}
+
+/*************************************************************************/
+
+/**
+ * Find a server by UID, returns NULL if not found
+ * @param s Server struct
+ * @param name Server Name
+ * @return Server struct
+ */
+Server *findserver_uid(Server * s, const char *name)
+{
+ Server *sl;
+
+ if (!name || !*name) {
+ return NULL;
+ }
+
+ if (debug >= 3) {
+ alog("debug: findserver_uid(%p)", name);
+ }
+ while (s && s->suid && (stricmp(s->suid, name) != 0)) {
+ if (s->links) {
+ sl = findserver_uid(s->links, name);
+ if (sl) {
+ s = sl;
+ } else {
+ s = s->next;
+ }
+ } else {
+ s = s->next;
+ }
+ }
+ if (debug >= 3) {
+ alog("debug: findserver_uid(%s) -> %p", name, (void *) s);
+ }
+ return s;
+}
+
+/*************************************************************************/
+
+/**
+ * Find if the server is synced with the network
+ * @param s Server struct
+ * @param name Server Name
+ * @return Not Synced returns -1, Synced returns 1, Error returns 0
+ */
+int anope_check_sync(const char *name)
+{
+ Server *s;
+ s = findserver(servlist, name);
+
+ if (!s)
+ return 0;
+
+ if (is_sync(s))
+ return 1;
+ else
+ return -1;
+}
+
+/*************************************************************************/
+
+/**
+ * Handle adding the server to the Server struct
+ * @param source Name of the uplink if any
+ * @param servername Name of the server being linked
+ * @param hops Number of hops to reach this server
+ * @param descript Description of the server
+ * @param numeric Server Numberic/SUID
+ * @return void
+ */
+void do_server(const char *source, char *servername, char *hops,
+ char *descript, char *numeric)
+{
+ Server *s;
+
+ if (debug) {
+ if (!*source) {
+ alog("debug: Server introduced (%s)", servername);
+ } else {
+ alog("debug: Server introduced (%s) from %s", servername,
+ source);
+ }
+ }
+
+ if (source[0] == '\0')
+ s = me_server;
+ else
+ s = findserver(servlist, source);
+
+ new_server(s, servername, descript, 0, numeric);
+ send_event(EVENT_SERVER_CONNECT, 1, servername);
+}
+
+/*************************************************************************/
+
+/**
+ * Handle removing the server from the Server struct
+ * @param source Name of the server leaving
+ * @param ac Number of arguments in av
+ * @param av Agruments as part of the SQUIT
+ * @return void
+ */
+void do_squit(const char *source, int ac, char **av)
+{
+ char buf[BUFSIZE];
+ Server *s;
+
+ if (UseTS6 && ircd->ts6) {
+ s = findserver_uid(servlist, av[0]);
+ if (!s) {
+ s = findserver(servlist, av[0]);
+ }
+ } else {
+ s = findserver(servlist, av[0]);
+ }
+ if (!s) {
+ alog("SQUIT for nonexistent server (%s)!!", av[0]);
+ return;
+ }
+ send_event(EVENT_SERVER_SQUIT, 1, s->name);
+
+ /* If this is a juped server, send a nice global to inform the online
+ * opers that we received it.
+ */
+ if (s->flags & SERVER_JUPED) {
+ snprintf(buf, BUFSIZE, "Received SQUIT for juped server %s",
+ s->name);
+ anope_cmd_global(s_OperServ, buf);
+ }
+
+ snprintf(buf, sizeof(buf), "%s %s", s->name,
+ (s->uplink ? s->uplink->name : ""));
+
+ if (ircdcap->unconnect) {
+ if ((s->uplink == me_server)
+ && (uplink_capab & ircdcap->unconnect)) {
+ if (debug) {
+ alog("debug: Sending UNCONNECT SQUIT for %s", s->name);
+ }
+ /* need to fix */
+ anope_cmd_squit(s->name, buf);
+ }
+ }
+
+ delete_server(s, buf);
+}
+
+/*************************************************************************/
+
+/**
+ * Handle parsing the CAPAB/PROTOCTL messages
+ * @param ac Number of arguments in av
+ * @param av Agruments
+ * @return void
+ */
+void capab_parse(int ac, char **av)
+{
+ int i;
+ int j;
+ char *s, *tmp;
+
+ char *temp;
+
+ for (i = 0; i < ac; i++) {
+ temp = av[i];
+
+ s = myStrGetToken(temp, '=', 0);
+ tmp = myStrGetTokenRemainder(temp, '=', 1);
+
+ if (!s)
+ continue;
+
+ for (j = 0; capab_info[j].token; j++) {
+ if (stricmp(s, capab_info[j].token) == 0)
+ uplink_capab |= capab_info[j].flag;
+ /* Special cases */
+ if ((stricmp(s, "NICKIP") == 0) && !ircd->nickip)
+ ircd->nickip = 1;
+ if ((stricmp(s, "CHANMODES") == 0) && tmp)
+ ircd->chanmodes = sstrdup(tmp);
+ if ((stricmp(s, "NICKCHARS") == 0) && tmp)
+ ircd->nickchars = sstrdup(tmp);
+ }
+
+ if (s)
+ free(s);
+ if (tmp)
+ free(tmp);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Search the uline servers array to find out if the server that just set the
+ * mode is in our uline list
+ * @param server Server Setting the mode
+ * @return int 0 if not found, 1 if found
+ */
+int is_ulined(char *server)
+{
+ int j;
+
+ for (j = 0; j < NumUlines; j++) {
+ if (stricmp(Ulines[j], server) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * See if the current server is synced, or has an unknown sync state
+ * (in which case we pretend it is always synced)
+ * @param server Server of which we want to know the state
+ * @return int 0 if not synced, 1 if synced
+ */
+int is_sync(Server * server)
+{
+ if ((server->sync == SSYNC_DONE) || (server->sync == SSYNC_UNKNOWN))
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Finish the syncing process for this server and (optionally) for all
+ * it's leaves as well
+ * @param serv Server to finish syncing
+ * @param sync_links Should all leaves be synced as well? (1: yes, 0: no)
+ * @return void
+ */
+void finish_sync(Server * serv, int sync_links)
+{
+ Server *s;
+
+ if (!serv || is_sync(serv))
+ return;
+
+ /* Mark each server as in sync */
+ s = serv;
+ do {
+ if (!is_sync(s)) {
+ if (debug)
+ alog("debug: Finishing sync for server %s", s->name);
+
+ s->sync = SSYNC_DONE;
+ }
+
+ if (!sync_links)
+ break;
+
+ if (s->links) {
+ s = s->links;
+ } else if (s->next) {
+ s = s->next;
+ } else {
+ do {
+ s = s->uplink;
+ if (s == serv)
+ s = NULL;
+ if (s == me_server)
+ s = NULL;
+ } while (s && !(s->next));
+ if (s)
+ s = s->next;
+ }
+ } while (s);
+
+ /* Do some general stuff which should only be done once */
+ restore_unsynced_topics();
+ alog("Server %s is done syncing", serv->name);
+}
+
+/*******************************************************************/
+
+/* TS6 UID generator common code.
+ *
+ * Derived from atheme-services, uid.c (hg 2954:116d46894b4c).
+ * -nenolod
+ */
+static int ts6_uid_initted = 0;
+static char ts6_new_uid[10]; /* allow for \0 */
+static unsigned int ts6_uid_index = 9; /* last slot in uid buf */
+
+void ts6_uid_init(void)
+{
+ unsigned int i;
+ char buf[BUFSIZE];
+
+ /* check just in case... you can never be too safe. */
+ if (TS6SID != NULL) {
+ snprintf(ts6_new_uid, 10, "%sAAAAAA", TS6SID);
+ ts6_uid_initted = 1;
+ } else {
+ alog("warning: no TS6SID specified, disabling TS6 support.");
+ UseTS6 = 0;
+
+ return;
+ }
+}
+
+void ts6_uid_increment(unsigned int slot)
+{
+ if (slot != strlen(TS6SID)) {
+ if (ts6_new_uid[slot] == 'Z')
+ ts6_new_uid[slot] = '0';
+ else if (ts6_new_uid[slot] == '9') {
+ ts6_new_uid[slot] = 'A';
+ ts6_uid_increment(slot - 1);
+ } else
+ ts6_new_uid[slot]++;
+ } else {
+ if (ts6_new_uid[slot] == 'Z')
+ for (slot = 3; slot < 9; slot++)
+ ts6_new_uid[slot] = 'A';
+ else
+ ts6_new_uid[slot]++;
+ }
+}
+
+char *ts6_uid_retrieve(void)
+{
+ if (ts6_uid_initted != 1)
+ ts6_uid_init();
+
+ ts6_uid_increment(ts6_uid_index - 1);
+
+ return ts6_new_uid;
+}
+
+/* EOF */
diff --git a/src/sessions.c b/src/sessions.c
new file mode 100644
index 000000000..05e90a76d
--- /dev/null
+++ b/src/sessions.c
@@ -0,0 +1,873 @@
+/* Session Limiting functions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+/*************************************************************************/
+
+/* SESSION LIMITING
+ *
+ * The basic idea of session limiting is to prevent one host from having more
+ * than a specified number of sessions (client connections/clones) on the
+ * network at any one time. To do this we have a list of sessions and
+ * exceptions. Each session structure records information about a single host,
+ * including how many clients (sessions) that host has on the network. When a
+ * host reaches it's session limit, no more clients from that host will be
+ * allowed to connect.
+ *
+ * When a client connects to the network, we check to see if their host has
+ * reached the default session limit per host, and thus whether it is allowed
+ * any more. If it has reached the limit, we kill the connecting client; all
+ * the other clients are left alone. Otherwise we simply increment the counter
+ * within the session structure. When a client disconnects, we decrement the
+ * counter. When the counter reaches 0, we free the session.
+ *
+ * Exceptions allow one to specify custom session limits for a specific host
+ * or a range thereof. The first exception that the host matches is the one
+ * used.
+ *
+ * "Session Limiting" is likely to slow down services when there are frequent
+ * client connects and disconnects. The size of the exception list can also
+ * play a large role in this performance decrease. It is therefore recommened
+ * that you keep the number of exceptions to a minimum. A very simple hashing
+ * method is currently used to store the list of sessions. I'm sure there is
+ * room for improvement and optimisation of this, along with the storage of
+ * exceptions. Comments and suggestions are more than welcome!
+ *
+ * -TheShadow (02 April 1999)
+ */
+
+/*************************************************************************/
+
+/* I'm sure there is a better way to hash the list of hosts for which we are
+ * storing session information. This should be sufficient for the mean time.
+ * -TheShadow */
+
+#define HASH(host) (((host)[0]&31)<<5 | ((host)[1]&31))
+
+Session *sessionlist[1024];
+int32 nsessions = 0;
+
+Exception *exceptions = NULL;
+int16 nexceptions = 0;
+
+/*************************************************************************/
+/****************************** Statistics *******************************/
+/*************************************************************************/
+
+void get_session_stats(long *nrec, long *memuse)
+{
+ Session *session;
+ long mem;
+ int i;
+
+ mem = sizeof(Session) * nsessions;
+ for (i = 0; i < 1024; i++) {
+ for (session = sessionlist[i]; session; session = session->next) {
+ mem += strlen(session->host) + 1;
+ }
+ }
+
+ *nrec = nsessions;
+ *memuse = mem;
+}
+
+void get_exception_stats(long *nrec, long *memuse)
+{
+ long mem;
+ int i;
+
+ mem = sizeof(Exception) * nexceptions;
+ for (i = 0; i < nexceptions; i++) {
+ mem += strlen(exceptions[i].mask) + 1;
+ mem += strlen(exceptions[i].reason) + 1;
+ }
+ *nrec = nexceptions;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+/************************* Session List Display **************************/
+/*************************************************************************/
+
+/* Syntax: SESSION LIST threshold
+ * Lists all sessions with atleast threshold clients.
+ * The threshold value must be greater than 1. This is to prevent
+ * accidental listing of the large number of single client sessions.
+ *
+ * Syntax: SESSION VIEW host
+ * Displays detailed session information about the supplied host.
+ */
+
+int do_session(User * u)
+{
+ Session *session;
+ Exception *exception;
+ char *cmd = strtok(NULL, " ");
+ char *param1 = strtok(NULL, " ");
+ int mincount;
+ int i;
+
+ if (!LimitSessions) {
+ notice_lang(s_OperServ, u, OPER_SESSION_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!cmd)
+ cmd = "";
+
+ if (stricmp(cmd, "LIST") == 0) {
+ if (!param1) {
+ syntax_error(s_OperServ, u, "SESSION",
+ OPER_SESSION_LIST_SYNTAX);
+
+ } else if ((mincount = atoi(param1)) <= 1) {
+ notice_lang(s_OperServ, u, OPER_SESSION_INVALID_THRESHOLD);
+
+ } else {
+ notice_lang(s_OperServ, u, OPER_SESSION_LIST_HEADER, mincount);
+ notice_lang(s_OperServ, u, OPER_SESSION_LIST_COLHEAD);
+ for (i = 0; i < 1024; i++) {
+ for (session = sessionlist[i]; session;
+ session = session->next) {
+ if (session->count >= mincount)
+ notice_lang(s_OperServ, u,
+ OPER_SESSION_LIST_FORMAT,
+ session->count, session->host);
+ }
+ }
+ }
+ } else if (stricmp(cmd, "VIEW") == 0) {
+ if (!param1) {
+ syntax_error(s_OperServ, u, "SESSION",
+ OPER_SESSION_VIEW_SYNTAX);
+
+ } else {
+ session = findsession(param1);
+ if (!session) {
+ notice_lang(s_OperServ, u, OPER_SESSION_NOT_FOUND, param1);
+ } else {
+ exception = find_host_exception(param1);
+
+ notice_lang(s_OperServ, u, OPER_SESSION_VIEW_FORMAT,
+ param1, session->count,
+ exception ? exception->
+ limit : DefSessionLimit);
+ }
+ }
+
+ } else {
+ syntax_error(s_OperServ, u, "SESSION", OPER_SESSION_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
+/********************* Internal Session Functions ************************/
+/*************************************************************************/
+
+Session *findsession(const char *host)
+{
+ Session *session;
+ int i;
+
+ if (!host) {
+ return NULL;
+ }
+
+ for (i = 0; i < 1024; i++) {
+ for (session = sessionlist[i]; session; session = session->next) {
+ if (stricmp(host, session->host) == 0) {
+ return session;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Attempt to add a host to the session list. If the addition of the new host
+ * causes the the session limit to be exceeded, kill the connecting user.
+ * Returns 1 if the host was added or 0 if the user was killed.
+ */
+
+int add_session(char *nick, char *host, char *hostip)
+{
+ Session *session, **list;
+ Exception *exception;
+ int sessionlimit = 0;
+
+ session = findsession(host);
+
+ if (session) {
+ exception = find_hostip_exception(host, hostip);
+
+ if (checkDefCon(DEFCON_REDUCE_SESSION)) {
+ sessionlimit =
+ exception ? exception->limit : DefConSessionLimit;
+ } else {
+ sessionlimit = exception ? exception->limit : DefSessionLimit;
+ }
+
+ if (sessionlimit != 0 && session->count >= sessionlimit) {
+ if (SessionLimitExceeded)
+ notice(s_OperServ, nick, SessionLimitExceeded, host);
+ if (SessionLimitDetailsLoc)
+ notice(s_OperServ, nick, "%s", SessionLimitDetailsLoc);
+
+ /* We don't use kill_user() because a user stucture has not yet
+ * been created. Simply kill the user. -TheShadow
+ */
+ kill_user(s_OperServ, nick, "Session limit exceeded");
+
+ session->hits++;
+ if (MaxSessionKill && session->hits >= MaxSessionKill) {
+ char akillmask[BUFSIZE];
+ snprintf(akillmask, sizeof(akillmask), "*@%s", host);
+ add_akill(NULL, akillmask, s_OperServ,
+ time(NULL) + SessionAutoKillExpiry,
+ "Session limit exceeded");
+ anope_cmd_global(s_OperServ,
+ "Added a temporary AKILL for \2%s\2 due to excessive connections",
+ akillmask);
+ }
+ return 0;
+ } else {
+ session->count++;
+ return 1;
+ }
+ }
+
+ nsessions++;
+ session = scalloc(sizeof(Session), 1);
+ session->host = sstrdup(host);
+ list = &sessionlist[HASH(session->host)];
+ session->next = *list;
+ if (*list)
+ (*list)->prev = session;
+ *list = session;
+ session->count = 1;
+
+ return 1;
+}
+
+void del_session(const char *host)
+{
+ Session *session;
+
+ if (!LimitSessions) {
+ if (debug) {
+ alog("debug: del_session called when LimitSessions is disabled");
+ }
+ return;
+ }
+
+ if (!host || !*host) {
+ if (debug) {
+ alog("debug: del_session called with NULL values");
+ }
+ return;
+ }
+
+ if (debug >= 2)
+ alog("debug: del_session() called");
+
+ session = findsession(host);
+
+ if (!session) {
+ if (debug) {
+ anope_cmd_global(s_OperServ,
+ "WARNING: Tried to delete non-existant session: \2%s",
+ host);
+ alog("session: Tried to delete non-existant session: %s",
+ host);
+ }
+ return;
+ }
+
+ if (session->count > 1) {
+ session->count--;
+ return;
+ }
+
+ if (session->prev)
+ session->prev->next = session->next;
+ else
+ sessionlist[HASH(session->host)] = session->next;
+ if (session->next)
+ session->next->prev = session->prev;
+
+ if (debug >= 2)
+ alog("debug: del_session(): free session structure");
+
+ free(session->host);
+ free(session);
+
+ nsessions--;
+
+ if (debug >= 2)
+ alog("debug: del_session() done");
+}
+
+
+/*************************************************************************/
+/********************** Internal Exception Functions *********************/
+/*************************************************************************/
+
+void expire_exceptions(void)
+{
+ int i;
+ time_t now = time(NULL);
+
+ for (i = 0; i < nexceptions; i++) {
+ if (exceptions[i].expires == 0 || exceptions[i].expires > now)
+ continue;
+ if (WallExceptionExpire)
+ anope_cmd_global(s_OperServ,
+ "Session limit exception for %s has expired.",
+ exceptions[i].mask);
+ free(exceptions[i].mask);
+ free(exceptions[i].reason);
+ nexceptions--;
+ memmove(exceptions + i, exceptions + i + 1,
+ sizeof(Exception) * (nexceptions - i));
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+ i--;
+ }
+}
+
+/* Find the first exception this host matches and return it. */
+Exception *find_host_exception(const char *host)
+{
+ int i;
+
+ for (i = 0; i < nexceptions; i++) {
+ if ((match_wild_nocase(exceptions[i].mask, host))) {
+ return &exceptions[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Same as find_host_exception() except
+ * this tries to find the exception by IP also. */
+Exception *find_hostip_exception(const char *host, const char *hostip)
+{
+ int i;
+
+ for (i = 0; i < nexceptions; i++) {
+ if ((match_wild_nocase(exceptions[i].mask, host))
+ || ((ircd->nickip && hostip)
+ && (match_wild_nocase(exceptions[i].mask, hostip)))) {
+ return &exceptions[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*************************************************************************/
+/*********************** Exception Load/Save *****************************/
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ if (!forceload) \
+ fatal("Read error on %s", ExceptionDBName); \
+ nexceptions = i; \
+ break; \
+ } \
+} while (0)
+
+void load_exceptions()
+{
+ dbFILE *f;
+ int i;
+ uint16 n;
+ uint16 tmp16;
+ uint32 tmp32;
+
+ if (!
+ (f = open_db(s_OperServ, ExceptionDBName, "r", EXCEPTION_VERSION)))
+ return;
+ switch (i = get_file_version(f)) {
+ case 9:
+ case 8:
+ case 7:
+ SAFE(read_int16(&n, f));
+ nexceptions = n;
+ exceptions = scalloc(sizeof(Exception) * nexceptions, 1);
+ if (!nexceptions) {
+ close_db(f);
+ return;
+ }
+ for (i = 0; i < nexceptions; i++) {
+ SAFE(read_string(&exceptions[i].mask, f));
+ SAFE(read_int16(&tmp16, f));
+ exceptions[i].limit = tmp16;
+ SAFE(read_buffer(exceptions[i].who, f));
+ SAFE(read_string(&exceptions[i].reason, f));
+ SAFE(read_int32(&tmp32, f));
+ exceptions[i].time = tmp32;
+ SAFE(read_int32(&tmp32, f));
+ exceptions[i].expires = tmp32;
+ }
+ break;
+
+ default:
+ fatal("Unsupported version (%d) on %s", i, ExceptionDBName);
+ } /* switch (ver) */
+
+ close_db(f);
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ restore_db(f); \
+ log_perror("Write error on %s", ExceptionDBName); \
+ if (time(NULL) - lastwarn > WarningTimeout) { \
+ anope_cmd_global(NULL, "Write error on %s: %s", ExceptionDBName, \
+ strerror(errno)); \
+ lastwarn = time(NULL); \
+ } \
+ return; \
+ } \
+} while (0)
+
+void save_exceptions()
+{
+ dbFILE *f;
+ int i;
+ static time_t lastwarn = 0;
+
+ if (!
+ (f = open_db(s_OperServ, ExceptionDBName, "w", EXCEPTION_VERSION)))
+ return;
+ SAFE(write_int16(nexceptions, f));
+ for (i = 0; i < nexceptions; i++) {
+ SAFE(write_string(exceptions[i].mask, f));
+ SAFE(write_int16(exceptions[i].limit, f));
+ SAFE(write_buffer(exceptions[i].who, f));
+ SAFE(write_string(exceptions[i].reason, f));
+ SAFE(write_int32(exceptions[i].time, f));
+ SAFE(write_int32(exceptions[i].expires, f));
+ }
+ close_db(f);
+}
+
+#undef SAFE
+
+/*************************************************************************/
+
+void save_rdb_exceptions()
+{
+#ifdef USE_RDB
+ int i;
+ Exception *e;
+
+ if (!rdb_open())
+ return;
+ if (rdb_tag_table("anope_os_exceptions") == 0) {
+ alog("Unable to tag table 'anope_os_exceptions' - Exception RDB save failed.");
+ return;
+ }
+ for (i = 0; i < nexceptions; i++) {
+ e = &exceptions[i];
+ if (rdb_save_exceptions(e) == 0) {
+ alog("Unable to save Exception '%s' - Exception RDB save failed.", e->mask);
+ return;
+ }
+ }
+ if (rdb_clean_table("anope_os_exceptions") == 0) {
+ alog("Unable to clean table 'anope_os_exceptions' - Exception RDB save failed.");
+ return;
+ }
+ rdb_close();
+#endif
+}
+
+/*************************************************************************/
+/************************ Exception Manipulation *************************/
+/*************************************************************************/
+
+int exception_add(User * u, const char *mask, const int limit,
+ const char *reason, const char *who,
+ const time_t expires)
+{
+ int i;
+
+ /* Check if an exception already exists for this mask */
+ for (i = 0; i < nexceptions; i++) {
+ if (!stricmp(mask, exceptions[i].mask)) {
+ if (exceptions[i].limit != limit) {
+ exceptions[i].limit = limit;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_CHANGED,
+ mask, exceptions[i].limit);
+ return -2;
+ } else {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_EXISTS,
+ mask);
+ return -1;
+ }
+ }
+ }
+
+ nexceptions++;
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+
+ exceptions[nexceptions - 1].mask = sstrdup(mask);
+ exceptions[nexceptions - 1].limit = limit;
+ exceptions[nexceptions - 1].reason = sstrdup(reason);
+ exceptions[nexceptions - 1].time = time(NULL);
+ strscpy(exceptions[nexceptions - 1].who, who, NICKMAX);
+ exceptions[nexceptions - 1].expires = expires;
+ exceptions[nexceptions - 1].num = nexceptions - 1;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+static int exception_del(const int index)
+{
+ if (index < 0 || index >= nexceptions)
+ return 0;
+
+ free(exceptions[index].mask);
+ free(exceptions[index].reason);
+ nexceptions--;
+ memmove(exceptions + index, exceptions + index + 1,
+ sizeof(Exception) * (nexceptions - index));
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+
+ return 1;
+}
+
+/* We use the "num" property to keep track of the position of each exception
+ * when deleting using ranges. This is because an exception's position changes
+ * as others are deleted. The positions will be recalculated once the process
+ * is complete. -TheShadow
+ */
+
+static int exception_del_callback(User * u, int num, va_list args)
+{
+ int i;
+ int *last = va_arg(args, int *);
+
+ *last = num;
+ for (i = 0; i < nexceptions; i++) {
+ if (num - 1 == exceptions[i].num)
+ break;
+ }
+ if (i < nexceptions)
+ return exception_del(i);
+ else
+ return 0;
+}
+
+static int exception_list(User * u, const int index, int *sent_header)
+{
+ if (index < 0 || index >= nexceptions)
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_COLHEAD);
+ *sent_header = 1;
+ }
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_FORMAT, index + 1,
+ exceptions[index].limit, exceptions[index].mask);
+ return 1;
+}
+
+static int exception_list_callback(User * u, int num, va_list args)
+{
+ int *sent_header = va_arg(args, int *);
+
+ return exception_list(u, num - 1, sent_header);
+}
+
+static int exception_view(User * u, const int index, int *sent_header)
+{
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+ time_t t = time(NULL);
+
+ if (index < 0 || index >= nexceptions)
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ tm = *localtime(exceptions[index].time ? &exceptions[index].time : &t);
+ strftime_lang(timebuf, sizeof(timebuf),
+ u, STRFTIME_SHORT_DATE_FORMAT, &tm);
+
+ expire_left(u->na, expirebuf, sizeof(expirebuf),
+ exceptions[index].expires);
+
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_VIEW_FORMAT,
+ index + 1, exceptions[index].mask,
+ *exceptions[index].who ?
+ exceptions[index].who : "<unknown>",
+ timebuf, expirebuf, exceptions[index].limit,
+ exceptions[index].reason);
+ return 1;
+}
+
+static int exception_view_callback(User * u, int num, va_list args)
+{
+ int *sent_header = va_arg(args, int *);
+
+ return exception_view(u, num - 1, sent_header);
+}
+
+/*************************************************************************/
+
+/* Syntax: EXCEPTION ADD [+expiry] mask limit reason
+ * Adds mask to the exception list with limit as the maximum session
+ * limit and +expiry as an optional expiry time.
+ *
+ * Syntax: EXCEPTION DEL mask
+ * Deletes the first exception that matches mask exactly.
+ *
+ * Syntax: EXCEPTION LIST [mask]
+ * Lists all exceptions or those matching mask.
+ *
+ * Syntax: EXCEPTION VIEW [mask]
+ * Displays detailed information about each exception or those matching
+ * mask.
+ *
+ * Syntax: EXCEPTION MOVE num position
+ * Moves the exception at position num to position.
+ */
+
+int do_exception(User * u)
+{
+ char *cmd = strtok(NULL, " ");
+ char *mask, *reason, *expiry, *limitstr;
+ int limit, expires;
+ int i;
+ int x;
+
+ if (!LimitSessions) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DISABLED);
+ return MOD_CONT;
+ }
+
+ if (!cmd)
+ cmd = "";
+
+ if (stricmp(cmd, "ADD") == 0) {
+ if (nexceptions >= 32767) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_TOO_MANY);
+ return MOD_CONT;
+ }
+
+ mask = strtok(NULL, " ");
+ if (mask && *mask == '+') {
+ expiry = mask;
+ mask = strtok(NULL, " ");
+ } else {
+ expiry = NULL;
+ }
+ limitstr = strtok(NULL, " ");
+ reason = strtok(NULL, "");
+
+ if (!reason) {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_ADD_SYNTAX);
+ return MOD_CONT;
+ }
+
+ expires = expiry ? dotime(expiry) : ExceptionExpiry;
+ if (expires < 0) {
+ notice_lang(s_OperServ, u, BAD_EXPIRY_TIME);
+ return MOD_CONT;
+ } else if (expires > 0) {
+ expires += time(NULL);
+ }
+
+ limit = (limitstr && isdigit(*limitstr)) ? atoi(limitstr) : -1;
+
+ if (limit < 0 || limit > MaxSessionLimit) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_INVALID_LIMIT,
+ MaxSessionLimit);
+ return MOD_CONT;
+
+ } else {
+ if (strchr(mask, '!') || strchr(mask, '@')) {
+ notice_lang(s_OperServ, u,
+ OPER_EXCEPTION_INVALID_HOSTMASK);
+ return MOD_CONT;
+ }
+
+ x = exception_add(u, mask, limit, reason, u->nick, expires);
+
+ if (x == 1) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask,
+ limit);
+ }
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ }
+ } else if (stricmp(cmd, "DEL") == 0) {
+ mask = strtok(NULL, " ");
+
+ if (!mask) {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_DEL_SYNTAX);
+ return MOD_CONT;
+ }
+
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ int count, deleted, last = -1;
+ deleted =
+ process_numlist(mask, &count, exception_del_callback, u,
+ &last);
+ if (!deleted) {
+ if (count == 1) {
+ notice_lang(s_OperServ, u,
+ OPER_EXCEPTION_NO_SUCH_ENTRY, last);
+ } else {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_SEVERAL,
+ deleted);
+ }
+ } else {
+ int deleted = 0;
+
+ for (i = 0; i < nexceptions; i++) {
+ if (stricmp(mask, exceptions[i].mask) == 0) {
+ exception_del(i);
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED,
+ mask);
+ deleted = 1;
+ break;
+ }
+ }
+ if (!deleted && i == nexceptions)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask);
+ }
+
+ /* Renumber the exception list. I don't believe in having holes in
+ * lists - it makes code more complex, harder to debug and we end up
+ * with huge index numbers. Imho, fixed numbering is only beneficial
+ * when one doesn't have range capable manipulation. -TheShadow */
+
+ for (i = 0; i < nexceptions; i++)
+ exceptions[i].num = i;
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+
+ } else if (stricmp(cmd, "MOVE") == 0) {
+ Exception *exception;
+ char *n1str = strtok(NULL, " "); /* From position */
+ char *n2str = strtok(NULL, " "); /* To position */
+ int n1, n2;
+
+ if (!n2str) {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_MOVE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ n1 = atoi(n1str) - 1;
+ n2 = atoi(n2str) - 1;
+
+ if ((n1 >= 0 && n1 < nexceptions) && (n2 >= 0 && n2 < nexceptions)
+ && (n1 != n2)) {
+ exception = scalloc(sizeof(Exception), 1);
+ memcpy(exception, &exceptions[n1], sizeof(Exception));
+
+ if (n1 < n2) {
+ /* Shift upwards */
+ memmove(&exceptions[n1], &exceptions[n1 + 1],
+ sizeof(Exception) * (n2 - n1));
+ memmove(&exceptions[n2], exception, sizeof(Exception));
+ } else {
+ /* Shift downwards */
+ memmove(&exceptions[n2 + 1], &exceptions[n2],
+ sizeof(Exception) * (n1 - n2));
+ memmove(&exceptions[n2], exception, sizeof(Exception));
+ }
+
+ free(exception);
+
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_MOVED,
+ exceptions[n1].mask, n1 + 1, n2 + 1);
+
+ /* Renumber the exception list. See the DEL block above for why. */
+ for (i = 0; i < nexceptions; i++)
+ exceptions[i].num = i;
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_MOVE_SYNTAX);
+ }
+ } else if (stricmp(cmd, "LIST") == 0) {
+ int sent_header = 0;
+ expire_exceptions();
+ mask = strtok(NULL, " ");
+ if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, exception_list_callback, u,
+ &sent_header);
+ } else {
+ for (i = 0; i < nexceptions; i++) {
+ if (!mask || match_wild_nocase(mask, exceptions[i].mask))
+ exception_list(u, i, &sent_header);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
+
+ } else if (stricmp(cmd, "VIEW") == 0) {
+ int sent_header = 0;
+ expire_exceptions();
+ mask = strtok(NULL, " ");
+ if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, exception_view_callback, u,
+ &sent_header);
+ } else {
+ for (i = 0; i < nexceptions; i++) {
+ if (!mask || match_wild_nocase(mask, exceptions[i].mask))
+ exception_view(u, i, &sent_header);
+ }
+ }
+ if (!sent_header)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
+
+ } else {
+ syntax_error(s_OperServ, u, "EXCEPTION", OPER_EXCEPTION_SYNTAX);
+ }
+ return MOD_CONT;
+}
+
+/*************************************************************************/
diff --git a/src/slist.c b/src/slist.c
new file mode 100644
index 000000000..099a59328
--- /dev/null
+++ b/src/slist.c
@@ -0,0 +1,395 @@
+/* Services list handler implementation.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "slist.h"
+
+static SListOpts slist_defopts = { 0, NULL, NULL, NULL };
+
+/*************************************************************************/
+
+/**
+ * Adds a pointer to the list. Returns the index of the new item.
+ * Returns -2 if there are too many items in the list, -3 if the
+ * item already exists when the flags of the list contain SLISTF_NODUP.
+ * @param slist Slist Struct
+ * @param item Item being added
+ * @return int
+ */
+int slist_add(SList * slist, void *item)
+{
+ if (slist->limit != 0 && slist->count >= slist->limit)
+ return -2;
+ if (slist->opts && (slist->opts->flags & SLISTF_NODUP)
+ && slist_indexof(slist, item) != -1)
+ return -3;
+ if (slist->capacity == slist->count)
+ slist_setcapacity(slist, slist->capacity + 1);
+
+ if (slist->opts && (slist->opts->flags & SLISTF_SORT)
+ && slist->opts->compareitem) {
+ int i;
+
+ for (i = 0; i < slist->count; i++) {
+ if (slist->opts->compareitem(slist, item, slist->list[i]) <= 0) {
+ memmove(&slist->list[i + 1], &slist->list[i],
+ sizeof(void *) * (slist->count - i));
+ slist->list[i] = item;
+ break;
+ }
+ }
+
+ if (i == slist->count)
+ slist->list[slist->count] = item;
+ } else {
+ slist->list[slist->count] = item;
+ }
+
+ return slist->count++;
+}
+
+/*************************************************************************/
+
+/**
+ * Clears the list. If free is 1, the freeitem function will be called
+ * for each item before clearing.
+ * @param slist Slist Struct
+ * @param mustfree What is being freed
+ * @return void
+ */
+void slist_clear(SList * slist, int mustfree)
+{
+ if (mustfree && slist->opts && slist->opts->freeitem && slist->count) {
+ int i;
+
+ for (i = 0; i < slist->count; i++)
+ if (slist->list[i])
+ slist->opts->freeitem(slist, slist->list[i]);
+ }
+
+ if (slist->list) {
+ free(slist->list);
+ slist->list = NULL;
+ }
+ slist->capacity = 0;
+ slist->count = 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Deletes an item from the list, by index. Returns 1 if successful,
+ * 0 otherwise.
+ * @param slist Slist Struct
+ * @param index beign deleted
+ * @return int Returns 1 if successful, 0 otherwise.
+ */
+int slist_delete(SList * slist, int index)
+{
+ /* Range check */
+ if (index >= slist->count)
+ return 0;
+
+ if (slist->list[index] && slist->opts && slist->opts->freeitem)
+ slist->opts->freeitem(slist, slist->list[index]);
+
+ slist->list[index] = NULL;
+ slist->count--;
+
+ if (index < slist->count)
+ memmove(&slist->list[index], &slist->list[index + 1],
+ sizeof(void *) * (slist->count - index));
+
+ slist_setcapacity(slist, slist->capacity - 1);
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/**
+ * Deletes a range of entries. Return -1 if the permission was denied,
+ * 0 if no records were deleted, or the number of records deleted
+ * @param slist Slist Struct
+ * @param range Range to delete
+ * @param cb Call back function
+ * @param ... various args
+ * @return int
+ */
+int slist_delete_range(SList * slist, char *range, slist_delcheckcb_t cb,
+ ...)
+{
+ int count = 0, i, n1, n2;
+ va_list args, preserve;
+
+ va_start(args, cb);
+
+ for (;;) {
+ n1 = n2 = strtol(range, (char **) &range, 10);
+ range += strcspn(range, "0123456789,-");
+
+ if (*range == '-') {
+ range++;
+ range += strcspn(range, "0123456789,");
+ if (isdigit(*range)) {
+ n2 = strtol(range, (char **) &range, 10);
+ range += strcspn(range, "0123456789,-");
+ }
+ }
+
+ for (i = n1; i <= n2 && i > 0 && i <= slist->count; i++) {
+
+ if (!slist->list[i - 1])
+ continue;
+
+ /* copy this off the stack for safety's sake --nenolod */
+ VA_COPY(preserve, args);
+
+ if (cb && !cb(slist, slist->list[i - 1], preserve)) {
+ va_end(preserve);
+ return -1;
+ }
+
+ /* if it's to be freed, lets free it */
+ if (slist->opts && slist->opts->freeitem)
+ slist->opts->freeitem(slist, slist->list[i - 1]);
+ slist->list[i - 1] = NULL;
+
+ /* and release the copied list */
+ va_end(preserve);
+
+ count++;
+ }
+
+ range += strcspn(range, ",");
+ if (*range)
+ range++;
+ else
+ break;
+ }
+
+ /* We only really delete the items from the list after having processed
+ * everything because it would change the position of the items in the
+ * list otherwise.
+ */
+ slist_pack(slist);
+
+ va_end(args);
+ return count;
+}
+
+/*************************************************************************/
+
+/**
+ * Enumerates all entries of the list. If range is not NULL, will only
+ * enumerate entries that are in the range. Returns the total number
+ * of entries enumerated.
+ * @param slit Slist struct
+ * @param range Range to enum
+ * @param cb Call back function
+ * @param ... various args
+ * @return int
+ */
+int slist_enum(SList * slist, char *range, slist_enumcb_t cb, ...)
+{
+ int count = 0, i, res;
+ va_list args, preserve;
+
+ va_start(args, cb);
+
+ if (!range) {
+ for (i = 0; i < slist->count; i++) {
+ if (!slist->list[i]) {
+ alog("SList: warning: NULL pointer in the list (?)");
+ continue;
+ }
+
+ /* copy off stack for safety */
+ VA_COPY(preserve, args);
+
+ res = cb(slist, i + 1, slist->list[i], preserve);
+ if (res < 0) {
+ va_end(preserve);
+ break;
+ }
+
+ /* and release our copy */
+ va_end(preserve);
+
+ count += res;
+ }
+ } else {
+ int n1, n2;
+
+ for (;;) {
+ res = 0;
+ n1 = n2 = strtol(range, (char **) &range, 10);
+ range += strcspn(range, "0123456789,-");
+ if (*range == '-') {
+ range++;
+ range += strcspn(range, "0123456789,");
+ if (isdigit(*range)) {
+ n2 = strtol(range, (char **) &range, 10);
+ range += strcspn(range, "0123456789,-");
+ }
+ }
+ for (i = n1; i <= n2 && i > 0 && i <= slist->count; i++) {
+ if (!slist->list[i - 1]) {
+ alog("SList: warning: NULL pointer in the list (?)");
+ continue;
+ }
+
+ /* copy off stack for safety */
+ VA_COPY(preserve, args);
+
+ res = cb(slist, i, slist->list[i - 1], preserve);
+ if (res < 0) {
+ va_end(preserve);
+ break;
+ }
+ count += res;
+
+ /* and release our copy */
+ va_end(preserve);
+ }
+ if (res < -1)
+ break;
+ range += strcspn(range, ",");
+ if (*range)
+ range++;
+ else
+ break;
+ }
+ }
+
+ va_end(args);
+
+ return count;
+}
+
+/*************************************************************************/
+
+/**
+ * Determines whether the list is full.
+ * @param slist Slist Struct
+ * @return int
+ */
+int slist_full(SList * slist)
+{
+ if (slist->limit != 0 && slist->count >= slist->limit)
+ return 1;
+ else
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Initialization of the list.
+ * @param slist Slist Struct
+ * @return int
+ */
+void slist_init(SList * slist)
+{
+ memset(slist, 0, sizeof(SList));
+ slist->limit = SLIST_DEFAULT_LIMIT;
+ slist->opts = &slist_defopts;
+}
+
+/*************************************************************************/
+
+/**
+ * Returns the index of an item in the list, -1 if inexistant.
+ * @param slist Slist Struct
+ * @param item Item index
+ * @return int
+ */
+int slist_indexof(SList * slist, void *item)
+{
+ int16 i;
+ void *entry;
+
+ if (slist->count == 0)
+ return -1;
+
+ for (i = 0, entry = slist->list[0]; i < slist->count;
+ i++, entry = slist->list[i]) {
+ if ((slist->opts
+ && slist->opts->isequal) ? (slist->opts->isequal(slist, item,
+ entry))
+ : (item == entry))
+ return i;
+ }
+
+ return -1;
+}
+
+/*************************************************************************/
+
+/**
+ * Removes all NULL pointers from the list.
+ * @param slist Slist Struct
+ * @return void
+ */
+void slist_pack(SList * slist)
+{
+ int i;
+
+ for (i = slist->count - 1; i >= 0; i--)
+ if (!slist->list[i])
+ slist_delete(slist, i);
+}
+
+/*************************************************************************/
+
+/**
+ * Removes a specific item from the list. Returns the old index of the
+ * deleted item, or -1 if the item was not found.
+ * @param slist Slist Struct
+ * @param item to remove
+ * @return int
+ */
+int slist_remove(SList * slist, void *item)
+{
+ int index = slist_indexof(slist, item);
+ if (index == -1)
+ return -1;
+ slist_delete(slist, index);
+ return index;
+}
+
+/*************************************************************************/
+
+/**
+ * Sets the maximum capacity of the list
+ * @param slist Slist Struct
+ * @param capacity How large the list can be
+ * @return int
+ */
+int slist_setcapacity(SList * slist, int16 capacity)
+{
+ if (slist->capacity == capacity)
+ return 1;
+ slist->capacity = capacity;
+ if (slist->capacity)
+ slist->list =
+ srealloc(slist->list, sizeof(void *) * slist->capacity);
+ else {
+ free(slist->list);
+ slist->list = NULL;
+ }
+ if (slist->capacity < slist->count)
+ slist->count = slist->capacity;
+ return 1;
+}
diff --git a/src/sockutil.c b/src/sockutil.c
new file mode 100644
index 000000000..b28989bdb
--- /dev/null
+++ b/src/sockutil.c
@@ -0,0 +1,737 @@
+/* Socket utility routines.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+/*************************************************************************/
+
+static char read_netbuf[NET_BUFSIZE];
+static char *read_curpos = read_netbuf; /* Next byte to return */
+static char *read_bufend = read_netbuf; /* Next position for data from socket */
+static char *const read_buftop = read_netbuf + NET_BUFSIZE;
+int32 total_read = 0;
+static char write_netbuf[NET_BUFSIZE];
+static char *write_curpos = write_netbuf; /* Next byte to write to socket */
+static char *write_bufend = write_netbuf; /* Next position for data to socket */
+static char *const write_buftop = write_netbuf + NET_BUFSIZE;
+static int write_fd = -1;
+int32 total_written;
+static int lastchar = EOF;
+
+/*************************************************************************/
+
+/**
+ * Return amount of data in read buffer.
+ * @return int32
+ */
+int32 read_buffer_len()
+{
+ if (read_bufend >= read_curpos) {
+ return read_bufend - read_curpos;
+ } else {
+ return (read_bufend + NET_BUFSIZE) - read_curpos;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Read data.
+ * @param fd File Pointer
+ * @param buf Buffer
+ * @param int Length of buffer
+ * @return int
+ */
+static int buffered_read(ano_socket_t fd, char *buf, int len)
+{
+ int nread, left = len;
+ fd_set fds;
+ struct timeval tv = { 0, 0 };
+ int errno_save = ano_sockgeterr();
+
+ if (fd < 0) {
+ ano_sockseterr(SOCKERR_EBADF);
+ return -1;
+ }
+ while (left > 0) {
+ struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ while (read_bufend != read_curpos - 1
+ && !(read_curpos == read_netbuf
+ && read_bufend == read_buftop - 1)
+ && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
+ int maxread;
+ tvptr = &tv; /* don't wait next time */
+ if (read_bufend < read_curpos) /* wrapped around? */
+ maxread = (read_curpos - 1) - read_bufend;
+ else if (read_curpos == read_netbuf)
+ maxread = read_buftop - read_bufend - 1;
+ else
+ maxread = read_buftop - read_bufend;
+ nread = ano_sockread(fd, read_bufend, maxread);
+ errno_save = ano_sockgeterr();
+ if (debug >= 3)
+ alog("debug: buffered_read wanted %d, got %d", maxread,
+ nread);
+ if (nread <= 0)
+ break;
+ read_bufend += nread;
+ if (read_bufend == read_buftop)
+ read_bufend = read_netbuf;
+ }
+ if (read_curpos == read_bufend) /* No more data on socket */
+ break;
+ /* See if we can gobble up the rest of the buffer. */
+ if (read_curpos + left >= read_buftop && read_bufend < read_curpos) {
+ nread = read_buftop - read_curpos;
+ memcpy(buf, read_curpos, nread);
+ buf += nread;
+ left -= nread;
+ read_curpos = read_netbuf;
+ }
+ /* Now everything we need is in a single chunk at read_curpos. */
+ if (read_bufend > read_curpos && read_bufend - read_curpos < left)
+ nread = read_bufend - read_curpos;
+ else
+ nread = left;
+ if (nread) {
+ memcpy(buf, read_curpos, nread);
+ buf += nread;
+ left -= nread;
+ read_curpos += nread;
+ }
+ }
+ total_read += len - left;
+ if (debug >= 4) {
+ alog("debug: buffered_read(%d,%p,%d) returning %d",
+ fd, buf, len, len - left);
+ }
+ ano_sockseterr(errno_save);
+ return len - left;
+}
+
+/*************************************************************************/
+
+/**
+ * Optimized version of the above for reading a single character; returns
+ * the character in an int or EOF, like fgetc().
+ * @param fd File Pointer
+ * @return int
+ */
+static int buffered_read_one(ano_socket_t fd)
+{
+ int nread;
+ fd_set fds;
+ struct timeval tv = { 0, 0 };
+ char c;
+ struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
+ int errno_save = ano_sockgeterr();
+
+ if (fd < 0) {
+ ano_sockseterr(SOCKERR_EBADF);
+ return -1;
+ }
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ while (read_bufend != read_curpos - 1
+ && !(read_curpos == read_netbuf
+ && read_bufend == read_buftop - 1)
+ && select(fd + 1, &fds, 0, 0, tvptr) == 1) {
+ int maxread;
+ tvptr = &tv; /* don't wait next time */
+ if (read_bufend < read_curpos) /* wrapped around? */
+ maxread = (read_curpos - 1) - read_bufend;
+ else if (read_curpos == read_netbuf)
+ maxread = read_buftop - read_bufend - 1;
+ else
+ maxread = read_buftop - read_bufend;
+ nread = ano_sockread(fd, read_bufend, maxread);
+ errno_save = ano_sockgeterr();
+ if (debug >= 3)
+ alog("debug: buffered_read_one wanted %d, got %d", maxread,
+ nread);
+ if (nread <= 0)
+ break;
+ read_bufend += nread;
+ if (read_bufend == read_buftop)
+ read_bufend = read_netbuf;
+ }
+ if (read_curpos == read_bufend) { /* No more data on socket */
+ if (debug >= 4)
+ alog("debug: buffered_read_one(%d) returning %d", fd, EOF);
+ ano_sockseterr(errno_save);
+ return EOF;
+ }
+ c = *read_curpos++;
+ if (read_curpos == read_buftop)
+ read_curpos = read_netbuf;
+ total_read++;
+ if (debug >= 4)
+ alog("debug: buffered_read_one(%d) returning %d", fd, c);
+ return (int) c & 0xFF;
+}
+
+/*************************************************************************/
+
+/**
+ * Return amount of data in write buffer.
+ * @return int
+ */
+int32 write_buffer_len()
+{
+ if (write_bufend >= write_curpos) {
+ return write_bufend - write_curpos;
+ } else {
+ return (write_bufend + NET_BUFSIZE) - write_curpos;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Helper routine to try and write up to one chunk of data from the buffer
+ * to the socket. Return how much was written.
+ * @param wait Wait
+ * @return int
+ */
+static int flush_write_buffer(int wait)
+{
+ fd_set fds;
+ struct timeval tv = { 0, 0 };
+ int errno_save = ano_sockgeterr();
+
+ if (write_bufend == write_curpos || write_fd == -1)
+ return 0;
+ FD_ZERO(&fds);
+ FD_SET(write_fd, &fds);
+ if (select(write_fd + 1, 0, &fds, 0, wait ? NULL : &tv) == 1) {
+ int maxwrite, nwritten;
+ if (write_curpos > write_bufend) /* wrapped around? */
+ maxwrite = write_buftop - write_curpos;
+ else if (write_bufend == write_netbuf)
+ maxwrite = write_buftop - write_curpos - 1;
+ else
+ maxwrite = write_bufend - write_curpos;
+ nwritten = ano_sockwrite(write_fd, write_curpos, maxwrite);
+ errno_save = ano_sockgeterr();
+ if (debug >= 3)
+ alog("debug: flush_write_buffer wanted %d, got %d", maxwrite,
+ nwritten);
+ if (nwritten > 0) {
+ write_curpos += nwritten;
+ if (write_curpos == write_buftop)
+ write_curpos = write_netbuf;
+ total_written += nwritten;
+ return nwritten;
+ }
+ }
+ ano_sockseterr(errno_save);
+ return 0;
+}
+
+/*************************************************************************/
+
+/**
+ * Write data.
+ * @param fd File Pointer
+ * @param buf Buffer to write
+ * @param len Length to write
+ * @return int
+ */
+static int buffered_write(ano_socket_t fd, char *buf, int len)
+{
+ int nwritten, left = len;
+ int errno_save = ano_sockgeterr();
+
+ if (fd < 0) {
+ errno = EBADF;
+ return -1;
+ }
+ write_fd = fd;
+
+ while (left > 0) {
+
+ /* Don't try putting anything in the buffer if it's full. */
+ if (write_curpos != write_bufend + 1 &&
+ (write_curpos != write_netbuf
+ || write_bufend != write_buftop - 1)) {
+ /* See if we need to write up to the end of the buffer. */
+ if (write_bufend + left >= write_buftop
+ && write_curpos <= write_bufend) {
+ nwritten = write_buftop - write_bufend;
+ memcpy(write_bufend, buf, nwritten);
+ buf += nwritten;
+ left -= nwritten;
+ write_bufend = write_netbuf;
+ }
+ /* Now we can copy a single chunk to write_bufend. */
+ if (write_curpos > write_bufend
+ && write_curpos - write_bufend - 1 < left)
+ nwritten = write_curpos - write_bufend - 1;
+ else
+ nwritten = left;
+ if (nwritten) {
+ memcpy(write_bufend, buf, nwritten);
+ buf += nwritten;
+ left -= nwritten;
+ write_bufend += nwritten;
+ }
+ }
+
+ /* Now write to the socket as much as we can. */
+ if (write_curpos == write_bufend + 1 ||
+ (write_curpos == write_netbuf
+ && write_bufend == write_buftop - 1))
+ flush_write_buffer(1);
+ else
+ flush_write_buffer(0);
+ errno_save = errno;
+ if (write_curpos == write_bufend + 1 ||
+ (write_curpos == write_netbuf
+ && write_bufend == write_buftop - 1)) {
+ /* Write failed on full buffer */
+ break;
+ }
+ }
+
+ if (debug >= 4) {
+ alog("debug: buffered_write(%d,%p,%d) returning %d",
+ fd, buf, len, len - left);
+ }
+ ano_sockseterr(errno_save);
+ return len - left;
+}
+
+
+/*************************************************************************/
+
+/**
+ * Optimized version of the above for writing a single character; returns
+ * the character in an int or EOF, like fputc(). Commented out because it
+ * isn't currently used.
+ * @param int to write
+ * @param fd Pointer
+ * @return int
+ */
+#if 0
+static int buffered_write_one(int c, ano_socket_t fd)
+{
+ struct timeval tv = { 0, 0 };
+
+ if (fd < 0) {
+ ano_sockseterr(SOCKERR_EBADF);
+ return -1;
+ }
+ write_fd = fd;
+
+ /* Try to flush the buffer if it's full. */
+ if (write_curpos == write_bufend + 1 ||
+ (write_curpos == write_netbuf
+ && write_bufend == write_buftop - 1)) {
+ flush_write_buffer(1);
+ if (write_curpos == write_bufend + 1 ||
+ (write_curpos == write_netbuf
+ && write_bufend == write_buftop - 1)) {
+ /* Write failed */
+ if (debug >= 4)
+ alog("debug: buffered_write_one(%d) returning %d", fd,
+ EOF);
+ return EOF;
+ }
+ }
+
+ /* Write the character. */
+ *write_bufend++ = c;
+ if (write_bufend == write_buftop)
+ write_bufend = write_netbuf;
+
+ /* Move it to the socket if we can. */
+ flush_write_buffer(0);
+
+ if (debug >= 4)
+ alog("debug: buffered_write_one(%d) returning %d", fd, c);
+ return (int) c & 0xFF;
+}
+#endif /* 0 */
+
+/*************************************************************************/
+
+/**
+ * sgetc ?
+ * @param int to read
+ * @return int
+ */
+int sgetc(ano_socket_t s)
+{
+ int c;
+
+ if (lastchar != EOF) {
+ c = lastchar;
+ lastchar = EOF;
+ return c;
+ }
+ return buffered_read_one(s);
+}
+
+/*************************************************************************/
+
+/**
+ * sungetc ?
+ * @param int c
+ * @param int s
+ * @return int
+ */
+int sungetc(int c, int s)
+{
+ return lastchar = c;
+}
+
+/*************************************************************************/
+
+/**
+ * If connection was broken, return NULL. If the read timed out, return
+ * (char *)-1.
+ * @param buf Buffer to get
+ * @param len Length
+ * @param s Socket
+ * @return buffer
+ */
+char *sgets(char *buf, int len, ano_socket_t s)
+{
+ int c = 0;
+ struct timeval tv;
+ fd_set fds;
+ char *ptr = buf;
+
+ flush_write_buffer(0);
+
+ if (len == 0)
+ return NULL;
+ FD_SET(s, &fds);
+ tv.tv_sec = ReadTimeout;
+ tv.tv_usec = 0;
+ while (read_buffer_len() == 0 &&
+ (c = select(s + 1, &fds, NULL, NULL, &tv)) < 0) {
+ if (ano_sockgeterr() != EINTR)
+ break;
+ flush_write_buffer(0);
+ }
+ if (read_buffer_len() == 0 && c == 0)
+ return (char *) -1;
+ c = sgetc(s);
+ while (--len && (*ptr++ = c) != '\n' && (c = sgetc(s)) >= 0);
+ if (c < 0)
+ return NULL;
+ *ptr = 0;
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * sgets2: Read a line of text from a socket, and strip newline and
+ * carriage return characters from the end of the line.
+ * @param buf Buffer to get
+ * @param len Length
+ * @param s Socket
+ * @return buffer
+ */
+char *sgets2(char *buf, int len, ano_socket_t s)
+{
+ char *str = sgets(buf, len, s);
+
+ if (!str || str == (char *) -1)
+ return str;
+ str = buf + strlen(buf) - 1;
+ if (*str == '\n')
+ *str-- = 0;
+ if (*str == '\r')
+ *str = 0;
+ return buf;
+}
+
+/*************************************************************************/
+
+/**
+ * Read from a socket. (Use this instead of read() because it has
+ * buffering.)
+ * @param s Socket
+ * @param buf Buffer to get
+ * @param len Length
+ * @return int
+ */
+int sread(ano_socket_t s, char *buf, int len)
+{
+ return buffered_read(s, buf, len);
+}
+
+/*************************************************************************/
+
+/**
+ * sputs : write buffer
+ * @param s Socket
+ * @param str Buffer to write
+ * @return int
+ */
+int sputs(char *str, ano_socket_t s)
+{
+ return buffered_write(s, str, strlen(str));
+}
+
+/*************************************************************************/
+
+/**
+ * sockprintf : a socket writting printf()
+ * @param s Socket
+ * @param fmt format of message
+ * @param ... various args
+ * @return int
+ */
+int sockprintf(ano_socket_t s, char *fmt, ...)
+{
+ va_list args;
+ char buf[16384]; /* Really huge, to try and avoid truncation */
+ int value;
+
+ va_start(args, fmt);
+ value = buffered_write(s, buf, vsnprintf(buf, sizeof(buf), fmt, args));
+ va_end(args);
+ return value;
+}
+
+/*************************************************************************/
+
+#if !HAVE_GETHOSTBYNAME
+
+/**
+ * Translate an IP dotted-quad address to a 4-byte character string.
+ * Return NULL if the given string is not in dotted-quad format.
+ * @param ipaddr IP Address
+ * @return char 4byte ip char string
+ */
+static char *pack_ip(const char *ipaddr)
+{
+ static char ipbuf[4];
+ int tmp[4], i;
+
+ if (sscanf(ipaddr, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3])
+ != 4)
+ return NULL;
+ for (i = 0; i < 4; i++) {
+ if (tmp[i] < 0 || tmp[i] > 255)
+ return NULL;
+ ipbuf[i] = tmp[i];
+ }
+ return ipbuf;
+}
+
+#endif
+
+/*************************************************************************/
+
+/**
+ * lhost/lport specify the local side of the connection. If they are not
+ * given (lhost==NULL, lport==0), then they are left free to vary.
+ * @param host Remote Host
+ * @param port Remote Port
+ * @param lhost LocalHost
+ * @param lport LocalPort
+ * @return int if successful
+ */
+int conn(const char *host, int port, const char *lhost, int lport)
+{
+#if HAVE_GETHOSTBYNAME
+ struct hostent *hp;
+#else
+ char *addr;
+#endif
+ struct sockaddr_in sa, lsa;
+ ano_socket_t sock;
+ int sockopt = 1;
+
+ memset(&lsa, 0, sizeof(lsa));
+ if (lhost) {
+#if HAVE_GETHOSTBYNAME
+ if ((hp = gethostbyname(lhost)) != NULL) {
+ memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length);
+ lsa.sin_family = hp->h_addrtype;
+#else
+ if (addr = pack_ip(lhost)) {
+ memcpy((char *) &lsa.sin_addr, addr, 4);
+ lsa.sin_family = AF_INET;
+#endif
+ } else {
+ lhost = NULL;
+ }
+ }
+ if (lport)
+ lsa.sin_port = htons((unsigned short) lport);
+
+ memset(&sa, 0, sizeof(sa));
+#if HAVE_GETHOSTBYNAME
+ if (!(hp = gethostbyname(host)))
+ return -1;
+ memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
+ sa.sin_family = hp->h_addrtype;
+#else
+ if (!(addr = pack_ip(host))) {
+ alog("conn(): `%s' is not a valid IP address", host);
+ ano_sockseterr(SOCKERR_EINVAL);
+ return -1;
+ }
+ memcpy((char *) &sa.sin_addr, addr, 4);
+ sa.sin_family = AF_INET;
+#endif
+ sa.sin_port = htons((unsigned short) port);
+
+ if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
+ return -1;
+
+ if (setsockopt
+ (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &sockopt,
+ sizeof(int)) < 0)
+ alog("debug: couldn't set SO_REUSEADDR on socket");
+
+ if ((lhost || lport)
+ && bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0) {
+ int errno_save = ano_sockgeterr();
+ ano_sockclose(sock);
+ ano_sockseterr(errno_save);
+ return -1;
+ }
+
+ if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ int errno_save = ano_sockgeterr();
+ ano_sockclose(sock);
+ ano_sockseterr(errno_save);
+ return -1;
+ }
+
+ return sock;
+}
+
+/*************************************************************************/
+
+/**
+ * Close up the connection
+ * @param s Socket
+ * @return void
+ */
+void disconn(ano_socket_t s)
+{
+ shutdown(s, 2);
+ ano_sockclose(s);
+}
+
+/*************************************************************************/
+/* Windows support functions */
+
+#ifdef _WIN32
+/* Microsoft makes things nice and fun for us! */
+struct u_WSA_errors {
+ int error_code;
+ char *error_string;
+};
+
+/* Must be sorted ascending by error code */
+struct u_WSA_errors WSAErrors[] = {
+ {WSAEINTR, "Interrupted system call"},
+ {WSAEBADF, "Bad file number"},
+ {WSAEACCES, "Permission denied"},
+ {WSAEFAULT, "Bad address"},
+ {WSAEINVAL, "Invalid argument"},
+ {WSAEMFILE, "Too many open sockets"},
+ {WSAEWOULDBLOCK, "Operation would block"},
+ {WSAEINPROGRESS, "Operation now in progress"},
+ {WSAEALREADY, "Operation already in progress"},
+ {WSAENOTSOCK, "Socket operation on non-socket"},
+ {WSAEDESTADDRREQ, "Destination address required"},
+ {WSAEMSGSIZE, "Message too long"},
+ {WSAEPROTOTYPE, "Protocol wrong type for socket"},
+ {WSAENOPROTOOPT, "Bad protocol option"},
+ {WSAEPROTONOSUPPORT, "Protocol not supported"},
+ {WSAESOCKTNOSUPPORT, "Socket type not supported"},
+ {WSAEOPNOTSUPP, "Operation not supported on socket"},
+ {WSAEPFNOSUPPORT, "Protocol family not supported"},
+ {WSAEAFNOSUPPORT, "Address family not supported"},
+ {WSAEADDRINUSE, "Address already in use"},
+ {WSAEADDRNOTAVAIL, "Can't assign requested address"},
+ {WSAENETDOWN, "Network is down"},
+ {WSAENETUNREACH, "Network is unreachable"},
+ {WSAENETRESET, "Net connection reset"},
+ {WSAECONNABORTED, "Software caused connection abort"},
+ {WSAECONNRESET, "Connection reset by peer"},
+ {WSAENOBUFS, "No buffer space available"},
+ {WSAEISCONN, "Socket is already connected"},
+ {WSAENOTCONN, "Socket is not connected"},
+ {WSAESHUTDOWN, "Can't send after socket shutdown"},
+ {WSAETOOMANYREFS, "Too many references, can't splice"},
+ {WSAETIMEDOUT, "Connection timed out"},
+ {WSAECONNREFUSED, "Connection refused"},
+ {WSAELOOP, "Too many levels of symbolic links"},
+ {WSAENAMETOOLONG, "File name too long"},
+ {WSAEHOSTDOWN, "Host is down"},
+ {WSAEHOSTUNREACH, "No route to host"},
+ {WSAENOTEMPTY, "Directory not empty"},
+ {WSAEPROCLIM, "Too many processes"},
+ {WSAEUSERS, "Too many users"},
+ {WSAEDQUOT, "Disc quota exceeded"},
+ {WSAESTALE, "Stale NFS file handle"},
+ {WSAEREMOTE, "Too many levels of remote in path"},
+ {WSASYSNOTREADY, "Network subsystem is unavailable"},
+ {WSAVERNOTSUPPORTED, "Winsock version not supported"},
+ {WSANOTINITIALISED, "Winsock not yet initialized"},
+ {WSAHOST_NOT_FOUND, "Host not found"},
+ {WSATRY_AGAIN, "Non-authoritative host not found"},
+ {WSANO_RECOVERY, "Non-recoverable errors"},
+ {WSANO_DATA, "Valid name, no data record of requested type"},
+ {WSAEDISCON, "Graceful disconnect in progress"},
+#ifdef WSASYSCALLFAILURE
+ {WSASYSCALLFAILURE, "System call failure"},
+#endif
+ {0, NULL}
+};
+
+char *ano_sockstrerror(int error)
+{
+ static char unkerr[64];
+ int start = 0;
+ int stop = sizeof(WSAErrors) / sizeof(WSAErrors[0]) - 1;
+ int mid;
+
+ /* Microsoft decided not to use sequential numbers for the error codes,
+ * so we can't just use the array index for the code. But, at least
+ * use a binary search to make it as fast as possible.
+ */
+ while (start <= stop) {
+ mid = (start + stop) / 2;
+ if (WSAErrors[mid].error_code > error)
+ stop = mid - 1;
+
+ else if (WSAErrors[mid].error_code < error)
+ start = mid + 1;
+ else
+ return WSAErrors[mid].error_string;
+ }
+ sprintf(unkerr, "Unknown Error: %d", error);
+ return unkerr;
+}
+
+int ano_socksetnonb(ano_socket_t fd)
+{
+ u_long i = 1;
+ return (!ioctlsocket(fd, FIONBIO, &i) ? -1 : 1);
+}
+#endif
diff --git a/src/timeout.c b/src/timeout.c
new file mode 100644
index 000000000..1db734654
--- /dev/null
+++ b/src/timeout.c
@@ -0,0 +1,132 @@
+/* Routines for time-delayed actions.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+#include "pseudo.h"
+
+static Timeout *timeouts = NULL;
+
+/*************************************************************************/
+
+#ifdef DEBUG_COMMANDS
+
+/* Send the timeout list to the given user. */
+
+int send_timeout_list(User * u)
+{
+ Timeout *to, *last;
+
+ notice(s_OperServ, u->nick, "Now: %ld", (long int) time(NULL));
+ for (to = timeouts, last = NULL; to; last = to, to = to->next) {
+ notice(s_OperServ, u->nick, "0x%p: %ld: 0x%p (0x%p)",
+ (void *) to, (long int) to->timeout, (void *) to->code,
+ (void *) to->data);
+ if (to->prev != last)
+ notice(s_OperServ, u->nick,
+ " to->prev incorrect! expected=0x%p seen=0x%p",
+ (void *) last, (void *) to->prev);
+ }
+ return MOD_CONT;
+}
+
+#endif /* DEBUG_COMMANDS */
+
+/*************************************************************************/
+
+/* Check the timeout list for any pending actions. */
+
+void check_timeouts(void)
+{
+ Timeout *to, *to2;
+ time_t t = time(NULL);
+
+ if (debug >= 2)
+ alog("debug: Checking timeouts at %ld", (long int) t);
+
+ to = timeouts;
+ while (to) {
+ if (t < to->timeout) {
+ to = to->next;
+ continue;
+ }
+ if (debug >= 4) {
+ alog("debug: Running timeout 0x%p (code=0x%p repeat=%d)",
+ (void *) to, (void *) to->code, to->repeat);
+ }
+ to->code(to);
+ if (to->repeat) {
+ to = to->next;
+ continue;
+ }
+ to2 = to->next;
+ if (to->next)
+ to->next->prev = to->prev;
+ if (to->prev)
+ to->prev->next = to->next;
+ else
+ timeouts = to->next;
+ free(to);
+ to = to2;
+ }
+ if (debug >= 2)
+ alog("debug: Finished timeout list");
+}
+
+/*************************************************************************/
+
+/* Add a timeout to the list to be triggered in `delay' seconds. If
+ * `repeat' is nonzero, do not delete the timeout after it is triggered.
+ * This must maintain the property that timeouts added from within a
+ * timeout routine do not get checked during that run of the timeout list.
+ */
+
+Timeout *add_timeout(int delay, void (*code) (Timeout *), int repeat)
+{
+ Timeout *t = scalloc(sizeof(Timeout), 1);
+ t->settime = time(NULL);
+ t->timeout = t->settime + delay;
+ t->code = code;
+ t->repeat = repeat;
+ t->next = timeouts;
+ t->prev = NULL;
+ if (timeouts)
+ timeouts->prev = t;
+ timeouts = t;
+ return t;
+}
+
+/*************************************************************************/
+
+/* Remove a timeout from the list (if it's there). */
+
+void del_timeout(Timeout * t)
+{
+ Timeout *ptr;
+
+ for (ptr = timeouts; ptr; ptr = ptr->next) {
+ if (ptr == t)
+ break;
+ }
+ if (!ptr)
+ return;
+ if (t->prev)
+ t->prev->next = t->next;
+ else
+ timeouts = t->next;
+ if (t->next)
+ t->next->prev = t->prev;
+ free(t);
+}
+
+/*************************************************************************/
diff --git a/src/tools/Anope_Install_Script.nsi b/src/tools/Anope_Install_Script.nsi
new file mode 100644
index 000000000..633a4aa19
--- /dev/null
+++ b/src/tools/Anope_Install_Script.nsi
@@ -0,0 +1,540 @@
+; Script generated by the HM NIS Edit Script Wizard.
+
+; HM NIS Edit Wizard helper defines
+!define PRODUCT_NAME "Anope IRC Services"
+!define PRODUCT_VERSION "1.8.0"
+!define PRODUCT_PUBLISHER "Anope"
+!define PRODUCT_WEB_SITE "http://www.anope.org"
+!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\anope.exe"
+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+
+; MUI 1.67 compatible ------
+!include "MUI.nsh"
+
+; MUI Settings
+!define MUI_ABORTWARNING
+!define MUI_ICON "anope-icon.ico"
+!define MUI_UNICON "anope-icon.ico"
+
+; Language Selection Dialog Settings
+!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
+!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
+!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"
+
+; Welcome page
+!insertmacro MUI_PAGE_WELCOME
+; License page
+!define MUI_LICENSEPAGE_RADIOBUTTONS
+!insertmacro MUI_PAGE_LICENSE "anope-1.8.0\docs\COPYING.txt"
+; Directory page
+!insertmacro MUI_PAGE_DIRECTORY
+; Instfiles page
+!insertmacro MUI_PAGE_INSTFILES
+; Finish page
+!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\docs\README.txt"
+!insertmacro MUI_PAGE_FINISH
+
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Language files
+!insertmacro MUI_LANGUAGE "Dutch"
+!insertmacro MUI_LANGUAGE "English"
+!insertmacro MUI_LANGUAGE "French"
+!insertmacro MUI_LANGUAGE "German"
+!insertmacro MUI_LANGUAGE "Italian"
+!insertmacro MUI_LANGUAGE "Portuguese"
+!insertmacro MUI_LANGUAGE "Spanish"
+
+; MUI end ------
+
+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+OutFile "Anope-1.8.0.exe"
+InstallDir "$PROGRAMFILES\Anope"
+InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
+ShowInstDetails show
+ShowUnInstDetails show
+
+Function .onInit
+ !insertmacro MUI_LANGDLL_DISPLAY
+FunctionEnd
+
+Section "MainSection" SEC01
+ SetOutPath "$INSTDIR"
+ File "anope-1.8.0\anope.exe"
+File "anope-1.8.0\anope.bat"
+ SetShellVarContext all
+ CreateDirectory "$SMPROGRAMS\Anope"
+ CreateShortCut "$SMPROGRAMS\Anope\Anope IRC Services.lnk" "$INSTDIR\anope.exe"
+ CreateDirectory "$SMPROGRAMS\Anope\Advanced"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Debug and Window Logging).lnk" "$INSTDIR\anope.bat" "-debug -nofork"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Window Logging).lnk" "$INSTDIR\anope.bat" "-nofork"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (No Third Party Modules).lnk" "$INSTDIR\anope.bat" "-nothird"
+ CreateShortCut "$DESKTOP\Anope IRC Services.lnk" "$INSTDIR\anope.exe"
+ File "anope-1.8.0\anope.exe.manifest"
+ File "anope-1.8.0\Changes.conf.txt"
+ File "anope-1.8.0\Changes.lang.txt"
+ File "anope-1.8.0\Changes.mysql.txt"
+ File "anope-1.8.0\Changes.txt"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0\data\anopesmtp.exe"
+ File "anope-1.8.0\data\anopesmtp.exe.manifest"
+ SetOutPath "$INSTDIR\data\bin"
+ File "anope-1.8.0\data\bin\am"
+ File "anope-1.8.0\data\bin\anoperc.in"
+ File "anope-1.8.0\data\bin\cp-recursive"
+ File "anope-1.8.0\data\bin\langtool"
+ File "anope-1.8.0\data\bin\mydbgen"
+ File "anope-1.8.0\data\bin\register"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0\data\db-merger.exe"
+ File "anope-1.8.0\data\db-merger.exe.manifest"
+ File "anope-1.8.0\data\epona2anope.exe"
+ File "anope-1.8.0\data\epona2anope.exe.manifest"
+ File "anope-1.8.0\data\example.conf"
+ SetOutPath "$INSTDIR\data\languages"
+ File "anope-1.8.0\data\languages\cat"
+ File "anope-1.8.0\data\languages\de"
+ File "anope-1.8.0\data\languages\en_us"
+ File "anope-1.8.0\data\languages\es"
+ File "anope-1.8.0\data\languages\fr"
+ File "anope-1.8.0\data\languages\gr"
+ File "anope-1.8.0\data\languages\hun"
+ File "anope-1.8.0\data\languages\it"
+ File "anope-1.8.0\data\languages\nl"
+ File "anope-1.8.0\data\languages\pl"
+ File "anope-1.8.0\data\languages\pt"
+ File "anope-1.8.0\data\languages\ru"
+ File "anope-1.8.0\data\languages\tr"
+ SetOutPath "$INSTDIR\data\logs"
+ SetOutPath "$INSTDIR\data\backups"
+ SetOutPath "$INSTDIR\data\modules"
+ File "anope-1.8.0\data\modules\bahamut.dll"
+ File "anope-1.8.0\data\modules\bs_act.dll"
+ File "anope-1.8.0\data\modules\bs_assign.dll"
+ File "anope-1.8.0\data\modules\bs_badwords.dll"
+ File "anope-1.8.0\data\modules\bs_bot.dll"
+ File "anope-1.8.0\data\modules\bs_botlist.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy_kick.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy_kickban.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy_owner.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy_seen.dll"
+ File "anope-1.8.0\data\modules\bs_fantasy_unban.dll"
+ File "anope-1.8.0\data\modules\bs_help.dll"
+ File "anope-1.8.0\data\modules\bs_info.dll"
+ File "anope-1.8.0\data\modules\bs_kick.dll"
+ File "anope-1.8.0\data\modules\bs_say.dll"
+ File "anope-1.8.0\data\modules\bs_set.dll"
+ File "anope-1.8.0\data\modules\bs_unassign.dll"
+ File "anope-1.8.0\data\modules\charybdis.dll"
+ File "anope-1.8.0\data\modules\cs_access.dll"
+ File "anope-1.8.0\data\modules\cs_akick.dll"
+ File "anope-1.8.0\data\modules\cs_appendtopic.dll"
+ File "anope-1.8.0\data\modules\cs_ban.dll"
+ File "anope-1.8.0\data\modules\cs_clear.dll"
+ File "anope-1.8.0\data\modules\cs_drop.dll"
+ File "anope-1.8.0\data\modules\cs_enforce.dll"
+ File "anope-1.8.0\data\modules\cs_forbid.dll"
+ File "anope-1.8.0\data\modules\cs_getkey.dll"
+ File "anope-1.8.0\data\modules\cs_getpass.dll"
+ File "anope-1.8.0\data\modules\cs_help.dll"
+ File "anope-1.8.0\data\modules\cs_identify.dll"
+ File "anope-1.8.0\data\modules\cs_info.dll"
+ File "anope-1.8.0\data\modules\cs_invite.dll"
+ File "anope-1.8.0\data\modules\cs_kick.dll"
+ File "anope-1.8.0\data\modules\cs_list.dll"
+ File "anope-1.8.0\data\modules\cs_logout.dll"
+ File "anope-1.8.0\data\modules\cs_modes.dll"
+ File "anope-1.8.0\data\modules\cs_register.dll"
+ File "anope-1.8.0\data\modules\cs_sendpass.dll"
+ File "anope-1.8.0\data\modules\cs_set.dll"
+ File "anope-1.8.0\data\modules\cs_status.dll"
+ File "anope-1.8.0\data\modules\cs_suspend.dll"
+ File "anope-1.8.0\data\modules\cs_tban.dll"
+ File "anope-1.8.0\data\modules\cs_topic.dll"
+ File "anope-1.8.0\data\modules\cs_xop.dll"
+ File "anope-1.8.0\data\modules\dreamforge.dll"
+ File "anope-1.8.0\data\modules\enc_md5.dll"
+ File "anope-1.8.0\data\modules\enc_sha1.dll"
+ File "anope-1.8.0\data\modules\enc_none.dll"
+ File "anope-1.8.0\data\modules\enc_old.dll"
+ File "anope-1.8.0\data\modules\he_help.dll"
+ File "anope-1.8.0\data\modules\hs_del.dll"
+ File "anope-1.8.0\data\modules\hs_delall.dll"
+ File "anope-1.8.0\data\modules\hs_group.dll"
+ File "anope-1.8.0\data\modules\hs_help.dll"
+ File "anope-1.8.0\data\modules\hs_list.dll"
+ File "anope-1.8.0\data\modules\hs_off.dll"
+ File "anope-1.8.0\data\modules\hs_on.dll"
+ File "anope-1.8.0\data\modules\hs_request.dll"
+ File "anope-1.8.0\data\modules\hs_set.dll"
+ File "anope-1.8.0\data\modules\hs_setall.dll"
+ File "anope-1.8.0\data\modules\hybrid.dll"
+ File "anope-1.8.0\data\modules\inspircd10.dll"
+ File "anope-1.8.0\data\modules\inspircd11.dll"
+ File "anope-1.8.0\data\modules\ms_cancel.dll"
+ File "anope-1.8.0\data\modules\ms_check.dll"
+ File "anope-1.8.0\data\modules\ms_del.dll"
+ File "anope-1.8.0\data\modules\ms_help.dll"
+ File "anope-1.8.0\data\modules\ms_info.dll"
+ File "anope-1.8.0\data\modules\ms_list.dll"
+ File "anope-1.8.0\data\modules\ms_read.dll"
+ File "anope-1.8.0\data\modules\ms_rsend.dll"
+ File "anope-1.8.0\data\modules\ms_send.dll"
+ File "anope-1.8.0\data\modules\ms_sendall.dll"
+ File "anope-1.8.0\data\modules\ms_set.dll"
+ File "anope-1.8.0\data\modules\ms_staff.dll"
+ File "anope-1.8.0\data\modules\ns_access.dll"
+ File "anope-1.8.0\data\modules\ns_alist.dll"
+ File "anope-1.8.0\data\modules\ns_drop.dll"
+ File "anope-1.8.0\data\modules\ns_forbid.dll"
+ File "anope-1.8.0\data\modules\ns_getemail.dll"
+ File "anope-1.8.0\data\modules\ns_getpass.dll"
+ File "anope-1.8.0\data\modules\ns_ghost.dll"
+ File "anope-1.8.0\data\modules\ns_group.dll"
+ File "anope-1.8.0\data\modules\ns_help.dll"
+ File "anope-1.8.0\data\modules\ns_identify.dll"
+ File "anope-1.8.0\data\modules\ns_info.dll"
+ File "anope-1.8.0\data\modules\ns_list.dll"
+ File "anope-1.8.0\data\modules\ns_logout.dll"
+ File "anope-1.8.0\data\modules\ns_maxemail.dll"
+ File "anope-1.8.0\data\modules\ns_recover.dll"
+ File "anope-1.8.0\data\modules\ns_register.dll"
+ File "anope-1.8.0\data\modules\ns_release.dll"
+ File "anope-1.8.0\data\modules\ns_saset.dll"
+ File "anope-1.8.0\data\modules\ns_sendpass.dll"
+ File "anope-1.8.0\data\modules\ns_set.dll"
+ File "anope-1.8.0\data\modules\ns_status.dll"
+ File "anope-1.8.0\data\modules\ns_suspend.dll"
+ File "anope-1.8.0\data\modules\ns_update.dll"
+ File "anope-1.8.0\data\modules\os_admin.dll"
+ File "anope-1.8.0\data\modules\os_akill.dll"
+ File "anope-1.8.0\data\modules\os_chankill.dll"
+ File "anope-1.8.0\data\modules\os_chanlist.dll"
+ File "anope-1.8.0\data\modules\os_clearmodes.dll"
+ File "anope-1.8.0\data\modules\os_defcon.dll"
+ File "anope-1.8.0\data\modules\os_global.dll"
+ File "anope-1.8.0\data\modules\os_help.dll"
+ File "anope-1.8.0\data\modules\os_ignore.dll"
+ File "anope-1.8.0\data\modules\os_info.dll"
+ File "anope-1.8.0\data\modules\os_jupe.dll"
+ File "anope-1.8.0\data\modules\os_kick.dll"
+ File "anope-1.8.0\data\modules\os_logonnews.dll"
+ File "anope-1.8.0\data\modules\os_mode.dll"
+ File "anope-1.8.0\data\modules\os_modinfo.dll"
+ File "anope-1.8.0\data\modules\os_modlist.dll"
+ File "anope-1.8.0\data\modules\os_modload.dll"
+ File "anope-1.8.0\data\modules\os_modunload.dll"
+ File "anope-1.8.0\data\modules\os_noop.dll"
+ File "anope-1.8.0\data\modules\os_oline.dll"
+ File "anope-1.8.0\data\modules\os_oper.dll"
+ File "anope-1.8.0\data\modules\os_opernews.dll"
+ File "anope-1.8.0\data\modules\os_quit.dll"
+ File "anope-1.8.0\data\modules\os_randomnews.dll"
+ File "anope-1.8.0\data\modules\os_raw.dll"
+ File "anope-1.8.0\data\modules\os_reload.dll"
+ File "anope-1.8.0\data\modules\os_restart.dll"
+ File "anope-1.8.0\data\modules\os_session.dll"
+ File "anope-1.8.0\data\modules\os_set.dll"
+ File "anope-1.8.0\data\modules\os_sgline.dll"
+ File "anope-1.8.0\data\modules\os_shutdown.dll"
+ File "anope-1.8.0\data\modules\os_sqline.dll"
+ File "anope-1.8.0\data\modules\os_staff.dll"
+ File "anope-1.8.0\data\modules\os_stats.dll"
+ File "anope-1.8.0\data\modules\os_svsnick.dll"
+ File "anope-1.8.0\data\modules\os_szline.dll"
+ File "anope-1.8.0\data\modules\os_umode.dll"
+ File "anope-1.8.0\data\modules\os_update.dll"
+ File "anope-1.8.0\data\modules\os_userlist.dll"
+ File "anope-1.8.0\data\modules\plexus2.dll"
+ File "anope-1.8.0\data\modules\plexus3.dll"
+ File "anope-1.8.0\data\modules\ptlink.dll"
+ File "anope-1.8.0\data\modules\rageircd.dll"
+ File "anope-1.8.0\data\modules\ratbox.dll"
+ File "anope-1.8.0\data\modules\shadowircd.dll"
+ File "anope-1.8.0\data\modules\solidircd.dll"
+ File "anope-1.8.0\data\modules\ultimate2.dll"
+ File "anope-1.8.0\data\modules\ultimate3.dll"
+ File "anope-1.8.0\data\modules\unreal31.dll"
+ File "anope-1.8.0\data\modules\unreal32.dll"
+ File "anope-1.8.0\data\modules\viagra.dll"
+ SetOutPath "$INSTDIR\data\modules\runtime"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0\data\tables.sql"
+ SetOutPath "$INSTDIR\docs"
+ File "anope-1.8.0\docs\BUGS.txt"
+ File "anope-1.8.0\docs\COPYING.txt"
+ File "anope-1.8.0\docs\DEFCON.txt"
+ File "anope-1.8.0\docs\EVENTS.txt"
+ File "anope-1.8.0\docs\FAQ.txt"
+ File "anope-1.8.0\docs\INSTALL.txt"
+ File "anope-1.8.0\docs\IRCD.txt"
+ File "anope-1.8.0\docs\MODULES.txt"
+ File "anope-1.8.0\docs\MYSQL.txt"
+ File "anope-1.8.0\docs\NEWS.txt"
+ File "anope-1.8.0\docs\OLDCHANGES.txt"
+ File "anope-1.8.0\docs\PROXY.txt"
+ File "anope-1.8.0\docs\README.txt"
+ File "anope-1.8.0\docs\WIN32.txt"
+ File "anope-1.8.0\docs\OLDNEWS.txt"
+
+SectionEnd
+
+Section -AdditionalIcons
+ SetOutPath $INSTDIR
+ WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
+ CreateShortCut "$SMPROGRAMS\Anope\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
+ CreateShortCut "$SMPROGRAMS\Anope\Uninstall.lnk" "$INSTDIR\uninst.exe"
+SectionEnd
+
+Section -Post
+ WriteUninstaller "$INSTDIR\uninst.exe"
+ WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\anope.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\anope.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+SectionEnd
+
+
+Function un.onUninstSuccess
+ HideWindow
+ MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
+FunctionEnd
+
+Function un.onInit
+!insertmacro MUI_UNGETLANGUAGE
+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
+ Abort
+FunctionEnd
+
+Section Uninstall
+ Delete "$INSTDIR\${PRODUCT_NAME}.url"
+ Delete "$INSTDIR\uninst.exe"
+ Delete "$INSTDIR\docs\WIN32.txt"
+ Delete "$INSTDIR\docs\README.txt"
+ Delete "$INSTDIR\docs\PROXY.txt"
+ Delete "$INSTDIR\docs\OLDCHANGES.txt"
+ Delete "$INSTDIR\docs\OLDNEWS.txt"
+ Delete "$INSTDIR\docs\NEWS.txt"
+ Delete "$INSTDIR\docs\MYSQL.txt"
+ Delete "$INSTDIR\docs\MODULES.txt"
+ Delete "$INSTDIR\docs\IRCD.txt"
+ Delete "$INSTDIR\docs\INSTALL.txt"
+ Delete "$INSTDIR\docs\FAQ.txt"
+ Delete "$INSTDIR\docs\EVENTS.txt"
+ Delete "$INSTDIR\docs\DEFCON.txt"
+ Delete "$INSTDIR\docs\COPYING.txt"
+ Delete "$INSTDIR\docs\BUGS.txt"
+ Delete "$INSTDIR\data\tables.sql"
+ Delete "$INSTDIR\data\modules\viagra.dll"
+ Delete "$INSTDIR\data\modules\unreal32.dll"
+ Delete "$INSTDIR\data\modules\unreal31.dll"
+ Delete "$INSTDIR\data\modules\ultimate3.dll"
+ Delete "$INSTDIR\data\modules\ultimate2.dll"
+ Delete "$INSTDIR\data\modules\solidircd.dll"
+ Delete "$INSTDIR\data\modules\shadowircd.dll"
+ Delete "$INSTDIR\data\modules\ratbox.dll"
+ Delete "$INSTDIR\data\modules\rageircd.dll"
+ Delete "$INSTDIR\data\modules\ptlink.dll"
+ Delete "$INSTDIR\data\modules\plexus3.dll"
+ Delete "$INSTDIR\data\modules\plexus2.dll"
+ Delete "$INSTDIR\data\modules\os_userlist.dll"
+ Delete "$INSTDIR\data\modules\os_update.dll"
+ Delete "$INSTDIR\data\modules\os_umode.dll"
+ Delete "$INSTDIR\data\modules\os_szline.dll"
+ Delete "$INSTDIR\data\modules\os_svsnick.dll"
+ Delete "$INSTDIR\data\modules\os_stats.dll"
+ Delete "$INSTDIR\data\modules\os_staff.dll"
+ Delete "$INSTDIR\data\modules\os_sqline.dll"
+ Delete "$INSTDIR\data\modules\os_shutdown.dll"
+ Delete "$INSTDIR\data\modules\os_sgline.dll"
+ Delete "$INSTDIR\data\modules\os_set.dll"
+ Delete "$INSTDIR\data\modules\os_session.dll"
+ Delete "$INSTDIR\data\modules\os_restart.dll"
+ Delete "$INSTDIR\data\modules\os_reload.dll"
+ Delete "$INSTDIR\data\modules\os_raw.dll"
+ Delete "$INSTDIR\data\modules\os_randomnews.dll"
+ Delete "$INSTDIR\data\modules\os_quit.dll"
+ Delete "$INSTDIR\data\modules\os_opernews.dll"
+ Delete "$INSTDIR\data\modules\os_oper.dll"
+ Delete "$INSTDIR\data\modules\os_oline.dll"
+ Delete "$INSTDIR\data\modules\os_noop.dll"
+ Delete "$INSTDIR\data\modules\os_modunload.dll"
+ Delete "$INSTDIR\data\modules\os_modload.dll"
+ Delete "$INSTDIR\data\modules\os_modlist.dll"
+ Delete "$INSTDIR\data\modules\os_modinfo.dll"
+ Delete "$INSTDIR\data\modules\os_mode.dll"
+ Delete "$INSTDIR\data\modules\os_logonnews.dll"
+ Delete "$INSTDIR\data\modules\os_kick.dll"
+ Delete "$INSTDIR\data\modules\os_jupe.dll"
+ Delete "$INSTDIR\data\modules\os_info.dll"
+ Delete "$INSTDIR\data\modules\os_ignore.dll"
+ Delete "$INSTDIR\data\modules\os_help.dll"
+ Delete "$INSTDIR\data\modules\os_global.dll"
+ Delete "$INSTDIR\data\modules\os_defcon.dll"
+ Delete "$INSTDIR\data\modules\os_clearmodes.dll"
+ Delete "$INSTDIR\data\modules\os_chanlist.dll"
+ Delete "$INSTDIR\data\modules\os_chankill.dll"
+ Delete "$INSTDIR\data\modules\os_akill.dll"
+ Delete "$INSTDIR\data\modules\os_admin.dll"
+ Delete "$INSTDIR\data\modules\ns_update.dll"
+ Delete "$INSTDIR\data\modules\ns_suspend.dll"
+ Delete "$INSTDIR\data\modules\ns_status.dll"
+ Delete "$INSTDIR\data\modules\ns_set.dll"
+ Delete "$INSTDIR\data\modules\ns_sendpass.dll"
+ Delete "$INSTDIR\data\modules\ns_saset.dll"
+ Delete "$INSTDIR\data\modules\ns_release.dll"
+ Delete "$INSTDIR\data\modules\ns_register.dll"
+ Delete "$INSTDIR\data\modules\ns_recover.dll"
+ Delete "$INSTDIR\data\modules\ns_maxemail.dll"
+ Delete "$INSTDIR\data\modules\ns_logout.dll"
+ Delete "$INSTDIR\data\modules\ns_list.dll"
+ Delete "$INSTDIR\data\modules\ns_info.dll"
+ Delete "$INSTDIR\data\modules\ns_identify.dll"
+ Delete "$INSTDIR\data\modules\ns_help.dll"
+ Delete "$INSTDIR\data\modules\ns_group.dll"
+ Delete "$INSTDIR\data\modules\ns_ghost.dll"
+ Delete "$INSTDIR\data\modules\ns_getpass.dll"
+ Delete "$INSTDIR\data\modules\ns_getemail.dll"
+ Delete "$INSTDIR\data\modules\ns_forbid.dll"
+ Delete "$INSTDIR\data\modules\ns_drop.dll"
+ Delete "$INSTDIR\data\modules\ns_alist.dll"
+ Delete "$INSTDIR\data\modules\ns_access.dll"
+ Delete "$INSTDIR\data\modules\ms_staff.dll"
+ Delete "$INSTDIR\data\modules\ms_set.dll"
+ Delete "$INSTDIR\data\modules\ms_sendall.dll"
+ Delete "$INSTDIR\data\modules\ms_send.dll"
+ Delete "$INSTDIR\data\modules\ms_rsend.dll"
+ Delete "$INSTDIR\data\modules\ms_read.dll"
+ Delete "$INSTDIR\data\modules\ms_list.dll"
+ Delete "$INSTDIR\data\modules\ms_info.dll"
+ Delete "$INSTDIR\data\modules\ms_help.dll"
+ Delete "$INSTDIR\data\modules\ms_del.dll"
+ Delete "$INSTDIR\data\modules\ms_check.dll"
+ Delete "$INSTDIR\data\modules\ms_cancel.dll"
+ Delete "$INSTDIR\data\modules\inspircd11.dll"
+ Delete "$INSTDIR\data\modules\inspircd10.dll"
+ Delete "$INSTDIR\data\modules\hybrid.dll"
+ Delete "$INSTDIR\data\modules\hs_setall.dll"
+ Delete "$INSTDIR\data\modules\hs_set.dll"
+ Delete "$INSTDIR\data\modules\hs_request.dll"
+ Delete "$INSTDIR\data\modules\hs_on.dll"
+ Delete "$INSTDIR\data\modules\hs_off.dll"
+ Delete "$INSTDIR\data\modules\hs_list.dll"
+ Delete "$INSTDIR\data\modules\hs_help.dll"
+ Delete "$INSTDIR\data\modules\hs_group.dll"
+ Delete "$INSTDIR\data\modules\hs_delall.dll"
+ Delete "$INSTDIR\data\modules\hs_del.dll"
+ Delete "$INSTDIR\data\modules\he_help.dll"
+ Delete "$INSTDIR\data\modules\enc_old.dll"
+ Delete "$INSTDIR\data\modules\enc_none.dll"
+ Delete "$INSTDIR\data\modules\enc_md5.dll"
+ Delete "$INSTDIR\data\modules\enc_sha1.dll"
+ Delete "$INSTDIR\data\modules\dreamforge.dll"
+ Delete "$INSTDIR\data\modules\cs_xop.dll"
+ Delete "$INSTDIR\data\modules\cs_topic.dll"
+ Delete "$INSTDIR\data\modules\cs_tban.dll"
+ Delete "$INSTDIR\data\modules\cs_suspend.dll"
+ Delete "$INSTDIR\data\modules\cs_status.dll"
+ Delete "$INSTDIR\data\modules\cs_set.dll"
+ Delete "$INSTDIR\data\modules\cs_sendpass.dll"
+ Delete "$INSTDIR\data\modules\cs_register.dll"
+ Delete "$INSTDIR\data\modules\cs_modes.dll"
+ Delete "$INSTDIR\data\modules\cs_logout.dll"
+ Delete "$INSTDIR\data\modules\cs_list.dll"
+ Delete "$INSTDIR\data\modules\cs_kick.dll"
+ Delete "$INSTDIR\data\modules\cs_invite.dll"
+ Delete "$INSTDIR\data\modules\cs_info.dll"
+ Delete "$INSTDIR\data\modules\cs_identify.dll"
+ Delete "$INSTDIR\data\modules\cs_help.dll"
+ Delete "$INSTDIR\data\modules\cs_getpass.dll"
+ Delete "$INSTDIR\data\modules\cs_getkey.dll"
+ Delete "$INSTDIR\data\modules\cs_forbid.dll"
+ Delete "$INSTDIR\data\modules\cs_enforce.dll"
+ Delete "$INSTDIR\data\modules\cs_drop.dll"
+ Delete "$INSTDIR\data\modules\cs_clear.dll"
+ Delete "$INSTDIR\data\modules\cs_ban.dll"
+ Delete "$INSTDIR\data\modules\cs_appendtopic.dll"
+ Delete "$INSTDIR\data\modules\cs_akick.dll"
+ Delete "$INSTDIR\data\modules\cs_access.dll"
+ Delete "$INSTDIR\data\modules\charybdis.dll"
+ Delete "$INSTDIR\data\modules\bs_unassign.dll"
+ Delete "$INSTDIR\data\modules\bs_set.dll"
+ Delete "$INSTDIR\data\modules\bs_say.dll"
+ Delete "$INSTDIR\data\modules\bs_kick.dll"
+ Delete "$INSTDIR\data\modules\bs_info.dll"
+ Delete "$INSTDIR\data\modules\bs_help.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_unban.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_seen.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_owner.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_kickban.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_kick.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy.dll"
+ Delete "$INSTDIR\data\modules\bs_botlist.dll"
+ Delete "$INSTDIR\data\modules\bs_bot.dll"
+ Delete "$INSTDIR\data\modules\bs_badwords.dll"
+ Delete "$INSTDIR\data\modules\bs_assign.dll"
+ Delete "$INSTDIR\data\modules\bs_act.dll"
+ Delete "$INSTDIR\data\modules\bahamut.dll"
+ Delete "$INSTDIR\data\languages\tr"
+ Delete "$INSTDIR\data\languages\ru"
+ Delete "$INSTDIR\data\languages\pt"
+ Delete "$INSTDIR\data\languages\pl"
+ Delete "$INSTDIR\data\languages\nl"
+ Delete "$INSTDIR\data\languages\it"
+ Delete "$INSTDIR\data\languages\hun"
+ Delete "$INSTDIR\data\languages\gr"
+ Delete "$INSTDIR\data\languages\fr"
+ Delete "$INSTDIR\data\languages\es"
+ Delete "$INSTDIR\data\languages\en_us"
+ Delete "$INSTDIR\data\languages\de"
+ Delete "$INSTDIR\data\languages\cat"
+ Delete "$INSTDIR\data\example.conf"
+ Delete "$INSTDIR\data\epona2anope.exe.manifest"
+ Delete "$INSTDIR\data\epona2anope.exe"
+ Delete "$INSTDIR\data\db-merger.exe.manifest"
+ Delete "$INSTDIR\data\db-merger.exe"
+ Delete "$INSTDIR\data\bin\register"
+ Delete "$INSTDIR\data\bin\mydbgen"
+ Delete "$INSTDIR\data\bin\langtool"
+ Delete "$INSTDIR\data\bin\cp-recursive"
+ Delete "$INSTDIR\data\bin\anoperc.in"
+ Delete "$INSTDIR\data\bin\am"
+ Delete "$INSTDIR\data\anopesmtp.exe.manifest"
+ Delete "$INSTDIR\data\anopesmtp.exe"
+ Delete "$INSTDIR\Changes.txt"
+ Delete "$INSTDIR\Changes.mysql.txt"
+ Delete "$INSTDIR\Changes.lang.txt"
+ Delete "$INSTDIR\Changes.conf.txt"
+ Delete "$INSTDIR\anope.exe.manifest"
+ Delete "$INSTDIR\anope.exe"
+Delete "$INSTDIR\anope.bat"
+ SetShellVarContext all
+ Delete "$SMPROGRAMS\Anope\Uninstall.lnk"
+ Delete "$SMPROGRAMS\Anope\Website.lnk"
+ Delete "$DESKTOP\Anope IRC Services.lnk"
+ Delete "$SMPROGRAMS\Anope\Anope IRC Services.lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Debug and Window Logging).lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Window Logging).lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (No Third Party Modules).lnk"
+
+RMDir "$SMPROGRAMS\Anope\Advanced"
+ RMDir "$SMPROGRAMS\Anope"
+ RMDir "$INSTDIR\docs"
+ RMDir "$INSTDIR\data\modules"
+RMDir "$INSTDIR\data\backups"
+ RMDir "$INSTDIR\data\logs"
+ RMDir "$INSTDIR\data\languages"
+ RMDir "$INSTDIR\data\bin"
+ RMDir "$INSTDIR\data"
+ RMDir "$INSTDIR"
+
+ DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+ DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
+ SetAutoClose true
+SectionEnd \ No newline at end of file
diff --git a/src/tools/Anope_MySQL_Install_Script.nsi b/src/tools/Anope_MySQL_Install_Script.nsi
new file mode 100644
index 000000000..ead85e449
--- /dev/null
+++ b/src/tools/Anope_MySQL_Install_Script.nsi
@@ -0,0 +1,542 @@
+; Script generated by the HM NIS Edit Script Wizard.
+
+; HM NIS Edit Wizard helper defines
+!define PRODUCT_NAME "Anope IRC Services"
+!define PRODUCT_VERSION "1.8.0-MySQL"
+!define PRODUCT_PUBLISHER "Anope"
+!define PRODUCT_WEB_SITE "http://www.anope.org"
+!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\anope.exe"
+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+
+; MUI 1.67 compatible ------
+!include "MUI.nsh"
+
+; MUI Settings
+!define MUI_ABORTWARNING
+!define MUI_ICON "anope-icon.ico"
+!define MUI_UNICON "anope-icon.ico"
+
+; Language Selection Dialog Settings
+!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
+!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
+!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"
+
+; Welcome page
+!insertmacro MUI_PAGE_WELCOME
+; License page
+!define MUI_LICENSEPAGE_RADIOBUTTONS
+!insertmacro MUI_PAGE_LICENSE "anope-1.8.0-MySQL\docs\COPYING.txt"
+; Directory page
+!insertmacro MUI_PAGE_DIRECTORY
+; Instfiles page
+!insertmacro MUI_PAGE_INSTFILES
+; Finish page
+!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\docs\README.txt"
+!insertmacro MUI_PAGE_FINISH
+
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Language files
+!insertmacro MUI_LANGUAGE "Dutch"
+!insertmacro MUI_LANGUAGE "English"
+!insertmacro MUI_LANGUAGE "French"
+!insertmacro MUI_LANGUAGE "German"
+!insertmacro MUI_LANGUAGE "Italian"
+!insertmacro MUI_LANGUAGE "Portuguese"
+!insertmacro MUI_LANGUAGE "Spanish"
+
+; MUI end ------
+
+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+OutFile "Anope-1.8.0-MySQL.exe"
+InstallDir "$PROGRAMFILES\Anope"
+InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
+ShowInstDetails show
+ShowUnInstDetails show
+
+Function .onInit
+ !insertmacro MUI_LANGDLL_DISPLAY
+FunctionEnd
+
+Section "MainSection" SEC01
+ SetOutPath "$INSTDIR"
+ File "anope-1.8.0-MySQL\anope.exe"
+File "anope-1.8.0\anope.bat"
+ SetShellVarContext all
+ CreateDirectory "$SMPROGRAMS\Anope"
+ CreateShortCut "$SMPROGRAMS\Anope\Anope IRC Services.lnk" "$INSTDIR\anope.exe"
+ CreateShortCut "$DESKTOP\Anope IRC Services.lnk" "$INSTDIR\anope.exe"
+ CreateDirectory "$SMPROGRAMS\Anope\Advanced"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Debug and Window Logging).lnk" "$INSTDIR\anope.bat" "-debug -nofork"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Window Logging).lnk" "$INSTDIR\anope.bat" "-nofork"
+ CreateShortCut "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (No Third Party Modules).lnk" "$INSTDIR\anope.bat" "-nothird"
+
+ File "anope-1.8.0-MySQL\anope.exe.manifest"
+ File "anope-1.8.0-MySQL\Changes.conf.txt"
+ File "anope-1.8.0-MySQL\Changes.lang.txt"
+ File "anope-1.8.0-MySQL\Changes.mysql.txt"
+ File "anope-1.8.0-MySQL\Changes.txt"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0-MySQL\data\anopesmtp.exe"
+ File "anope-1.8.0-MySQL\data\anopesmtp.exe.manifest"
+ SetOutPath "$INSTDIR\data\bin"
+ File "anope-1.8.0-MySQL\data\bin\am"
+ File "anope-1.8.0-MySQL\data\bin\anoperc.in"
+ File "anope-1.8.0-MySQL\data\bin\cp-recursive"
+ File "anope-1.8.0-MySQL\data\bin\langtool"
+ File "anope-1.8.0-MySQL\data\bin\mydbgen"
+ File "anope-1.8.0-MySQL\data\bin\register"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0-MySQL\data\db-merger.exe"
+ File "anope-1.8.0-MySQL\data\db-merger.exe.manifest"
+ File "anope-1.8.0-MySQL\data\epona2anope.exe"
+ File "anope-1.8.0-MySQL\data\epona2anope.exe.manifest"
+ File "anope-1.8.0-MySQL\data\example.conf"
+ SetOutPath "$INSTDIR\data\languages"
+ File "anope-1.8.0-MySQL\data\languages\cat"
+ File "anope-1.8.0-MySQL\data\languages\de"
+ File "anope-1.8.0-MySQL\data\languages\en_us"
+ File "anope-1.8.0-MySQL\data\languages\es"
+ File "anope-1.8.0-MySQL\data\languages\fr"
+ File "anope-1.8.0-MySQL\data\languages\gr"
+ File "anope-1.8.0-MySQL\data\languages\hun"
+ File "anope-1.8.0-MySQL\data\languages\it"
+ File "anope-1.8.0-MySQL\data\languages\nl"
+ File "anope-1.8.0-MySQL\data\languages\pl"
+ File "anope-1.8.0-MySQL\data\languages\pt"
+ File "anope-1.8.0-MySQL\data\languages\ru"
+ File "anope-1.8.0-MySQL\data\languages\tr"
+ SetOutPath "$INSTDIR\data\logs"
+SetOutPath "$INSTDIR\data\backups"
+ SetOutPath "$INSTDIR\data\modules"
+ File "anope-1.8.0-MySQL\data\modules\bahamut.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_act.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_assign.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_badwords.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_bot.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_botlist.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy_kick.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy_kickban.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy_owner.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy_seen.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_fantasy_unban.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_info.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_kick.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_say.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\bs_unassign.dll"
+ File "anope-1.8.0-MySQL\data\modules\charybdis.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_access.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_akick.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_appendtopic.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_ban.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_clear.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_drop.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_enforce.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_forbid.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_getkey.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_getpass.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_identify.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_info.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_invite.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_kick.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_list.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_logout.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_modes.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_register.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_sendpass.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_status.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_suspend.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_tban.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_topic.dll"
+ File "anope-1.8.0-MySQL\data\modules\cs_xop.dll"
+ File "anope-1.8.0-MySQL\data\modules\dreamforge.dll"
+ File "anope-1.8.0-MySQL\data\modules\enc_md5.dll"
+ File "anope-1.8.0-MySQL\data\modules\enc_sha1.dll"
+ File "anope-1.8.0-MySQL\data\modules\enc_none.dll"
+ File "anope-1.8.0-MySQL\data\modules\enc_old.dll"
+ File "anope-1.8.0-MySQL\data\modules\he_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_del.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_delall.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_group.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_list.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_off.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_on.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_request.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\hs_setall.dll"
+ File "anope-1.8.0-MySQL\data\modules\hybrid.dll"
+ File "anope-1.8.0-MySQL\data\modules\inspircd10.dll"
+ File "anope-1.8.0-MySQL\data\modules\inspircd11.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_cancel.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_check.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_del.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_info.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_list.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_read.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_rsend.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_send.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_sendall.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\ms_staff.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_access.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_alist.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_drop.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_forbid.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_getemail.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_getpass.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_ghost.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_group.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_identify.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_info.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_list.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_logout.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_maxemail.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_recover.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_register.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_release.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_saset.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_sendpass.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_status.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_suspend.dll"
+ File "anope-1.8.0-MySQL\data\modules\ns_update.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_admin.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_akill.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_chankill.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_chanlist.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_clearmodes.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_defcon.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_global.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_help.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_ignore.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_info.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_jupe.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_kick.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_logonnews.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_mode.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_modinfo.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_modlist.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_modload.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_modunload.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_noop.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_oline.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_oper.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_opernews.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_quit.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_randomnews.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_raw.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_reload.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_restart.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_session.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_set.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_sgline.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_shutdown.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_sqline.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_staff.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_stats.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_svsnick.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_szline.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_umode.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_update.dll"
+ File "anope-1.8.0-MySQL\data\modules\os_userlist.dll"
+ File "anope-1.8.0-MySQL\data\modules\plexus2.dll"
+ File "anope-1.8.0-MySQL\data\modules\plexus3.dll"
+ File "anope-1.8.0-MySQL\data\modules\ptlink.dll"
+ File "anope-1.8.0-MySQL\data\modules\rageircd.dll"
+ File "anope-1.8.0-MySQL\data\modules\ratbox.dll"
+ File "anope-1.8.0-MySQL\data\modules\shadowircd.dll"
+ File "anope-1.8.0-MySQL\data\modules\solidircd.dll"
+ File "anope-1.8.0-MySQL\data\modules\ultimate2.dll"
+ File "anope-1.8.0-MySQL\data\modules\ultimate3.dll"
+ File "anope-1.8.0-MySQL\data\modules\unreal31.dll"
+ File "anope-1.8.0-MySQL\data\modules\unreal32.dll"
+ File "anope-1.8.0-MySQL\data\modules\viagra.dll"
+ SetOutPath "$INSTDIR\data\modules\runtime"
+ SetOutPath "$INSTDIR\data"
+ File "anope-1.8.0-MySQL\data\tables.sql"
+ SetOutPath "$INSTDIR\docs"
+ File "anope-1.8.0-MySQL\docs\BUGS.txt"
+ File "anope-1.8.0-MySQL\docs\COPYING.txt"
+ File "anope-1.8.0-MySQL\docs\DEFCON.txt"
+ File "anope-1.8.0-MySQL\docs\EVENTS.txt"
+ File "anope-1.8.0-MySQL\docs\FAQ.txt"
+ File "anope-1.8.0-MySQL\docs\INSTALL.txt"
+ File "anope-1.8.0-MySQL\docs\IRCD.txt"
+ File "anope-1.8.0-MySQL\docs\MODULES.txt"
+ File "anope-1.8.0-MySQL\docs\MYSQL.txt"
+ File "anope-1.8.0-MySQL\docs\NEWS.txt"
+ File "anope-1.8.0-MySQL\docs\OLDNEWS.txt"
+ File "anope-1.8.0-MySQL\docs\OLDCHANGES.txt"
+ File "anope-1.8.0-MySQL\docs\PROXY.txt"
+ File "anope-1.8.0-MySQL\docs\README.txt"
+ File "anope-1.8.0-MySQL\docs\WIN32.txt"
+SectionEnd
+
+Section -AdditionalIcons
+ SetOutPath $INSTDIR
+ WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
+ CreateShortCut "$SMPROGRAMS\Anope\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
+ CreateShortCut "$SMPROGRAMS\Anope\Uninstall.lnk" "$INSTDIR\uninst.exe"
+SectionEnd
+
+Section -Post
+ WriteUninstaller "$INSTDIR\uninst.exe"
+ WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\anope.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\anope.exe"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+SectionEnd
+
+
+Function un.onUninstSuccess
+ HideWindow
+ MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
+FunctionEnd
+
+Function un.onInit
+!insertmacro MUI_UNGETLANGUAGE
+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
+ Abort
+FunctionEnd
+
+Section Uninstall
+ Delete "$INSTDIR\${PRODUCT_NAME}.url"
+ Delete "$INSTDIR\uninst.exe"
+ Delete "$INSTDIR\docs\WIN32.txt"
+ Delete "$INSTDIR\docs\README.txt"
+ Delete "$INSTDIR\docs\PROXY.txt"
+ Delete "$INSTDIR\docs\OLDCHANGES.txt"
+ Delete "$INSTDIR\docs\OLDNEWS.txt"
+ Delete "$INSTDIR\docs\NEWS.txt"
+ Delete "$INSTDIR\docs\MYSQL.txt"
+ Delete "$INSTDIR\docs\MODULES.txt"
+ Delete "$INSTDIR\docs\IRCD.txt"
+ Delete "$INSTDIR\docs\INSTALL.txt"
+ Delete "$INSTDIR\docs\FAQ.txt"
+ Delete "$INSTDIR\docs\EVENTS.txt"
+ Delete "$INSTDIR\docs\DEFCON.txt"
+ Delete "$INSTDIR\docs\COPYING.txt"
+ Delete "$INSTDIR\docs\BUGS.txt"
+ Delete "$INSTDIR\data\tables.sql"
+ Delete "$INSTDIR\data\modules\viagra.dll"
+ Delete "$INSTDIR\data\modules\unreal32.dll"
+ Delete "$INSTDIR\data\modules\unreal31.dll"
+ Delete "$INSTDIR\data\modules\ultimate3.dll"
+ Delete "$INSTDIR\data\modules\ultimate2.dll"
+ Delete "$INSTDIR\data\modules\solidircd.dll"
+ Delete "$INSTDIR\data\modules\shadowircd.dll"
+ Delete "$INSTDIR\data\modules\ratbox.dll"
+ Delete "$INSTDIR\data\modules\rageircd.dll"
+ Delete "$INSTDIR\data\modules\ptlink.dll"
+ Delete "$INSTDIR\data\modules\plexus3.dll"
+ Delete "$INSTDIR\data\modules\plexus2.dll"
+ Delete "$INSTDIR\data\modules\os_userlist.dll"
+ Delete "$INSTDIR\data\modules\os_update.dll"
+ Delete "$INSTDIR\data\modules\os_umode.dll"
+ Delete "$INSTDIR\data\modules\os_szline.dll"
+ Delete "$INSTDIR\data\modules\os_svsnick.dll"
+ Delete "$INSTDIR\data\modules\os_stats.dll"
+ Delete "$INSTDIR\data\modules\os_staff.dll"
+ Delete "$INSTDIR\data\modules\os_sqline.dll"
+ Delete "$INSTDIR\data\modules\os_shutdown.dll"
+ Delete "$INSTDIR\data\modules\os_sgline.dll"
+ Delete "$INSTDIR\data\modules\os_set.dll"
+ Delete "$INSTDIR\data\modules\os_session.dll"
+ Delete "$INSTDIR\data\modules\os_restart.dll"
+ Delete "$INSTDIR\data\modules\os_reload.dll"
+ Delete "$INSTDIR\data\modules\os_raw.dll"
+ Delete "$INSTDIR\data\modules\os_randomnews.dll"
+ Delete "$INSTDIR\data\modules\os_quit.dll"
+ Delete "$INSTDIR\data\modules\os_opernews.dll"
+ Delete "$INSTDIR\data\modules\os_oper.dll"
+ Delete "$INSTDIR\data\modules\os_oline.dll"
+ Delete "$INSTDIR\data\modules\os_noop.dll"
+ Delete "$INSTDIR\data\modules\os_modunload.dll"
+ Delete "$INSTDIR\data\modules\os_modload.dll"
+ Delete "$INSTDIR\data\modules\os_modlist.dll"
+ Delete "$INSTDIR\data\modules\os_modinfo.dll"
+ Delete "$INSTDIR\data\modules\os_mode.dll"
+ Delete "$INSTDIR\data\modules\os_logonnews.dll"
+ Delete "$INSTDIR\data\modules\os_kick.dll"
+ Delete "$INSTDIR\data\modules\os_jupe.dll"
+ Delete "$INSTDIR\data\modules\os_info.dll"
+ Delete "$INSTDIR\data\modules\os_ignore.dll"
+ Delete "$INSTDIR\data\modules\os_help.dll"
+ Delete "$INSTDIR\data\modules\os_global.dll"
+ Delete "$INSTDIR\data\modules\os_defcon.dll"
+ Delete "$INSTDIR\data\modules\os_clearmodes.dll"
+ Delete "$INSTDIR\data\modules\os_chanlist.dll"
+ Delete "$INSTDIR\data\modules\os_chankill.dll"
+ Delete "$INSTDIR\data\modules\os_akill.dll"
+ Delete "$INSTDIR\data\modules\os_admin.dll"
+ Delete "$INSTDIR\data\modules\ns_update.dll"
+ Delete "$INSTDIR\data\modules\ns_suspend.dll"
+ Delete "$INSTDIR\data\modules\ns_status.dll"
+ Delete "$INSTDIR\data\modules\ns_set.dll"
+ Delete "$INSTDIR\data\modules\ns_sendpass.dll"
+ Delete "$INSTDIR\data\modules\ns_saset.dll"
+ Delete "$INSTDIR\data\modules\ns_release.dll"
+ Delete "$INSTDIR\data\modules\ns_register.dll"
+ Delete "$INSTDIR\data\modules\ns_recover.dll"
+ Delete "$INSTDIR\data\modules\ns_maxemail.dll"
+ Delete "$INSTDIR\data\modules\ns_logout.dll"
+ Delete "$INSTDIR\data\modules\ns_list.dll"
+ Delete "$INSTDIR\data\modules\ns_info.dll"
+ Delete "$INSTDIR\data\modules\ns_identify.dll"
+ Delete "$INSTDIR\data\modules\ns_help.dll"
+ Delete "$INSTDIR\data\modules\ns_group.dll"
+ Delete "$INSTDIR\data\modules\ns_ghost.dll"
+ Delete "$INSTDIR\data\modules\ns_getpass.dll"
+ Delete "$INSTDIR\data\modules\ns_getemail.dll"
+ Delete "$INSTDIR\data\modules\ns_forbid.dll"
+ Delete "$INSTDIR\data\modules\ns_drop.dll"
+ Delete "$INSTDIR\data\modules\ns_alist.dll"
+ Delete "$INSTDIR\data\modules\ns_access.dll"
+ Delete "$INSTDIR\data\modules\ms_staff.dll"
+ Delete "$INSTDIR\data\modules\ms_set.dll"
+ Delete "$INSTDIR\data\modules\ms_sendall.dll"
+ Delete "$INSTDIR\data\modules\ms_send.dll"
+ Delete "$INSTDIR\data\modules\ms_rsend.dll"
+ Delete "$INSTDIR\data\modules\ms_read.dll"
+ Delete "$INSTDIR\data\modules\ms_list.dll"
+ Delete "$INSTDIR\data\modules\ms_info.dll"
+ Delete "$INSTDIR\data\modules\ms_help.dll"
+ Delete "$INSTDIR\data\modules\ms_del.dll"
+ Delete "$INSTDIR\data\modules\ms_check.dll"
+ Delete "$INSTDIR\data\modules\ms_cancel.dll"
+ Delete "$INSTDIR\data\modules\inspircd11.dll"
+ Delete "$INSTDIR\data\modules\inspircd10.dll"
+ Delete "$INSTDIR\data\modules\hybrid.dll"
+ Delete "$INSTDIR\data\modules\hs_setall.dll"
+ Delete "$INSTDIR\data\modules\hs_set.dll"
+ Delete "$INSTDIR\data\modules\hs_request.dll"
+ Delete "$INSTDIR\data\modules\hs_on.dll"
+ Delete "$INSTDIR\data\modules\hs_off.dll"
+ Delete "$INSTDIR\data\modules\hs_list.dll"
+ Delete "$INSTDIR\data\modules\hs_help.dll"
+ Delete "$INSTDIR\data\modules\hs_group.dll"
+ Delete "$INSTDIR\data\modules\hs_delall.dll"
+ Delete "$INSTDIR\data\modules\hs_del.dll"
+ Delete "$INSTDIR\data\modules\he_help.dll"
+ Delete "$INSTDIR\data\modules\enc_old.dll"
+ Delete "$INSTDIR\data\modules\enc_none.dll"
+ Delete "$INSTDIR\data\modules\enc_md5.dll"
+ Delete "$INSTDIR\data\modules\enc_sha1.dll"
+ Delete "$INSTDIR\data\modules\dreamforge.dll"
+ Delete "$INSTDIR\data\modules\cs_xop.dll"
+ Delete "$INSTDIR\data\modules\cs_topic.dll"
+ Delete "$INSTDIR\data\modules\cs_tban.dll"
+ Delete "$INSTDIR\data\modules\cs_suspend.dll"
+ Delete "$INSTDIR\data\modules\cs_status.dll"
+ Delete "$INSTDIR\data\modules\cs_set.dll"
+ Delete "$INSTDIR\data\modules\cs_sendpass.dll"
+ Delete "$INSTDIR\data\modules\cs_register.dll"
+ Delete "$INSTDIR\data\modules\cs_modes.dll"
+ Delete "$INSTDIR\data\modules\cs_logout.dll"
+ Delete "$INSTDIR\data\modules\cs_list.dll"
+ Delete "$INSTDIR\data\modules\cs_kick.dll"
+ Delete "$INSTDIR\data\modules\cs_invite.dll"
+ Delete "$INSTDIR\data\modules\cs_info.dll"
+ Delete "$INSTDIR\data\modules\cs_identify.dll"
+ Delete "$INSTDIR\data\modules\cs_help.dll"
+ Delete "$INSTDIR\data\modules\cs_getpass.dll"
+ Delete "$INSTDIR\data\modules\cs_getkey.dll"
+ Delete "$INSTDIR\data\modules\cs_forbid.dll"
+ Delete "$INSTDIR\data\modules\cs_enforce.dll"
+ Delete "$INSTDIR\data\modules\cs_drop.dll"
+ Delete "$INSTDIR\data\modules\cs_clear.dll"
+ Delete "$INSTDIR\data\modules\cs_ban.dll"
+ Delete "$INSTDIR\data\modules\cs_appendtopic.dll"
+ Delete "$INSTDIR\data\modules\cs_akick.dll"
+ Delete "$INSTDIR\data\modules\cs_access.dll"
+ Delete "$INSTDIR\data\modules\charybdis.dll"
+ Delete "$INSTDIR\data\modules\bs_unassign.dll"
+ Delete "$INSTDIR\data\modules\bs_set.dll"
+ Delete "$INSTDIR\data\modules\bs_say.dll"
+ Delete "$INSTDIR\data\modules\bs_kick.dll"
+ Delete "$INSTDIR\data\modules\bs_info.dll"
+ Delete "$INSTDIR\data\modules\bs_help.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_unban.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_seen.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_owner.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_kickban.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy_kick.dll"
+ Delete "$INSTDIR\data\modules\bs_fantasy.dll"
+ Delete "$INSTDIR\data\modules\bs_botlist.dll"
+ Delete "$INSTDIR\data\modules\bs_bot.dll"
+ Delete "$INSTDIR\data\modules\bs_badwords.dll"
+ Delete "$INSTDIR\data\modules\bs_assign.dll"
+ Delete "$INSTDIR\data\modules\bs_act.dll"
+ Delete "$INSTDIR\data\modules\bahamut.dll"
+ Delete "$INSTDIR\data\languages\tr"
+ Delete "$INSTDIR\data\languages\ru"
+ Delete "$INSTDIR\data\languages\pt"
+ Delete "$INSTDIR\data\languages\pl"
+ Delete "$INSTDIR\data\languages\nl"
+ Delete "$INSTDIR\data\languages\it"
+ Delete "$INSTDIR\data\languages\hun"
+ Delete "$INSTDIR\data\languages\gr"
+ Delete "$INSTDIR\data\languages\fr"
+ Delete "$INSTDIR\data\languages\es"
+ Delete "$INSTDIR\data\languages\en_us"
+ Delete "$INSTDIR\data\languages\de"
+ Delete "$INSTDIR\data\languages\cat"
+ Delete "$INSTDIR\data\example.conf"
+ Delete "$INSTDIR\data\epona2anope.exe.manifest"
+ Delete "$INSTDIR\data\epona2anope.exe"
+ Delete "$INSTDIR\data\db-merger.exe.manifest"
+ Delete "$INSTDIR\data\db-merger.exe"
+ Delete "$INSTDIR\data\bin\register"
+ Delete "$INSTDIR\data\bin\mydbgen"
+ Delete "$INSTDIR\data\bin\langtool"
+ Delete "$INSTDIR\data\bin\cp-recursive"
+ Delete "$INSTDIR\data\bin\anoperc.in"
+ Delete "$INSTDIR\data\bin\am"
+ Delete "$INSTDIR\data\anopesmtp.exe.manifest"
+ Delete "$INSTDIR\data\anopesmtp.exe"
+ Delete "$INSTDIR\Changes.txt"
+ Delete "$INSTDIR\Changes.mysql.txt"
+ Delete "$INSTDIR\Changes.lang.txt"
+ Delete "$INSTDIR\Changes.conf.txt"
+ Delete "$INSTDIR\anope.exe.manifest"
+ Delete "$INSTDIR\anope.exe"
+Delete "$INSTDIR\anope.bat"
+ SetShellVarContext all
+
+ Delete "$SMPROGRAMS\Anope\Uninstall.lnk"
+ Delete "$SMPROGRAMS\Anope\Website.lnk"
+ Delete "$DESKTOP\Anope IRC Services.lnk"
+ Delete "$SMPROGRAMS\Anope\Anope IRC Services.lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Debug and Window Logging).lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (Window Logging).lnk"
+ Delete "$SMPROGRAMS\Anope\Advanced\Anope IRC Services (No Third Party Modules).lnk"
+
+RMDir "$SMPROGRAMS\Anope\Advanced"
+
+ RMDir "$SMPROGRAMS\Anope"
+ RMDir "$INSTDIR\docs"
+ RMDir "$INSTDIR\data\modules"
+ RMDir "$INSTDIR\data\logs"
+ RMDir "$INSTDIR\data\languages"
+ RMDir "$INSTDIR\data\bin"
+RMDir "$INSTDIR\data\backups"
+ RMDir "$INSTDIR\data"
+ RMDir "$INSTDIR"
+
+ DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+ DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
+ SetAutoClose true
+SectionEnd \ No newline at end of file
diff --git a/src/tools/Makefile b/src/tools/Makefile
new file mode 100644
index 000000000..c0aa9fb85
--- /dev/null
+++ b/src/tools/Makefile
@@ -0,0 +1,39 @@
+SRCS = anopesmtp.c db-merger.c epona2anope.c
+OBJS = $(SRCS:.c=.o)
+
+INCLUDES = ../../include/services.h
+
+MAKEARGS = 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'ANOPELIBS=${ANOPELIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'BINDEST=${BINDEST}' 'INSTALL=${INSTALL}' \
+ 'INCLUDEDIR=${INCLUDEDIR}' 'RM=${RM}' 'CP=${CP}' \
+ 'TOUCH=${TOUCH}' 'SHELL=${SHELL}' 'DATDEST=${DATDEST}' \
+ 'RUNGROUP=${RUNGROUP}'
+
+.c.o:
+ $(CC) $(CFLAGS) -I../include/ -c $<
+
+all: ${OBJS}
+
+distclean: spotless
+
+anopesmpt: $(OBJS)
+ $(CC) $(CFLAGS) $(OBJS) $(ANOPELIBS) $(MLIBS) -o $@ $(LDFLAGS)
+
+$(OBJS): Makefile
+anopesmtp.o: anopesmtp.c $(INCLUDES)
+db-merger.o: db-merger.c $(INCLUDES)
+epona2anope.o: epona2anope.c $(INCLUDES)
+
+clean:
+ rm -f *.o anopesmtp a.out db-merger epona2anope
+
+spotless: clean
+
+install: anopesmtp db-merger epona2anope
+ test -d ${BINDEST} || mkdir ${BINDEST}
+ test -d $(BINDEST)/tools || mkdir $(BINDEST)/tools
+ $(INSTALL) anopesmtp $(BINDEST)/tools/anopesmtp
+ $(INSTALL) db-merger $(BINDEST)/tools/db-merger
+ $(INSTALL) epona2anope $(BINDEST)/tools/epona2anope
+
+DUMMY:
diff --git a/src/tools/Makefile.win32 b/src/tools/Makefile.win32
new file mode 100644
index 000000000..77e7f2c91
--- /dev/null
+++ b/src/tools/Makefile.win32
@@ -0,0 +1,29 @@
+include ../../Makefile.inc.win32
+
+SRCS=anopesmtp.c epona2anope.c db-merger.c
+OBJECTS= $(SRCS:.c=.exe)
+CFLAGS=$(CFLAGS) /I"../../include"
+LFLAGS=/link wsock32.lib $(LIBS) $(LFLAGS)
+
+all: $(OBJECTS)
+
+distclean: clean spotless
+
+.c.exe:
+ $(CC) $(CFLAGS) $< $(LFLAGS)
+
+clean:
+ -@del *.obj
+
+spotless: clean
+ -@del *.exe *.lib *.exp
+
+install: exe_install manifest_install
+
+exe_install: FRC
+ -@copy *.exe ..\..\$(DATDEST)\
+
+manifest_install: FRC
+ -@copy *.manifest ..\..\$(DATDEST)\
+
+FRC:
diff --git a/src/tools/README b/src/tools/README
new file mode 100644
index 000000000..3acb80ad2
--- /dev/null
+++ b/src/tools/README
@@ -0,0 +1,58 @@
+Anope Bundled Tools
+-------------------
+
+1) Anope SMTP Client
+2) Anope Database Merger
+3) Epona to Anope Database Converter
+
+1) Anope SMTP Client
+
+ Provided with Anope is a simple SMTP client which can be used instead of
+ programs like SendMail in some cases.
+
+ The SMTP client can be used instead of sendmail for use with Anope's mail
+ options. To use the SMTP client instead of sendmail, find the line in your
+ services configuration file (services.conf) that defines SendMailPath. On
+ that line, change the path to your services installation directory, then
+ followed by "tools/anopesmtp" and the IP address of a valid SMTP server. It
+ should look like this:
+
+ SendMailPath "/home/anope/services/tools/anopesmtp 127.0.0.1"
+
+ If the SMTP client doesn't send mail, or if there's an other problem with
+ it, you can compile it in debug mode. To do this, open smtp.h, and look
+ for "smtp_debug" near the bottom. Change this from 0 to 1 and recompile
+ the code. This should generate a log file of what happened when it tried
+ to connect to the SMTP server.
+
+ Credits:
+ Originally written by Dominick Meglio <codemastr@unrealircd.com>
+ Ported to *nix by Trystan Scott Lee <trystan@nomadirc.net>
+
+2) Anope Database Merger
+
+ This program tries to merge two standard Anope database sets (ChanServ,
+ NickServ, BotServ, and MemoServ).
+
+ To merge two database sets, put them both in the folder where the merger
+ is located. The first database set must be named <name>1.db (nick1.db,
+ chan1.db, etc); the second database set must be named <name>2.db (nick2.db,
+ chan2.db, etc). If you execute the merger now the databases will be merged
+ into databases named <name>.db.
+
+ Credits:
+ Written by Florian Schulze <certus@anope.org>
+
+3) Epona to Anope Database Converter
+
+ This program tries to convert databases made by epona .4.15 and up to
+ standard anope databases. Currently, only the ChanServ database needs to
+ be converted.
+
+ Put your Epona (ChanServ) database in the folder where the epona2anope
+ executable file is located. Rename this ChanServ database file to
+ chan1.db and then run the converter (epona2anope). A new database called
+ chan.db will be created; this file is Anope-compatible.
+
+ Credits:
+ Written by Florian Schulze <certus@anope.org>
diff --git a/src/tools/anopesmtp.c b/src/tools/anopesmtp.c
new file mode 100644
index 000000000..4ff0c6fcf
--- /dev/null
+++ b/src/tools/anopesmtp.c
@@ -0,0 +1,604 @@
+/* smtp stuff handler for win32.
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ * Written by Dominick Meglio <codemastr@unrealircd.com>
+ * *nix port by Trystan Scott Lee <trystan@nomadirc.net>
+ *
+ */
+
+#include "smtp.h"
+
+static FILE *logfile;
+static int curday = 0;
+
+/*************************************************************************/
+
+#ifdef _WIN32
+int strcasecmp(const char *s1, const char *s2)
+{
+ register int c;
+
+ while ((c = tolower(*s1)) == tolower(*s2)) {
+ if (c == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ if (c < tolower(*s2))
+ return -1;
+ return 1;
+}
+#endif
+
+static int get_logname(char *name, int count, struct tm *tm)
+{
+
+ char timestamp[32];
+
+ if (!tm) {
+ time_t t;
+
+ time(&t);
+ tm = localtime(&t);
+ }
+
+ strftime(timestamp, count, "%Y%m%d", tm);
+ snprintf(name, count, "logs/%s.%s", "anopesmtp", timestamp);
+ curday = tm->tm_yday;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Close the log file. */
+
+void close_log(void)
+{
+ if (!logfile)
+ return;
+ fclose(logfile);
+ logfile = NULL;
+}
+
+/*************************************************************************/
+
+static void remove_log(void)
+{
+ time_t t;
+ struct tm tm;
+
+ char name[PATH_MAX];
+
+ time(&t);
+ t -= (60 * 60 * 24 * 30);
+ tm = *localtime(&t);
+
+ if (!get_logname(name, sizeof(name), &tm))
+ return;
+ unlink(name);
+}
+
+/*************************************************************************/
+
+/* Open the log file. Return -1 if the log file could not be opened, else
+ * return 0. */
+
+int open_log(void)
+{
+ char name[PATH_MAX];
+
+ if (logfile)
+ return 0;
+
+ if (!get_logname(name, sizeof(name), NULL))
+ return 0;
+ logfile = fopen(name, "a");
+
+ if (logfile)
+ setbuf(logfile, NULL);
+ return logfile != NULL ? 0 : -1;
+}
+
+/*************************************************************************/
+
+static void checkday(void)
+{
+ time_t t;
+ struct tm tm;
+
+ time(&t);
+ tm = *localtime(&t);
+
+ if (curday != tm.tm_yday) {
+ close_log();
+ remove_log();
+ open_log();
+ }
+}
+
+/*************************************************************************/
+
+/* Log stuff to the log file with a datestamp. Note that errno is
+ * preserved by this routine and log_perror().
+ */
+
+void alog(const char *fmt, ...)
+{
+ va_list args;
+ time_t t;
+ struct tm tm;
+ char buf[256];
+ int errno_save = errno;
+
+ if (!smtp_debug) {
+ return;
+ }
+
+ checkday();
+
+ if (!fmt) {
+ return;
+ }
+
+ va_start(args, fmt);
+ time(&t);
+ tm = *localtime(&t);
+ strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
+ if (logfile && args) {
+ fputs(buf, logfile);
+ vfprintf(logfile, fmt, args);
+ fputc('\n', logfile);
+ }
+ va_end(args);
+ errno = errno_save;
+}
+
+/*************************************************************************/
+
+/* Remove a trailing \r\n */
+char *strip(char *buf)
+{
+ char *c;
+ if ((c = strchr(buf, '\n')))
+ *c = 0;
+ if ((c = strchr(buf, '\r')))
+ *c = 0;
+ return buf;
+}
+
+/*************************************************************************/
+
+/* Convert a trailing \n to \r\n
+ * The caller must free the allocated memory
+ */
+char *lftocrlf(char *buf)
+{
+ char *result = malloc(strlen(buf) + 2);
+ strip(buf);
+ strcpy(result, buf);
+ strcat(result, "\r\n");
+ return result;
+}
+
+/*************************************************************************/
+
+/* Add a header to the list */
+void smtp_add_header(char *header)
+{
+ struct smtp_header *head = malloc(sizeof(struct smtp_header));
+
+ head->header = lftocrlf(header);
+ head->next = NULL;
+
+ if (!mail.smtp_headers) {
+ mail.smtp_headers = head;
+ }
+ if (mail.smtp_headers_tail) {
+ mail.smtp_headers_tail->next = head;
+ }
+ mail.smtp_headers_tail = head;
+}
+
+/*************************************************************************/
+
+/* Is the buffer a header? */
+int smtp_is_header(char *buf)
+{
+ char *tmp = strchr(buf, ' ');
+
+ if (!tmp)
+ return 0;
+
+ if (*(tmp - 1) == ':')
+ return 1;
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Parse a header into a name and value */
+void smtp_parse_header(char *buf, char **header, char **value)
+{
+ strip(buf);
+
+ *header = strtok(buf, " ");
+ *value = strtok(NULL, "");
+ if (*header)
+ (*header)[strlen(*header) - 1] = 0;
+}
+
+/*************************************************************************/
+
+/* Have we reached the end of input? */
+int smtp_is_end(char *buf)
+{
+ if (*buf == '.')
+ if (*(buf + 1) == '\r' || *(buf + 1) == '\n')
+ return 1;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Set who the email is from */
+void smtp_set_from(char *from)
+{
+ mail.from = strdup(from);
+}
+
+/*************************************************************************/
+
+/* Set who the email is to */
+void smtp_set_to(char *to)
+{
+ char *c;
+
+ if ((c = strrchr(to, '<')) && *(c + 1)) {
+ to = c + 1;
+ to[strlen(to) - 1] = 0;
+ }
+ mail.to = strdup(to);
+}
+
+/*************************************************************************/
+
+/* Add a line of body text */
+void smtp_add_body_line(char *line)
+{
+ struct smtp_body_line *body;
+
+ body = malloc(sizeof(struct smtp_body_line));
+
+ body->line = lftocrlf(line);
+ body->next = NULL;
+
+ if (!mail.smtp_body)
+ mail.smtp_body = body;
+ if (mail.smtp_body_tail)
+ mail.smtp_body_tail->next = body;
+ mail.smtp_body_tail = body;
+
+}
+
+/*************************************************************************/
+
+/* Establish a connection to the SMTP server */
+int smtp_connect(char *host, unsigned short port)
+{
+ struct sockaddr_in addr;
+
+ if ((mail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
+ return 0;
+
+ if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
+ struct hostent *hent;
+ if (!(hent = gethostbyname(host)))
+ return 0;
+ memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port ? port : 25);
+ if (connect(mail.sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
+ ano_sockclose(mail.sock);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+/* Send a line of text */
+int smtp_send(char *text)
+{
+ int result = ano_sockwrite(mail.sock, text, strlen(text));
+
+ alog("SMTP: sent %s",text);
+
+ if (result == SOCKET_ERROR)
+ ano_sockclose(mail.sock);
+
+ return result;
+}
+
+/*************************************************************************/
+
+/* Read a line of text */
+int smtp_read(char *buf, int len)
+{
+ int result;
+
+ memset(buf, 0, len);
+ result = ano_sockread(mail.sock, buf, len);
+
+ if (result == SOCKET_ERROR)
+ ano_sockclose(mail.sock);
+
+ return result;
+}
+
+/*************************************************************************/
+
+/* Retrieve a response code */
+int smtp_get_code(char *text)
+{
+ char *tmp = strtok(text, " ");
+
+ if (!tmp)
+ return 0;
+
+ return atol(tmp);
+}
+
+/*************************************************************************/
+
+/* Send the email */
+int smtp_send_email()
+{
+ char buf[1024];
+ struct smtp_header *head;
+ struct smtp_body_line *body;
+ int code;
+ int skip_done = 0;
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 220) {
+ alog("SMTP: error expected code 220 got %d",code);
+ return 0;
+ }
+
+ if (!smtp_send("HELO anope\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 250) {
+ alog("SMTP: error expected code 250 got %d",code);
+ return 0;
+ }
+
+ strcpy(buf, "MAIL FROM: <");
+ strcat(buf, mail.from);
+ strcat(buf, ">\r\n");
+
+ if (!smtp_send(buf)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 250)
+ return 0;
+
+ strcpy(buf, "RCPT TO: <");
+ strcat(buf, mail.to);
+ strcat(buf, ">\r\n");
+
+ if (!smtp_send(buf)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (smtp_get_code(buf) != 250) {
+ alog("SMTP: error expected code 250 got %d",code);
+ return 0;
+ }
+
+ if (!smtp_send("DATA\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ if (!smtp_read(buf, 1024)) {
+ alog("SMTP: error reading buffer");
+ return 0;
+ }
+
+ code = smtp_get_code(buf);
+ if (code != 354) {
+ alog("SMTP: error expected code 354 got %d",code);
+ return 0;
+ }
+
+ for (head = mail.smtp_headers; head; head = head->next) {
+ if (!smtp_send(head->header)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+ }
+
+ if (!smtp_send("\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ for (body = mail.smtp_body; body; body = body->next) {
+ if (skip_done) {
+ if (!smtp_send(body->line)) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+ } else {
+ skip_done = 1;
+ }
+ }
+
+ if (!smtp_send("\r\n.\r\n")) {
+ alog("SMTP: error writting to socket");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*************************************************************************/
+
+void smtp_disconnect()
+{
+ smtp_send("QUIT\r\n");
+ ano_sockclose(mail.sock);
+}
+
+/*************************************************************************/
+
+void mail_cleanup()
+{
+ struct smtp_header *headers, *nexth;
+ struct smtp_body_line *body, *nextb;
+
+ if (mail.from)
+ free(mail.from);
+ if (mail.to)
+ free(mail.to);
+
+ headers = mail.smtp_headers;
+ while (headers) {
+ nexth = headers->next;
+ free(headers->header);
+ free(headers);
+ headers = nexth;
+ }
+
+ body = mail.smtp_body;
+ while (body) {
+ nextb = body->next;
+ free(body->line);
+ free(body);
+ body = nextb;
+ }
+}
+
+/*************************************************************************/
+
+int main(int argc, char *argv[])
+{
+ char buf[8192];
+/* These are somehow unused - why are they here? -GD
+
+ struct smtp_body_line *b;
+ struct smtp_header *h;
+*/
+ int headers_done = 0;
+/* Win32 stuff */
+#ifdef _WIN32
+ WSADATA wsa;
+#endif
+ char *server, *aport;
+ short port;
+
+ if (argc == 1)
+ return 0;
+
+ server = strtok(argv[1], ":");
+ if ((aport = strtok(NULL, ""))) {
+ port = atoi(aport);
+ } else {
+ port = 25;
+ }
+
+ if (!server) {
+ alog("No Server");
+ /* Bad, bad, bad. This was a eturn from main with no value! -GD */
+ return 0;
+ } else {
+ alog("SMTP: server %s port %d",server,port);
+ }
+
+ memset(&mail, 0, sizeof(mail));
+
+/* The WSAStartup function initiates use of WS2_32.DLL by a process. */
+/* guessing we can skip it under *nix */
+#ifdef _WIN32
+ if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
+ return 0;
+#endif
+
+ /* Read the message and parse it */
+ while (fgets(buf, 8192, stdin)) {
+ if (smtp_is_header(buf) && !headers_done) {
+ char *header, *value;
+ smtp_add_header(buf);
+ smtp_parse_header(buf, &header, &value);
+ if (!strcasecmp(header, "from")) {
+ alog("SMTP: from: %s",value);
+ smtp_set_from(value);
+ } else if (!strcasecmp(header, "to")) {
+ alog("SMTP: to: %s",value);
+ smtp_set_to(value);
+ } else if (smtp_is_end(buf)) {
+ break;
+ } else {
+ headers_done = 1;
+ smtp_add_body_line(buf);
+ }
+ } else {
+ smtp_add_body_line(buf);
+ }
+ }
+
+ if (!smtp_connect(server, port)) {
+ alog("SMTP: failed to connect to %s:%d",server, port);
+ mail_cleanup();
+ return 0;
+ }
+ if (!smtp_send_email()) {
+ alog("SMTP: error during sending of mail");
+ mail_cleanup();
+ return 0;
+ }
+ smtp_disconnect();
+ mail_cleanup();
+
+ return 1;
+}
diff --git a/src/tools/db-merger.c b/src/tools/db-merger.c
new file mode 100644
index 000000000..b44e5b9d0
--- /dev/null
+++ b/src/tools/db-merger.c
@@ -0,0 +1,2031 @@
+/*
+ * Anope Database Merger
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ *****
+ *
+ * Based on the original IRC, db-merger.c
+ * (C) Copyright 2005-2006, Florian Schulze (Certus)
+ * Based on the original code of Anope, (C) 2003-2005 Anope Team
+ *
+ */
+
+/*
+ * Known issues:
+ * - When merging it is possible that ownership of a channel is transferred
+ * to another nickgroup if the founder's main nick is dropped and granted
+ * to another user in the other database. This user will then become
+ * founder of the channel.
+ *
+ * - The count of channels a nickgroup has registered is not recalculated
+ * after the merge. This means that if a channel was dropped, the owner may
+ * have an incorrect counter and may sooner reach the maximum number of
+ * allowed registered channels.
+ *
+ * Ideally, this should be rewritten from scratch to only merge after both
+ * database sets are fully loaded, however since we will be migrating to
+ * another database architecture, this is unlikely to be done for the
+ * current "stable" DB architecture.
+ *
+ * ~ Viper
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include "sysconf.h"
+#include <windows.h>
+#endif
+
+/* Some SUN fixs */
+#ifdef __sun
+/* Solaris specific code, types that do not exist in Solaris'
+ * sys/types.h
+ **/
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int_64_t
+#define u_int8_t uint8_t
+#define u_int16_t uint16_t
+#define u_int32_t uint32_t
+#define u_int64_t uint64_t
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+#endif
+
+
+/* CONFIGURATION BLOCK */
+
+#define NICK_DB_1 "nick1.db"
+#define NICK_DB_2 "nick2.db"
+#define NICK_DB_NEW "nick.db"
+
+#define CHAN_DB_1 "chan1.db"
+#define CHAN_DB_2 "chan2.db"
+#define CHAN_DB_NEW "chan.db"
+
+#define BOT_DB_1 "bot1.db"
+#define BOT_DB_2 "bot2.db"
+#define BOT_DB_NEW "bot.db"
+
+#define HOST_DB_1 "hosts1.db"
+#define HOST_DB_2 "hosts2.db"
+#define HOST_DB_NEW "hosts.db"
+
+/* END OF CONFIGURATION BLOCK */
+
+#ifndef _WIN32
+#define C_LBLUE "\033[1;34m"
+#define C_NONE "\033[m"
+#else
+#define C_LBLUE ""
+#define C_NONE ""
+#endif
+
+#define getc_db(f) (fgetc((f)->fp))
+#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
+#define HASH2(chan) ((chan)[1] ? ((chan)[1]&31)<<5 | ((chan)[2]&31) : 0)
+#define read_buffer(buf,f) (read_db((f),(buf),sizeof(buf)) == sizeof(buf))
+#define write_buffer(buf,f) (write_db((f),(buf),sizeof(buf)) == sizeof(buf))
+#define read_db(f,buf,len) (fread((buf),1,(len),(f)->fp))
+#define write_db(f,buf,len) (fwrite((buf),1,(len),(f)->fp))
+#define read_int8(ret,f) ((*(ret)=fgetc((f)->fp))==EOF ? -1 : 0)
+#define write_int8(val,f) (fputc((val),(f)->fp)==EOF ? -1 : 0)
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
+ } \
+} while (0)
+#define READ(x) do { \
+ if ((x) < 0) { \
+ printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
+ exit(0); \
+ } \
+} while (0)
+
+typedef int16_t int16;
+typedef u_int16_t uint16;
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef struct memo_ Memo;
+typedef struct dbFILE_ dbFILE;
+typedef struct nickalias_ NickAlias;
+typedef struct nickcore_ NickCore;
+typedef struct chaninfo_ ChannelInfo;
+typedef struct botinfo_ BotInfo;
+typedef struct badword_ BadWord;
+typedef struct hostcore_ HostCore;
+
+struct memo_ {
+ uint32 number; /* Index number -- not necessarily array position! */
+ uint16 flags; /* Flags */
+ time_t time; /* When was it sent? */
+ char sender[32]; /* Name of the sender */
+ char *text;
+};
+
+struct dbFILE_ {
+ int mode; /* 'r' for reading, 'w' for writing */
+ FILE *fp; /* The normal file descriptor */
+ char filename[1024]; /* Name of the database file */
+};
+
+typedef struct {
+ int16 memocount; /* Current # of memos */
+ int16 memomax; /* Max # of memos one can hold*/
+ Memo *memos; /* Pointer to original memos */
+} MemoInfo;
+
+typedef struct {
+ uint16 in_use; /* 1 if this entry is in use, else 0 */
+ int16 level;
+ NickCore *nc; /* Guaranteed to be non-NULL if in use, NULL if not */
+ time_t last_seen;
+} ChanAccess;
+
+typedef struct {
+ int16 in_use; /* Always 0 if not in use */
+ int16 is_nick; /* 1 if a regged nickname, 0 if a nick!user@host mask */
+ uint16 flags;
+ union {
+ char *mask; /* Guaranteed to be non-NULL if in use, NULL if not */
+ NickCore *nc; /* Same */
+ } u;
+ char *reason;
+ char *creator;
+ time_t addtime;
+} AutoKick;
+
+struct nickalias_ {
+ NickAlias *next, *prev;
+ char *nick; /* Nickname */
+ char *last_quit; /* Last quit message */
+ char *last_realname; /* Last realname */
+ char *last_usermask; /* Last usermask */
+ time_t time_registered; /* When the nick was registered */
+ time_t last_seen; /* When it was seen online for the last time */
+ uint16 status; /* See NS_* below */
+ NickCore *nc; /* I'm an alias of this */
+};
+
+struct nickcore_ {
+ NickCore *next, *prev;
+
+ char *display; /* How the nick is displayed */
+ char pass[32]; /* Password of the nicks */
+ char *email; /* E-mail associated to the nick */
+ char *greet; /* Greet associated to the nick */
+ uint32 icq; /* ICQ # associated to the nick */
+ char *url; /* URL associated to the nick */
+ uint32 flags; /* See NI_* below */
+ uint16 language; /* Language selected by nickname owner (LANG_*) */
+ uint16 accesscount; /* # of entries */
+ char **access; /* Array of strings */
+ MemoInfo memos; /* Memo information */
+ uint16 channelcount; /* Number of channels currently registered */
+ uint16 channelmax; /* Maximum number of channels allowed */
+ int unused; /* Used for nick collisions */
+ int aliascount; /* How many aliases link to us? Remove the core if 0 */
+};
+
+struct chaninfo_ {
+ ChannelInfo *next, *prev;
+
+ char name[64]; /* Channel name */
+ char *founder; /* Who registered the channel */
+ char *successor; /* Who gets the channel if the founder nick is dropped or expires */
+ char founderpass[32]; /* Channel password */
+ char *desc; /* Description */
+ char *url; /* URL */
+ char *email; /* Email address */
+ time_t time_registered; /* When was it registered */
+ time_t last_used; /* When was it used hte last time */
+ char *last_topic; /* Last topic on the channel */
+ char last_topic_setter[32]; /* Who set the last topic */
+ time_t last_topic_time; /* When the last topic was set */
+ uint32 flags; /* Flags */
+ char *forbidby; /* if forbidden: who did it */
+ char *forbidreason; /* if forbidden: why */
+ int16 bantype; /* Bantype */
+ int16 *levels; /* Access levels for commands */
+ uint16 accesscount; /* # of pple with access */
+ ChanAccess *access; /* List of authorized users */
+ uint16 akickcount; /* # of akicked pple */
+ AutoKick *akick; /* List of users to kickban */
+ uint32 mlock_on, mlock_off; /* See channel modes below */
+ uint32 mlock_limit; /* 0 if no limit */
+ char *mlock_key; /* NULL if no key */
+ char *mlock_flood; /* NULL if no +f */
+ char *mlock_redirect; /* NULL if no +L */
+ char *entry_message; /* Notice sent on entering channel */
+ MemoInfo memos; /* Memos */
+ char *bi; /* Bot used on this channel */
+ uint32 botflags; /* BS_* below */
+ int16 *ttb; /* Times to ban for each kicker */
+ uint16 bwcount; /* Badword count */
+ BadWord *badwords; /* For BADWORDS kicker */
+ int16 capsmin, capspercent; /* For CAPS kicker */
+ int16 floodlines, floodsecs; /* For FLOOD kicker */
+ int16 repeattimes; /* For REPEAT kicker */
+};
+
+struct botinfo_ {
+ BotInfo *next, *prev;
+ char *nick; /* Nickname of the bot */
+ char *user; /* Its user name */
+ char *host; /* Its hostname */
+ char *real; /* Its real name */
+ int16 flags; /* Bot flags */
+ time_t created; /* Birth date */
+ int16 chancount; /* Number of channels that use the bot. */
+};
+
+struct badword_ {
+ uint16 in_use;
+ char *word;
+ uint16 type;
+};
+
+struct hostcore_ {
+ HostCore *next, *last;
+ char *nick; /* Owner of the vHost */
+ char *vIdent; /* vIdent for the user */
+ char *vHost; /* Vhost for this user */
+ char *creator; /* Oper Nick of the oper who set the vhost */
+ time_t time; /* Date/Time vHost was set */
+};
+
+dbFILE *open_db_write(const char *service, const char *filename, int version);
+dbFILE *open_db_read(const char *service, const char *filename, int version);
+NickCore *findcore(const char *nick, int version);
+NickAlias *findnick(const char *nick);
+BotInfo *findbot(char *nick);
+ChannelInfo *cs_findchan(const char *chan);
+char *strscpy(char *d, const char *s, size_t len);
+int write_file_version(dbFILE * f, uint32 version);
+int mystricmp(const char *s1, const char *s2);
+int delnick(NickAlias *na, int donttouchthelist);
+int write_string(const char *s, dbFILE * f);
+int write_ptr(const void *ptr, dbFILE * f);
+int read_int16(int16 * ret, dbFILE * f);
+int read_int32(int32 * ret, dbFILE * f);
+int read_uint16(uint16 * ret, dbFILE * f);
+int read_uint32(uint32 * ret, dbFILE * f);
+int read_string(char **ret, dbFILE * f);
+int write_int16(uint16 val, dbFILE * f);
+int write_int32(uint32 val, dbFILE * f);
+int read_ptr(void **ret, dbFILE * f);
+int delcore(NickCore *nc);
+void alpha_insert_chan(ChannelInfo * ci);
+void insert_bot(BotInfo * bi);
+void close_db(dbFILE * f);
+
+ChannelInfo *chanlists[256];
+NickAlias *nalists[1024];
+NickCore *nclists[1024];
+BotInfo *botlists[256];
+
+int preferfirst = 0, prefersecond = 0, preferoldest = 0, prefernewest = 0;
+int nonick = 0, nochan = 0, nobot = 0, nohost = 0;
+
+int main(int argc, char *argv[])
+{
+ dbFILE *f;
+ int i;
+ NickCore *nc, *ncnext;
+ HostCore *firsthc = NULL;
+
+ printf("\n"C_LBLUE"DB Merger for Anope IRC Services"C_NONE"\n");
+ printf("Version: $Id$"C_NONE"\n\n");
+
+ if (argc >= 2) {
+ if (!mystricmp(argv[1], "--PREFEROLDEST")) {
+ printf("Preferring oldest database entries on collision.\n");
+ preferoldest = 1;
+ } else if (!mystricmp(argv[1], "--PREFERFIRST")) {
+ printf("Preferring first database's entries on collision .\n");
+ preferfirst = 1;
+ } else if (!mystricmp(argv[1], "--PREFERSECOND")) {
+ printf("Preferring second database's entries on collision.\n");
+ prefersecond = 1;
+ } else if (!mystricmp(argv[1], "--PREFERNEWEST")) {
+ printf("Preferring newest database entries on collision.\n");
+ prefernewest = 1;
+ }
+ }
+
+ /* Section I: Nicks */
+ /* Ia: First database */
+ if ((f = open_db_read("NickServ", NICK_DB_1, 14))) {
+
+ NickAlias *na, **nalast, *naprev;
+ NickCore *nc, **nclast, *ncprev;
+ int16 tmp16;
+ int32 tmp32;
+ int i, j, c;
+
+ printf("Trying to merge nicks...\n");
+
+ /* Nick cores */
+ for (i = 0; i < 1024; i++) {
+ nclast = &nclists[i];
+ ncprev = NULL;
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", NICK_DB_1);
+ exit(0);
+ }
+
+ nc = calloc(1, sizeof(NickCore));
+ nc->aliascount = 0;
+ nc->unused = 0;
+
+ *nclast = nc;
+ nclast = &nc->next;
+ nc->prev = ncprev;
+ ncprev = nc;
+
+ READ(read_string(&nc->display, f));
+ READ(read_buffer(nc->pass, f));
+ READ(read_string(&nc->email, f));
+ READ(read_string(&nc->greet, f));
+ READ(read_uint32(&nc->icq, f));
+ READ(read_string(&nc->url, f));
+ READ(read_uint32(&nc->flags, f));
+ READ(read_uint16(&nc->language, f));
+ READ(read_uint16(&nc->accesscount, f));
+ if (nc->accesscount) {
+ char **access;
+ access = calloc(sizeof(char *) * nc->accesscount, 1);
+ nc->access = access;
+ for (j = 0; j < nc->accesscount; j++, access++)
+ READ(read_string(access, f));
+ }
+ READ(read_int16(&nc->memos.memocount, f));
+ READ(read_int16(&nc->memos.memomax, f));
+ if (nc->memos.memocount) {
+ Memo *memos;
+ memos = calloc(sizeof(Memo) * nc->memos.memocount, 1);
+ nc->memos.memos = memos;
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ READ(read_uint32(&memos->number, f));
+ READ(read_uint16(&memos->flags, f));
+ READ(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ READ(read_buffer(memos->sender, f));
+ READ(read_string(&memos->text, f));
+ }
+ }
+ READ(read_uint16(&nc->channelcount, f));
+ READ(read_int16(&tmp16, f));
+ } /* getc_db() */
+ *nclast = NULL;
+ } /* for() loop */
+
+ /* Nick aliases */
+ for (i = 0; i < 1024; i++) {
+ char *s = NULL;
+
+ nalast = &nalists[i];
+ naprev = NULL;
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", NICK_DB_1);
+ exit(0);
+ }
+
+ na = calloc(1, sizeof(NickAlias));
+
+ READ(read_string(&na->nick, f));
+ READ(read_string(&na->last_usermask, f));
+ READ(read_string(&na->last_realname, f));
+ READ(read_string(&na->last_quit, f));
+
+ READ(read_int32(&tmp32, f));
+ na->time_registered = tmp32;
+ READ(read_int32(&tmp32, f));
+ na->last_seen = tmp32;
+ READ(read_uint16(&na->status, f));
+ READ(read_string(&s, f));
+ na->nc = findcore(s, 0);
+ na->nc->aliascount++;
+ free(s);
+
+ *nalast = na;
+ nalast = &na->next;
+ na->prev = naprev;
+ naprev = na;
+ } /* getc_db() */
+ *nalast = NULL;
+ } /* for() loop */
+ close_db(f); /* End of section Ia */
+ } else
+ nonick = 1;
+
+ /* Ib: Second database */
+ if (!nonick) {
+ if ((f = open_db_read("NickServ", NICK_DB_2, 14))) {
+
+ NickAlias *na, *naptr;
+ NickCore *nc;
+ int16 tmp16;
+ int32 tmp32;
+ int i, j, index, c;
+
+ /* Nick cores */
+ for (i = 0; i < 1024; i++) {
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", NICK_DB_2);
+ exit(0);
+ }
+
+ nc = calloc(1, sizeof(NickCore));
+ READ(read_string(&nc->display, f));
+ READ(read_buffer(nc->pass, f));
+ READ(read_string(&nc->email, f));
+
+ naptr = findnick(nc->display);
+ if (naptr)
+ nc->unused = 1;
+ else
+ nc->unused = 0;
+
+ nc->aliascount = 0;
+
+ index = HASH(nc->display);
+ nc->prev = NULL;
+ nc->next = nclists[index];
+ if (nc->next)
+ nc->next->prev = nc;
+ nclists[index] = nc;
+
+ READ(read_string(&nc->greet, f));
+ READ(read_uint32(&nc->icq, f));
+ READ(read_string(&nc->url, f));
+ READ(read_uint32(&nc->flags, f));
+ READ(read_uint16(&nc->language, f));
+ READ(read_uint16(&nc->accesscount, f));
+ if (nc->accesscount) {
+ char **access;
+ access = calloc(sizeof(char *) * nc->accesscount, 1);
+ nc->access = access;
+ for (j = 0; j < nc->accesscount; j++, access++)
+ READ(read_string(access, f));
+ }
+ READ(read_int16(&nc->memos.memocount, f));
+ READ(read_int16(&nc->memos.memomax, f));
+ if (nc->memos.memocount) {
+ Memo *memos;
+ memos = calloc(sizeof(Memo) * nc->memos.memocount, 1);
+ nc->memos.memos = memos;
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ READ(read_uint32(&memos->number, f));
+ READ(read_uint16(&memos->flags, f));
+ READ(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ READ(read_buffer(memos->sender, f));
+ READ(read_string(&memos->text, f));
+ }
+ }
+ READ(read_uint16(&nc->channelcount, f));
+ READ(read_int16(&tmp16, f));
+ } /* getc_db() */
+ } /* for() loop */
+
+ /* Nick aliases */
+ for (i = 0; i < 1024; i++) {
+ char *s = NULL;
+ NickAlias *ptr, *prev, *naptr;
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", NICK_DB_2);
+ exit(0);
+ }
+
+ na = calloc(1, sizeof(NickAlias));
+
+ READ(read_string(&na->nick, f));
+ READ(read_string(&na->last_usermask, f));
+ READ(read_string(&na->last_realname, f));
+ READ(read_string(&na->last_quit, f));
+ READ(read_int32(&tmp32, f));
+ na->time_registered = tmp32;
+ READ(read_int32(&tmp32, f));
+ na->last_seen = tmp32;
+ READ(read_uint16(&na->status, f));
+ READ(read_string(&s, f));
+
+ naptr = findnick(na->nick);
+ if (naptr) { /* COLLISION! na = collision #2 = new (na->nc doesn't exist yet), naptr = collision #1 = old (naptr->nc exists) */
+ char input[1024];
+ NickCore *ncptr = findcore(na->nick, 1); /* Find core for #2, ncptr MUST exist since we've read all cores, if it doesn't eixst, we have a malformed db */;
+
+ if (!ncptr) { /* malformed */
+ printf("\n\n WARNING! Malformed database. No nickcore for nick %s, droping it.\n\n\n", na->nick);
+ delnick(na, 1);
+ } else { /* not malformed */
+ if (!preferoldest && !preferfirst && !prefersecond && !prefernewest) {
+ printf("Nick collision for nick %s:\n\n", na->nick);
+ printf("Group 1: %s (%s)\n", naptr->nc->display, naptr->nc->email);
+ printf("Time registered: %s\n", ctime(&naptr->time_registered));
+ printf("Group 2: %s (%s)\n", ncptr->display, ncptr->email);
+ printf("Time registered: %s\n", ctime(&na->time_registered));
+ printf("What group do you want to keep? Enter the related group number \"1\" or \"2\".\n");
+ }
+
+ if (preferoldest) {
+ input[0] = (na->time_registered > naptr->time_registered) ? '1' : '2';
+ } else if (prefernewest) {
+ input[0] = (na->time_registered > naptr->time_registered) ? '2' : '1';
+ } else if (preferfirst) {
+ input[0] = '1';
+ } else if (prefersecond) {
+ input[0] = '2';
+ } else {
+ waiting_for_input:
+ scanf("%s", input);
+ }
+ if (input[0] == '1') { /* #2 isn't in the list yet, #1 is. free #2 alias. */
+ printf("Deleting nick alias %s (#2).\n", na->nick);
+ delnick(na, 1); /* free()s the alias without touching the list since na isn't in the list */
+ } else if (input[0] == '2') { /* get alias #1 out of the list, then free() it, then add #2 to the list */
+ printf("Deleting nick alias %s (#1).\n", naptr->nick);
+ naptr->nc->aliascount--; /* tell the core it has one alias less */
+ delnick(naptr, 0); /* removes the alias from the list and free()s it */
+ na->nc = ncptr;
+ na->nc->aliascount++;
+ index = HASH(na->nick);
+ for (prev = NULL, ptr = nalists[index]; ptr && mystricmp(ptr->nick, na->nick) < 0; prev = ptr, ptr = ptr->next);
+ na->prev = prev;
+ na->next = ptr;
+ if (!prev)
+ nalists[index] = na;
+ else
+ prev->next = na;
+ if (ptr)
+ ptr->prev = na;
+ } else {
+ printf("Invalid number, give us a valid one (1 or 2).\n");
+ goto waiting_for_input;
+ }
+ } /* not malformed */
+ } else { /* No collision, add the core pointer and put the alias in the list */
+ na->nc = findcore(s, 0);
+ if (!na->nc) {
+ printf("\n\n WARNING! Malformed database. No nickcore for nick %s, droping it.\n\n\n", na->nick);
+ delnick(na, 1);
+ } else {
+ na->nc->aliascount++;
+ index = HASH(na->nick);
+ for (prev = NULL, ptr = nalists[index]; ptr && mystricmp(ptr->nick, na->nick) < 0; prev = ptr, ptr = ptr->next);
+ na->prev = prev;
+ na->next = ptr;
+ if (!prev)
+ nalists[index] = na;
+ else
+ prev->next = na;
+ if (ptr)
+ ptr->prev = na;
+ }
+ }
+ free(s);
+ } /* getc_db() */
+ } /* for() loop */
+ close_db(f); /* End of section Ib */
+ } else
+ nonick = 1;
+ }
+
+ /* CLEAN THE CORES */
+
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = ncnext) {
+ ncnext = nc->next;
+ if (nc->aliascount < 1) {
+ printf("Deleting core %s (%s).\n", nc->display, nc->email);
+ delcore(nc);
+ }
+ }
+ }
+
+ /* Ic: Saving */
+ if (!nonick) {
+ if ((f = open_db_write("NickServ", NICK_DB_NEW, 14))) {
+
+ NickAlias *na;
+ NickCore *nc;
+ char **access;
+ Memo *memos;
+ int i, j;
+
+ /* Nick cores */
+ for (i = 0; i < 1024; i++) {
+ for (nc = nclists[i]; nc; nc = nc->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(nc->display, f));
+ SAFE(write_buffer(nc->pass, f));
+ SAFE(write_string(nc->email, f));
+ SAFE(write_string(nc->greet, f));
+ SAFE(write_int32(nc->icq, f));
+ SAFE(write_string(nc->url, f));
+ SAFE(write_int32(nc->flags, f));
+ SAFE(write_int16(nc->language, f));
+ SAFE(write_int16(nc->accesscount, f));
+ for (j = 0, access = nc->access; j < nc->accesscount; j++, access++)
+ SAFE(write_string(*access, f));
+
+ SAFE(write_int16(nc->memos.memocount, f));
+ SAFE(write_int16(nc->memos.memomax, f));
+ memos = nc->memos.memos;
+ for (j = 0; j < nc->memos.memocount; j++, memos++) {
+ SAFE(write_int32(memos->number, f));
+ SAFE(write_int16(memos->flags, f));
+ SAFE(write_int32(memos->time, f));
+ SAFE(write_buffer(memos->sender, f));
+ SAFE(write_string(memos->text, f));
+ }
+ SAFE(write_int16(nc->channelcount, f));
+ SAFE(write_int16(nc->channelmax, f));
+ } /* for (nc) */
+ SAFE(write_int8(0, f));
+ } /* for (i) */
+
+ /* Nick aliases */
+ for (i = 0; i < 1024; i++) {
+ for (na = nalists[i]; na; na = na->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(na->nick, f));
+ SAFE(write_string(na->last_usermask, f));
+ SAFE(write_string(na->last_realname, f));
+ SAFE(write_string(na->last_quit, f));
+ SAFE(write_int32(na->time_registered, f));
+ SAFE(write_int32(na->last_seen, f));
+ SAFE(write_int16(na->status, f));
+ SAFE(write_string(na->nc->display, f));
+
+ } /* for (na) */
+ SAFE(write_int8(0, f));
+ } /* for (i) */
+ close_db(f); /* End of section Ic */
+ printf("Nick merging done. New database saved as %s.\n", NICK_DB_NEW);
+ }
+ } /* End of section I */
+
+ /* Section II: Chans */
+ /* IIa: First database */
+ if ((f = open_db_read("ChanServ", CHAN_DB_1, 16))) {
+ ChannelInfo *ci, **last, *prev;
+ int c;
+
+ printf("Trying to merge channels...\n");
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+ int32 tmp32;
+ int n_levels;
+ char *s;
+ int n_ttb;
+ /* Unused variable - why? -GD
+ int J;
+ */
+
+ last = &chanlists[i];
+ prev = NULL;
+
+ while ((c = getc_db(f)) == 1) {
+ int j;
+
+ if (c != 1) {
+ printf("Invalid format in %s.\n", CHAN_DB_1);
+ exit(0);
+ }
+
+ ci = calloc(sizeof(ChannelInfo), 1);
+ *last = ci;
+ last = &ci->next;
+ ci->prev = prev;
+ prev = ci;
+ READ(read_buffer(ci->name, f));
+ READ(read_string(&ci->founder, f));
+ READ(read_string(&ci->successor, f));
+ READ(read_buffer(ci->founderpass, f));
+ READ(read_string(&ci->desc, f));
+ if (!ci->desc)
+ ci->desc = strdup("");
+ READ(read_string(&ci->url, f));
+ READ(read_string(&ci->email, f));
+ READ(read_int32(&tmp32, f));
+ ci->time_registered = tmp32;
+ READ(read_int32(&tmp32, f));
+ ci->last_used = tmp32;
+ READ(read_string(&ci->last_topic, f));
+ READ(read_buffer(ci->last_topic_setter, f));
+ READ(read_int32(&tmp32, f));
+ ci->last_topic_time = tmp32;
+ READ(read_uint32(&ci->flags, f));
+ /* Temporary flags cleanup */
+ ci->flags &= ~0x80000000;
+ READ(read_string(&ci->forbidby, f));
+ READ(read_string(&ci->forbidreason, f));
+ READ(read_int16(&tmp16, f));
+ ci->bantype = tmp16;
+ READ(read_int16(&tmp16, f));
+ n_levels = tmp16;
+ ci->levels = calloc(36 * sizeof(*ci->levels), 1);
+ for (j = 0; j < n_levels; j++) {
+ if (j < 36)
+ READ(read_int16(&ci->levels[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ READ(read_uint16(&ci->accesscount, f));
+ if (ci->accesscount) {
+ ci->access = calloc(ci->accesscount, sizeof(ChanAccess));
+ for (j = 0; j < ci->accesscount; j++) {
+ READ(read_uint16(&ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ READ(read_int16(&ci->access[j].level, f));
+ READ(read_string(&s, f));
+ if (s) {
+ ci->access[j].nc = findcore(s, 0);
+ free(s);
+ }
+ if (ci->access[j].nc == NULL)
+ ci->access[j].in_use = 0;
+ READ(read_int32(&tmp32, f));
+ ci->access[j].last_seen = tmp32;
+ }
+ }
+ } else {
+ ci->access = NULL;
+ }
+ READ(read_uint16(&ci->akickcount, f));
+ if (ci->akickcount) {
+ ci->akick = calloc(ci->akickcount, sizeof(AutoKick));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(read_uint16(&ci->akick[j].flags, f));
+ if (ci->akick[j].flags & 0x0001) {
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0002) {
+ ci->akick[j].u.nc = findcore(s, 0);
+ if (!ci->akick[j].u.nc)
+ ci->akick[j].flags &= ~0x0001;
+ free(s);
+ } else {
+ ci->akick[j].u.mask = s;
+ }
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].reason = s;
+ else if (s)
+ free(s);
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001) {
+ ci->akick[j].creator = s;
+ } else if (s) {
+ free(s);
+ }
+ SAFE(read_int32(&tmp32, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].addtime = tmp32;
+ }
+ }
+ } else {
+ ci->akick = NULL;
+ }
+ READ(read_uint32(&ci->mlock_on, f));
+ READ(read_uint32(&ci->mlock_off, f));
+ READ(read_uint32(&ci->mlock_limit, f));
+ READ(read_string(&ci->mlock_key, f));
+ READ(read_string(&ci->mlock_flood, f));
+ READ(read_string(&ci->mlock_redirect, f));
+ READ(read_int16(&ci->memos.memocount, f));
+ READ(read_int16(&ci->memos.memomax, f));
+ if (ci->memos.memocount) {
+ Memo *memos;
+ memos = calloc(sizeof(Memo) * ci->memos.memocount, 1);
+ ci->memos.memos = memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ READ(read_uint32(&memos->number, f));
+ READ(read_uint16(&memos->flags, f));
+ READ(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ READ(read_buffer(memos->sender, f));
+ READ(read_string(&memos->text, f));
+ }
+ }
+ READ(read_string(&ci->entry_message, f));
+
+ /* BotServ options */
+ READ(read_string(&ci->bi, f));
+ READ(read_int32(&tmp32, f));
+ ci->botflags = tmp32;
+ READ(read_int16(&tmp16, f));
+ n_ttb = tmp16;
+ ci->ttb = calloc(2 * 8, 1);
+ for (j = 0; j < n_ttb; j++) {
+ if (j < 8)
+ READ(read_int16(&ci->ttb[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ for (j = n_ttb; j < 8; j++)
+ ci->ttb[j] = 0;
+ READ(read_int16(&tmp16, f));
+ ci->capsmin = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->capspercent = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodlines = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodsecs = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->repeattimes = tmp16;
+
+ READ(read_uint16(&ci->bwcount, f));
+ if (ci->bwcount) {
+ ci->badwords = calloc(ci->bwcount, sizeof(BadWord));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(read_uint16(&ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(read_string(&ci->badwords[j].word, f));
+ SAFE(read_uint16(&ci->badwords[j].type, f));
+ }
+ }
+ } else {
+ ci->badwords = NULL;
+ }
+ } /* getc_db() */
+ *last = NULL;
+ } /* for() loop */
+ close_db(f);
+ } else
+ nochan = 1;
+
+ /* IIb: Second database */
+ if (!nochan) {
+ if ((f = open_db_read("ChanServ", CHAN_DB_2, 16))) {
+ int c;
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+ int32 tmp32;
+ int n_levels;
+ char *s;
+ int n_ttb;
+ /* Unused variables - why? -GD
+ char input[1024];
+ NickAlias *na;
+ int J;
+ */
+
+ while ((c = getc_db(f)) == 1) {
+ ChannelInfo *ci = NULL, *ciptr = NULL;
+ int j;
+
+ if (c != 1) {
+ printf("Invalid format in %s.\n", CHAN_DB_2);
+ exit(0);
+ }
+
+ ci = calloc(sizeof(ChannelInfo), 1);
+ READ(read_buffer(ci->name, f));
+ READ(read_string(&ci->founder, f));
+ READ(read_string(&ci->successor, f));
+ READ(read_buffer(ci->founderpass, f));
+ READ(read_string(&ci->desc, f));
+ if (!ci->desc)
+ ci->desc = strdup("");
+ READ(read_string(&ci->url, f));
+ READ(read_string(&ci->email, f));
+ READ(read_int32(&tmp32, f));
+ ci->time_registered = tmp32;
+ READ(read_int32(&tmp32, f));
+ ci->last_used = tmp32;
+ READ(read_string(&ci->last_topic, f));
+ READ(read_buffer(ci->last_topic_setter, f));
+ READ(read_int32(&tmp32, f));
+ ci->last_topic_time = tmp32;
+ READ(read_uint32(&ci->flags, f));
+ /* Temporary flags cleanup */
+ ci->flags &= ~0x80000000;
+ READ(read_string(&ci->forbidby, f));
+ READ(read_string(&ci->forbidreason, f));
+ READ(read_int16(&tmp16, f));
+ ci->bantype = tmp16;
+ READ(read_int16(&tmp16, f));
+ n_levels = tmp16;
+ ci->levels = calloc(36 * sizeof(*ci->levels), 1);
+ for (j = 0; j < n_levels; j++) {
+ if (j < 36)
+ READ(read_int16(&ci->levels[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ READ(read_uint16(&ci->accesscount, f));
+ if (ci->accesscount) {
+ ci->access = calloc(ci->accesscount, sizeof(ChanAccess));
+ for (j = 0; j < ci->accesscount; j++) {
+ READ(read_uint16(&ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ READ(read_int16(&ci->access[j].level, f));
+ READ(read_string(&s, f));
+ if (s) {
+ ci->access[j].nc = findcore(s, 0);
+ free(s);
+ }
+ if (ci->access[j].nc == NULL)
+ ci->access[j].in_use = 0;
+ READ(read_int32(&tmp32, f));
+ ci->access[j].last_seen = tmp32;
+ }
+ }
+ } else {
+ ci->access = NULL;
+ }
+ READ(read_uint16(&ci->akickcount, f));
+ if (ci->akickcount) {
+ ci->akick = calloc(ci->akickcount, sizeof(AutoKick));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(read_uint16(&ci->akick[j].flags, f));
+ if (ci->akick[j].flags & 0x0001) {
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0002) {
+ ci->akick[j].u.nc = findcore(s, 0);
+ if (!ci->akick[j].u.nc)
+ ci->akick[j].flags &= ~0x0001;
+ free(s);
+ } else {
+ ci->akick[j].u.mask = s;
+ }
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].reason = s;
+ else if (s)
+ free(s);
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001) {
+ ci->akick[j].creator = s;
+ } else if (s) {
+ free(s);
+ }
+ SAFE(read_int32(&tmp32, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].addtime = tmp32;
+ }
+ }
+ } else {
+ ci->akick = NULL;
+ }
+ READ(read_uint32(&ci->mlock_on, f));
+ READ(read_uint32(&ci->mlock_off, f));
+ READ(read_uint32(&ci->mlock_limit, f));
+ READ(read_string(&ci->mlock_key, f));
+ READ(read_string(&ci->mlock_flood, f));
+ READ(read_string(&ci->mlock_redirect, f));
+ READ(read_int16(&ci->memos.memocount, f));
+ READ(read_int16(&ci->memos.memomax, f));
+ if (ci->memos.memocount) {
+ Memo *memos;
+ memos = calloc(sizeof(Memo) * ci->memos.memocount, 1);
+ ci->memos.memos = memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ READ(read_uint32(&memos->number, f));
+ READ(read_uint16(&memos->flags, f));
+ READ(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ READ(read_buffer(memos->sender, f));
+ READ(read_string(&memos->text, f));
+ }
+ }
+ READ(read_string(&ci->entry_message, f));
+
+ /* BotServ options */
+ READ(read_string(&ci->bi, f));
+ READ(read_int32(&tmp32, f));
+ ci->botflags = tmp32;
+ READ(read_int16(&tmp16, f));
+ n_ttb = tmp16;
+ ci->ttb = calloc(32, 1);
+ for (j = 0; j < n_ttb; j++) {
+ if (j < 8)
+ READ(read_int16(&ci->ttb[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ for (j = n_ttb; j < 8; j++)
+ ci->ttb[j] = 0;
+ READ(read_int16(&tmp16, f));
+ ci->capsmin = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->capspercent = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodlines = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodsecs = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->repeattimes = tmp16;
+
+ READ(read_uint16(&ci->bwcount, f));
+ if (ci->bwcount) {
+ ci->badwords = calloc(ci->bwcount, sizeof(BadWord));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(read_uint16(&ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(read_string(&ci->badwords[j].word, f));
+ SAFE(read_uint16(&ci->badwords[j].type, f));
+ }
+ }
+ } else {
+ ci->badwords = NULL;
+ }
+ /* READING DONE */
+ ciptr = cs_findchan(ci->name);
+ if (ciptr) { /* COLLISION! ciptr = old = 1; ci = new = 2*/
+ char input[1024];
+
+ if (!preferoldest && !preferfirst && !prefersecond && !prefernewest) {
+ printf("Chan collision for channel %s:\n\n", ci->name);
+
+ printf("Owner of channel 1: %s (%s)\n", (ciptr->founder) ? ciptr->founder : "none", (ciptr->email) ? ciptr->email : "no valid email");
+ printf("Accesscount: %u\n", ciptr->accesscount);
+ if (ciptr->flags & 0x00000080) {
+ printf("Status: Channel is forbidden");
+ } else if (ciptr->flags & 0x00010000) {
+ printf("Status: Channel is suspended");
+ }
+ printf("Time registered: %s\n", ctime(&ciptr->time_registered));
+
+ printf("Owner of channel 2: %s (%s)\n", (ci->founder) ? ci->founder : "none", (ci->email) ? ci->email : "no valid email");
+ printf("Accesscount: %u\n", ci->accesscount);
+ if (ci->flags & 0x00000080) {
+ printf("Status: Channel is forbidden");
+ } else if (ci->flags & 0x00010000) {
+ printf("Status: Channel is suspended");
+ }
+ printf("Time registered: %s\n", ctime(&ci->time_registered));
+
+ printf("What channel do you want to keep? Enter the related number \"1\" or \"2\".\n");
+ }
+
+ if (preferoldest) {
+ input[0] = (ci->time_registered > ciptr->time_registered) ? '1' : '2';
+ } else if (prefernewest) {
+ input[0] = (ci->time_registered > ciptr->time_registered) ? '2' : '1';
+ } else if (preferfirst) {
+ input[0] = '1';
+ } else if (prefersecond) {
+ input[0] = '2';
+ } else {
+ waiting_for_input4:
+ scanf("%s", input);
+ }
+ if (input[0] == '1') { /* #2 isn't in the list yet, #1 is. -> free() #2 [ci] */
+ NickCore *nc = NULL;
+ int i;
+ printf("Deleting chan %s (#2).\n", ci->name);
+
+ if (ci->founder) {
+ nc = findcore(ci->founder, 0);
+ if (nc)
+ nc->channelcount--;
+ }
+ free(ci->desc);
+ free(ci->founder);
+ free(ci->successor);
+ if (ci->url)
+ free(ci->url);
+ if (ci->email)
+ free(ci->email);
+ if (ci->last_topic)
+ free(ci->last_topic);
+ if (ci->forbidby)
+ free(ci->forbidby);
+ if (ci->forbidreason)
+ free(ci->forbidreason);
+ if (ci->mlock_key)
+ free(ci->mlock_key);
+ if (ci->mlock_flood)
+ free(ci->mlock_flood);
+ if (ci->mlock_redirect)
+ free(ci->mlock_redirect);
+ if (ci->entry_message)
+ free(ci->entry_message);
+ if (ci->access)
+ free(ci->access);
+ for (i = 0; i < ci->akickcount; i++) {
+ if (!(ci->akick[i].flags & 0x0002) && ci->akick[i].u.mask)
+ free(ci->akick[i].u.mask);
+ if (ci->akick[i].reason)
+ free(ci->akick[i].reason);
+ if (ci->akick[i].creator)
+ free(ci->akick[i].creator);
+ }
+ if (ci->akick)
+ free(ci->akick);
+ if (ci->levels)
+ free(ci->levels);
+ if (ci->memos.memos) {
+ for (i = 0; i < ci->memos.memocount; i++) {
+ if (ci->memos.memos[i].text)
+ free(ci->memos.memos[i].text);
+ }
+ free(ci->memos.memos);
+ }
+ if (ci->ttb)
+ free(ci->ttb);
+ for (i = 0; i < ci->bwcount; i++) {
+ if (ci->badwords[i].word)
+ free(ci->badwords[i].word);
+ }
+ if (ci->badwords)
+ free(ci->badwords);
+ if (ci->bi)
+ free(ci->bi);
+ free(ci);
+
+ } else if (input[0] == '2') { /* get #1 out of the list, free() it and add #2 to the list */
+ NickCore *nc = NULL;
+ printf("Deleting chan %s (#1).\n", ciptr->name);
+
+ if (ciptr->next)
+ ciptr->next->prev = ciptr->prev;
+ if (ciptr->prev)
+ ciptr->prev->next = ciptr->next;
+ else
+ chanlists[tolower(ciptr->name[1])] = ciptr->next;
+
+ if (ciptr->founder) {
+ nc = findcore(ciptr->founder, 0);
+ if (nc)
+ nc->channelcount--;
+ }
+ free(ciptr->desc);
+ if (ciptr->url)
+ free(ciptr->url);
+ if (ciptr->email)
+ free(ciptr->email);
+ if (ciptr->last_topic)
+ free(ciptr->last_topic);
+ if (ciptr->forbidby)
+ free(ciptr->forbidby);
+ if (ciptr->forbidreason)
+ free(ciptr->forbidreason);
+ if (ciptr->mlock_key)
+ free(ciptr->mlock_key);
+ if (ciptr->mlock_flood)
+ free(ciptr->mlock_flood);
+ if (ciptr->mlock_redirect)
+ free(ciptr->mlock_redirect);
+ if (ciptr->entry_message)
+ free(ciptr->entry_message);
+ if (ciptr->access)
+ free(ciptr->access);
+ for (i = 0; i < ciptr->akickcount; i++) {
+ if (!(ciptr->akick[i].flags & 0x0002) && ciptr->akick[i].u.mask)
+ free(ciptr->akick[i].u.mask);
+ if (ciptr->akick[i].reason)
+ free(ciptr->akick[i].reason);
+ if (ciptr->akick[i].creator)
+ free(ciptr->akick[i].creator);
+ }
+ if (ciptr->akick)
+ free(ciptr->akick);
+ if (ciptr->levels)
+ free(ciptr->levels);
+ if (ciptr->memos.memos) {
+ for (i = 0; i < ciptr->memos.memocount; i++) {
+ if (ciptr->memos.memos[i].text)
+ free(ciptr->memos.memos[i].text);
+ }
+ free(ciptr->memos.memos);
+ }
+ if (ciptr->ttb)
+ free(ciptr->ttb);
+ for (i = 0; i < ciptr->bwcount; i++) {
+ if (ciptr->badwords[i].word)
+ free(ciptr->badwords[i].word);
+ }
+ if (ciptr->badwords)
+ free(ciptr->badwords);
+ free(ciptr);
+
+ alpha_insert_chan(ci);
+
+ } else {
+ printf("Invalid number, give us a valid one (1 or 2).\n");
+ goto waiting_for_input4;
+ }
+ } else { /* no collision, put the chan into the list */
+ alpha_insert_chan(ci);
+ }
+ } /* getc_db() */
+ } /* for() loop */
+ close_db(f);
+ } else
+ nochan = 1;
+ }
+
+ /* IIc: Saving */
+ if (!nochan) {
+ if ((f = open_db_write("ChanServ", CHAN_DB_NEW, 16))) {
+ ChannelInfo *ci;
+ Memo *memos;
+ /* Unused variable - why? -GD
+ static time_t lastwarn = 0;
+ */
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ int j;
+ SAFE(write_int8(1, f));
+ SAFE(write_buffer(ci->name, f));
+ if (ci->founder)
+ SAFE(write_string(ci->founder, f));
+ else
+ SAFE(write_string(NULL, f));
+ if (ci->successor)
+ SAFE(write_string(ci->successor, f));
+ else
+ SAFE(write_string(NULL, f));
+ SAFE(write_buffer(ci->founderpass, f));
+ SAFE(write_string(ci->desc, f));
+ SAFE(write_string(ci->url, f));
+ SAFE(write_string(ci->email, f));
+ SAFE(write_int32(ci->time_registered, f));
+ SAFE(write_int32(ci->last_used, f));
+ SAFE(write_string(ci->last_topic, f));
+ SAFE(write_buffer(ci->last_topic_setter, f));
+ SAFE(write_int32(ci->last_topic_time, f));
+ SAFE(write_int32(ci->flags, f));
+ SAFE(write_string(ci->forbidby, f));
+ SAFE(write_string(ci->forbidreason, f));
+ SAFE(write_int16(ci->bantype, f));
+ tmp16 = 36;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < 36; j++)
+ SAFE(write_int16(ci->levels[j], f));
+
+ SAFE(write_int16(ci->accesscount, f));
+ for (j = 0; j < ci->accesscount; j++) {
+ SAFE(write_int16(ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ SAFE(write_int16(ci->access[j].level, f));
+ SAFE(write_string(ci->access[j].nc->display, f));
+ SAFE(write_int32(ci->access[j].last_seen, f));
+ }
+ }
+ SAFE(write_int16(ci->akickcount, f));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(write_int16(ci->akick[j].flags, f));
+ if (ci->akick[j].flags & 0x0001) {
+ if (ci->akick[j].flags & 0x0002)
+ SAFE(write_string(ci->akick[j].u.nc->display, f));
+ else
+ SAFE(write_string(ci->akick[j].u.mask, f));
+ SAFE(write_string(ci->akick[j].reason, f));
+ SAFE(write_string(ci->akick[j].creator, f));
+ SAFE(write_int32(ci->akick[j].addtime, f));
+ }
+ }
+
+ SAFE(write_int32(ci->mlock_on, f));
+ SAFE(write_int32(ci->mlock_off, f));
+ SAFE(write_int32(ci->mlock_limit, f));
+ SAFE(write_string(ci->mlock_key, f));
+ SAFE(write_string(ci->mlock_flood, f));
+ SAFE(write_string(ci->mlock_redirect, f));
+ SAFE(write_int16(ci->memos.memocount, f));
+ SAFE(write_int16(ci->memos.memomax, f));
+ memos = ci->memos.memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ SAFE(write_int32(memos->number, f));
+ SAFE(write_int16(memos->flags, f));
+ SAFE(write_int32(memos->time, f));
+ SAFE(write_buffer(memos->sender, f));
+ SAFE(write_string(memos->text, f));
+ }
+ SAFE(write_string(ci->entry_message, f));
+ if (ci->bi)
+ SAFE(write_string(ci->bi, f));
+ else
+ SAFE(write_string(NULL, f));
+ SAFE(write_int32(ci->botflags, f));
+ tmp16 = 8;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < 8; j++)
+ SAFE(write_int16(ci->ttb[j], f));
+ SAFE(write_int16(ci->capsmin, f));
+ SAFE(write_int16(ci->capspercent, f));
+ SAFE(write_int16(ci->floodlines, f));
+ SAFE(write_int16(ci->floodsecs, f));
+ SAFE(write_int16(ci->repeattimes, f));
+
+ SAFE(write_int16(ci->bwcount, f));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(write_int16(ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(write_string(ci->badwords[j].word, f));
+ SAFE(write_int16(ci->badwords[j].type, f));
+ }
+ }
+ } /* for (chanlists[i]) */
+ SAFE(write_int8(0, f));
+ } /* for (i) */
+ close_db(f);
+ printf("Chan merging done. New database saved as %s.\n", CHAN_DB_NEW);
+ }
+ }
+
+ /* Section III: Bots */
+ /* IIIa: First database */
+ if ((f = open_db_read("Botserv", BOT_DB_1, 10))) {
+ BotInfo *bi;
+ int c;
+ int32 tmp32;
+ int16 tmp16;
+
+ printf("Trying to merge bots...\n");
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", BOT_DB_1);
+ exit(0);
+ }
+
+ bi = calloc(sizeof(BotInfo), 1);
+ READ(read_string(&bi->nick, f));
+ READ(read_string(&bi->user, f));
+ READ(read_string(&bi->host, f));
+ READ(read_string(&bi->real, f));
+ SAFE(read_int16(&tmp16, f));
+ bi->flags = tmp16;
+ READ(read_int32(&tmp32, f));
+ bi->created = tmp32;
+ READ(read_int16(&tmp16, f));
+ bi->chancount = tmp16;
+ insert_bot(bi);
+ }
+ } else
+ nobot = 1;
+
+ /* IIIb: Second database */
+ if (!nobot) {
+ if ((f = open_db_read("Botserv", BOT_DB_2, 10))) {
+ BotInfo *bi, *biptr;
+ int c;
+ int32 tmp32;
+ int16 tmp16;
+ char input[1024];
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", BOT_DB_2);
+ exit(0);
+ }
+
+ bi = calloc(sizeof(BotInfo), 1);
+ READ(read_string(&bi->nick, f));
+ READ(read_string(&bi->user, f));
+ READ(read_string(&bi->host, f));
+ READ(read_string(&bi->real, f));
+ SAFE(read_int16(&tmp16, f));
+ bi->flags = tmp16;
+ READ(read_int32(&tmp32, f));
+ bi->created = tmp32;
+ READ(read_int16(&tmp16, f));
+ bi->chancount = tmp16;
+ biptr = findbot(bi->nick);
+ if (biptr) { /* BOT COLLISION! #1 is biptr-> (db1), #2 is bi-> (db2) */
+ if (!preferoldest && !preferfirst && !prefersecond && !prefernewest) {
+ printf("Bot collision for botnick %s:\n\n", biptr->nick);
+ printf("Bot 1: %s@%s (%s) is assigned to %d chans\n", biptr->user, biptr->host, biptr->real, biptr->chancount);
+ printf("Time registered: %s\n", ctime(&biptr->created));
+ printf("Bot 2: %s@%s (%s) is assigned to %d chans\n", bi->user, bi->host, bi->real, bi->chancount);
+ printf("Time registered: %s\n", ctime(&bi->created));
+ printf("What bot do you want to keep? Enter the related bot number \"1\" or \"2\".\n");
+ }
+
+ if (preferoldest) {
+ input[0] = (biptr->created > bi->created) ? '1' : '2';
+ } else if (prefernewest) {
+ input[0] = (biptr->created > bi->created) ? '2' : '1';
+ } else if (preferfirst) {
+ input[0] = '2';
+ } else if (prefersecond) {
+ input[0] = '1';
+ } else {
+ waiting_for_input3:
+ scanf("%s", input);
+ }
+ if (input[0] == '1') { /* free() bot #2 (bi) */
+ printf("Deleting Bot %s!%s@%s (%s) (#2).\n", bi->nick, bi->user, bi->host, bi->real);
+ free(bi->nick);
+ free(bi->user);
+ free(bi->host);
+ free(bi->real);
+ free(bi);
+ } else if (input[0] == '2') { /* get bot #1 (biptr) out of the list, free() it and add #2 to the list */
+ printf("Deleting Bot %s!%s@%s (%s) (#1).\n", biptr->nick, biptr->user, biptr->host, biptr->real);
+ if (biptr->next)
+ biptr->next->prev = biptr->prev;
+ if (biptr->prev)
+ biptr->prev->next = biptr->next;
+ else
+ botlists[tolower(*biptr->nick)] = biptr->next;
+ free(biptr->nick);
+ free(biptr->user);
+ free(biptr->host);
+ free(biptr->real);
+ free(biptr);
+ insert_bot(bi);
+ } else {
+ printf("Invalid number, give us a valid one (1 or 2).\n");
+ goto waiting_for_input3;
+ }
+ } /* NO COLLISION (biptr) */
+ insert_bot(bi);
+ }
+ } else
+ nobot = 1;
+ }
+
+ /* IIIc: Saving */
+ if (!nobot) {
+ if ((f = open_db_write("Botserv", BOT_DB_NEW, 10))) {
+ BotInfo *bi;
+ for (i = 0; i < 256; i++) {
+ for (bi = botlists[i]; bi; bi = bi->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(bi->nick, f));
+ SAFE(write_string(bi->user, f));
+ SAFE(write_string(bi->host, f));
+ SAFE(write_string(bi->real, f));
+ SAFE(write_int16(bi->flags, f));
+ SAFE(write_int32(bi->created, f));
+ SAFE(write_int16(bi->chancount, f));
+ }
+ }
+ SAFE(write_int8(0, f));
+ close_db(f);
+ printf("Bot merging done. New database saved as %s.\n", BOT_DB_NEW);
+ }
+ } /* End of section III */
+
+ /* Section IV: Hosts */
+ /* IVa: First database */
+ if ((f = open_db_read("HostServ", HOST_DB_1, 3))) {
+ HostCore *hc;
+ int c;
+ int32 tmp32;
+
+ printf("Trying to merge hosts...\n");
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", HOST_DB_1);
+ exit(0);
+ }
+ hc = calloc(1, sizeof(HostCore));
+ READ(read_string(&hc->nick, f));
+ READ(read_string(&hc->vIdent, f));
+ READ(read_string(&hc->vHost, f));
+ READ(read_string(&hc->creator, f));
+ READ(read_int32(&tmp32, f));
+ hc->time = tmp32;
+ hc->next = firsthc;
+ if (firsthc)
+ firsthc->last = hc;
+ hc->last = NULL;
+ firsthc = hc;
+ }
+ } else
+ nohost = 1;
+
+ /* IVb: Second database */
+ if (!nohost) {
+ if ((f = open_db_read("HostServ", HOST_DB_2, 3))) {
+ HostCore *hc, *hcptr;
+ char input[1024];
+ int32 tmp32;
+ int c;
+ int collision = 0;
+
+ while ((c = getc_db(f)) == 1) {
+ if (c != 1) {
+ printf("Invalid format in %s.\n", HOST_DB_2);
+ exit(0);
+ }
+ collision = 0;
+ hc = calloc(1, sizeof(HostCore));
+ READ(read_string(&hc->nick, f));
+ READ(read_string(&hc->vIdent, f));
+ READ(read_string(&hc->vHost, f));
+ READ(read_string(&hc->creator, f));
+ READ(read_int32(&tmp32, f));
+ hc->time = tmp32;
+
+ for (hcptr = firsthc; hcptr; hcptr = hcptr->next) {
+ if (!mystricmp(hcptr->nick, hc->nick)) { /* COLLISION: #1 is from db1 (hcptr), #2 is from db2 (hc) */
+ collision++;
+ if (!preferoldest && !preferfirst && !prefersecond && !prefernewest) {
+ printf("vHost collision for nick %s:\n\n", hcptr->nick);
+ printf("vHost 1: %s (vIdent: %s)\n", hcptr->vHost, (hcptr->vIdent) ? hcptr->vIdent : "none");
+ printf("Time set: %s\n", ctime(&hcptr->time));
+ printf("vHost 2: %s (vIdent: %s)\n", hc->vHost, (hc->vIdent) ? hc->vIdent : "none");
+ printf("Time set: %s\n", ctime(&hc->time));
+ printf("What vhost do you want to keep? Enter the related number \"1\" or \"2\".\n");
+ }
+ if (preferoldest) {
+ input[0] = (hcptr->time > hc->time) ? '1' : '2';
+ } else if (prefernewest) {
+ input[0] = (hcptr->time > hc->time) ? '2' : '1';
+ } else if (preferfirst) {
+ input[0] = '1';
+ } else if (prefersecond) {
+ input[0] = '2';
+ } else {
+ waiting_for_input2:
+ scanf("%s", input);
+ }
+ if (input[0] == '2') { /* free() hcptr and get it out of the list, put hc into the list */
+ printf("Deleting vHost %s (vIdent: %s) for nick %s (#1).\n", hcptr->vHost, (hcptr->vIdent) ? hcptr->vIdent : "none", hcptr->nick);
+ if (hcptr->last)
+ hcptr->last->next = hcptr->next;
+ if (hcptr->next)
+ hcptr->next->last = hcptr->last;
+ free(hcptr->nick);
+ free(hcptr->vHost);
+ free(hcptr->vIdent);
+ free(hcptr->creator);
+ free(hcptr);
+ hc->next = firsthc;
+ if (firsthc)
+ firsthc->last = hc;
+ hc->last = NULL;
+ firsthc = hc;
+ } else if (input[0] == '1') { /* free() hc */
+ printf("Deleting vHost %s (vIdent: %s) for nick %s (#2).\n", hc->vHost, (hc->vIdent) ? hc->vIdent : "none", hc->nick);
+ free(hc->nick);
+ free(hc->vHost);
+ free(hc->vIdent);
+ free(hc->creator);
+ free(hc);
+ } else {
+ printf("Invalid number, give us a valid one (1 or 2).\n");
+ goto waiting_for_input2;
+ } /* input[0] */
+ } /* mystricmp */
+ } /* for (hcptr...) */
+ if (!collision) { /* No collision */
+ hc->next = firsthc;
+ if (firsthc)
+ firsthc->last = hc;
+ hc->last = NULL;
+ firsthc = hc;
+ }
+ } /* while */
+ } else
+ nohost = 1;
+ }
+
+ /* IVc: Saving */
+ if (!nohost) {
+ if ((f = open_db_write("HostServ", HOST_DB_NEW, 3))) {
+ HostCore *hcptr;
+ for (hcptr = firsthc; hcptr; hcptr = hcptr->next) {
+ SAFE(write_int8(1, f));
+ SAFE(write_string(hcptr->nick, f));
+ SAFE(write_string(hcptr->vIdent, f));
+ SAFE(write_string(hcptr->vHost, f));
+ SAFE(write_string(hcptr->creator, f));
+ SAFE(write_int32(hcptr->time, f));
+ }
+ SAFE(write_int8(0, f));
+ close_db(f);
+ printf("Host merging done. New database saved as %s.\n", HOST_DB_NEW);
+ }
+ } /* End of section IV */
+
+ /* MERGING DONE \o/ HURRAY! */
+
+ printf("\n\nMerging is now done. I give NO guarantee for your DBs.\n");
+ return 0;
+} /* End of main() */
+
+/* Open a database file for reading and check for the version */
+dbFILE *open_db_read(const char *service, const char *filename, int version)
+{
+ dbFILE *f;
+ FILE *fp;
+ int myversion;
+
+ f = calloc(sizeof(*f), 1);
+ if (!f) {
+ printf("Can't allocate memory for %s database %s.\n", service, filename);
+ exit(0);
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+ f->mode = 'r';
+ fp = fopen(f->filename, "rb");
+ if (!fp) {
+ printf("Can't read %s database %s.\n", service, f->filename);
+ free(f);
+ return NULL;
+ }
+ f->fp = fp;
+ myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
+ if (feof(fp)) {
+ printf("Error reading version number on %s: End of file detected.\n", f->filename);
+ exit(0);
+ } else if (myversion < version) {
+ printf("Unsuported database version (%d) on %s.\n", myversion, f->filename);
+ exit(0);
+ }
+ return f;
+}
+
+/* Open a database file for reading and check for the version */
+dbFILE *open_db_write(const char *service, const char *filename, int version)
+{
+ dbFILE *f;
+ int fd;
+
+ f = calloc(sizeof(*f), 1);
+ if (!f) {
+ printf("Can't allocate memory for %s database %s.\n", service, filename);
+ exit(0);
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+ filename = f->filename;
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ f->mode = 'w';
+#ifndef _WIN32
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+#else
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL | _O_BINARY, 0666);
+#endif
+ f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */
+ if (!f->fp || !write_file_version(f, version)) {
+ printf("Can't write to %s database %s.\n", service, filename);
+ if (f->fp) {
+ fclose(f->fp);
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ }
+ free(f);
+ return NULL;
+ }
+ return f;
+}
+
+/* Close it */
+void close_db(dbFILE * f)
+{
+ fclose(f->fp);
+ free(f);
+}
+
+int read_int16(int16 * ret, dbFILE * f)
+{
+ int c1, c2;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF)
+ return -1;
+ *ret = c1 << 8 | c2;
+ return 0;
+}
+
+int read_uint16(uint16 * ret, dbFILE * f)
+{
+ int c1, c2;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF)
+ return -1;
+ *ret = c1 << 8 | c2;
+ return 0;
+}
+
+
+int write_int16(uint16 val, dbFILE * f)
+{
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF
+ || fputc(val & 0xFF, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+int read_int32(int32 * ret, dbFILE * f)
+{
+ int c1, c2, c3, c4;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ c3 = fgetc(f->fp);
+ c4 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
+ return -1;
+ *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ return 0;
+}
+
+int read_uint32(uint32 * ret, dbFILE * f)
+{
+ int c1, c2, c3, c4;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ c3 = fgetc(f->fp);
+ c4 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
+ return -1;
+ *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ return 0;
+}
+
+int write_int32(uint32 val, dbFILE * f)
+{
+ if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val) & 0xFF, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+
+int read_ptr(void **ret, dbFILE * f)
+{
+ int c;
+
+ c = fgetc(f->fp);
+ if (c == EOF)
+ return -1;
+ *ret = (c ? (void *) 1 : (void *) 0);
+ return 0;
+}
+
+int write_ptr(const void *ptr, dbFILE * f)
+{
+ if (fputc(ptr ? 1 : 0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+
+int read_string(char **ret, dbFILE * f)
+{
+ char *s;
+ uint16 len;
+
+ if (read_uint16(&len, f) < 0)
+ return -1;
+ if (len == 0) {
+ *ret = NULL;
+ return 0;
+ }
+ s = calloc(len, 1);
+ if (len != fread(s, 1, len, f->fp)) {
+ free(s);
+ return -1;
+ }
+ *ret = s;
+ return 0;
+}
+
+int write_string(const char *s, dbFILE * f)
+{
+ uint32 len;
+
+ if (!s)
+ return write_int16(0, f);
+ len = strlen(s);
+ if (len > 65534)
+ len = 65534;
+ if (write_int16((uint16) (len + 1), f) < 0)
+ return -1;
+ if (len > 0 && fwrite(s, 1, len, f->fp) != len)
+ return -1;
+ if (fputc(0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+NickCore *findcore(const char *nick, int unused)
+{
+ NickCore *nc;
+
+ for (nc = nclists[HASH(nick)]; nc; nc = nc->next) {
+ if (!mystricmp(nc->display, nick))
+ if ((nc->unused && unused) || (!nc->unused && !unused))
+ return nc;
+ }
+
+ return NULL;
+}
+
+NickAlias *findnick(const char *nick)
+{
+ NickAlias *na;
+
+ for (na = nalists[HASH(nick)]; na; na = na->next) {
+ if (!mystricmp(na->nick, nick))
+ return na;
+ }
+
+ return NULL;
+}
+
+int write_file_version(dbFILE * f, uint32 version)
+{
+ FILE *fp = f->fp;
+ if (fputc(version >> 24 & 0xFF, fp) < 0 ||
+ fputc(version >> 16 & 0xFF, fp) < 0 ||
+ fputc(version >> 8 & 0xFF, fp) < 0 ||
+ fputc(version & 0xFF, fp) < 0) {
+ printf("Error writing version number on %s.\n", f->filename);
+ exit(0);
+ }
+ return 1;
+}
+
+/* strscpy: Copy at most len-1 characters from a string to a buffer, and
+ * add a null terminator after the last character copied.
+ */
+
+char *strscpy(char *d, const char *s, size_t len)
+{
+ char *d_orig = d;
+
+ if (!len)
+ return d;
+ while (--len && (*d++ = *s++));
+ *d = '\0';
+ return d_orig;
+}
+
+int mystricmp(const char *s1, const char *s2)
+{
+ register int c;
+
+ while ((c = tolower(*s1)) == tolower(*s2)) {
+ if (c == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ if (c < tolower(*s2))
+ return -1;
+ return 1;
+}
+
+int delnick(NickAlias *na, int donttouchthelist)
+{
+ if (!donttouchthelist) {
+ /* Remove us from the aliases list */
+ if (na->next)
+ na->next->prev = na->prev;
+ if (na->prev)
+ na->prev->next = na->next;
+ else
+ nalists[HASH(na->nick)] = na->next;
+ }
+
+ /* free() us */
+ free(na->nick);
+ if (na->last_usermask)
+ free(na->last_usermask);
+ if (na->last_realname)
+ free(na->last_realname);
+ if (na->last_quit)
+ free(na->last_quit);
+ free(na);
+ return 1;
+}
+
+int delcore(NickCore *nc)
+{
+ int i;
+ /* Remove the core from the list */
+ if (nc->next)
+ nc->next->prev = nc->prev;
+ if (nc->prev)
+ nc->prev->next = nc->next;
+ else
+ nclists[HASH(nc->display)] = nc->next;
+
+ free(nc->display);
+ if (nc->email)
+ free(nc->email);
+ if (nc->greet)
+ free(nc->greet);
+ if (nc->url)
+ free(nc->url);
+ if (nc->access) {
+ for (i = 0; i < nc->accesscount; i++) {
+ if (nc->access[i])
+ free(nc->access[i]);
+ }
+ free(nc->access);
+ }
+ if (nc->memos.memos) {
+ for (i = 0; i < nc->memos.memocount; i++) {
+ if (nc->memos.memos[i].text)
+ free(nc->memos.memos[i].text);
+ }
+ free(nc->memos.memos);
+ }
+ free(nc);
+ return 1;
+}
+
+void insert_bot(BotInfo * bi)
+{
+ BotInfo *ptr, *prev;
+
+ for (prev = NULL, ptr = botlists[tolower(*bi->nick)];
+ ptr != NULL && mystricmp(ptr->nick, bi->nick) < 0;
+ prev = ptr, ptr = ptr->next);
+ bi->prev = prev;
+ bi->next = ptr;
+ if (!prev)
+ botlists[tolower(*bi->nick)] = bi;
+ else
+ prev->next = bi;
+ if (ptr)
+ ptr->prev = bi;
+}
+
+BotInfo *findbot(char *nick)
+{
+ BotInfo *bi;
+
+ for (bi = botlists[tolower(*nick)]; bi; bi = bi->next)
+ if (!mystricmp(nick, bi->nick))
+ return bi;
+
+ return NULL;
+}
+
+ChannelInfo *cs_findchan(const char *chan)
+{
+ ChannelInfo *ci;
+ for (ci = chanlists[tolower(chan[1])]; ci; ci = ci->next) {
+ if (!mystricmp(ci->name, chan))
+ return ci;
+ }
+ return NULL;
+}
+
+void alpha_insert_chan(ChannelInfo * ci)
+{
+ ChannelInfo *ptr, *prev;
+ char *chan = ci->name;
+
+ for (prev = NULL, ptr = chanlists[tolower(chan[1])];
+ ptr != NULL && mystricmp(ptr->name, chan) < 0;
+ prev = ptr, ptr = ptr->next);
+ ci->prev = prev;
+ ci->next = ptr;
+ if (!prev)
+ chanlists[tolower(chan[1])] = ci;
+ else
+ prev->next = ci;
+ if (ptr)
+ ptr->prev = ci;
+}
+
diff --git a/src/tools/epona2anope.c b/src/tools/epona2anope.c
new file mode 100644
index 000000000..d89be6d12
--- /dev/null
+++ b/src/tools/epona2anope.c
@@ -0,0 +1,856 @@
+/*
+ * IRC - Internet Relay Chat, epona2anope.c
+ * (C) Copyright 2005-2006, Florian Schulze (Certus)
+ *
+ * Based on the original code of Anope, (C) 2003-2005 Anope Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (see it online
+ * at http://www.gnu.org/copyleft/gpl.html) as published by the Free
+ * Software Foundation;
+ *
+ * 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.
+ *
+ * This program tries to convert epona-1.4.15+ dbs to anope standard dbs.
+ * At the moment this only affects chanserv dbs.
+ *
+ * - Certus
+ * February 26, 2005
+ *
+ * Added win32 fix. Who needs that anyways? :P
+ * - Certus
+ * July 20, 2006
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include "sysconf.h"
+#include <windows.h>
+#endif
+
+/* Some SUN fixs */
+#ifdef __sun
+/* Solaris specific code, types that do not exist in Solaris'
+ * * sys/types.h
+ * **/
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int_64_t
+#define u_int8_t uint8_t
+#define u_int16_t uint16_t
+#define u_int32_t uint32_t
+#define u_int64_t uint64_t
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+#endif
+
+
+/* CONFIGURATION BLOCK */
+
+#define CHAN_DB_EPONA "chan1.db"
+#define CHAN_DB_ANOPE "chan.db"
+
+/* END OF CONFIGURATION BLOCK */
+
+#ifndef _WIN32
+#define C_LBLUE "\033[1;34m"
+#define C_NONE "\033[m"
+#else
+#define C_LBLUE ""
+#define C_NONE ""
+#endif
+
+#define getc_db(f) (fgetc((f)->fp))
+#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
+#define HASH2(chan) ((chan)[1] ? ((chan)[1]&31)<<5 | ((chan)[2]&31) : 0)
+#define read_buffer(buf,f) (read_db((f),(buf),sizeof(buf)) == sizeof(buf))
+#define write_buffer(buf,f) (write_db((f),(buf),sizeof(buf)) == sizeof(buf))
+#define read_db(f,buf,len) (fread((buf),1,(len),(f)->fp))
+#define write_db(f,buf,len) (fwrite((buf),1,(len),(f)->fp))
+#define read_int8(ret,f) ((*(ret)=fgetc((f)->fp))==EOF ? -1 : 0)
+#define write_int8(val,f) (fputc((val),(f)->fp)==EOF ? -1 : 0)
+#define SAFE(x) do { \
+ if ((x) < 0) { \
+ printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
+ } \
+} while (0)
+#define READ(x) do { \
+ if ((x) < 0) { \
+ printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
+ exit(0); \
+ } \
+} while (0)
+
+typedef int16_t int16;
+typedef u_int16_t uint16;
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef struct memo_ Memo;
+typedef struct dbFILE_ dbFILE;
+typedef struct nickalias_ NickAlias;
+typedef struct nickcore_ NickCore;
+typedef struct chaninfo_ ChannelInfo;
+typedef struct botinfo_ BotInfo;
+typedef struct badword_ BadWord;
+typedef struct hostcore_ HostCore;
+
+struct memo_ {
+ uint32 number; /* Index number -- not necessarily array position! */
+ int16 flags; /* Flags */
+ time_t time; /* When was it sent? */
+ char sender[32]; /* Name of the sender */
+ char *text;
+};
+
+struct dbFILE_ {
+ int mode; /* 'r' for reading, 'w' for writing */
+ FILE *fp; /* The normal file descriptor */
+ char filename[1024]; /* Name of the database file */
+};
+
+typedef struct {
+ int16 memocount; /* Current # of memos */
+ int16 memomax; /* Max # of memos one can hold*/
+ Memo *memos; /* Pointer to original memos */
+} MemoInfo;
+
+typedef struct {
+ int16 in_use; /* 1 if this entry is in use, else 0 */
+ int16 level;
+ NickCore *nc; /* Guaranteed to be non-NULL if in use, NULL if not */
+ time_t last_seen;
+} ChanAccess;
+
+typedef struct {
+ int16 in_use; /* Always 0 if not in use */
+ int16 is_nick; /* 1 if a regged nickname, 0 if a nick!user@host mask */
+ int16 flags;
+ union {
+ char *mask; /* Guaranteed to be non-NULL if in use, NULL if not */
+ NickCore *nc; /* Same */
+ } u;
+ char *reason;
+ char *creator;
+ time_t addtime;
+} AutoKick;
+
+struct nickcore_ {
+ NickCore *next, *prev;
+
+ char *display; /* How the nick is displayed */
+ int unused; /* Used for nick collisions */
+};
+
+struct chaninfo_ {
+ ChannelInfo *next, *prev;
+
+ char name[64]; /* Channel name */
+ char *founder; /* Who registered the channel */
+ char *successor; /* Who gets the channel if the founder nick is dropped or expires */
+ char founderpass[32]; /* Channel password */
+ char *desc; /* Description */
+ char *url; /* URL */
+ char *email; /* Email address */
+ time_t time_registered; /* When was it registered */
+ time_t last_used; /* When was it used hte last time */
+ char *last_topic; /* Last topic on the channel */
+ char last_topic_setter[32]; /* Who set the last topic */
+ time_t last_topic_time; /* When the last topic was set */
+ uint32 flags; /* Flags */
+ char *forbidby; /* if forbidden: who did it */
+ char *forbidreason; /* if forbidden: why */
+ int16 bantype; /* Bantype */
+ int16 *levels; /* Access levels for commands */
+ int16 accesscount; /* # of pple with access */
+ ChanAccess *access; /* List of authorized users */
+ int16 akickcount; /* # of akicked pple */
+ AutoKick *akick; /* List of users to kickban */
+ uint32 mlock_on, mlock_off; /* See channel modes below */
+ uint32 mlock_limit; /* 0 if no limit */
+ char *mlock_key; /* NULL if no key */
+ char *mlock_flood; /* NULL if no +f */
+ char *mlock_joinrate; /* NULL if no +j */
+ char *mlock_redirect; /* NULL if no +L */
+ char *entry_message; /* Notice sent on entering channel */
+ MemoInfo memos; /* Memos */
+ char *bi; /* Bot used on this channel */
+ uint32 botflags; /* BS_* below */
+ int16 *ttb; /* Times to ban for each kicker */
+ int16 bwcount; /* Badword count */
+ BadWord *badwords; /* For BADWORDS kicker */
+ int16 capsmin, capspercent; /* For CAPS kicker */
+ int16 floodlines, floodsecs; /* For FLOOD kicker */
+ int16 repeattimes; /* For REPEAT kicker */
+};
+
+struct botinfo_ {
+ BotInfo *next, *prev;
+ char *nick; /* Nickname of the bot */
+ char *user; /* Its user name */
+ char *host; /* Its hostname */
+ char *real; /* Its real name */
+ int16 flags; /* Bot flags */
+ time_t created; /* Birth date */
+ int16 chancount; /* Number of channels that use the bot. */
+};
+
+struct badword_ {
+ int16 in_use;
+ char *word;
+ int16 type;
+};
+
+dbFILE *open_db_write(const char *service, const char *filename, int version);
+dbFILE *open_db_read(const char *service, const char *filename, int version);
+NickCore *findcore(const char *nick, int version);
+ChannelInfo *cs_findchan(const char *chan);
+char *strscpy(char *d, const char *s, size_t len);
+int write_file_version(dbFILE * f, uint32 version);
+int mystricmp(const char *s1, const char *s2);
+int write_string(const char *s, dbFILE * f);
+int write_ptr(const void *ptr, dbFILE * f);
+int read_int16(int16 * ret, dbFILE * f);
+int read_uint16(uint16 * ret, dbFILE * f);
+int read_int32(int32 * ret, dbFILE * f);
+int read_uint32(uint32 * ret, dbFILE * f);
+int read_string(char **ret, dbFILE * f);
+int write_int16(uint16 val, dbFILE * f);
+int write_int32(uint32 val, dbFILE * f);
+int read_ptr(void **ret, dbFILE * f);
+void alpha_insert_chan(ChannelInfo * ci);
+void close_db(dbFILE * f);
+
+ChannelInfo *chanlists[256];
+NickCore *nclists[1024];
+
+int main(int argc, char *argv[])
+{
+ dbFILE *f;
+ int i;
+ long countr = 0, countw = 0;
+ /* Unused variables - why? -GD
+ NickCore *nc, *ncnext;
+ */
+
+ printf("\n"C_LBLUE"Epona to Anope DB converter by Certus"C_NONE"\n\n");
+
+ /* Section I: Reading */
+ if ((f = open_db_read("ChanServ", CHAN_DB_EPONA, 17))) {
+ ChannelInfo *ci, **last, *prev;
+ int c;
+
+ printf("Trying to convert channel database...\n");
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+ int32 tmp32;
+ int n_levels;
+ char *s;
+ int n_ttb;
+ /* Unused variable - why? -GD
+ int J;
+ */
+
+ last = &chanlists[i];
+ prev = NULL;
+
+ while ((c = getc_db(f)) == 1) {
+ int j;
+
+ if (c != 1) {
+ printf("Invalid format in %s.\n", CHAN_DB_EPONA);
+ exit(0);
+ }
+
+ ci = calloc(sizeof(ChannelInfo), 1);
+ *last = ci;
+ last = &ci->next;
+ ci->prev = prev;
+ prev = ci;
+ READ(read_buffer(ci->name, f));
+ READ(read_string(&ci->founder, f));
+ READ(read_string(&ci->successor, f));
+ READ(read_buffer(ci->founderpass, f));
+ READ(read_string(&ci->desc, f));
+ if (!ci->desc)
+ ci->desc = strdup("");
+ READ(read_string(&ci->url, f));
+ READ(read_string(&ci->email, f));
+ READ(read_int32(&tmp32, f));
+ ci->time_registered = tmp32;
+ READ(read_int32(&tmp32, f));
+ ci->last_used = tmp32;
+ READ(read_string(&ci->last_topic, f));
+ READ(read_buffer(ci->last_topic_setter, f));
+ READ(read_int32(&tmp32, f));
+ ci->last_topic_time = tmp32;
+ READ(read_uint32(&ci->flags, f));
+ /* Temporary flags cleanup */
+ ci->flags &= ~0x80000000;
+ READ(read_string(&ci->forbidby, f));
+ READ(read_string(&ci->forbidreason, f));
+ READ(read_int16(&tmp16, f));
+ ci->bantype = tmp16;
+ READ(read_int16(&tmp16, f));
+ n_levels = tmp16;
+ ci->levels = calloc(36 * sizeof(*ci->levels), 1);
+ for (j = 0; j < n_levels; j++) {
+ if (j < 36)
+ READ(read_int16(&ci->levels[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ READ(read_int16(&ci->accesscount, f));
+ if (ci->accesscount) {
+ ci->access = calloc(ci->accesscount, sizeof(ChanAccess));
+ for (j = 0; j < ci->accesscount; j++) {
+ READ(read_int16(&ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ READ(read_int16(&ci->access[j].level, f));
+ READ(read_string(&s, f));
+ if (s) {
+ ci->access[j].nc = findcore(s, 0);
+ free(s);
+ }
+ if (ci->access[j].nc == NULL)
+ ci->access[j].in_use = 0;
+ READ(read_int32(&tmp32, f));
+ ci->access[j].last_seen = tmp32;
+ }
+ }
+ } else {
+ ci->access = NULL;
+ }
+ READ(read_int16(&ci->akickcount, f));
+ if (ci->akickcount) {
+ ci->akick = calloc(ci->akickcount, sizeof(AutoKick));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(read_int16(&ci->akick[j].flags, f));
+ if (ci->akick[j].flags & 0x0001) {
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0002) {
+ ci->akick[j].u.nc = findcore(s, 0);
+ if (!ci->akick[j].u.nc)
+ ci->akick[j].flags &= ~0x0001;
+ free(s);
+ } else {
+ ci->akick[j].u.mask = s;
+ }
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].reason = s;
+ else if (s)
+ free(s);
+ SAFE(read_string(&s, f));
+ if (ci->akick[j].flags & 0x0001) {
+ ci->akick[j].creator = s;
+ } else if (s) {
+ free(s);
+ }
+ SAFE(read_int32(&tmp32, f));
+ if (ci->akick[j].flags & 0x0001)
+ ci->akick[j].addtime = tmp32;
+ }
+ }
+ } else {
+ ci->akick = NULL;
+ }
+ READ(read_uint32(&ci->mlock_on, f));
+ READ(read_uint32(&ci->mlock_off, f));
+ READ(read_uint32(&ci->mlock_limit, f));
+ READ(read_string(&ci->mlock_key, f));
+ READ(read_string(&ci->mlock_flood, f));
+ READ(read_string(&ci->mlock_joinrate, f));
+ READ(read_string(&ci->mlock_redirect, f));
+ READ(read_int16(&ci->memos.memocount, f));
+ READ(read_int16(&ci->memos.memomax, f));
+ if (ci->memos.memocount) {
+ Memo *memos;
+ memos = calloc(sizeof(Memo) * ci->memos.memocount, 1);
+ ci->memos.memos = memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ READ(read_uint32(&memos->number, f));
+ READ(read_int16(&memos->flags, f));
+ READ(read_int32(&tmp32, f));
+ memos->time = tmp32;
+ READ(read_buffer(memos->sender, f));
+ READ(read_string(&memos->text, f));
+ }
+ }
+ READ(read_string(&ci->entry_message, f));
+
+ /* BotServ options */
+ READ(read_string(&ci->bi, f));
+ READ(read_int32(&tmp32, f));
+ ci->botflags = tmp32;
+ READ(read_int16(&tmp16, f));
+ n_ttb = tmp16;
+ ci->ttb = calloc(2 * 8, 1);
+ for (j = 0; j < n_ttb; j++) {
+ if (j < 8)
+ READ(read_int16(&ci->ttb[j], f));
+ else
+ READ(read_int16(&tmp16, f));
+ }
+ for (j = n_ttb; j < 8; j++)
+ ci->ttb[j] = 0;
+ READ(read_int16(&tmp16, f));
+ ci->capsmin = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->capspercent = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodlines = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->floodsecs = tmp16;
+ READ(read_int16(&tmp16, f));
+ ci->repeattimes = tmp16;
+
+ READ(read_int16(&ci->bwcount, f));
+ if (ci->bwcount) {
+ ci->badwords = calloc(ci->bwcount, sizeof(BadWord));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(read_int16(&ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(read_string(&ci->badwords[j].word, f));
+ SAFE(read_int16(&ci->badwords[j].type, f));
+ }
+ }
+ } else {
+ ci->badwords = NULL;
+ }
+ countr++;
+ } /* getc_db() */
+ *last = NULL;
+ } /* for() loop */
+ close_db(f);
+ }
+
+ /* II: Saving */
+ {
+ if ((f = open_db_write("ChanServ", CHAN_DB_ANOPE, 16))) {
+ ChannelInfo *ci;
+ Memo *memos;
+ /* Unused variable - why? -GD
+ static time_t lastwarn = 0;
+ */
+
+ for (i = 0; i < 256; i++) {
+ int16 tmp16;
+ for (ci = chanlists[i]; ci; ci = ci->next) {
+ int j;
+ SAFE(write_int8(1, f));
+ SAFE(write_buffer(ci->name, f));
+ if (ci->founder)
+ SAFE(write_string(ci->founder, f));
+ else
+ SAFE(write_string(NULL, f));
+ if (ci->successor)
+ SAFE(write_string(ci->successor, f));
+ else
+ SAFE(write_string(NULL, f));
+ SAFE(write_buffer(ci->founderpass, f));
+ SAFE(write_string(ci->desc, f));
+ SAFE(write_string(ci->url, f));
+ SAFE(write_string(ci->email, f));
+ SAFE(write_int32(ci->time_registered, f));
+ SAFE(write_int32(ci->last_used, f));
+ SAFE(write_string(ci->last_topic, f));
+ SAFE(write_buffer(ci->last_topic_setter, f));
+ SAFE(write_int32(ci->last_topic_time, f));
+ SAFE(write_int32(ci->flags, f));
+ SAFE(write_string(ci->forbidby, f));
+ SAFE(write_string(ci->forbidreason, f));
+ SAFE(write_int16(ci->bantype, f));
+ tmp16 = 36;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < 36; j++)
+ SAFE(write_int16(ci->levels[j], f));
+
+ SAFE(write_int16(ci->accesscount, f));
+ for (j = 0; j < ci->accesscount; j++) {
+ SAFE(write_int16(ci->access[j].in_use, f));
+ if (ci->access[j].in_use) {
+ SAFE(write_int16(ci->access[j].level, f));
+ SAFE(write_string(ci->access[j].nc->display, f));
+ SAFE(write_int32(ci->access[j].last_seen, f));
+ }
+ }
+ SAFE(write_int16(ci->akickcount, f));
+ for (j = 0; j < ci->akickcount; j++) {
+ SAFE(write_int16(ci->akick[j].flags, f));
+ if (ci->akick[j].flags & 0x0001) {
+ if (ci->akick[j].flags & 0x0002)
+ SAFE(write_string(ci->akick[j].u.nc->display, f));
+ else
+ SAFE(write_string(ci->akick[j].u.mask, f));
+ SAFE(write_string(ci->akick[j].reason, f));
+ SAFE(write_string(ci->akick[j].creator, f));
+ SAFE(write_int32(ci->akick[j].addtime, f));
+ }
+ }
+
+ SAFE(write_int32(ci->mlock_on, f));
+ SAFE(write_int32(ci->mlock_off, f));
+ SAFE(write_int32(ci->mlock_limit, f));
+ SAFE(write_string(ci->mlock_key, f));
+ SAFE(write_string(ci->mlock_flood, f));
+ SAFE(write_string(ci->mlock_redirect, f));
+ SAFE(write_int16(ci->memos.memocount, f));
+ SAFE(write_int16(ci->memos.memomax, f));
+ memos = ci->memos.memos;
+ for (j = 0; j < ci->memos.memocount; j++, memos++) {
+ SAFE(write_int32(memos->number, f));
+ SAFE(write_int16(memos->flags, f));
+ SAFE(write_int32(memos->time, f));
+ SAFE(write_buffer(memos->sender, f));
+ SAFE(write_string(memos->text, f));
+ }
+ SAFE(write_string(ci->entry_message, f));
+ if (ci->bi)
+ SAFE(write_string(ci->bi, f));
+ else
+ SAFE(write_string(NULL, f));
+ SAFE(write_int32(ci->botflags, f));
+ tmp16 = 8;
+ SAFE(write_int16(tmp16, f));
+ for (j = 0; j < 8; j++)
+ SAFE(write_int16(ci->ttb[j], f));
+ SAFE(write_int16(ci->capsmin, f));
+ SAFE(write_int16(ci->capspercent, f));
+ SAFE(write_int16(ci->floodlines, f));
+ SAFE(write_int16(ci->floodsecs, f));
+ SAFE(write_int16(ci->repeattimes, f));
+
+ SAFE(write_int16(ci->bwcount, f));
+ for (j = 0; j < ci->bwcount; j++) {
+ SAFE(write_int16(ci->badwords[j].in_use, f));
+ if (ci->badwords[j].in_use) {
+ SAFE(write_string(ci->badwords[j].word, f));
+ SAFE(write_int16(ci->badwords[j].type, f));
+ }
+ }
+ countw++;
+ } /* for (chanlists[i]) */
+ SAFE(write_int8(0, f));
+ } /* for (i) */
+ close_db(f);
+ printf("%ld channels read, %ld channels written. New database saved as %s.\n", countr, countw, CHAN_DB_ANOPE);
+ }
+ }
+
+ printf("\n\nConverting is now done.\n");
+ return 0;
+} /* End of main() */
+
+/* Open a database file for reading and check for the version */
+dbFILE *open_db_read(const char *service, const char *filename, int version)
+{
+ dbFILE *f;
+ FILE *fp;
+ int myversion;
+
+ f = calloc(sizeof(*f), 1);
+ if (!f) {
+ printf("Can't allocate memory for %s database %s.\n", service, filename);
+ exit(0);
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+ f->mode = 'r';
+ fp = fopen(f->filename, "rb");
+ if (!fp) {
+ printf("Can't read %s database %s.\n", service, f->filename);
+ free(f);
+ return NULL;
+ }
+ f->fp = fp;
+ myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
+ if (feof(fp)) {
+ printf("Error reading version number on %s: End of file detected.\n", f->filename);
+ exit(0);
+ } else if (myversion < version) {
+ printf("Unsuported database version (%d) on %s.\n", myversion, f->filename);
+ exit(0);
+ }
+ return f;
+}
+
+/* Open a database file for reading and check for the version */
+dbFILE *open_db_write(const char *service, const char *filename, int version)
+{
+ dbFILE *f;
+ int fd;
+
+ f = calloc(sizeof(*f), 1);
+ if (!f) {
+ printf("Can't allocate memory for %s database %s.\n", service, filename);
+ exit(0);
+ }
+ strscpy(f->filename, filename, sizeof(f->filename));
+ filename = f->filename;
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ f->mode = 'w';
+#ifndef _WIN32
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+#else
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL | _O_BINARY, 0666);
+#endif
+ f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */
+ if (!f->fp || !write_file_version(f, version)) {
+ printf("Can't write to %s database %s.\n", service, filename);
+ if (f->fp) {
+ fclose(f->fp);
+#ifndef _WIN32
+ unlink(filename);
+#else
+ DeleteFile(filename);
+#endif
+ }
+ free(f);
+ return NULL;
+ }
+ return f;
+}
+
+/* Close it */
+void close_db(dbFILE * f)
+{
+ fclose(f->fp);
+ free(f);
+}
+
+int read_int16(int16 * ret, dbFILE * f)
+{
+ int c1, c2;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF)
+ return -1;
+ *ret = c1 << 8 | c2;
+ return 0;
+}
+
+int read_uint16(uint16 * ret, dbFILE * f)
+{
+ int c1, c2;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF)
+ return -1;
+ *ret = c1 << 8 | c2;
+ return 0;
+}
+
+int write_int16(uint16 val, dbFILE * f)
+{
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF
+ || fputc(val & 0xFF, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+
+int read_int32(int32 * ret, dbFILE * f)
+{
+ int c1, c2, c3, c4;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ c3 = fgetc(f->fp);
+ c4 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
+ return -1;
+ *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ return 0;
+}
+
+int read_uint32(uint32 * ret, dbFILE * f)
+{
+ int c1, c2, c3, c4;
+
+ c1 = fgetc(f->fp);
+ c2 = fgetc(f->fp);
+ c3 = fgetc(f->fp);
+ c4 = fgetc(f->fp);
+ if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
+ return -1;
+ *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
+ return 0;
+}
+
+int write_int32(uint32 val, dbFILE * f)
+{
+ if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
+ return -1;
+ if (fputc((val) & 0xFF, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+
+int read_ptr(void **ret, dbFILE * f)
+{
+ int c;
+
+ c = fgetc(f->fp);
+ if (c == EOF)
+ return -1;
+ *ret = (c ? (void *) 1 : (void *) 0);
+ return 0;
+}
+
+int write_ptr(const void *ptr, dbFILE * f)
+{
+ if (fputc(ptr ? 1 : 0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+
+int read_string(char **ret, dbFILE * f)
+{
+ char *s;
+ uint16 len;
+
+ if (read_uint16(&len, f) < 0)
+ return -1;
+ if (len == 0) {
+ *ret = NULL;
+ return 0;
+ }
+ s = calloc(len, 1);
+ if (len != fread(s, 1, len, f->fp)) {
+ free(s);
+ return -1;
+ }
+ *ret = s;
+ return 0;
+}
+
+int write_string(const char *s, dbFILE * f)
+{
+ uint32 len;
+
+ if (!s)
+ return write_int16(0, f);
+ len = strlen(s);
+ if (len > 65534)
+ len = 65534;
+ if (write_int16((uint16) (len + 1), f) < 0)
+ return -1;
+ if (len > 0 && fwrite(s, 1, len, f->fp) != len)
+ return -1;
+ if (fputc(0, f->fp) == EOF)
+ return -1;
+ return 0;
+}
+
+NickCore *findcore(const char *nick, int unused)
+{
+ NickCore *nc;
+
+ for (nc = nclists[HASH(nick)]; nc; nc = nc->next) {
+ if (!mystricmp(nc->display, nick))
+ if ((nc->unused && unused) || (!nc->unused && !unused))
+ return nc;
+ }
+
+ return NULL;
+}
+
+int write_file_version(dbFILE * f, uint32 version)
+{
+ FILE *fp = f->fp;
+ if (fputc(version >> 24 & 0xFF, fp) < 0 ||
+ fputc(version >> 16 & 0xFF, fp) < 0 ||
+ fputc(version >> 8 & 0xFF, fp) < 0 ||
+ fputc(version & 0xFF, fp) < 0) {
+ printf("Error writing version number on %s.\n", f->filename);
+ exit(0);
+ }
+ return 1;
+}
+
+/* strscpy: Copy at most len-1 characters from a string to a buffer, and
+ * add a null terminator after the last character copied.
+ */
+
+char *strscpy(char *d, const char *s, size_t len)
+{
+ char *d_orig = d;
+
+ if (!len)
+ return d;
+ while (--len && (*d++ = *s++));
+ *d = '\0';
+ return d_orig;
+}
+
+int mystricmp(const char *s1, const char *s2)
+{
+ register int c;
+
+ while ((c = tolower(*s1)) == tolower(*s2)) {
+ if (c == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ if (c < tolower(*s2))
+ return -1;
+ return 1;
+}
+
+ChannelInfo *cs_findchan(const char *chan)
+{
+ ChannelInfo *ci;
+ for (ci = chanlists[tolower(chan[1])]; ci; ci = ci->next) {
+ if (!mystricmp(ci->name, chan))
+ return ci;
+ }
+ return NULL;
+}
+
+void alpha_insert_chan(ChannelInfo * ci)
+{
+ ChannelInfo *ptr, *prev;
+ char *chan = ci->name;
+
+ for (prev = NULL, ptr = chanlists[tolower(chan[1])];
+ ptr != NULL && mystricmp(ptr->name, chan) < 0;
+ prev = ptr, ptr = ptr->next);
+ ci->prev = prev;
+ ci->next = ptr;
+ if (!prev)
+ chanlists[tolower(chan[1])] = ci;
+ else
+ prev->next = ci;
+ if (ptr)
+ ptr->prev = ci;
+}
+
diff --git a/src/tools/smtp.h b/src/tools/smtp.h
new file mode 100644
index 000000000..7a30cc0fe
--- /dev/null
+++ b/src/tools/smtp.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * (C) 2003-2008 Anope Team
+ * Contact us at info@anope.org
+ *
+ * Please read COPYING and README for furhter details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ *
+ *
+ */
+
+#ifndef SMTP_H
+#define SMTP_H
+
+/*************************************************************************/
+
+/* Some Linux boxes (or maybe glibc includes) require this for the
+ * prototype of strsignal(). */
+#define _GNU_SOURCE
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Windows does not have:
+ * unistd.h, grp.h,
+ * netdb.h, netinet/in.h,
+ * sys/socket.h, sys/time.h
+ * Windows requires:
+ * winsock.h
+ * -- codemastr
+ */
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef _WIN32
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#else
+#include <winsock.h>
+#include <windows.h>
+#endif
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#ifdef _AIX
+extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, size_t);
+# if 0 /* These break on some AIX boxes (4.3.1 reported). */
+extern int socket(int, int, int);
+extern int connect(int, struct sockaddr *, int);
+# endif
+#endif /* _AIX */
+
+/* Some SUN fixs */
+#ifdef __sun
+/* Solaris specific code, types that do not exist in Solaris'
+ * * sys/types.h
+ * **/
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+#endif
+
+
+#ifdef _WIN32
+#define PATH_MAX MAX_PATH
+#define snprintf _snprintf
+#endif
+
+
+/*************************************************************************/
+
+#ifdef _WIN32
+#include <winsock.h>
+typedef SOCKET ano_socket_t;
+#define ano_sockclose(fd) closesocket(fd)
+#define ano_sockread(fd, buf, len) recv(fd, buf, len, 0)
+#define ano_sockwrite(fd, buf, len) send(fd, buf, len, 0)
+#else
+typedef int ano_socket_t;
+#define ano_sockclose(fd) close(fd)
+#define ano_sockread(fd, buf, len) read(fd, buf, len)
+#define ano_sockwrite(fd, buf, len) write(fd, buf, len)
+#define SOCKET_ERROR -1
+#endif
+
+
+/* Data structures */
+struct smtp_header {
+ char *header;
+ struct smtp_header *next;
+};
+
+struct smtp_body_line {
+ char *line;
+ struct smtp_body_line *next;
+};
+
+struct smtp_message {
+ struct smtp_header *smtp_headers, *smtp_headers_tail;
+ struct smtp_body_line *smtp_body, *smtp_body_tail;
+ char *from;
+ char *to;
+ ano_socket_t sock;
+};
+
+struct smtp_message mail;
+
+/* set this to 1 if you want to get a log otherwise it runs silent */
+int smtp_debug = 0;
+
+#endif /* SMTP_H */
diff --git a/src/users.c b/src/users.c
new file mode 100644
index 000000000..44faaf9d5
--- /dev/null
+++ b/src/users.c
@@ -0,0 +1,1125 @@
+/* Routines to maintain a list of online users.
+ *
+ * (C) 2003-2008 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.
+ *
+ * $Id$
+ *
+ */
+
+#include "services.h"
+
+#define HASH(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31))
+User *userlist[1024];
+
+#define HASH2(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31))
+Uid *uidlist[1024];
+
+int32 usercnt = 0, opcnt = 0;
+uint32 maxusercnt = 0;
+time_t maxusertime;
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Allocate a new User structure, fill in basic values, link it to the
+ * overall list, and return it. Always successful.
+ */
+
+static User *new_user(const char *nick)
+{
+ User *user, **list;
+
+ user = scalloc(sizeof(User), 1);
+ if (!nick)
+ nick = "";
+ strscpy(user->nick, nick, NICKMAX);
+ list = &userlist[HASH(user->nick)];
+ user->next = *list;
+ if (*list)
+ (*list)->prev = user;
+ *list = user;
+ user->na = findnick(nick);
+ if (user->na)
+ user->na->u = user;
+ usercnt++;
+ if (usercnt > maxusercnt) {
+ maxusercnt = usercnt;
+ maxusertime = time(NULL);
+ if (LogMaxUsers)
+ alog("user: New maximum user count: %d", maxusercnt);
+ }
+ user->isSuperAdmin = 0; /* always set SuperAdmin to 0 for new users */
+ user->nickTrack = NULL; /* ensure no default tracking nick */
+ return user;
+}
+
+/*************************************************************************/
+
+/* Change the nickname of a user, and move pointers as necessary. */
+
+static void change_user_nick(User * user, const char *nick)
+{
+ User **list;
+ int is_same;
+
+ /* Sanity check to make sure we don't segfault */
+ if (!user || !nick || !*nick) {
+ return;
+ }
+
+ is_same = (!stricmp(user->nick, nick) ? 1 : 0);
+
+ if (user->prev)
+ user->prev->next = user->next;
+ else
+ userlist[HASH(user->nick)] = user->next;
+ if (user->next)
+ user->next->prev = user->prev;
+ user->nick[1] = 0; /* paranoia for zero-length nicks */
+ strscpy(user->nick, nick, NICKMAX);
+ list = &userlist[HASH(user->nick)];
+ user->next = *list;
+ user->prev = NULL;
+ if (*list)
+ (*list)->prev = user;
+ *list = user;
+
+ /* Only if old and new nick aren't the same; no need to waste time */
+ if (!is_same) {
+ if (user->na)
+ user->na->u = NULL;
+ user->na = findnick(nick);
+ if (user->na)
+ user->na->u = user;
+ }
+}
+
+/*************************************************************************/
+
+void update_host(User * user)
+{
+ if (user->na && (nick_identified(user)
+ || (!(user->na->nc->flags & NI_SECURE)
+ && nick_recognized(user)))) {
+ if (user->na->last_usermask)
+ free(user->na->last_usermask);
+
+ user->na->last_usermask =
+ smalloc(strlen(common_get_vident(user)) +
+ strlen(common_get_vhost(user)) + 2);
+ sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
+ common_get_vhost(user));
+ }
+
+ if (debug)
+ alog("debug: %s changes its host to %s", user->nick,
+ common_get_vhost(user));
+}
+
+
+/*************************************************************************/
+
+/* Change the (virtual) hostname of a user. */
+
+void change_user_host(User * user, const char *host)
+{
+ if (user->vhost)
+ free(user->vhost);
+ user->vhost = sstrdup(host);
+
+ if (debug)
+ alog("debug: %s changes its vhost to %s", user->nick, host);
+
+
+
+ update_host(user);
+}
+
+/*************************************************************************/
+
+/* Change the realname of a user. */
+
+void change_user_realname(User * user, const char *realname)
+{
+ if (user->realname)
+ free(user->realname);
+ user->realname = sstrdup(realname);
+
+ if (user->na && (nick_identified(user)
+ || (!(user->na->nc->flags & NI_SECURE)
+ && nick_recognized(user)))) {
+ if (user->na->last_realname)
+ free(user->na->last_realname);
+ user->na->last_realname = sstrdup(realname);
+ }
+
+ if (debug)
+ alog("debug: %s changes its realname to %s", user->nick, realname);
+}
+
+
+/*************************************************************************/
+
+/* Change the username of a user. */
+
+void change_user_username(User * user, const char *username)
+{
+ if (user->vident)
+ free(user->vident);
+ user->vident = sstrdup(username);
+ if (user->na && (nick_identified(user)
+ || (!(user->na->nc->flags & NI_SECURE)
+ && nick_recognized(user)))) {
+ if (user->na->last_usermask)
+ free(user->na->last_usermask);
+
+ user->na->last_usermask =
+ smalloc(strlen(common_get_vident(user)) +
+ strlen(common_get_vhost(user)) + 2);
+ sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
+ common_get_vhost(user));
+ }
+ if (debug)
+ alog("debug: %s changes its username to %s", user->nick, username);
+}
+
+/*************************************************************************/
+
+/* Remove and free a User structure. */
+
+void delete_user(User * user)
+{
+ struct u_chanlist *c, *c2;
+ struct u_chaninfolist *ci, *ci2;
+ char *realname;
+
+ if (LogUsers) {
+ realname = normalizeBuffer(user->realname);
+ if (ircd->vhost) {
+ alog("LOGUSERS: %s (%s@%s => %s) (%s) left the network (%s).",
+ user->nick, user->username, user->host,
+ (user->vhost ? user->vhost : "(none)"),
+ realname, user->server->name);
+ } else {
+ alog("LOGUSERS: %s (%s@%s) (%s) left the network (%s).",
+ user->nick, user->username, user->host,
+ realname, user->server->name);
+ }
+ free(realname);
+ }
+ send_event(EVENT_USER_LOGOFF, 1, user->nick);
+
+ if (debug >= 2)
+ alog("debug: delete_user() called");
+ usercnt--;
+ if (is_oper(user))
+ opcnt--;
+ if (debug >= 2)
+ alog("debug: delete_user(): free user data");
+ free(user->username);
+ free(user->host);
+ if (user->vhost)
+ free(user->vhost);
+ if (user->vident)
+ free(user->vident);
+ if (user->uid) {
+ free(user->uid);
+ }
+ Anope_Free(user->realname);
+ Anope_Free(user->hostip);
+ if (debug >= 2) {
+ alog("debug: delete_user(): remove from channels");
+ }
+ c = user->chans;
+ while (c) {
+ c2 = c->next;
+ chan_deluser(user, c->chan);
+ free(c);
+ c = c2;
+ }
+ /* This called only here now */
+ cancel_user(user);
+ if (user->na)
+ user->na->u = NULL;
+ if (debug >= 2)
+ alog("debug: delete_user(): free founder data");
+ ci = user->founder_chans;
+ while (ci) {
+ ci2 = ci->next;
+ free(ci);
+ ci = ci2;
+ }
+
+ if (user->nickTrack)
+ free(user->nickTrack);
+
+ moduleCleanStruct(&user->moduleData);
+
+ if (debug >= 2)
+ alog("debug: delete_user(): delete from list");
+ if (user->prev)
+ user->prev->next = user->next;
+ else
+ userlist[HASH(user->nick)] = user->next;
+ if (user->next)
+ user->next->prev = user->prev;
+ if (debug >= 2)
+ alog("debug: delete_user(): free user structure");
+ free(user);
+ if (debug >= 2)
+ alog("debug: delete_user() done");
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Return statistics. Pointers are assumed to be valid. */
+
+void get_user_stats(long *nusers, long *memuse)
+{
+ long count = 0, mem = 0;
+ int i;
+ User *user;
+ struct u_chanlist *uc;
+ struct u_chaninfolist *uci;
+
+ for (i = 0; i < 1024; i++) {
+ for (user = userlist[i]; user; user = user->next) {
+ count++;
+ mem += sizeof(*user);
+ if (user->username)
+ mem += strlen(user->username) + 1;
+ if (user->host)
+ mem += strlen(user->host) + 1;
+ if (ircd->vhost) {
+ if (user->vhost)
+ mem += strlen(user->vhost) + 1;
+ }
+ if (user->realname)
+ mem += strlen(user->realname) + 1;
+ if (user->server->name)
+ mem += strlen(user->server->name) + 1;
+ for (uc = user->chans; uc; uc = uc->next)
+ mem += sizeof(*uc);
+ for (uci = user->founder_chans; uci; uci = uci->next)
+ mem += sizeof(*uci);
+ }
+ }
+ *nusers = count;
+ *memuse = mem;
+}
+
+/*************************************************************************/
+
+/* Find a user by nick. Return NULL if user could not be found. */
+
+User *finduser(const char *nick)
+{
+ User *user;
+
+ if (!nick || !*nick) {
+ if (debug) {
+ alog("debug: finduser() called with NULL values");
+ }
+ return NULL;
+ }
+
+ if (debug >= 3)
+ alog("debug: finduser(%p)", nick);
+ user = userlist[HASH(nick)];
+ while (user && stricmp(user->nick, nick) != 0)
+ user = user->next;
+ if (debug >= 3)
+ alog("debug: finduser(%s) -> 0x%p", nick, (void *) user);
+ return user;
+}
+
+
+/*************************************************************************/
+
+/* Iterate over all users in the user list. Return NULL at end of list. */
+
+static User *current;
+static int next_index;
+
+User *firstuser(void)
+{
+ next_index = 0;
+ current = NULL;
+ while (next_index < 1024 && current == NULL)
+ current = userlist[next_index++];
+ if (debug)
+ alog("debug: firstuser() returning %s",
+ current ? current->nick : "NULL (end of list)");
+ return current;
+}
+
+User *nextuser(void)
+{
+ if (current)
+ current = current->next;
+ if (!current && next_index < 1024) {
+ while (next_index < 1024 && current == NULL)
+ current = userlist[next_index++];
+ }
+ if (debug)
+ alog("debug: nextuser() returning %s",
+ current ? current->nick : "NULL (end of list)");
+ return current;
+}
+
+User *find_byuid(const char *uid)
+{
+ User *u, *next;
+
+ if (!uid) {
+ if (debug)
+ alog("debug: find_byuid() called with NULL-value");
+ return NULL;
+ }
+
+ u = first_uid();
+ while (u) {
+ next = next_uid();
+ if (u->uid) {
+ if (!stricmp(uid, u->uid)) {
+ return u;
+ }
+ }
+ u = next;
+ }
+ return NULL;
+}
+
+static User *current_uid;
+static int next_index_uid;
+
+User *first_uid(void)
+{
+ next_index_uid = 0;
+ current_uid = NULL;
+ while (next_index_uid < 1024 && current_uid == NULL) {
+ current_uid = userlist[next_index_uid++];
+ }
+ if (debug >= 2) {
+ alog("debug: first_uid() returning %s %s",
+ current_uid ? current_uid->nick : "NULL (end of list)",
+ current_uid ? current_uid->uid : "");
+ }
+ return current_uid;
+}
+
+User *next_uid(void)
+{
+ if (current_uid)
+ current_uid = current_uid->next;
+ if (!current_uid && next_index_uid < 1024) {
+ while (next_index_uid < 1024 && current_uid == NULL)
+ current_uid = userlist[next_index_uid++];
+ }
+ if (debug >= 2) {
+ alog("debug: next_uid() returning %s %s",
+ current_uid ? current_uid->nick : "NULL (end of list)",
+ current_uid ? current_uid->uid : "");
+ }
+ return current_uid;
+}
+
+Uid *new_uid(const char *nick, char *uid)
+{
+ Uid *u, **list;
+
+ u = scalloc(sizeof(Uid), 1);
+ if (!nick || !uid) {
+ return NULL;
+ }
+ strscpy(u->nick, nick, NICKMAX);
+ list = &uidlist[HASH2(u->nick)];
+ u->next = *list;
+ if (*list)
+ (*list)->prev = u;
+ *list = u;
+ u->uid = sstrdup(uid);
+ return u;
+}
+
+Uid *find_uid(const char *nick)
+{
+ Uid *u;
+ int i;
+
+ for (i = 0; i < 1024; i++) {
+ for (u = uidlist[i]; u; u = u->next) {
+ if (!stricmp(nick, u->nick)) {
+ return u;
+ }
+ }
+ }
+ return NULL;
+}
+
+Uid *find_nickuid(const char *uid)
+{
+ Uid *u;
+ int i;
+
+ for (i = 0; i < 1024; i++) {
+ for (u = uidlist[i]; u; u = u->next) {
+ if (!stricmp(uid, u->uid)) {
+ return u;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Handle a server NICK command. */
+
+User *do_nick(const char *source, char *nick, char *username, char *host,
+ char *server, char *realname, time_t ts, uint32 svid,
+ uint32 ip, char *vhost, char *uid)
+{
+ User *user = NULL;
+
+ char *tmp = NULL;
+ NickAlias *old_na; /* Old nick rec */
+ int nc_changed = 1; /* Did nick core change? */
+ int status = 0; /* Status to apply */
+ char mask[USERMAX + HOSTMAX + 2];
+ char *logrealname;
+
+ if (!*source) {
+ char ipbuf[16];
+ struct in_addr addr;
+
+ if (ircd->nickvhost) {
+ if (vhost) {
+ if (!strcmp(vhost, "*")) {
+ vhost = NULL;
+ if (debug)
+ alog("debug: new user�with no vhost in NICK command: %s", nick);
+ }
+ }
+ }
+
+ /* This is a new user; create a User structure for it. */
+ if (debug)
+ alog("debug: new user: %s", nick);
+
+ if (ircd->nickip) {
+ addr.s_addr = htonl(ip);
+ ntoa(addr, ipbuf, sizeof(ipbuf));
+ }
+
+
+ if (LogUsers) {
+ /**
+ * Ugly swap routine for Flop's bug :)
+ **/
+ if (realname) {
+ tmp = strchr(realname, '%');
+ while (tmp) {
+ *tmp = '-';
+ tmp = strchr(realname, '%');
+ }
+ }
+ logrealname = normalizeBuffer(realname);
+
+ /**
+ * End of ugly swap
+ **/
+
+ if (ircd->nickvhost) {
+ if (ircd->nickip) {
+ alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, ipbuf, server);
+ } else {
+ alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, server);
+ }
+ } else {
+ if (ircd->nickip) {
+ alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, logrealname, ipbuf, server);
+ } else {
+ alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, logrealname, server);
+ }
+ }
+ Anope_Free(logrealname);
+ }
+
+ /* We used to ignore the ~ which a lot of ircd's use to indicate no
+ * identd response. That caused channel bans to break, so now we
+ * just take what the server gives us. People are still encouraged
+ * to read the RFCs and stop doing anything to usernames depending
+ * on the result of an identd lookup.
+ */
+
+ /* First check for AKILLs. */
+ /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are
+ * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/
+ * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice
+ * comes in from the ircd.
+ **/
+ if (check_akill(nick, username, host, vhost, ipbuf)) {
+/* return NULL; */
+ }
+
+/**
+ * DefCon AKILL system, if we want to akill all connecting user's here's where to do it
+ * then force check_akill again on them...
+ **/
+ /* don't akill on netmerges -Certus */
+ /* don't akill clients introduced by ulines. -Viper */
+ if (is_sync(findserver(servlist, server))
+ && checkDefCon(DEFCON_AKILL_NEW_CLIENTS) && !is_ulined(server)) {
+ strncpy(mask, "*@", 3);
+ strncat(mask, host, HOSTMAX);
+ alog("DEFCON: adding akill for %s", mask);
+ add_akill(NULL, mask, s_OperServ,
+ time(NULL) + dotime(DefConAKILL),
+ DefConAkillReason ? DefConAkillReason :
+ "DEFCON AKILL");
+ if (check_akill(nick, username, host, vhost, ipbuf)) {
+/* return NULL; */
+ }
+ }
+
+ /* SGLINE */
+ if (ircd->sgline) {
+ if (check_sgline(nick, realname))
+ return NULL;
+ }
+
+ /* SQLINE */
+ if (ircd->sqline) {
+ if (check_sqline(nick, 0))
+ return NULL;
+ }
+
+ /* SZLINE */
+ if (ircd->szline && ircd->nickip) {
+ if (check_szline(nick, ipbuf))
+ return NULL;
+ }
+ /* Now check for session limits */
+ if (LimitSessions && !is_ulined(server)
+ && !add_session(nick, host, ipbuf))
+ return NULL;
+
+ /* Allocate User structure and fill it in. */
+ user = new_user(nick);
+ user->username = sstrdup(username);
+ user->host = sstrdup(host);
+ user->server = findserver(servlist, server);
+ user->realname = sstrdup(realname);
+ user->timestamp = ts;
+ user->my_signon = time(NULL);
+ user->vhost = vhost ? sstrdup(vhost) : sstrdup(host);
+ if (uid) {
+ user->uid = sstrdup(uid); /* p10/ts6 stuff */
+ } else {
+ user->uid = NULL;
+ }
+ user->vident = sstrdup(username);
+ /* We now store the user's ip in the user_ struct,
+ * because we will use it in serveral places -- DrStein */
+ if (ircd->nickip) {
+ user->hostip = sstrdup(ipbuf);
+ } else {
+ user->hostip = NULL;
+ }
+
+ if (svid == 0) {
+ display_news(user, NEWS_LOGON);
+ display_news(user, NEWS_RANDOM);
+ }
+
+ if (svid == ts && user->na) {
+ /* Timestamp and svid match, and nick is registered; automagically identify the nick */
+ user->svid = svid;
+ user->na->status |= NS_IDENTIFIED;
+ check_memos(user);
+ nc_changed = 0;
+
+ /* Start nick tracking if available */
+ if (NSNickTracking)
+ nsStartNickTracking(user);
+
+ } else if (svid != 1) {
+ /* Resets the svid because it doesn't match */
+ user->svid = 1;
+
+ anope_cmd_svid_umode(user->nick, user->timestamp);
+
+ } else {
+ user->svid = 1;
+ }
+ send_event(EVENT_NEWNICK, 1, nick);
+
+ } else {
+ /* An old user changing nicks. */
+ if (UseTS6)
+ user = find_byuid(source);
+
+ if (!user)
+ user = finduser(source);
+
+ if (!user) {
+ alog("user: NICK from nonexistent nick %s", source);
+ return NULL;
+ }
+ user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */
+ if (debug)
+ alog("debug: %s changes nick to %s", source, nick);
+
+ if (LogUsers) {
+ logrealname = normalizeBuffer(user->realname);
+ if (ircd->vhost) {
+ alog("LOGUSERS: %s (%s@%s => %s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), logrealname, nick, user->server->name);
+ } else {
+ alog("LOGUSERS: %s (%s@%s) (%s) changed nick to %s (%s).",
+ user->nick, user->username, user->host, logrealname,
+ nick, user->server->name);
+ }
+ if (logrealname) {
+ free(logrealname);
+ }
+ }
+
+ user->timestamp = ts;
+
+ if (stricmp(nick, user->nick) == 0) {
+ /* No need to redo things */
+ change_user_nick(user, nick);
+ nc_changed = 0;
+ } else {
+ /* Update this only if nicks aren't the same */
+ user->my_signon = time(NULL);
+
+ old_na = user->na;
+ if (old_na) {
+ if (nick_recognized(user))
+ user->na->last_seen = time(NULL);
+ status = old_na->status & NS_TRANSGROUP;
+ cancel_user(user);
+ }
+
+ change_user_nick(user, nick);
+ send_event(EVENT_CHANGE_NICK, 1, nick);
+
+ if ((old_na ? old_na->nc : NULL) ==
+ (user->na ? user->na->nc : NULL))
+ nc_changed = 0;
+
+ if (!nc_changed && (user->na))
+ user->na->status |= status;
+ else {
+ anope_cmd_nc_change(user);
+ }
+ }
+
+ if (ircd->sqline) {
+ if (!is_oper(user) && check_sqline(user->nick, 1))
+ return NULL;
+ }
+
+ } /* if (!*source) */
+
+ /* Check for nick tracking to bypass identification */
+ if (NSNickTracking && nsCheckNickTracking(user)) {
+ user->na->status |= NS_IDENTIFIED;
+ nc_changed = 0;
+ }
+
+ if (nc_changed || !nick_recognized(user)) {
+ if (validate_user(user))
+ check_memos(user);
+
+ } else {
+ if (nick_identified(user)) {
+ char tsbuf[16];
+ user->na->last_seen = time(NULL);
+
+ if (user->na->last_usermask)
+ free(user->na->last_usermask);
+ user->na->last_usermask =
+ smalloc(strlen(common_get_vident(user)) +
+ strlen(common_get_vhost(user)) + 2);
+ sprintf(user->na->last_usermask, "%s@%s",
+ common_get_vident(user), common_get_vhost(user));
+
+ snprintf(tsbuf, sizeof(tsbuf), "%lu",
+ (unsigned long int) user->timestamp);
+ anope_cmd_svid_umode2(user, tsbuf);
+
+ alog("%s: %s!%s@%s automatically identified for nick %s",
+ s_NickServ, user->nick, user->username,
+ user->host, user->nick);
+ }
+ }
+
+ /* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */
+ if (ircd->check_nick_id) {
+ if (nick_identified(user)) {
+ char tsbuf[16];
+ snprintf(tsbuf, sizeof(tsbuf), "%lu",
+ (unsigned long int) user->timestamp);
+ anope_cmd_svid_umode3(user, tsbuf);
+ }
+ }
+
+ return user;
+}
+
+/*************************************************************************/
+
+/* Handle a MODE command for a user.
+ * av[0] = nick to change mode for
+ * av[1] = modes
+ */
+
+void do_umode(const char *source, int ac, char **av)
+{
+ User *user;
+
+ user = finduser(av[0]);
+ if (!user) {
+ alog("user: MODE %s for nonexistent nick %s: %s", av[1], av[0],
+ merge_args(ac, av));
+ return;
+ }
+
+ anope_set_umode(user, ac - 1, &av[1]);
+}
+
+/* Handle a UMODE2 command for a user.
+ * av[0] = modes
+ */
+
+void do_umode2(const char *source, int ac, char **av)
+{
+ User *user;
+
+ user = finduser(source);
+ if (!user) {
+ alog("user: MODE %s for nonexistent nick %s: %s", av[0], source,
+ merge_args(ac, av));
+ return;
+ }
+
+ anope_set_umode(user, ac, &av[0]);
+}
+
+/*************************************************************************/
+
+/* Handle a QUIT command.
+ * av[0] = reason
+ */
+
+void do_quit(const char *source, int ac, char **av)
+{
+ User *user;
+ NickAlias *na;
+
+ user = finduser(source);
+ if (!user) {
+ alog("user: QUIT from nonexistent user %s: %s", source,
+ merge_args(ac, av));
+ return;
+ }
+ if (debug) {
+ alog("debug: %s quits", source);
+ }
+ if ((na = user->na) && (!(na->status & NS_VERBOTEN))
+ && (!(na->nc->flags & NI_SUSPENDED))
+ && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
+ na->last_seen = time(NULL);
+ if (na->last_quit)
+ free(na->last_quit);
+ na->last_quit = *av[0] ? sstrdup(av[0]) : NULL;
+ }
+ if (LimitSessions && !is_ulined(user->server->name)) {
+ del_session(user->host);
+ }
+ delete_user(user);
+}
+
+/*************************************************************************/
+
+/* Handle a KILL command.
+ * av[0] = nick being killed
+ * av[1] = reason
+ */
+
+void do_kill(char *nick, char *msg)
+{
+ User *user;
+ NickAlias *na;
+
+ user = finduser(nick);
+ if (!user) {
+ if (debug) {
+ alog("debug: KILL of nonexistent nick: %s", nick);
+ }
+ return;
+ }
+ if (debug) {
+ alog("debug: %s killed", nick);
+ }
+ if ((na = user->na) && (!(na->status & NS_VERBOTEN))
+ && (!(na->nc->flags & NI_SUSPENDED))
+ && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
+ na->last_seen = time(NULL);
+ if (na->last_quit)
+ free(na->last_quit);
+ na->last_quit = *msg ? sstrdup(msg) : NULL;
+
+ }
+ if (LimitSessions && !is_ulined(user->server->name)) {
+ del_session(user->host);
+ }
+ delete_user(user);
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Is the given user protected from kicks and negative mode changes? */
+
+int is_protected(User * user)
+{
+ if (ircd->protectedumode) {
+ return (user->mode & ircd->protectedumode);
+ } else {
+ return 0;
+ }
+}
+
+/*************************************************************************/
+
+/* Is the given nick an oper? */
+
+int is_oper(User * user)
+{
+ if (user) {
+ return (user->mode & anope_get_oper_mode());
+ } else {
+ return 0;
+ }
+}
+
+/*************************************************************************/
+/*************************************************************************/
+
+/* Is the given user ban-excepted? */
+int is_excepted(ChannelInfo * ci, User * user)
+{
+ if (!ci->c || !ircd->except)
+ return 0;
+
+ if (elist_match_user(ci->c->excepts, user))
+ return 1;
+
+ return 0;
+}
+
+/*************************************************************************/
+
+/* Is the given MASK ban-excepted? */
+int is_excepted_mask(ChannelInfo * ci, char *mask)
+{
+ if (!ci->c || !ircd->except)
+ return 0;
+
+ if (elist_match_mask(ci->c->excepts, mask, 0))
+ return 1;
+
+ return 0;
+}
+
+
+/*************************************************************************/
+
+/* Does the user's usermask match the given mask (either nick!user@host or
+ * just user@host)?
+ */
+
+int match_usermask(const char *mask, User * user)
+{
+ char *mask2;
+ char *nick, *username, *host;
+ int result;
+
+ if (!mask || !*mask) {
+ return 0;
+ }
+
+ mask2 = sstrdup(mask);
+
+ if (strchr(mask2, '!')) {
+ nick = strtok(mask2, "!");
+ username = strtok(NULL, "@");
+ } else {
+ nick = NULL;
+ username = strtok(mask2, "@");
+ }
+ host = strtok(NULL, "");
+ if (!username || !host) {
+ free(mask2);
+ return 0;
+ }
+
+ if (nick) {
+ result = match_wild_nocase(nick, user->nick)
+ && match_wild_nocase(username, user->username)
+ && (match_wild_nocase(host, user->host)
+ || match_wild_nocase(host, user->vhost));
+ } else {
+ result = match_wild_nocase(username, user->username)
+ && (match_wild_nocase(host, user->host)
+ || match_wild_nocase(host, user->vhost));
+ }
+
+ free(mask2);
+ return result;
+}
+
+
+/*************************************************************************/
+
+/* simlar to match_usermask, except here we pass the host as the IP */
+
+int match_userip(const char *mask, User * user, char *iphost)
+{
+ char *mask2;
+ char *nick, *username, *host;
+ int result;
+
+ if (!mask || !*mask) {
+ return 0;
+ }
+
+ mask2 = sstrdup(mask);
+
+ if (strchr(mask2, '!')) {
+ nick = strtok(mask2, "!");
+ username = strtok(NULL, "@");
+ } else {
+ nick = NULL;
+ username = strtok(mask2, "@");
+ }
+ host = strtok(NULL, "");
+ if (!username || !host) {
+ free(mask2);
+ return 0;
+ }
+
+ if (nick) {
+ result = match_wild_nocase(nick, user->nick)
+ && match_wild_nocase(username, user->username)
+ && (match_wild_nocase(host, iphost)
+ || match_wild_nocase(host, user->vhost));
+ } else {
+ result = match_wild_nocase(username, user->username)
+ && (match_wild_nocase(host, iphost)
+ || match_wild_nocase(host, user->vhost));
+ }
+
+ free(mask2);
+ return result;
+}
+
+/*************************************************************************/
+
+/* Split a usermask up into its constitutent parts. Returned strings are
+ * malloc()'d, and should be free()'d when done with. Returns "*" for
+ * missing parts.
+ */
+
+void split_usermask(const char *mask, char **nick, char **user,
+ char **host)
+{
+ char *mask2 = sstrdup(mask);
+
+ *nick = strtok(mask2, "!");
+ *user = strtok(NULL, "@");
+ *host = strtok(NULL, "");
+ /* Handle special case: mask == user@host */
+ if (*nick && !*user && strchr(*nick, '@')) {
+ *nick = NULL;
+ *user = strtok(mask2, "@");
+ *host = strtok(NULL, "");
+ }
+ if (!*nick)
+ *nick = "*";
+ if (!*user)
+ *user = "*";
+ if (!*host)
+ *host = "*";
+ *nick = sstrdup(*nick);
+ *user = sstrdup(*user);
+ *host = sstrdup(*host);
+ free(mask2);
+}
+
+/*************************************************************************/
+
+/* Given a user, return a mask that will most likely match any address the
+ * user will have from that location. For IP addresses, wildcards the
+ * appropriate subnet mask (e.g. 35.1.1.1 -> 35.*; 128.2.1.1 -> 128.2.*);
+ * for named addresses, wildcards the leftmost part of the name unless the
+ * name only contains two parts. If the username begins with a ~, delete
+ * it. The returned character string is malloc'd and should be free'd
+ * when done with.
+ */
+
+char *create_mask(User * u)
+{
+ char *mask, *s, *end;
+ int ulen = strlen(common_get_vident(u));
+
+ /* Get us a buffer the size of the username plus hostname. The result
+ * will never be longer than this (and will often be shorter), thus we
+ * can use strcpy() and sprintf() safely.
+ */
+ end = mask = smalloc(ulen + strlen(common_get_vhost(u)) + 3);
+ end += sprintf(end, "%s%s@",
+ (ulen <
+ (*(common_get_vident(u)) ==
+ '~' ? USERMAX + 1 : USERMAX) ? "*" : ""),
+ (*(common_get_vident(u)) ==
+ '~' ? common_get_vident(u) +
+ 1 : common_get_vident(u)));
+
+ if (strspn(common_get_vhost(u), "0123456789.") ==
+ strlen(common_get_vhost(u))
+ && (s = strchr(common_get_vhost(u), '.'))
+ && (s = strchr(s + 1, '.'))
+ && (s = strchr(s + 1, '.'))
+ && (!strchr(s + 1, '.'))) { /* IP addr */
+ s = sstrdup(common_get_vhost(u));
+ *strrchr(s, '.') = 0;
+
+ sprintf(end, "%s.*", s);
+ free(s);
+ } else {
+ if ((s = strchr(common_get_vhost(u), '.')) && strchr(s + 1, '.')) {
+ s = sstrdup(strchr(common_get_vhost(u), '.') - 1);
+ *s = '*';
+ strcpy(end, s);
+ free(s);
+ } else {
+ strcpy(end, common_get_vhost(u));
+ }
+ }
+ return mask;
+}
+
+/*************************************************************************/
diff --git a/src/win32.rc.template b/src/win32.rc.template
new file mode 100644
index 000000000..7f1ee7e32
--- /dev/null
+++ b/src/win32.rc.template
@@ -0,0 +1,90 @@
+///Microsoft Developer Studio generated resource script.
+//
+#include "../include/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "../include/resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VER_ANOPE VERSIONINFO
+ FILEVERSION VERSION_COMMA
+ PRODUCTVERSION VERSION_COMMA
+ FILEFLAGSMASK 0x17L10
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Anope Team"
+ VALUE "FileDescription", "Anope IRC Services"
+ VALUE "FileVersion", "VERSION_FULL"
+ VALUE "InternalName", "Anope"
+ VALUE "LegalCopyright", "Copyright (C) 2003-2008 Anope Team"
+ VALUE "OriginalFilename", "anope.exe"
+ VALUE "ProductName", "Anope"
+ VALUE "ProductVersion", "VERSION_DOTTED"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+ICON_APP ICON "anope-icon.ico"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED