summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-02-28 17:33:31 +0000
committerAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-02-28 17:33:31 +0000
commit3f80e1cad02735f692a5a300ee3b200a21f330aa (patch)
treed7bcd3c5d1cfd54c725f4c9a0eb7984632b6be67
parent393b5ab26e952f427f40a8ed6d10acfdf6ead96c (diff)
Added in support for live updating MySQL databases and the ability to execute commands to Anope through MySQL. Currently database support only applies to NickServ, ChanServ and BotServ but will be expanded soon.
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2798 5417fbe8-f217-4b02-8779-1006273d7864
-rw-r--r--Changes1
-rwxr-xr-xconfigure482
-rw-r--r--configure.in48
-rw-r--r--data/CMakeLists.txt2
-rw-r--r--data/example.conf7
-rw-r--r--data/tables.sql243
-rw-r--r--docs/MYSQL25
-rw-r--r--docs/NEWS3
-rw-r--r--include/account.h6
-rw-r--r--include/extern.h1
-rw-r--r--include/modules.h22
-rw-r--r--include/services.h15
-rw-r--r--include/users.h14
-rw-r--r--lang/en_us.l4
-rw-r--r--src/Makefile1
-rw-r--r--src/bin/CMakeLists.txt2
-rwxr-xr-xsrc/bin/mydbgen225
-rw-r--r--src/core/cs_access.c13
-rw-r--r--src/core/cs_xop.c10
-rw-r--r--src/core/db_plain.cpp20
-rw-r--r--src/core/ns_register.c3
-rw-r--r--src/misc.c12
-rw-r--r--src/modules/CMakeLists.txt1
-rw-r--r--src/modules/Makefile8
-rw-r--r--src/modules/mysql/db_mysql.h238
-rw-r--r--src/modules/mysql/db_mysql_execute.cpp162
-rw-r--r--src/modules/mysql/db_mysql_read.cpp515
-rw-r--r--src/modules/mysql/db_mysql_write.cpp740
-rw-r--r--src/nickcore.cpp6
29 files changed, 2411 insertions, 418 deletions
diff --git a/Changes b/Changes
index e1ddf12df..f3317a3db 100644
--- a/Changes
+++ b/Changes
@@ -5,6 +5,7 @@ A KB alias to chanserv ban command
F Unban command to accept an optional nick arg
F Small typo in services.conf
F Crash when users change their host that are identified to a group, but not a nick
+A Added in live updating SQL and the ability to execute commands through SQL
Anope Version 1.9.1
--------------------
diff --git a/configure b/configure
index 76559d6db..691d652ca 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.62.
+# Generated by GNU Autoconf 2.63.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -635,71 +635,68 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL
-PATH_SEPARATOR
-PACKAGE_NAME
-PACKAGE_TARNAME
-PACKAGE_VERSION
-PACKAGE_STRING
-PACKAGE_BUGREPORT
-exec_prefix
-prefix
-program_transform_name
-bindir
-sbindir
-libexecdir
-datarootdir
-datadir
-sysconfdir
-sharedstatedir
-localstatedir
-includedir
-oldincludedir
-docdir
-infodir
-htmldir
-dvidir
-pdfdir
-psdir
-libdir
-localedir
-mandir
-DEFS
-ECHO_C
-ECHO_N
-ECHO_T
-LIBS
-build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-CPPFLAGS
-ac_ct_CC
-EXEEXT
-OBJEXT
-RM
-CP
-TOUCH
-INSTALL
-MYSQLCONF
-ANOPELIBS
-CPP
-GREP
-EGREP
-SHARED
-MODULEFLAGS
-RUNGROUP
-INSTDIR
-MAKEBIN
+ac_subst_vars='LTLIBOBJS
LIBOBJS
-LTLIBOBJS'
+MAKEBIN
+INSTDIR
+RUNGROUP
+MODULEFLAGS
+SHARED
+EGREP
+GREP
+CPP
+ANOPELIBS
+INSTALL
+TOUCH
+CP
+RM
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
ac_subst_files=''
ac_user_opts='
enable_option_checking
-with_mysql
-with_mysqlconfig_path
with_rungroup
with_permissions
with_instdir
@@ -1138,9 +1135,9 @@ fi
if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
- fatal) { $as_echo "$as_me: error: Unrecognized options: $ac_unrecognized_opts" >&2
+ fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
{ (exit 1); exit 1; }; } ;;
- *) $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1193,7 +1190,7 @@ test "$silent" = yes && exec 6>/dev/null
ac_pwd=`pwd` && test -n "$ac_pwd" &&
ac_ls_di=`ls -di .` &&
ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- { $as_echo "$as_me: error: Working directory cannot be determined" >&2
+ { $as_echo "$as_me: error: working directory cannot be determined" >&2
{ (exit 1); exit 1; }; }
test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
{ $as_echo "$as_me: error: pwd does not report name of working directory" >&2
@@ -1334,8 +1331,6 @@ if test -n "$ac_init_help"; then
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --without-mysql Do not use MySQL or attempt to find it
- --with-mysqlconfig-path=PATH Complete path to the mysql_config executable
--with-rungroup=group Specify the rungroup for anope
--with-permissions=permissions Specify the default permissions for anope
--with-instdir=instdir Specify the default install dir for anope
@@ -1419,7 +1414,7 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
configure
-generated by GNU Autoconf 2.62
+generated by GNU Autoconf 2.63
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -1433,7 +1428,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was
-generated by GNU Autoconf 2.62. Invocation command line was
+generated by GNU Autoconf 2.63. Invocation command line was
$ $0 $@
@@ -1556,8 +1551,8 @@ _ASBOX
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
-$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -1760,6 +1755,8 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
fi
done
if $ac_cache_corrupted; then
+ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
{ { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
@@ -1891,12 +1888,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet. If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet. If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -2095,12 +2088,8 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet. If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet. If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -2110,11 +2099,13 @@ fi
fi
-test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
See \`config.log' for more details." >&5
$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
# Provide some information about the compiler.
$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
@@ -2244,11 +2235,13 @@ if test -z "$ac_file"; then
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
See \`config.log' for more details." >&5
$as_echo "$as_me: error: C compiler cannot create executables
See \`config.log' for more details." >&2;}
- { (exit 77); exit 77; }; }
+ { (exit 77); exit 77; }; }; }
fi
ac_exeext=$ac_cv_exeext
@@ -2276,13 +2269,15 @@ $as_echo "$ac_try_echo") >&5
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
- { { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details." >&5
$as_echo "$as_me: error: cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
fi
fi
fi
@@ -2325,11 +2320,13 @@ for ac_file in conftest.exe conftest conftest.*; do
esac
done
else
- { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details." >&5
$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
fi
rm -f conftest$ac_cv_exeext
@@ -2383,11 +2380,13 @@ else
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
See \`config.log' for more details." >&5
$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
@@ -3024,7 +3023,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_inet_ntoa" >&5
$as_echo "$ac_cv_lib_nsl_inet_ntoa" >&6; }
-if test $ac_cv_lib_nsl_inet_ntoa = yes; then
+if test "x$ac_cv_lib_nsl_inet_ntoa" = x""yes; then
ANOPELIBS="$ANOPELIBS-lnsl "
fi
@@ -3093,7 +3092,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5
$as_echo "$ac_cv_lib_socket_socket" >&6; }
-if test $ac_cv_lib_socket_socket = yes; then
+if test "x$ac_cv_lib_socket_socket" = x""yes; then
ANOPELIBS="$ANOPELIBS-lsocket "
fi
@@ -3162,7 +3161,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_query" >&5
$as_echo "$ac_cv_lib_resolv_res_query" >&6; }
-if test $ac_cv_lib_resolv_res_query = yes; then
+if test "x$ac_cv_lib_resolv_res_query" = x""yes; then
ANOPELIBS="$ANOPELIBS-lresolv "
fi
@@ -3231,7 +3230,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_revoke" >&5
$as_echo "$ac_cv_lib_bsd_revoke" >&6; }
-if test $ac_cv_lib_bsd_revoke = yes; then
+if test "x$ac_cv_lib_bsd_revoke" = x""yes; then
ANOPELIBS="$ANOPELIBS-lbsd "
fi
@@ -3317,163 +3316,16 @@ $as_echo "no" >&6; }
fi
-DIS_MYSQL=" MySQL: No"
-
-# Check whether --with-mysql was given.
-if test "${with_mysql+set}" = set; then
- withval=$with_mysql;
-else
-
-
-# Check whether --with-mysqlconfig-path was given.
-if test "${with_mysqlconfig_path+set}" = set; then
- withval=$with_mysqlconfig_path; mysql_config_path="$withval"
-else
- mysql_config_path=""
-fi
-
- MYSQLCONF=""
- if test "$mysql_config_path" != ""; then
- if test -x "$mysql_config_path"; then
- MYSQLCONF="$mysql_config_path"
- echo "checking for mysql_config... $MYSQLCONF" >&6
- fi
- fi
- if test "$MYSQLCONF" = ""; then
- # Extract the first word of "mysql_config", so it can be a program name with args.
-set dummy mysql_config; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_path_MYSQLCONF+set}" = set; then
- $as_echo_n "(cached) " >&6
-else
- case $MYSQLCONF in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_MYSQLCONF="$MYSQLCONF" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
- ac_cv_path_MYSQLCONF="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_path_MYSQLCONF" && ac_cv_path_MYSQLCONF=""""
- ;;
-esac
-fi
-MYSQLCONF=$ac_cv_path_MYSQLCONF
-if test -n "$MYSQLCONF"; then
- { $as_echo "$as_me:$LINENO: result: $MYSQLCONF" >&5
-$as_echo "$MYSQLCONF" >&6; }
-else
- { $as_echo "$as_me:$LINENO: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- fi
- if test "$MYSQLCONF" != ""; then
- hold_cflags="$CFLAGS"
- hold_ldflags="$LDFLAGS"
- if test "$MYSQL_CFLAGS" = ""; then
- MYSQL_CFLAGS="`$MYSQLCONF --cflags`"
- fi
- if test "$MYSQL_LDFLAGS" = ""; then
- MYSQL_LDFLAGS="`$MYSQLCONF --libs`"
- fi
- CFLAGS="$CFLAGS $MYSQL_CFLAGS"
- LDFLAGS="$LDFLAGS $MYSQL_LDFLAGS"
- echo $ECHO_N "checking if mysql_config produces valid values... $ECHO_C" >&6
- if test "$cross_compiling" = yes; then
- { { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot run test program while cross compiling
-See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
-else
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
-#include <mysql.h>
-
-int main()
-{
- MYSQL *mysql = mysql_init(0);
-
- return 0;
-}
-
-_ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
- { (case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_mysql_valid=yes
-else
- $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-ac_cv_mysql_valid=no
-fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-
-
- echo $ac_cv_mysql_valid >&6
- if test "$ac_cv_mysql_valid" = "yes"; then
- DIS_MYSQL=" MySQL: Yes"
- else
- CFLAGS="$hold_cflags"
- LDFLAGS="$hold_ldflags"
- fi
- fi
-
-fi
-
-
{ $as_echo "$as_me:$LINENO: checking whether this is a bit or little endian system" >&5
$as_echo_n "checking whether this is a bit or little endian system... " >&6; }
if test "$cross_compiling" = yes; then
- { { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling
See \`config.log' for more details." >&5
$as_echo "$as_me: error: cannot run test program while cross compiling
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -3765,11 +3617,13 @@ rm -f conftest.err conftest.$ac_ext
if $ac_preproc_ok; then
:
else
- { { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+ { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details." >&5
$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details." >&2;}
- { (exit 1); exit 1; }; }
+ { (exit 1); exit 1; }; }; }
fi
ac_ext=c
@@ -4152,8 +4006,9 @@ ac_res=`eval 'as_val=${'$as_ac_Header'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_Header'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_Header'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
@@ -4290,7 +4145,7 @@ fi
$as_echo "$ac_cv_header_sys_types_h" >&6; }
fi
-if test $ac_cv_header_sys_types_h = yes; then
+if test "x$ac_cv_header_sys_types_h" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAS_SYS_TYPES_H 1
@@ -4387,7 +4242,7 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
$as_echo "$ac_cv_func_dlopen" >&6; }
-if test $ac_cv_func_dlopen = yes; then
+if test "x$ac_cv_func_dlopen" = x""yes; then
:
else
{ $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
@@ -4455,7 +4310,7 @@ LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test $ac_cv_lib_dl_dlopen = yes; then
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then
ANOPELIBS="$ANOPELIBS -ldl"
@@ -4709,7 +4564,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint8_t" >&5
$as_echo "$ac_cv_type_uint8_t" >&6; }
-if test $ac_cv_type_uint8_t = yes; then
+if test "x$ac_cv_type_uint8_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_UINT8_T 1
@@ -4811,7 +4666,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_u_int8_t" >&5
$as_echo "$ac_cv_type_u_int8_t" >&6; }
-if test $ac_cv_type_u_int8_t = yes; then
+if test "x$ac_cv_type_u_int8_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_U_INT8_T 1
@@ -4913,7 +4768,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int16_t" >&5
$as_echo "$ac_cv_type_int16_t" >&6; }
-if test $ac_cv_type_int16_t = yes; then
+if test "x$ac_cv_type_int16_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_INT16_T 1
@@ -5015,7 +4870,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint16_t" >&5
$as_echo "$ac_cv_type_uint16_t" >&6; }
-if test $ac_cv_type_uint16_t = yes; then
+if test "x$ac_cv_type_uint16_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_UINT16_T 1
@@ -5117,7 +4972,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_u_int16_t" >&5
$as_echo "$ac_cv_type_u_int16_t" >&6; }
-if test $ac_cv_type_u_int16_t = yes; then
+if test "x$ac_cv_type_u_int16_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_U_INT16_T 1
@@ -5219,7 +5074,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_int32_t" >&5
$as_echo "$ac_cv_type_int32_t" >&6; }
-if test $ac_cv_type_int32_t = yes; then
+if test "x$ac_cv_type_int32_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_INT32_T 1
@@ -5321,7 +5176,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_uint32_t" >&5
$as_echo "$ac_cv_type_uint32_t" >&6; }
-if test $ac_cv_type_uint32_t = yes; then
+if test "x$ac_cv_type_uint32_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_UINT32_T 1
@@ -5423,7 +5278,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_u_int32_t" >&5
$as_echo "$ac_cv_type_u_int32_t" >&6; }
-if test $ac_cv_type_u_int32_t = yes; then
+if test "x$ac_cv_type_u_int32_t" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_U_INT32_T 1
@@ -5560,7 +5415,7 @@ fi
$as_echo "$ac_cv_header_strings_h" >&6; }
fi
-if test $ac_cv_header_strings_h = yes; then
+if test "x$ac_cv_header_strings_h" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_STRINGS_H 1
@@ -5696,7 +5551,7 @@ fi
$as_echo "$ac_cv_header_sys_select_h" >&6; }
fi
-if test $ac_cv_header_sys_select_h = yes; then
+if test "x$ac_cv_header_sys_select_h" = x""yes; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_SYS_SELECT_H 1
@@ -5797,8 +5652,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -5900,8 +5756,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6003,8 +5860,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6106,8 +5964,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6209,8 +6068,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6312,8 +6172,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6415,8 +6276,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6518,8 +6380,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6621,8 +6484,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6724,8 +6588,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6827,8 +6692,9 @@ ac_res=`eval 'as_val=${'$as_ac_var'}
$as_echo "$as_val"'`
{ $as_echo "$as_me:$LINENO: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
- $as_echo "$as_val"'` = yes; then
+as_val=`eval 'as_val=${'$as_ac_var'}
+ $as_echo "$as_val"'`
+ if test "x$as_val" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
@@ -6893,13 +6759,12 @@ fi
# If we're using run-cc.pl suppress the make process (run-cc.pl does it for us)
if test "$MAKEBIN"; then
- MAKEBIN="@$MAKEBIN"
+ MAKEBIN="@$MAKEBIN"
fi
-
# Check whether --with-optimization was given.
if test "${with_optimization+set}" = set; then
withval=$with_optimization;
@@ -6948,8 +6813,8 @@ _ACEOF
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
-$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -7341,7 +7206,7 @@ exec 6>&1
# values after options handling.
ac_log="
This file was extended by $as_me, which was
-generated by GNU Autoconf 2.62. Invocation command line was
+generated by GNU Autoconf 2.63. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -7354,6 +7219,15 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q`
_ACEOF
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"
@@ -7366,16 +7240,17 @@ ac_cs_usage="\
\`$as_me' instantiates files from templates according to the
current configuration.
-Usage: $0 [OPTIONS] [FILE]...
+Usage: $0 [OPTION]... [FILE]...
-h, --help print this help, then exit
-V, --version print version number and configuration settings, then exit
- -q, --quiet do not print progress messages
+ -q, --quiet, --silent
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
+ --file=FILE[:TEMPLATE]
instantiate the configuration file FILE
- --header=FILE[:TEMPLATE]
+ --header=FILE[:TEMPLATE]
instantiate the configuration header FILE
Configuration files:
@@ -7390,7 +7265,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
config.status
-configured by $0, generated by GNU Autoconf 2.62,
+configured by $0, generated by GNU Autoconf 2.63,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
Copyright (C) 2008 Free Software Foundation, Inc.
@@ -7587,7 +7462,8 @@ for ac_last_try in false false false false false :; do
$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
{ (exit 1); exit 1; }; }
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = $ac_delim_num; then
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
break
elif $ac_last_try; then
{ { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -7792,9 +7668,9 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
}
split(mac1, mac2, "(") #)
macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
if (D_is_set[macro]) {
# Preserve the white space surrounding the "#".
- prefix = substr(line, 1, index(line, defundef) - 1)
print prefix "define", macro P[macro] D[macro]
next
} else {
@@ -7802,7 +7678,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# in the case of _POSIX_SOURCE, which is predefined and required
# on some systems where configure will not decide to define it.
if (defundef == "undef") {
- print "/*", line, "*/"
+ print "/*", prefix defundef, macro, "*/"
next
}
}
@@ -7826,8 +7702,8 @@ do
esac
case $ac_mode$ac_tag in
:[FHL]*:*);;
- :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
-$as_echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+ :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
{ (exit 1); exit 1; }; };;
:[FH]-) ac_tag=-:-;;
:[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
@@ -8145,16 +8021,14 @@ if test "$no_create" != yes; then
$ac_cs_success || { (exit 1); exit 1; }
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { $as_echo "$as_me:$LINENO: WARNING: Unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2;}
+ { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
cat <<EOT
$DIS_MODULES
-$DIS_MYSQL
-
All done! Now run "make" (or possibly "gmake") to compile Anope.
diff --git a/configure.in b/configure.in
index 3a377aee7..e907e4c0f 100644
--- a/configure.in
+++ b/configure.in
@@ -77,52 +77,6 @@ else
fi
-DIS_MYSQL=" MySQL: No"
-AC_ARG_WITH(mysql, [ --without-mysql Do not use MySQL or attempt to find it],,[
- AC_ARG_WITH(mysqlconfig-path, [ --with-mysqlconfig-path=PATH Complete path to the mysql_config executable],
- mysql_config_path="$withval", mysql_config_path="")
- MYSQLCONF=""
- if test "$mysql_config_path" != ""; then
- if test -x "$mysql_config_path"; then
- MYSQLCONF="$mysql_config_path"
- echo "checking for mysql_config... $MYSQLCONF" >&6
- fi
- fi
- if test "$MYSQLCONF" = ""; then
- AC_PATH_PROG(MYSQLCONF,mysql_config, "")
- fi
- if test "$MYSQLCONF" != ""; then
- hold_cflags="$CFLAGS"
- hold_ldflags="$LDFLAGS"
- if test "$MYSQL_CFLAGS" = ""; then
- MYSQL_CFLAGS="`$MYSQLCONF --cflags`"
- fi
- if test "$MYSQL_LDFLAGS" = ""; then
- MYSQL_LDFLAGS="`$MYSQLCONF --libs`"
- fi
- CFLAGS="$CFLAGS $MYSQL_CFLAGS"
- LDFLAGS="$LDFLAGS $MYSQL_LDFLAGS"
- echo $ECHO_N "checking if mysql_config produces valid values... $ECHO_C" >&6
- AC_TRY_RUN([
-#include <mysql.h>
-
-int main()
-{
- MYSQL *mysql = mysql_init(0);
-
- return 0;
-}
- ], ac_cv_mysql_valid=yes, ac_cv_mysql_valid=no)
- echo $ac_cv_mysql_valid >&6
- if test "$ac_cv_mysql_valid" = "yes"; then
- DIS_MYSQL=" MySQL: Yes"
- else
- CFLAGS="$hold_cflags"
- LDFLAGS="$hold_ldflags"
- fi
- fi
-])
-
AC_MSG_CHECKING(whether this is a bit or little endian system)
AC_TRY_RUN([
int main()
@@ -280,8 +234,6 @@ AC_OUTPUT
cat <<EOT
$DIS_MODULES
-$DIS_MYSQL
-
All done! Now run "make" (or possibly "gmake") to compile Anope.
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index 6c49d2890..63d55d4cd 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -1,6 +1,6 @@
# Only install example.chk and example.conf from this directory
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
-set(DATA example.chk example.conf)
+set(DATA example.chk example.conf tables.sql)
install(FILES ${DATA}
DESTINATION data
)
diff --git a/data/example.conf b/data/example.conf
index c2ba553a6..b346f91e5 100644
--- a/data/example.conf
+++ b/data/example.conf
@@ -266,7 +266,12 @@ options
/*
* The database modules are used for saving and loading databases for Anope.
- * Currently, there is only one database module - db_plain
+ *
+ * Supported:
+ * - db_plain
+ * - db_mysql_write
+ * - db_mysql_read
+ * - db_mysql_execute
*/
database = "db_plain"
diff --git a/data/tables.sql b/data/tables.sql
new file mode 100644
index 000000000..6b1394e56
--- /dev/null
+++ b/data/tables.sql
@@ -0,0 +1,243 @@
+
+-- If you need to create your db, uncomment the following lines.
+--
+-- CREATE DATABASE anope;
+-- USE anope;
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_extra'
+--
+
+DROP TABLE IF EXISTS anope_extra;
+CREATE TABLE anope_extra (
+ data text NOT NULL default ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_commands'
+--
+
+DROP TABLE IF EXISTS anope_commands;
+CREATE TABLE anope_commands (
+ nick varchar(255) NOT NULL default '',
+ service varchar(255) NOT NULL default '',
+ command text NOT NULL default ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_ns_core'
+--
+
+DROP TABLE IF EXISTS anope_ns_core;
+CREATE TABLE anope_ns_core (
+ display varchar(255) NOT NULL default '',
+ pass text NOT NULL,
+ email text NOT NULL default '',
+ greet text NOT NULL default '',
+ icq int(10) unsigned NOT NULL default '0',
+ url text NOT NULL default '',
+ flags text NOT NULL default '',
+ language smallint(5) unsigned NOT NULL default '0',
+ channelcount smallint(5) unsigned NOT NULL default '0',
+ memomax smallint(5) unsigned NOT NULL default '0',
+ PRIMARY KEY (display)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+--
+-- Table structure for table 'anope_ns_core_metadata'
+--
+
+DROP TABLE IF EXISTS anope_ns_core_metadata;
+CREATE TABLE anope_ns_core_metadata (
+ nick varchar(255) NOT NULL default '',
+ name varchar(255) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (name)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- ---------------------------------------------------------
+--
+-- Table structure for table 'anope_ns_alias'
+--
+
+DROP TABLE IF EXISTS anope_ns_alias;
+CREATE TABLE anope_ns_alias (
+ nick varchar(255) NOT NULL default '',
+ last_quit text NOT NULL,
+ last_realname text NOT NULL,
+ last_usermask text NOT NULL,
+ time_registered int(11) unsigned NOT NULL default '0',
+ last_seen int(10) unsigned NOT NULL default '0',
+ flags text NOT NULL default '',
+ display varchar(255) NOT NULL default '',
+ PRIMARY KEY (nick)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+--
+-- Table structure for table 'anope_ns_alias_metadata'
+--
+
+DROP TABLE IF EXISTS anope_ns_alias_metadata;
+CREATE TABLE anope_ns_alias_metadata (
+ nick varchar(255) NOT NULL default '',
+ name varchar(255) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (name)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_ns_access'
+--
+
+DROP TABLE IF EXISTS anope_ns_access;
+CREATE TABLE anope_ns_access (
+ display varchar(255) NOT NULL default '',
+ access varchar(160) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- ---------------------------------------------------------
+
+--
+-- Table structure for table 'anope_ns_request'
+--
+
+DROP TABLE IF EXISTS anope_ns_request;
+CREATE TABLE anope_ns_request (
+ nick varchar(255) NOT NULL default '',
+ passcode text NOT NULL,
+ password text NOT NULL,
+ email text NOT NULL,
+ requested int(11) NOT NULL default '0',
+ PRIMARY KEY (nick)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+--
+-- Table structure for table 'anope_cs_access'
+--
+
+DROP TABLE IF EXISTS anope_cs_access;
+CREATE TABLE anope_cs_access (
+ level int(11) NOT NULL default '0',
+ display varchar(255) NOT NULL default '',
+ channel varchar(255) NOT NULL default '',
+ last_seen int(11) NOT NULL default '0',
+ creator varchar(255) NOT NULL default '',
+ UNIQUE KEY (channel,display)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_cs_info'
+--
+
+DROP TABLE IF EXISTS anope_cs_info;
+CREATE TABLE anope_cs_info (
+ name varchar(255) NOT NULL default '',
+ founder text NOT NULL,
+ successor text NOT NULL,
+ descr text NOT NULL,
+ url text NOT NULL,
+ email text NOT NULL,
+ time_registered int(11) unsigned NOT NULL default '0',
+ last_used int(10) unsigned NOT NULL default '0',
+ last_topic text NOT NULL,
+ last_topic_setter text NOT NULL,
+ last_topic_time int(11) unsigned NOT NULL default '0',
+ flags text NOT NULL default '',
+ forbidby text NOT NULL,
+ forbidreason text NOT NULL,
+ bantype smallint(6) NOT NULL default '0',
+ mlock_on text NOT NULL default '',
+ mlock_off text NOT NULL default '',
+ mlock_params text NOT NULL default '',
+ entry_message text NOT NULL,
+ memomax smallint(5) unsigned NOT NULL default '0',
+ botnick varchar(255) NOT NULL default '',
+ botflags text NOT NULL default '',
+ capsmin smallint(6) NOT NULL default '0',
+ capspercent smallint(6) NOT NULL default '0',
+ floodlines smallint(6) NOT NULL default '0',
+ floodsecs smallint(6) NOT NULL default '0',
+ repeattimes smallint(6) NOT NULL default '0',
+ PRIMARY KEY (name)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+--
+-- Table structure for table 'anope_cs_info_metadata'
+--
+
+DROP TABLE IF EXISTS anope_cs_info_metadata;
+CREATE TABLE anope_cs_info_metadata (
+ channel varchar(255) NOT NULL default '',
+ name varchar(255) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (name)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_cs_levels'
+--
+
+DROP TABLE IF EXISTS anope_cs_levels;
+CREATE TABLE anope_cs_levels (
+ channel varchar(255) NOT NULL default '',
+ position int(11) NOT NULL default '0',
+ level int(11) NOT NULL default '0',
+ UNIQUE KEY channel (channel,position)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_bs_core'
+--
+
+DROP TABLE IF EXISTS anope_bs_core;
+CREATE TABLE anope_bs_core (
+ nick varchar(255) NOT NULL default '',
+ user varchar(255) NOT NULL default '',
+ host text NOT NULL default '',
+ rname text NOT NULL default '',
+ flags text NOT NULL default '',
+ created int(11) NOT NULL default '0',
+ chancount int(11) NOT NULL default '0',
+ PRIMARY KEY (nick)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_metadata'
+--
+
+DROP TABLE IF EXISTS anope_metadata;
+CREATE TABLE anope_metadata (
+ name varchar(255) NOT NULL default '',
+ value text NOT NULL default '',
+ PRIMARY KEY (name)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table 'anope_info'
+--
+
+DROP TABLE IF EXISTS anope_info;
+CREATE TABLE anope_info (
+ version int(11) default NULL,
+ date datetime default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
diff --git a/docs/MYSQL b/docs/MYSQL
index 6bd71a9b9..42d9c928b 100644
--- a/docs/MYSQL
+++ b/docs/MYSQL
@@ -1,6 +1,29 @@
Anope MySQL Support
-------------------
-MySQL Support was removed in 1.9.0 until it can be better implemented moving forward.
+MySQL support was readded in version 1.9.2 In the form of three modules.
+db_mysql_read - Allows you to load your databases from MySQL.
+ Note: At the time of writing, MySQL did not support full databases (no support for OperServ, MemoServ, and HostServ)
+ which means using this is limited. I recommend using db_plain with db_mysql_write and db_mysql_execute
+db_mysql_write - Allows live updating of SQL tables whenever something is executed in Anope.
+db_mysql_execute - Allows executing of Anope commands via SQL.
+
+To execute commands via SQL, you must insert the command into the anope_commands table, an example is as follows:
+
+INSERT INTO `anope_commands` (nick, service, command) VALUES('Adam', 'NickServ', 'REGISTER qwerty Adam@anope.org');
+
+By default, every 60 seconds Anope checks this table for commands to execute. When Anope sees a new command to execute, it checks the following.
+
+If the nick given is -SQLUser, then the command gets executed by a special fake user within Anope called -SQLUser. -SQLUser has every permission and command available, there are no permission checks at all for this user, it can do anything.
+
+If the nick is not -SQLUser, it checks to see if it is a registered nick. If it is, it sees if there are any users online using the NickCore of that nick.
+ If there is a user online with that core the command gets executed as if that user executed it, and the reply goes to that user.
+ If there isn't a user online with the core, it creates a fake user as the nick given to it, and gives to it the permissions the user would have if they were online and identified.
+If the nick is not registered, it checks to see if there is a user currently on that nick. If there is, it executes the command as that user, and the reply goes to that user.
+ If the nick is not registered and no one is using the nick, it creates a fake user of the nick given to it, and gives it regular nonidentified user access.
+
+Currently there is no way to check to see if a command was executed successfully within Anope from SQL (even if there was, the possibly update delay would be a problem).
+
+IMPORTANT: When using db_mysql_write when you already have a database, you need to do an initial import of the data to SQL (as db_mysql_write only updates it when it is changed, it never actually mass-dumps all of your data into SQL). To do this, start Anope and execute /OperServ SQLSYNC.
diff --git a/docs/NEWS b/docs/NEWS
index fb5fe3ff9..1010816cf 100644
--- a/docs/NEWS
+++ b/docs/NEWS
@@ -1,8 +1,7 @@
Highlighted News in Anope 1.9
=============================
-* Removed MySQL Support (pending better implementation)
+* Added in live updating SQL and the ability to execute commands through SQL
* Re-designed configuration file
* Code refresh / rewrite into C++
-
diff --git a/include/account.h b/include/account.h
index 3f39c3b4a..25c3ff87d 100644
--- a/include/account.h
+++ b/include/account.h
@@ -145,18 +145,18 @@ class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag>
* @param cmdstr The string to check, e.g. botserv/set/private.
* @return True if this opertype may run the specified command, false otherwise.
*/
- bool HasCommand(const std::string &cmdstr) const;
+ virtual bool HasCommand(const std::string &cmdstr) const;
/** Checks whether this account is a services oper or not.
* @return True if this account is a services oper, false otherwise.
*/
- bool IsServicesOper() const;
+ virtual bool IsServicesOper() const;
/** Check whether this opertype has access to the given special permission.
* @param privstr The priv to check for, e.g. users/auspex.
* @return True if this opertype has the specified priv, false otherwise.
*/
- bool HasPriv(const std::string &privstr) const;
+ virtual bool HasPriv(const std::string &privstr) const;
/** Add an entry to the nick's access list
*
diff --git a/include/extern.h b/include/extern.h
index d20f28c59..a46314081 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -337,6 +337,7 @@ E void ntoa(struct in_addr addr, char *ipaddr, int len);
E std::list<std::string> BuildStringList(const std::string &);
E std::list<ci::string> BuildStringList(const ci::string &);
+E std::vector<std::string> BuildStringVector(const std::string &);
E void binary_to_hex(unsigned char *bin, char *hex, int length);
diff --git a/include/modules.h b/include/modules.h
index cbb3a6eb3..4a94cd830 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -811,25 +811,25 @@ class CoreExport Module
/** Called when access is deleted from a channel
* @param ci The channel
* @param u The user who removed the access
- * @param nick The name of the user whos access was removed
+ * @param nc The user who was deleted
*/
- virtual void OnAccessDel(ChannelInfo *ci, User *u, const char *nick) { }
+ virtual void OnAccessDel(ChannelInfo *ci, User *u, NickCore *nc) { }
/** Called when access is changed
* @param ci The channel
* @param u The user who changed the access
- * @param nick The nick whos access was changed
+ * @param na The nick whos access was changed
* @param level The level of the new access
*/
- virtual void OnAccessChange(ChannelInfo *ci, User *u, const char *nick, int level) { }
+ virtual void OnAccessChange(ChannelInfo *ci, User *u, NickAlias *na, int level) { }
/** Called when access is added
* @param ci The channel
* @param u The user who added the access
- * @param nick The nick who was added to access
+ * @para na The nick who was added to access
* @param level The level they were added at
*/
- virtual void OnAccessAdd(ChannelInfo *ci, User *u, const char *nick, int level) { }
+ virtual void OnAccessAdd(ChannelInfo *ci, User *u, NickAlias *na, int level) { }
/** Called when the access list is cleared
* @param ci The channel
@@ -840,7 +840,7 @@ class CoreExport Module
/** Called when a channel is dropped
* @param chname The channel name
*/
- virtual void OnChanDrop(const char *chname) { }
+ virtual void OnChanDrop(const std::string &chname) { }
/** Called when a channel is forbidden
* @param ci The channel
@@ -968,6 +968,12 @@ class CoreExport Module
*/
virtual void OnNickClearAccess(NickCore *nc) { }
+ /** Called when a user adds an entry to their access list
+ * @param nc The nick
+ * @param entry The entry
+ */
+ virtual void OnNickAddAccess(NickCore *nc, const std::string &entry) { }
+
/** called from NickCore::EraseAccess()
* @param nc pointer to the NickCore
* @param entry The access mask
@@ -1060,7 +1066,7 @@ enum Implementation
I_OnNickServHelp, I_OnPreNickExpire, I_OnNickExpire, I_OnNickForbidden, I_OnNickGroup, I_OnNickLogout, I_OnNickIdentify, I_OnNickDrop,
I_OnNickRegister, I_OnNickSuspended, I_OnNickUnsuspended,
I_OnFindUser, I_OnFindNick, I_OnDelNick, I_OnFindCore, I_OnDelCore, I_OnChangeCoreDisplay,
- I_OnFindRequestNick, I_OnDelNickRequest, I_OnMakeNickRequest, I_OnNickClearAccess, I_OnNickEraseAccess,
+ I_OnFindRequestNick, I_OnDelNickRequest, I_OnMakeNickRequest, I_OnNickClearAccess, I_OnNickAddAccess, I_OnNickEraseAccess,
/* ChanServ */
I_OnChanServHelp, I_OnChanForbidden, I_OnChanSuspend, I_OnChanDrop, I_OnPreChanExpire, I_OnChanExpire, I_OnAccessAdd, I_OnAccessChange,
diff --git a/include/services.h b/include/services.h
index 1901e6b86..10304c757 100644
--- a/include/services.h
+++ b/include/services.h
@@ -422,21 +422,6 @@ struct ircdvars_ {
/*************************************************************************/
-/* File version for each database. Was one version for all before but was
- changed so they are now easier to maintain. =) */
-
-#define BOT_VERSION 10
-#define CHAN_VERSION 16
-#define EXCEPTION_VERSION 9
-#define NEWS_VERSION 9
-#define NICK_VERSION 14
-#define PRE_NICK_VERSION 2
-#define OPER_VERSION 13
-#define HELP_VERSION 1
-#define HOST_VERSION 3
-
-/*************************************************************************/
-
/** Memo Flags
*/
enum MemoFlag
diff --git a/include/users.h b/include/users.h
index 525df393b..0d701f839 100644
--- a/include/users.h
+++ b/include/users.h
@@ -23,7 +23,7 @@ typedef std::list<ChannelContainer *> UChannelList;
/* Online user and channel data. */
class CoreExport User : public Extensible
{
- private:
+ protected:
std::string vident;
std::string ident;
std::string uid;
@@ -76,7 +76,7 @@ class CoreExport User : public Extensible
/** Update the nickname of a user record accordingly, should be
* called from ircd protocol.
*/
- void SetNewNick(const std::string &newnick);
+ virtual void SetNewNick(const std::string &newnick);
/** Update the displayed (vhost) of a user record.
* This is used (if set) instead of real host.
@@ -140,8 +140,8 @@ class CoreExport User : public Extensible
* @param fmt Format of the Message
* @param ... any number of parameters
*/
- void SendMessage(const std::string &source, const char *fmt, ...);
- void SendMessage(const std::string &source, const std::string &msg);
+ virtual void SendMessage(const std::string &source, const char *fmt, ...);
+ virtual void SendMessage(const std::string &source, const std::string &msg);
/** Check if the user should become identified because
* their svid matches the one stored in their nickcore
@@ -166,17 +166,17 @@ class CoreExport User : public Extensible
/** Get the account the user is logged in using
* @reurn The account or NULL
*/
- NickCore *Account() const;
+ virtual NickCore *Account() const;
/** Check if the user is identified for their nick
* @return true or false
*/
- const bool IsIdentified() const;
+ virtual const bool IsIdentified() const;
/** Check if the user is recognized for their nick (on the nicks access list)
* @return true or false
*/
- const bool IsRecognized() const;
+ virtual const bool IsRecognized() const;
/** Update the last usermask stored for a user, and check to see if they are recognized
*/
diff --git a/lang/en_us.l b/lang/en_us.l
index 0d2ba1369..46e9e3cbb 100644
--- a/lang/en_us.l
+++ b/lang/en_us.l
@@ -6321,3 +6321,7 @@ OPER_UMODE_UNSUPPORTED
OPER_SUPER_ADMIN_NOT_ENABLED
SuperAdmin setting not enabled in services.conf
+MYSQL_SYNC_UPDATING
+ Updating MySQL.
+MYSQL_SYNC_UPDATED
+ Finished updating MySQL.
diff --git a/src/Makefile b/src/Makefile
index 90705ce29..b0b4c8863 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -117,6 +117,7 @@ install: services
test -d ${INSTDIR}/data || mkdir ${INSTDIR}/data
(cd ../lang ; $(MAKE) install)
$(CP) ../data/* $(INSTDIR)/data
+ $(INSTALL) bin/mydbgen $(INSTDIR)/data/mydbgen
test -d $(INSTDIR)/data/backups || mkdir $(INSTDIR)/data/backups
test -d $(INSTDIR)/data/logs || mkdir $(INSTDIR)/data/logs
@if [ "$(INSTDIR)/data/modules" ] ; then \
diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt
index 5b50147ee..7c6fe514b 100644
--- a/src/bin/CMakeLists.txt
+++ b/src/bin/CMakeLists.txt
@@ -1,7 +1,7 @@
# If not on Windows, generate anoperc and install it along with mydbgen
if(NOT WIN32)
configure_file(${Anope_SOURCE_DIR}/src/bin/anoperc.in ${Anope_BINARY_DIR}/src/bin/anoperc)
- install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anoperc
+ install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anoperc ${CMAKE_CURRENT_SOURCE_DIR}/mydbgen
DESTINATION bin
)
diff --git a/src/bin/mydbgen b/src/bin/mydbgen
new file mode 100755
index 000000000..f3599a252
--- /dev/null
+++ b/src/bin/mydbgen
@@ -0,0 +1,225 @@
+#!/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 "mysql"
+ echo "{"
+ echo " database = \"$SQLDB\""
+ echo " server = \"$SQLHOST\""
+ echo " username = \"$SQLUSER\""
+ echo " password = \"$SQLPASS\""
+ echo " port = \"$SQLPORT\""
+ echo " updatedelay = \"60\""
+ echo "}"
+ echo ""
+else
+ echo "The following operations failed:"
+ echo "$FAILED"
+fi
+
+exit
diff --git a/src/core/cs_access.c b/src/core/cs_access.c
index d26891d73..bc05695a2 100644
--- a/src/core/cs_access.c
+++ b/src/core/cs_access.c
@@ -17,7 +17,6 @@
static int access_del(User * u, ChannelInfo *ci, ChanAccess * access, int *perm, int uacc)
{
- char *nick;
if (!access->in_use)
return 0;
if (uacc <= access->level && !u->Account()->HasPriv("chanserv/access/modify"))
@@ -25,11 +24,11 @@ static int access_del(User * u, ChannelInfo *ci, ChanAccess * access, int *perm,
(*perm)++;
return 0;
}
- nick = access->nc->display;
+ NickCore *nc = access->nc;
access->nc = NULL;
access->in_use = 0;
- FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, nick));
+ FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, nc));
return 1;
}
@@ -225,7 +224,7 @@ class CommandCSAccess : public Command
}
access->level = level;
- FOREACH_MOD(I_OnAccessChange, OnAccessChange(ci, u, na->nick, level));
+ FOREACH_MOD(I_OnAccessChange, OnAccessChange(ci, u, na, level));
Alog() << Config.s_ChanServ << ": " << u->GetMask() << " (level " << ulev << ") set access level "
<< access->level << " to " << na->nick << " (group " << nc->display << ") on channel " << ci->name;
@@ -242,7 +241,7 @@ class CommandCSAccess : public Command
std::string usernick = u->nick;
ci->AddAccess(nc, level, usernick);
- FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, u, na->nick, level));
+ FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, u, na, level));
Alog() << Config.s_ChanServ << ": " << u->GetMask() << " (level " << ulev << ") set access level "
<< level << " to " << na->nick << " (group " << nc->display << ") on channel " << ci->name;
@@ -326,13 +325,11 @@ class CommandCSAccess : public Command
/* We'll free the access entries no longer in use... */
ci->CleanAccess();
- /* 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 */
/* Only call this event if na exists (if they deleted by user, not numlist).
* The callback for deleting by numlist will call this event otherwise - Adam */
if (na)
{
- FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, na->nick));
+ FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, na->nc));
}
}
}
diff --git a/src/core/cs_xop.c b/src/core/cs_xop.c
index 1fa32265e..0f5f863dc 100644
--- a/src/core/cs_xop.c
+++ b/src/core/cs_xop.c
@@ -195,12 +195,12 @@ class XOPBase : public Command
if (!change)
{
- FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, u, na->nick, level));
+ FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, u, na, level));
notice_lang(Config.s_ChanServ, u, messages[XOP_ADDED], nc->display, ci->name.c_str());
}
else
{
- FOREACH_MOD(I_OnAccessChange, OnAccessChange(ci, u, na->nick, level));
+ FOREACH_MOD(I_OnAccessChange, OnAccessChange(ci, u, na, level));
notice_lang(Config.s_ChanServ, u, messages[XOP_MOVED], nc->display, ci->name.c_str());
}
@@ -290,7 +290,7 @@ class XOPBase : public Command
access->nc = NULL;
access->in_use = 0;
- FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, na->nick));
+ FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, na->nc));
deleted = 1;
}
@@ -572,16 +572,16 @@ int xop_del(User *u, ChannelInfo *ci, ChanAccess *access, int *perm, int uacc, i
{
if (!access->in_use || access->level != xlev)
return 0;
- char *nick = access->nc->display;
if (uacc <= access->level && !u->Account()->HasPriv("chanserv/access/modify"))
{
++(*perm);
return 0;
}
+ NickCore *nc = access->nc;
access->nc = NULL;
access->in_use = 0;
- FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, nick));
+ FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, nc));
return 1;
}
diff --git a/src/core/db_plain.cpp b/src/core/db_plain.cpp
index c1c9cdae5..ff2a4cdf3 100644
--- a/src/core/db_plain.cpp
+++ b/src/core/db_plain.cpp
@@ -74,7 +74,7 @@ static void ReadDatabase(Module *m = NULL)
if (m)
MOD_RESULT = m->OnDatabaseRead(params);
- else
+ else
{
FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params));
}
@@ -119,7 +119,7 @@ static void ReadDatabase(Module *m = NULL)
try
{
if (m)
- MOD_RESULT = m->OnDatabaseReadMetadata(nc, key, params);
+ m->OnDatabaseReadMetadata(nc, key, params);
else
{
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, key, params));
@@ -127,7 +127,7 @@ static void ReadDatabase(Module *m = NULL)
}
catch (const char *err)
{
- Alog() << "[db_plain}: " << err;
+ Alog() << "[db_plain]: " << err;
}
}
else if (na && Type == MD_NA)
@@ -135,7 +135,7 @@ static void ReadDatabase(Module *m = NULL)
try
{
if (m)
- MOD_RESULT = m->OnDatabaseReadMetadata(na, key, params);
+ m->OnDatabaseReadMetadata(na, key, params);
else
{
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, key, params));
@@ -143,7 +143,7 @@ static void ReadDatabase(Module *m = NULL)
}
catch (const char *err)
{
- Alog() << "[db_plain}: " << err;
+ Alog() << "[db_plain]: " << err;
}
}
else if (bi && Type == MD_BI)
@@ -151,7 +151,7 @@ static void ReadDatabase(Module *m = NULL)
try
{
if (m)
- MOD_RESULT = m->OnDatabaseReadMetadata(bi, key, params);
+ m->OnDatabaseReadMetadata(bi, key, params);
else
{
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(bi, key, params));
@@ -159,15 +159,15 @@ static void ReadDatabase(Module *m = NULL)
}
catch (const char *err)
{
- Alog() << "[db_plain}: " << err;
- }
+ Alog() << "[db_plain]: " << err;
}
+ }
else if (ci && Type == MD_CH)
{
try
{
if (m)
- MOD_RESULT = m->OnDatabaseReadMetadata(ci, key, params);
+ m->OnDatabaseReadMetadata(ci, key, params);
else
{
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, key, params));
@@ -175,7 +175,7 @@ static void ReadDatabase(Module *m = NULL)
}
catch (const char *err)
{
- Alog() << "[db_plain}: " << err;
+ Alog() << "[db_plain]: " << err;
}
}
}
diff --git a/src/core/ns_register.c b/src/core/ns_register.c
index a351711dc..fcd9c329c 100644
--- a/src/core/ns_register.c
+++ b/src/core/ns_register.c
@@ -88,6 +88,9 @@ class CommandNSConfirm : public Command
validate_user(user);
}
}
+
+ FOREACH_MOD(I_OnNickRegister, OnNickRegister(na));
+
return MOD_CONT;
}
diff --git a/src/misc.c b/src/misc.c
index 4c786a83c..a39886ccb 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1056,6 +1056,18 @@ std::list<ci::string> BuildStringList(const ci::string &src)
return Ret;
}
+std::vector<std::string> BuildStringVector(const std::string &src)
+{
+ spacesepstream tokens(src);
+ std::string token;
+ std::vector<std::string> Ret;
+
+ while (tokens.GetToken(token))
+ Ret.push_back(token);
+
+ return Ret;
+}
+
/*************************************************************************/
/**
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt
index 79312cb8a..6745e8a67 100644
--- a/src/modules/CMakeLists.txt
+++ b/src/modules/CMakeLists.txt
@@ -58,6 +58,7 @@ endforeach(SRC)
file(GLOB MODULES_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*")
remove_item_from_list(MODULES_FILES ".svn")
remove_item_from_list(MODULES_FILES "CMakeFiles")
+remove_item_from_list(MODULES_FILES "mysql")
# Iterate through this directory searching for subdirectories, and creating modules for those subdirectories
foreach(FILE ${MODULES_FILES})
diff --git a/src/modules/Makefile b/src/modules/Makefile
index a65a497bd..b2686ae84 100644
--- a/src/modules/Makefile
+++ b/src/modules/Makefile
@@ -27,10 +27,14 @@ distclean: spotless
.SUFFIXES: .c .cpp .so
.c.so:
- $(MAKEBIN) $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../${INCLUDEDIR} -o $@ $<
+ $(MAKEBIN) $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} \
+ $(if $(shell grep RequiredLibraries $< | grep mysqlpp),-lmysqlpp) \
+ -I../${INCLUDEDIR} -o $@ $<
.cpp.so:
- $(MAKEBIN) $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} -I../${INCLUDEDIR} -o $@ $<
+ $(MAKEBIN) $(CC) ${CFLAGS} ${CDEFS} ${MODULEFLAGS} \
+ $(if $(shell grep RequiredLibraries $< | grep mysqlpp),-lmysqlpp) \
+ -I../${INCLUDEDIR} -o $@ $<
subs:
@for i in $(SUBS); do \
diff --git a/src/modules/mysql/db_mysql.h b/src/modules/mysql/db_mysql.h
new file mode 100644
index 000000000..b617b7dd5
--- /dev/null
+++ b/src/modules/mysql/db_mysql.h
@@ -0,0 +1,238 @@
+#include "module.h"
+
+struct NickAliasFlagInfo
+{
+ std::string Name;
+ NickNameFlag Flag;
+};
+
+NickAliasFlagInfo NickAliasFlags[] = {
+ {"FORBIDDEN", NS_FORBIDDEN},
+ {"NOEXPIRE", NS_NO_EXPIRE},
+ {"", static_cast<NickNameFlag>(-1)}
+};
+
+struct NickCoreFlagInfo
+{
+ std::string Name;
+ NickCoreFlag Flag;
+};
+
+NickCoreFlagInfo NickCoreFlags[] = {
+ {"KILLPROTECT", NI_KILLPROTECT},
+ {"SECURE", NI_SECURE},
+ {"MSG", NI_MSG},
+ {"MEMO_HARDMAX", NI_MEMO_HARDMAX},
+ {"MEMO_SIGNON", NI_MEMO_SIGNON},
+ {"MEMO_RECEIVE", NI_MEMO_RECEIVE},
+ {"PRIVATE", NI_PRIVATE},
+ {"HIDE_EMAIL", NI_HIDE_EMAIL},
+ {"HIDE_MASK", NI_HIDE_MASK},
+ {"HIDE_QUIT", NI_HIDE_QUIT},
+ {"KILL_QUICK", NI_KILL_QUICK},
+ {"KILL_IMMED", NI_KILL_IMMED},
+ {"MEMO_MAIL", NI_MEMO_MAIL},
+ {"HIDE_STATUS", NI_HIDE_STATUS},
+ {"SUSPENDED", NI_SUSPENDED},
+ {"AUTOOP", NI_AUTOOP},
+ {"FORBIDDEN", NI_FORBIDDEN},
+ {"", static_cast<NickCoreFlag>(-1)}
+};
+
+struct ChannelModeInfo
+{
+ std::string Name;
+ ChannelModeName Mode;
+};
+
+ChannelModeInfo ChannelModes[] = {
+ {"BLOCKCOLOR", CMODE_BLOCKCOLOR},
+ {"FLOOD", CMODE_FLOOD},
+ {"INVITE", CMODE_INVITE},
+ {"KEY", CMODE_KEY},
+ {"LIMIT", CMODE_LIMIT},
+ {"MODERATED", CMODE_MODERATED},
+ {"NOEXTERNAL", CMODE_NOEXTERNAL},
+ {"PRIVATE", CMODE_PRIVATE},
+ {"REGISTERED", CMODE_REGISTERED},
+ {"SECRET", CMODE_SECRET},
+ {"TOPIC", CMODE_TOPIC},
+ {"AUDITORIUM", CMODE_AUDITORIUM},
+ {"SSL", CMODE_SSL},
+ {"ADMINONLY", CMODE_ADMINONLY},
+ {"NOCTCP", CMODE_NOCTCP},
+ {"FILTER", CMODE_FILTER},
+ {"NOKNOCK", CMODE_NOKNOCK},
+ {"REDIRECT", CMODE_REDIRECT},
+ {"REGMODERATED", CMODE_REGMODERATED},
+ {"NONICK", CMODE_NONICK},
+ {"OPERONLY", CMODE_OPERONLY},
+ {"NONICK", CMODE_NONICK},
+ {"REGISTEREDONLY", CMODE_REGISTEREDONLY},
+ {"STRIPCOLOR", CMODE_STRIPCOLOR},
+ {"NONOTICE", CMODE_NONOTICE},
+ {"NOINVITE", CMODE_NOINVITE},
+ {"ALLINVITE", CMODE_ALLINVITE},
+ {"BLOCKCAPS", CMODE_BLOCKCAPS},
+ {"PERM", CMODE_PERM},
+ {"NICKFLOOD", CMODE_NICKFLOOD},
+ {"JOINFLOOD", CMODE_JOINFLOOD},
+ {"", static_cast<ChannelModeName>(-1)}
+};
+
+struct BotFlagInfo
+{
+ std::string Name;
+ BotServFlag Flag;
+};
+
+BotFlagInfo BotFlags[] = {
+ {"DONTKICKOPS", BS_DONTKICKOPS},
+ {"DONTKICKVOICES", BS_DONTKICKVOICES},
+ {"FANTASY", BS_FANTASY},
+ {"SYMBIOSIS", BS_SYMBIOSIS},
+ {"GREET", BS_GREET},
+ {"NOBOT", BS_NOBOT},
+ {"KICK_BOLDS", BS_KICK_BOLDS},
+ {"KICK_COLORS", BS_KICK_COLORS},
+ {"KICK_REVERSES", BS_KICK_REVERSES},
+ {"KICK_UNDERLINES", BS_KICK_UNDERLINES},
+ {"KICK_BADWORDS", BS_KICK_BADWORDS},
+ {"KICK_CAPS", BS_KICK_CAPS},
+ {"KICK_FLOOD", BS_KICK_FLOOD},
+ {"KICK_REPEAT", BS_KICK_REPEAT},
+ {"", static_cast<BotServFlag>(-1)}
+};
+
+struct ChannelFlagInfo
+{
+ std::string Name;
+ ChannelInfoFlag Flag;
+};
+
+ChannelFlagInfo ChannelFlags[] = {
+ {"KEEPTOPIC", CI_KEEPTOPIC},
+ {"SECUREOPS", CI_SECUREOPS},
+ {"PRIVATE", CI_PRIVATE},
+ {"TOPICLOCK", CI_TOPICLOCK},
+ {"RESTRICTED", CI_RESTRICTED},
+ {"PEACE", CI_PEACE},
+ {"SECURE", CI_SECURE},
+ {"FORBIDDEN", CI_FORBIDDEN},
+ {"NO_EXPIRE", CI_NO_EXPIRE},
+ {"MEMO_HARDMAX", CI_MEMO_HARDMAX},
+ {"OPNOTICE", CI_OPNOTICE},
+ {"SECUREFOUNDER", CI_SECUREFOUNDER},
+ {"SIGNKICK", CI_SIGNKICK},
+ {"SIGNKICK_LEVEL", CI_SIGNKICK_LEVEL},
+ {"XOP", CI_XOP},
+ {"SUSPENDED", CI_SUSPENDED},
+ {"PERSIST", CI_PERSIST},
+ {"", static_cast<ChannelInfoFlag>(-1)}
+};
+
+struct BotServFlagInfo
+{
+ std::string Name;
+ BotFlag Flag;
+};
+
+BotServFlagInfo BotServFlags[] = {
+ {"PRIVATE", BI_PRIVATE},
+ {"CHANSERV", BI_CHANSERV},
+ {"BOTSERV", BI_BOTSERV},
+ {"HOSTSERV", BI_HOSTSERV},
+ {"OPERSERV", BI_OPERSERV},
+ {"MEMOSERV", BI_MEMOSERV},
+ {"NICKSERV", BI_NICKSERV},
+ {"GLOBAL", BI_GLOBAL},
+ {"", static_cast<BotFlag>(-1)}
+};
+
+#define MYSQLPP_MYSQL_HEADERS_BURIED
+#include <mysql++/mysql++.h>
+
+inline std::string SQLAssign(const mysqlpp::String& s) { return s.c_str(); }
+
+class DBMySQL;
+static DBMySQL *Me;
+
+bool ExecuteQuery(mysqlpp::Query& query)
+{
+ Alog(LOG_DEBUG) << "MySQL: " << query.str();
+
+ if (!query.execute())
+ {
+ Alog(LOG_DEBUG) << "MySQL: error executing query: " << query.error();
+ return false;
+ }
+
+ return true;
+}
+
+mysqlpp::StoreQueryResult StoreQuery(mysqlpp::Query& query)
+{
+ Alog(LOG_DEBUG) << "MySQL: " << query.str();
+
+ mysqlpp::StoreQueryResult result = query.store();
+ if (!result)
+ {
+ Alog(LOG_DEBUG) << "MySQL: error executing query: " << query.error();
+ }
+ return result;
+}
+
+class DBMySQL : public Module
+{
+ private:
+ bool LoadConfig()
+ {
+ ConfigReader config;
+
+ Database = config.ReadValue("mysql", "database", "anope", 0);
+ Server = config.ReadValue("mysql", "server", "127.0.0.1", 0);
+ SQLUser = config.ReadValue("mysql", "username", "anope", 0);
+ Password = config.ReadValue("mysql", "password", "", 0);
+ Port = config.ReadInteger("mysql", "port", "3306", 0, true);
+ Delay = config.ReadInteger("mysql", "updatedelay", "60", 0, true);
+
+ return !Password.empty();
+ }
+
+ public:
+ mysqlpp::Connection *Con;
+
+ std::string Database;
+ std::string Server;
+ std::string SQLUser;
+ std::string Password;
+ unsigned int Port;
+ unsigned int Delay;
+
+ DBMySQL(const std::string &modname, const std::string &creator) : Module(modname, creator)
+ {
+ Me = this;
+
+ this->SetAuthor("Anope");
+ this->SetVersion("$Id$");
+ this->SetType(SUPPORTED);
+
+ if (!LoadConfig())
+ throw ModuleException("Couldn't load config");
+
+ Con = new mysqlpp::Connection(false);
+ if (!Con->connect(Database.c_str(), Server.c_str(), SQLUser.c_str(), Password.c_str(), Port))
+ {
+ std::string Error = "MySQL: Error connecting to SQL server: ";
+ Error += Con->error();
+ delete Con;
+ throw ModuleException(Error.c_str());
+ }
+ }
+
+ virtual ~DBMySQL()
+ {
+ delete Con;
+ }
+};
+
diff --git a/src/modules/mysql/db_mysql_execute.cpp b/src/modules/mysql/db_mysql_execute.cpp
new file mode 100644
index 000000000..adeabd267
--- /dev/null
+++ b/src/modules/mysql/db_mysql_execute.cpp
@@ -0,0 +1,162 @@
+/* RequiredLibraries: mysqlpp */
+
+#include "db_mysql.h"
+#define HASH(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31))
+
+class FakeNickCore : public NickCore
+{
+ public:
+ FakeNickCore() : NickCore("-SQLUser")
+ {
+ if (this->next)
+ this->next->prev = this->prev;
+ if (this->prev)
+ this->prev->next = this->next;
+ else
+ nclists[HASH(this->display)] = this->next;
+ }
+
+ ~FakeNickCore()
+ {
+ insert_core(this);
+ }
+
+ bool IsServicesOper() const { return true; }
+ bool HasCommand(const std::string &) const { return true; }
+ bool HasPriv(const std::string &) const { return true; }
+} SQLCore;
+
+class FakeUser : public User
+{
+ public:
+ FakeUser() : User("-SQLUser", "")
+ {
+ this->SetIdent("SQL");
+ this->host = sstrdup(Config.ServerName);
+ this->realname = sstrdup("Fake SQL User");
+ this->hostip = sstrdup("255.255.255.255");
+ this->vhost = NULL;
+
+ if (this->prev)
+ this->prev->next = this->next;
+ else
+ userlist[HASH(this->nick)] = this->next;
+ if (this->next)
+ this->next->prev = this->prev;
+ --usercnt;
+ }
+
+ ~FakeUser()
+ {
+ User **list = &userlist[HASH(this->nick)];
+ this->next = *list;
+ if (*list)
+ (*list)->prev = this;
+ *list = this;
+ ++usercnt;
+ }
+
+ void SetNewNick(const std::string &newnick) { this->nick = newnick; }
+
+ void SendMessage(const std::string &, const char *, ...) { }
+ void SendMessage(const std::string &, const std::string &) { }
+
+ NickCore *Account() const { return nc; }
+ const bool IsIdentified() const { return nc ? true : false; }
+} SQLUser;
+
+class SQLTimer : public Timer
+{
+ public:
+ SQLTimer() : Timer(Me->Delay, time(NULL), true) { }
+
+ void Tick(time_t)
+ {
+ mysqlpp::Query query(Me->Con);
+ mysqlpp::StoreQueryResult qres;
+
+ query << "SELECT * FROM `anope_commands`";
+ qres = StoreQuery(query);
+
+ if (qres && qres.num_rows())
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ User *u;
+ NickAlias *na = NULL;
+
+ /* If they want -SQLUser to execute the command, use it */
+ if (qres[i]["nick"] == "-SQLUser")
+ {
+ u = &SQLUser;
+ u->SetNewNick("-SQLUser");
+ SQLCore.Users.clear();
+ u->Login(&SQLCore);
+ }
+ else
+ {
+ /* See if the nick they want to execute the command is registered */
+ na = findnick(SQLAssign(qres[i]["nick"]));
+ if (na)
+ {
+ /* If it is and someone is online using that nick, use them */
+ if (!na->nc->Users.empty())
+ u = na->nc->Users.front();
+ /* Make a fake nick and use that logged in as the nick we want to use */
+ else
+ {
+ u = &SQLUser;
+ u->SetNewNick(SQLAssign(qres[i]["nick"]));
+ u->Login(na->nc);
+ }
+ }
+ else
+ {
+ /* Check if someone is online using the nick now */
+ u = finduser(SQLAssign(qres[i]["nick"]));
+ /* If they arent make a fake user, and use them */
+ if (!u)
+ {
+ u = &SQLUser;
+ u->SetNewNick(SQLAssign(qres[i]["nick"]));
+ u->Logout();
+ }
+ }
+ }
+
+ BotInfo *bi = findbot(SQLAssign(qres[i]["service"]));
+ if (!bi)
+ {
+ Alog() << "Warning: SQL command for unknown service " << qres[i]["service"];
+ continue;
+ }
+
+ // XXX this whole strtok thing needs to die
+ char *cmdbuf = sstrdup(qres[i]["command"].c_str());
+ char *cmd = strtok(cmdbuf, " ");
+ mod_run_cmd(bi->nick, u, bi->cmdTable, cmd);
+ delete [] cmdbuf;
+ }
+
+ query << "TRUNCATE TABLE `anope_commands`";
+ ExecuteQuery(query);
+ }
+ }
+};
+
+class DBMySQLExecute : public DBMySQL
+{
+ SQLTimer *_SQLTimer;
+ public:
+ DBMySQLExecute(const std::string &modname, const std::string &creator) : DBMySQL(modname, creator)
+ {
+ _SQLTimer = new SQLTimer();
+ }
+
+ ~DBMySQLExecute()
+ {
+ TimerManager::DelTimer(_SQLTimer);
+ }
+};
+
+MODULE_INIT(DBMySQLExecute)
diff --git a/src/modules/mysql/db_mysql_read.cpp b/src/modules/mysql/db_mysql_read.cpp
new file mode 100644
index 000000000..f9330270c
--- /dev/null
+++ b/src/modules/mysql/db_mysql_read.cpp
@@ -0,0 +1,515 @@
+/* RequiredLibraries: mysqlpp */
+
+#include "db_mysql.h"
+
+static std::vector<std::string> MakeVector(std::string buf)
+{
+ std::string s;
+ spacesepstream sep(buf);
+ std::vector<std::string> params;
+
+ while (sep.GetToken(s))
+ {
+ if (s[0] == ':')
+ {
+ s.erase(s.begin());
+ if (!s.empty() && !sep.StreamEnd())
+ params.push_back(s + " " + sep.GetRemaining());
+ else if (!s.empty())
+ params.push_back(s);
+ }
+ else
+ params.push_back(s);
+ }
+
+ return params;
+}
+
+static void LoadDatabase()
+{
+ mysqlpp::Query query(Me->Con);
+ mysqlpp::StoreQueryResult qres;
+
+ query << "SELECT * FROM `anope_ns_core`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc = new NickCore(SQLAssign(qres[i]["display"]));
+ nc->pass = SQLAssign(qres[i]["pass"]);
+ if (!qres[i]["email"].empty())
+ nc->email = sstrdup(qres[i]["email"].c_str());
+ if (!qres[i]["greet"].empty())
+ nc->greet = sstrdup(qres[i]["greet"].c_str());
+ if (!qres[i]["icq"].empty())
+ nc->icq = atol(qres[i]["icq"].c_str());
+ if (!qres[i]["url"].empty())
+ nc->url = sstrdup(qres[i]["url"].c_str());
+
+ spacesepstream sep(SQLAssign(qres[i]["flags"]));
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; NickCoreFlags[j].Flag != -1; ++j)
+ {
+ if (NickCoreFlags[j].Name == buf)
+ {
+ nc->SetFlag(NickCoreFlags[j].Flag);
+ }
+ }
+ }
+
+ nc->language = atoi(qres[i]["language"].c_str());
+ nc->channelcount = atoi(qres[i]["channelcount"].c_str());
+ nc->memos.memomax = atoi(qres[i]["memomax"].c_str());
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_access`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc = findcore(qres[i]["display"].c_str());
+ if (!nc)
+ {
+ Alog() << "MySQL: Got NickCore access entry for nonexistant core " << qres[i]["display"];
+ continue;
+ }
+
+ nc->AddAccess(SQLAssign(qres[i]["access"]));
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_core_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc = findcore(qres[i]["display"].c_str());
+ if (!nc)
+ {
+ Alog() << "MySQL: Got NickCore access entry for nonexistant core " << qres[i]["display"];
+ continue;
+ }
+ try
+ {
+ EventReturn MOD_RESULT;
+ std::vector<std::string> Params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, SQLAssign(qres[i]["name"]), Params));
+ }
+ catch (const char *err)
+ {
+ Alog() << "[db_mysql_read]: " << err;
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_alias`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc = findcore(qres[i]["display"].c_str());
+ if (!nc)
+ {
+ Alog() << "MySQL: Got NickAlias for nick " << qres[i]["nick"] << " with nonexistant core " << qres[i]["display"];
+ continue;
+ }
+
+ NickAlias *na = new NickAlias(SQLAssign(qres[i]["nick"]), nc);
+ na->last_quit = sstrdup(qres[i]["last_quit"].c_str());
+ na->last_realname = sstrdup(qres[i]["last_realname"].c_str());
+ na->last_usermask = sstrdup(qres[i]["last_usermask"].c_str());
+ na->time_registered = atol(qres[i]["time_registered"].c_str());
+ na->last_seen = atol(qres[i]["last_seen"].c_str());
+
+ spacesepstream sep(SQLAssign(qres[i]["flags"]));
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; NickAliasFlags[j].Flag != -1; ++j)
+ {
+ if (NickAliasFlags[j].Name == buf)
+ {
+ na->SetFlag(NickAliasFlags[j].Flag);
+ }
+ }
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_alias_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickAlias *na = findnick(SQLAssign(qres[i]["nick"]));
+ if (!na)
+ {
+ Alog() << "MySQL: Got metadata for nonexistant nick " << qres[i]["nick"];
+ continue;
+ }
+ try
+ {
+ EventReturn MOD_RESULT;
+ std::vector<std::string> Params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, SQLAssign(qres[i]["name"]), Params));
+ }
+ catch (const char *err)
+ {
+ Alog() << "[db_mysql_read]: " << err;
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_bs_core`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ BotInfo *bi = new BotInfo(SQLAssign(qres[i]["nick"]), SQLAssign(qres[i]["user"]), SQLAssign(qres[i]["host"]), SQLAssign(qres[i]["rname"]));
+ if (!qres[i]["flags"].empty())
+ {
+ spacesepstream sep(SQLAssign(qres[i]["flags"]));
+ std::string buf;
+ while (sep.GetToken(buf))
+ {
+ for (unsigned j = 0; BotServFlags[j].Flag != -1; ++j)
+ {
+ if (buf == BotServFlags[j].Name)
+ {
+ bi->SetFlag(BotServFlags[j].Flag);
+ break;
+ }
+ }
+ }
+ }
+ bi->created = atol(qres[i]["created"]);
+ bi->chancount = atol(qres[i]["chancount"]);
+ }
+ }
+
+ query << "SELECT * FROM `anope_cs_info`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc;
+ if (!qres[i]["founder"].empty())
+ {
+ nc = findcore(qres[i]["founder"].c_str());
+ if (!nc)
+ {
+ Alog() << "MySQL: Channel " << qres[i]["name"] << " with nonexistant founder " << qres[i]["founder"];
+ continue;
+ }
+ }
+
+ ChannelInfo *ci = new ChannelInfo(SQLAssign(qres[i]["name"]));
+ ci->founder = nc;
+ if (!qres[i]["successor"].empty())
+ ci->successor = findcore(qres[i]["successor"].c_str());
+ ci->desc = sstrdup(qres[i]["descr"].c_str());
+ if (!qres[i]["url"].empty())
+ ci->url = sstrdup(qres[i]["url"].c_str());
+ if (!qres[i]["email"].empty())
+ ci->email = sstrdup(qres[i]["email"].c_str());
+ ci->time_registered = atol(qres[i]["time_registered"]);
+ ci->last_used = atol(qres[i]["last_used"]);
+ if (!qres[i]["last_topic"].empty())
+ ci->last_topic = sstrdup(qres[i]["last_topic"].c_str());
+ if (!qres[i]["last_topic_setter"].empty())
+ ci->last_topic_setter = SQLAssign(qres[i]["last_topic_setter"]);
+ if (!qres[i]["last_topic_time"].empty())
+ ci->last_topic_time = atol(qres[i]["last_topic_time"].c_str());
+ if (!qres[i]["flags"].empty())
+ {
+ std::string buf;
+ spacesepstream sep(SQLAssign(qres[i]["flags"]));
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; ChannelFlags[j].Flag != -1; ++j)
+ {
+ if (buf == ChannelFlags[j].Name)
+ {
+ ci->SetFlag(ChannelFlags[j].Flag);
+ break;
+ }
+ }
+ }
+ }
+ if (!qres[i]["forbidby"].empty())
+ ci->forbidby = sstrdup(qres[i]["forbidby"].c_str());
+ if (!qres[i]["forbidreason"].empty())
+ ci->forbidreason = sstrdup(qres[i]["forbidreason"].c_str());
+ ci->bantype = atoi(qres[i]["bantype"].c_str());
+ if (!qres[i]["mlock_on"].empty())
+ {
+ std::string buf;
+ spacesepstream sep(SQLAssign(qres[i]["mlock_on"]));
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; ChannelModes[j].Mode != -1; ++j)
+ {
+ if (buf == ChannelModes[j].Name)
+ {
+ ci->SetMLock(ChannelModes[j].Mode, true);
+ break;
+ }
+ }
+ }
+ }
+ if (!qres[i]["mlock_off"].empty())
+ {
+ std::string buf;
+ spacesepstream sep(SQLAssign(qres[i]["mlock_off"]));
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; ChannelModes[j].Mode != -1; ++j)
+ {
+ if (buf == ChannelModes[j].Name)
+ {
+ ci->SetMLock(ChannelModes[j].Mode, false);
+ break;
+ }
+ }
+ }
+ }
+ if (!qres[i]["mlock_params"].empty())
+ {
+ std::string buf;
+ spacesepstream sep(SQLAssign(qres[i]["mlock_params"]));
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; ChannelModes[j].Mode != -1; ++j)
+ {
+ if (buf == ChannelModes[j].Name)
+ {
+ sep.GetToken(buf);
+ ci->SetMLock(ChannelModes[j].Mode, true, buf);
+ break;
+ }
+ }
+ }
+ }
+ if (!qres[i]["entry_message"].empty())
+ ci->entry_message = sstrdup(qres[i]["entry_message"].c_str());
+ ci->memos.memomax = atoi(qres[i]["memomax"].c_str());
+ if (!qres[i]["botnick"].empty())
+ ci->bi = findbot(SQLAssign(qres[i]["botnick"]));
+ if (ci->bi)
+ {
+ if (!qres[i]["botflags"].empty())
+ {
+ std::string buf;
+ spacesepstream sep(SQLAssign(qres[i]["botflags"]));
+ while (sep.GetToken(buf))
+ {
+ for (int j = 0; BotFlags[j].Flag != -1; ++j)
+ {
+ if (buf == BotFlags[j].Name)
+ {
+ ci->botflags.SetFlag(BotFlags[j].Flag);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!qres[i]["capsmin"].empty())
+ ci->capsmin = atoi(qres[i]["capsmin"].c_str());
+ if (!qres[i]["capspercent"].empty())
+ ci->capspercent = atoi(qres[i]["capspercent"].c_str());
+ if (!qres[i]["floodlines"].empty())
+ ci->floodlines = atoi(qres[i]["capspercent"].c_str());
+ if (!qres[i]["floodsecs"].empty())
+ ci->floodsecs = atoi(qres[i]["floodsecs"].c_str());
+ if (!qres[i]["repeattimes"].empty())
+ ci->repeattimes = atoi(qres[i]["repeattimes"].c_str());
+ }
+ }
+
+ query << "SELECT * FROM `anope_cs_access`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ ChannelInfo *ci = cs_findchan(SQLAssign(qres[i]["channel"]));
+ if (!ci)
+ {
+ Alog() << "MySQL: Channel access entry for nonexistant channel " << qres[i]["channel"];
+ continue;
+ }
+ NickCore *nc = findcore(qres[i]["display"]);
+ if (!nc)
+ {
+ Alog() << "MySQL: Channel access entry for " << ci->name << " with nonexistant nick " << qres[i]["display"];
+ continue;
+ }
+
+ ci->AddAccess(nc, atoi(qres[i]["level"]), SQLAssign(qres[i]["creator"]), atol(qres[i]["last_seen"]));
+ }
+ }
+
+ query << "SELECT * FROM `anope_cs_levels`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ ChannelInfo *ci = cs_findchan(SQLAssign(qres[i]["channel"]));
+ if (!ci)
+ {
+ Alog() << "MySQL: Channel level entry for nonexistant channel " << qres[i]["channel"];
+ continue;
+ }
+ ci->levels[atoi(qres[i]["position"])] = atoi(qres[i]["level"]);
+ }
+ }
+
+ query << "SELECT * FROM `anope_cs_info_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ ChannelInfo *ci = cs_findchan(SQLAssign(qres[i]["channel"]));
+ if (!ci)
+ {
+ Alog() << "MySQL: Channel level entry for nonexistant channel " << qres[i]["channel"];
+ continue;
+ }
+ try
+ {
+ EventReturn MOD_RESULT;
+ std::vector<std::string> Params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, SQLAssign(qres[i]["name"]), Params));
+ }
+ catch (const char *err)
+ {
+ Alog() << "[db_mysql_read]: " << err;
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_request`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickRequest *nr = new NickRequest(qres[i]["nick"].c_str());
+ nr->passcode = SQLAssign(qres[i]["passcode"]);
+ nr->password = SQLAssign(qres[i]["password"]);
+ nr->email = sstrdup(qres[i]["email"].c_str());
+ nr->requested = atol(qres[i]["requested"].c_str());
+ }
+ }
+
+ EventReturn MOD_RESULT;
+ query << "SELECT * FROM `anope_extra`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ std::vector<std::string> params = MakeVector(SQLAssign(qres[i]["data"]));
+ FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params));
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_core_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickCore *nc = findcore(qres[i]["nick"].c_str());
+ if (nc)
+ {
+ std::vector<std::string> params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, SQLAssign(qres[i]["name"]), params));
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_ns_alias_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ NickAlias *na = findnick(SQLAssign(qres[i]["nick"]));
+ if (na)
+ {
+ std::vector<std::string> params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, SQLAssign(qres[i]["name"]), params));
+ }
+ }
+ }
+
+ query << "SELECT * FROM `anope_cs_info_metadata`";
+ qres = StoreQuery(query);
+
+ if (qres)
+ {
+ for (size_t i = 0; i < qres.num_rows(); ++i)
+ {
+ ChannelInfo *ci = cs_findchan(SQLAssign(qres[i]["channel"]));
+ if (ci)
+ {
+ std::vector<std::string> params = MakeVector(SQLAssign(qres[i]["value"]));
+ FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, SQLAssign(qres[i]["name"]), params));
+ }
+ }
+ }
+}
+
+class DBMySQLRead : public DBMySQL
+{
+ public:
+ DBMySQLRead(const std::string &modname, const std::string &creator) : DBMySQL(modname, creator)
+ {
+ Implementation i[] = { I_OnLoadDatabase };
+ ModuleManager::Attach(i, this, 1);
+ }
+
+ ~DBMySQLRead()
+ {
+ }
+
+ EventReturn OnLoadDatabase()
+ {
+ LoadDatabase();
+
+ /* No need to ever reload this again, although this should never be triggered again */
+ ModuleManager::Detach(I_OnLoadDatabase, this);
+
+ return EVENT_STOP;
+ }
+};
+
+MODULE_INIT(DBMySQLRead)
diff --git a/src/modules/mysql/db_mysql_write.cpp b/src/modules/mysql/db_mysql_write.cpp
new file mode 100644
index 000000000..21f2513d1
--- /dev/null
+++ b/src/modules/mysql/db_mysql_write.cpp
@@ -0,0 +1,740 @@
+/* RequiredLibraries: mysqlpp */
+
+#include "db_mysql.h"
+
+static std::string BuildFlagsList(ChannelInfo *ci)
+{
+ std::string ret;
+
+ for (int i = 0; ChannelFlags[i].Flag != -1; ++i)
+ {
+ if (ci->HasFlag(ChannelFlags[i].Flag))
+ {
+ ret += " " + ChannelFlags[i].Name;
+ }
+ }
+
+ if (!ret.empty())
+ ret.erase(ret.begin());
+
+ return ret;
+}
+
+static std::string BuildFlagsList(NickAlias *na)
+{
+ std::string ret;
+
+ for (int i = 0; NickAliasFlags[i].Flag != -1; ++i)
+ {
+ if (na->HasFlag(NickAliasFlags[i].Flag))
+ {
+ ret += " " + NickAliasFlags[i].Name;
+ }
+ }
+
+ if (!ret.empty())
+ ret.erase(ret.begin());
+
+ return ret;
+}
+
+static std::string BuildFlagsList(NickCore *nc)
+{
+ std::string ret;
+
+ for (int i = 0; NickCoreFlags[i].Flag != -1; ++i)
+ {
+ if (nc->HasFlag(NickCoreFlags[i].Flag))
+ {
+ ret += " " + NickCoreFlags[i].Name;
+ }
+ }
+
+ if (!ret.empty())
+ ret.erase(ret.begin());
+
+ return ret;
+}
+
+static std::string MakeMLock(ChannelInfo *ci, bool status)
+{
+ std::string ret;
+
+ for (int i = 0; ChannelModes[i].Mode != -1; ++i)
+ {
+ if (ci->HasMLock(ChannelModes[i].Mode, status))
+ {
+ ret += " " + ChannelModes[i].Name;
+ }
+ }
+
+ if (!ret.empty())
+ ret.erase(ret.begin());
+
+ return ret;
+}
+
+static inline std::string GetMLockOn(ChannelInfo *ci)
+{
+ return MakeMLock(ci, true);
+}
+
+static inline std::string GetMLockOff(ChannelInfo *ci)
+{
+ return MakeMLock(ci, false);
+}
+
+static std::string GetMLockParams(ChannelInfo *ci)
+{
+ std::string ret;
+
+ for (int i = 0; ChannelModes[i].Mode != -1; ++i)
+ {
+ std::string param;
+ if (ci->GetParam(ChannelModes[i].Mode, &param))
+ {
+ ret += " " + param;
+ }
+ }
+
+ if (!ret.empty())
+ ret.erase(ret.begin());
+
+ return ret;
+}
+
+static std::string GetBotFlags(Flags<BotServFlag>& Flags)
+{
+ std::string buf;
+
+ for (int i = 0; BotFlags[i].Flag != -1; ++i)
+ {
+ if (Flags.HasFlag(BotFlags[i].Flag))
+ {
+ buf += " " + BotFlags[i].Name;
+ }
+ }
+
+ if (!buf.empty())
+ buf.erase(buf.begin());
+
+ return buf;
+}
+
+static std::string GetBotServFlags(BotInfo *bi)
+{
+ std::string buf;
+
+ for (int i = 0; BotServFlags[i].Flag != -1; ++i)
+ {
+ if (bi->HasFlag(BotServFlags[i].Flag))
+ {
+ buf += " " + BotServFlags[i].Name;
+ }
+ }
+
+ if (!buf.empty())
+ buf.erase(buf.begin());;
+
+ return buf;
+}
+
+static NickAlias *CurNick = NULL;
+static NickCore *CurCore = NULL;
+static ChannelInfo *CurChannel = NULL;
+
+void Write(const std::string &data)
+{
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_extra` (data) VALUES(" << mysqlpp::quote << data << ")";
+ ExecuteQuery(query);
+}
+
+void WriteMetadata(const std::string &key, const std::string &data)
+{
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_metadata` (name, value) VALUES(" << mysqlpp::quote << key << ", " << mysqlpp::quote << data << ")";
+ ExecuteQuery(query);
+}
+
+void WriteNickMetadata(const std::string &key, const std::string &data)
+{
+ if (!CurNick)
+ throw CoreException("WriteNickMetadata without a nick to write");
+
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_ns_alias_metadata` (nick, name, value) VALUES(" << mysqlpp::quote << CurNick->nick << ", " << mysqlpp::quote << key << ", " << mysqlpp::quote << data << ")";
+ ExecuteQuery(query);
+}
+
+void WriteCoreMetadata(const std::string &key, const std::string &data)
+{
+ if (!CurCore)
+ throw CoreException("WritCoreMetadata without a core to write");
+
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_ns_core_metadata` (nick, name, value) VALUES(" << mysqlpp::quote << CurCore->display << ", " << mysqlpp::quote << key << ", " << mysqlpp::quote << data << ")";
+ ExecuteQuery(query);
+}
+
+void WriteChannelMetadata(const std::string &key, const std::string &data)
+{
+ if (!CurChannel)
+ throw CoreException("WriteChannelMetadata without a channel to write");
+
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_cs_info_metadata` (channel, name, value) VALUES(" << mysqlpp::quote << CurChannel->name << ", " << mysqlpp::quote << key << ", " << mysqlpp::quote << data << ")";
+ ExecuteQuery(query);
+}
+
+static void SaveDatabases()
+{
+ int i;
+ mysqlpp::Query query(Me->Con);
+
+ query << "TRUNCATE TABLE `anope_ns_access`";
+ ExecuteQuery(query);
+ query << "TRUNCATE TABLE `anope_ns_core`";
+ ExecuteQuery(query);
+ for (i = 0; i < 1024; ++i)
+ {
+ for (NickCore *nc = nclists[i]; nc; nc = nc->next)
+ {
+ std::string flags = BuildFlagsList(nc);
+ query << "INSERT DELAYED INTO `anope_ns_core` (display, pass, email, greet, icq, url, flags, language, channelcount, memomax) VALUES(";
+ query << mysqlpp::quote << nc->display << ", " << mysqlpp::quote << nc->pass << ", ";
+ query << mysqlpp::quote << (nc->email ? nc->email : "") << ", " << mysqlpp::quote << (nc->greet ? nc->greet : "");
+ query << ", " << nc->icq << ", " << mysqlpp::quote << (nc->url ? nc->url : "");
+ query << ", '" << (!flags.empty() ? flags : "") << "', " << nc->language << ", " << nc->channelcount << ", ";
+ query << nc->memos.memomax << ") ";
+ query << "ON DUPLICATE KEY UPDATE pass=VALUES(pass), email=VALUES(email), greet=VALUES(greet), icq=VALUES(icq), flags=VALUES(flags), language=VALUES(language), ";
+ query << "channelcount=VALUES(channelcount), memomax=VALUES(memomax)";
+ ExecuteQuery(query);
+
+ for (std::vector<std::string>::iterator it = nc->access.begin(); it != nc->access.end(); ++it)
+ {
+ query << "INSERT DELAYED INTO `anope_ns_access` (display, access) VALUES(" << mysqlpp::quote << nc->display << ", " << mysqlpp::quote << *it << ")";
+ ExecuteQuery(query);
+ }
+ }
+ }
+
+ query << "TRUNCATE TABLE `anope_ns_alias`";
+ ExecuteQuery(query);
+ for (i = 0; i < 1024; ++i)
+ {
+ for (NickAlias *na = nalists[i]; na; na = na->next)
+ {
+ std::string flags = BuildFlagsList(na);
+ query << "INSERT DELAYED INTO `anope_ns_alias` (nick, last_quit, last_realname, last_usermask, time_registered, last_seen, flags, display) VALUES(";
+ query << mysqlpp::quote << na->nick << ", " << mysqlpp::quote << (na->last_quit ? na->last_quit : "") << ", ";
+ query << mysqlpp::quote << (na->last_realname ? na->last_realname : "") << ", ";
+ query << mysqlpp::quote << (na->last_usermask ? na->last_usermask : "") << ", " << na->time_registered << ", " << na->last_seen;
+ query << ", '" << (!flags.empty() ? flags : "") << "', " << mysqlpp::quote << na->nc->display << ") ";
+ query << "ON DUPLICATE KEY UPDATE last_quit=VALUES(last_quit), last_realname=VALUES(last_realname), last_usermask=VALUES(last_usermask), time_registered=VALUES(time_registered), last_seen=VALUES(last_seen), flags=VALUES(flags), display=VALUES(display)";
+ ExecuteQuery(query);
+ }
+ }
+
+ query << "TRUNCATE TABLE `anope_bs_core`";
+ ExecuteQuery(query);
+ for (i = 0; i < 256; ++i)
+ {
+ for (BotInfo *bi = botlists[i]; bi; bi = bi->next)
+ {
+ query << "INSERT DELAYED INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(";
+ query << mysqlpp::quote << bi->nick << ", " << mysqlpp::quote << bi->user << ", " << mysqlpp::quote << bi->host << ", ";
+ query << mysqlpp::quote << bi->real << ", '" << GetBotServFlags(bi) << "', " << bi->created << ", " << bi->chancount << ") ";
+ query << "ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)";
+ ExecuteQuery(query);
+ }
+ }
+
+ query << "TRUNCATE TABLE `anope_cs_info`";
+ ExecuteQuery(query);
+ query << "TRUNCATE TABLE `anope_cs_access`";
+ ExecuteQuery(query);
+
+ for (i = 0; i < 256; ++i)
+ {
+ for (ChannelInfo *ci = chanlists[i]; ci; ci = ci->next)
+ {
+ std::string flags = BuildFlagsList(ci), mlockon = GetMLockOn(ci), mlockoff = GetMLockOff(ci), mlockparams = GetMLockParams(ci);
+ query << "INSERT DELAYED INTO `anope_cs_info` (name, founder, successor, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, forbidby, forbidreason, bantype, mlock_on, mlock_off, mlock_params, entry_message, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES(";
+ query << mysqlpp::quote << ci->name << ", " << mysqlpp::quote << (ci->founder ? ci->founder->display : "") << ", ";
+ query << mysqlpp::quote << (ci->successor ? ci->successor->display : "") << ", " << mysqlpp::quote << ci->desc << ", ";
+ query << mysqlpp::quote << (ci->url ? ci->url : "") << ", " << mysqlpp::quote << (ci->email ? ci->email : "") << ", ";
+ query << ci->time_registered << ", " << ci->last_used << ", " << mysqlpp::quote << (ci->last_topic ? ci->last_topic : "");
+ query << ", " << mysqlpp::quote << (!ci->last_topic_setter.empty() ? ci->last_topic_setter : "");
+ query << ", " << ci->last_topic_time << ", '" << (!flags.empty() ? flags : "") << "', ";
+ query << mysqlpp::quote << (ci->forbidby ? ci->forbidby : "") << ", " << mysqlpp::quote << (ci->forbidreason ? ci->forbidreason : "") << ", " << ci->bantype << ", '";
+ query << mlockon << "', '" << mlockoff << "', '";
+ query << mlockparams << "', " << mysqlpp::quote << (ci->entry_message ? ci->entry_message : "") << ", ";
+ query << ci->memos.memomax << ", " << mysqlpp::quote << (ci->bi ? ci->bi->nick : "") << ", '" << GetBotFlags(ci->botflags);
+ query << "', " << ci->capsmin << ", " << ci->capspercent << ", " << ci->floodlines;
+ query << ", " << ci->floodsecs << ", " << ci->repeattimes << ") ";
+ query << "ON DUPLICATE KEY UPDATE founder=VALUES(founder), successor=VALUES(successor), descr=VALUES(descr), url=VALUES(url), email=VALUES(email), time_registered=VALUES(time_registered), last_used=VALUES(last_used), last_topic=VALUES(last_topic), last_topic_setter=VALUES(last_topic_setter), last_topic_time=VALUES(last_topic_time), flags=VALUES(flags), forbidby=VALUES(forbidby), forbidreason=VALUES(forbidreason), bantype=VALUES(bantype), mlock_on=VALUES(mlock_on), mlock_off=VALUES(mlock_off), mlock_params=VALUES(mlock_params), entry_message=VALUES(entry_message), memomax=VALUES(memomax), botnick=VALUES(botnick), botflags=VALUES(botflags), capsmin=VALUES(capsmin), capspercent=VALUES(capspercent), floodlines=VALUES(floodlines), floodsecs=VALUES(floodsecs), repeattimes=VALUES(repeattimes)";
+ ExecuteQuery(query);
+
+ for (unsigned j = 0; j < ci->GetAccessCount(); ++j)
+ {
+ ChanAccess *access = ci->GetAccess(j);
+
+ if (access->in_use)
+ {
+ query << "INSERT DELAYED INTO `anope_cs_access` (level, display, channel, last_seen, creator) VALUES('" << access->level << "', " << mysqlpp::quote << access->nc->display << ", " << mysqlpp::quote << ci->name << ", " << access->last_seen << ", " << mysqlpp::quote << access->creator << ") ON DUPLICATE KEY UPDATE level=VALUES(level), last_seen=VALUES(last_seen), creator=VALUES(creator)";
+ ExecuteQuery(query);
+ }
+ }
+
+ query << "TRUNCATE TABLE `anope_cs_levels`";
+ ExecuteQuery(query);
+ for (int k = 0; k < CA_SIZE; ++k)
+ {
+ query << "INSERT DELAYED INTO `anope_cs_levels` (channel, position, level) VALUES(" << mysqlpp::quote << ci->name << ", '" << k << "', '" << ci->levels[k] << "') ON DUPLICATE KEY UPDATE position=VALUES(position), level=VALUES(level)";
+ ExecuteQuery(query);
+ }
+ }
+ }
+
+ query << "TRUNCATE TABLE `anope_ns_request`";
+ ExecuteQuery(query);
+
+ for (i = 0; i < 1024; i++)
+ {
+ for (NickRequest *nr = nrlists[i]; nr; nr = nr->next)
+ {
+ query << "INSERT DELAYED INTO `anope_ns_request` (nick, passcode, password, email, requested) VALUES(" << mysqlpp::quote << nr->nick << ", '" << nr->passcode << "', '" << nr->password << "', " << mysqlpp::quote << nr->email << ", '" << nr->requested << "') ON DUPLICATE KEY UPDATE passcode=VALUES(passcode), pasword=VALUES(password), email=VALUES(email), requests=VALUES(requested)";
+ ExecuteQuery(query);
+ }
+ }
+}
+
+class CommandSyncSQL : public Command
+{
+ public:
+ CommandSyncSQL(const std::string &cname) : Command(cname, 0, 0)
+ {
+ }
+
+ CommandReturn Execute(User *u, const std::vector<ci::string> &params)
+ {
+ notice_lang(Config.s_OperServ, u, MYSQL_SYNC_UPDATING);
+ SaveDatabases();
+ notice_lang(Config.s_OperServ, u, MYSQL_SYNC_UPDATED);
+ return MOD_CONT;
+ }
+};
+
+class DBMySQLWrite : public DBMySQL
+{
+ public:
+ DBMySQLWrite(const std::string &modname, const std::string &creator) : DBMySQL(modname, creator)
+ {
+ ModuleManager::Attach(I_OnServerConnect, this);
+
+ this->AddCommand(OPERSERV, new CommandSyncSQL("SQLSYNC"));
+ }
+
+ ~DBMySQLWrite()
+ {
+ }
+
+ void OnServerConnect()
+ {
+ Implementation i[] = {
+ /* Misc */
+ I_OnSaveDatabase, I_OnPostCommand,
+ /* NickServ */
+ I_OnNickAddAccess, I_OnNickEraseAccess, I_OnNickClearAccess,
+ I_OnDelCore, I_OnNickForbidden, I_OnNickGroup, I_OnMakeNickRequest,
+ I_OnDelNickRequest, I_OnNickRegister, I_OnChangeCoreDisplay,
+ I_OnNickSuspended,
+ /* Chanserv */
+ I_OnAccessAdd, I_OnAccessDel, I_OnAccessChange, I_OnAccessClear,
+ I_OnChanForbidden, I_OnDelChan, I_OnChanRegistered, I_OnChanSuspend,
+ /* BotServ */
+ I_OnBotCreate, I_OnBotChange, I_OnBotDelete,
+ I_OnBotAssign, I_OnBotUnAssign
+ };
+ ModuleManager::Attach(i, this, 26);
+ }
+
+ EventReturn OnSaveDatabase()
+ {
+ for (int i = 0; i < 1024; ++i)
+ {
+ for (NickCore *nc = nclists[i]; nc; nc = nc->next)
+ {
+ CurCore = nc;
+ FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteCoreMetadata, nc));
+ }
+ }
+
+ for (int i = 0; i < 1024; ++i)
+ {
+ for (NickAlias *na = nalists[i]; na; na = na->next)
+ {
+ CurNick = na;
+ FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteNickMetadata, na));
+ }
+ }
+
+ for (int i = 0; i < 256; ++i)
+ {
+ for (ChannelInfo *ci = chanlists[i]; ci; ci = ci->next)
+ {
+ CurChannel = ci;
+ FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteChannelMetadata, ci));
+ }
+ }
+
+ FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write));
+
+ return EVENT_CONTINUE;
+ }
+
+ void OnPostCommand(User *u, const std::string &service, const ci::string &command, const std::vector<ci::string> &params)
+ {
+ mysqlpp::Query query(Me->Con);
+
+ if (service == Config.s_NickServ)
+ {
+ if (u->Account() && ((command == "SET" && !params.empty()) || (command == "SASET" && u->Account()->HasCommand("nickserv/saset") && params.size() > 1)))
+ {
+ ci::string cmd = (command == "SET" ? params[0] : params[1]);
+ NickCore *nc = (command == "SET" ? u->Account() : findcore(params[0].c_str()));
+ if (!nc)
+ return;
+ if (cmd == "PASSWORD" && params.size() > 1)
+ {
+ query << "UPDATE `anope_ns_core` SET `password` = " << mysqlpp::quote << nc->pass << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "LANGUAGE" && params.size() > 1)
+ {
+ query << "UPDATE `anope_ns_core` SET `language` = " << nc->language << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "URL")
+ {
+ query << "UPDATE `anope_ns_core` SET `url` = " << mysqlpp::quote << nc->url << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "EMAIL")
+ {
+ query << "UPDATE `anope_ns_core` SET `email` = " << mysqlpp::quote << nc->email << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "ICQ")
+ {
+ query << "UPDATE `anope_ns_core` SET `icq` = " << nc->icq << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "GREET")
+ {
+ query << "UPDATE `anope_ns_core` SET `greet` = " << mysqlpp::quote << nc->greet << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ else if (cmd == "KILL" || cmd == "SECURE" || cmd == "PRIVATE" || cmd == "MSG" || cmd == "HIDE" || cmd == "AUTOOP")
+ {
+ query << "UPDATE `anope_ns_core` SET `flags` = " << BuildFlagsList(nc) << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+ }
+ }
+ else if (service == Config.s_ChanServ)
+ {
+ if (command == "SET" && u->Account() && params.size() > 1)
+ {
+ ChannelInfo *ci = cs_findchan(params[0].c_str());
+ if (!ci)
+ return;
+ if (!u->Account()->HasPriv("chanserv/set") && check_access(u, ci, CA_SET))
+ return;
+ if (params[1] == "FOUNDER" && ci->founder)
+ {
+ query << "UPDATE `anope_cs_info` SET `founder` = " << mysqlpp::quote << ci->founder->display << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "SUCCESSOR")
+ {
+ query << "UPDATE `anope_cs_info` SET `successor` = " << mysqlpp::quote << (ci->successor ? ci->successor->display : "") << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "DESC")
+ {
+ query << "UPDATE `anope_cs_info` SET `descr` = " << mysqlpp::quote << ci->desc << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "URL")
+ {
+ query << "UPDATE `anope_cs_info` SET `url` = " << mysqlpp::quote << ci->url << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "EMAIL")
+ {
+ query << "UPDATE `anope_cs_info` SET `email` = " << mysqlpp::quote << ci->email << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "ENTRYMSG")
+ {
+ query << "UPDATE `anope_cs_info` SET `entry_message` = " << mysqlpp::quote << ci->entry_message << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "MLOCK")
+ {
+ query << "UPDATE `anope_cs_info` SET `mlock_on` = '" << GetMLockOn(ci) << "' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `mlock_off` = '" << GetMLockOff(ci) << "' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `mlock_params` = '" << GetMLockParams(ci) << "' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "BANTYPE")
+ {
+ query << "UPDATE `anope_cs_info` SET `bantype` = " << ci->bantype << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ else if (params[1] == "KEEPTOPIC" || params[1] == "TOPICLOCK" || params[1] == "PRIVATE" || params[1] == "SECUREOPS" || params[1] == "SECUREFOUNDER" || params[1] == "RESTRICTED" || params[1] == "SECURE" || params[1] == "SIGNKICK" || params[1] == "OPNOTICE" || params[1] == "XOP" || params[1] == "PEACE" || params[1] == "PERSIST" || params[1] == "NOEXPIRE")
+ {
+ query << "UPDATE `anope_cs_info` SET `flags` = '" << BuildFlagsList(ci) << "' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+ }
+ }
+ }
+
+ void OnNickAddAccess(NickCore *nc, const std::string &entry)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_ns_access` (display, access) VALUES(" << mysqlpp::quote << nc->display << ", " << mysqlpp::quote << entry << ")";
+ ExecuteQuery(query);
+ }
+
+ void OnNickEraseAccess(NickCore *nc, const std::string &entry)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_ns_access` WHERE `display` = " << mysqlpp::quote << nc->display << " AND `access` = " << mysqlpp::quote << entry;
+ ExecuteQuery(query);
+ }
+
+ void OnNickClearAccess(NickCore *nc)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_ns_access` WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+
+ void OnDelCore(NickCore *nc)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_cs_access` WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "DELETE FROM `anope_ns_access` WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "DELETE FROM `anope_ns_alias` WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "DELETE FROM `anope_ns_core` WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+
+ void OnNickForbidden(NickAlias *na)
+ {
+ std::string flags = BuildFlagsList(na);
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_ns_alias` SET `flags` = '" << (!flags.empty() ? flags : "") << "' WHERE `nick` = " << mysqlpp::quote << na->nick;
+ ExecuteQuery(query);
+ }
+
+ void OnNickGroup(User *u, NickAlias *)
+ {
+ OnNickRegister(findnick(u->nick));
+ }
+
+ void OnMakeNickRequest(NickRequest *nr)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_ns_request` (nick, passcode, password, email, requested) VALUES(" << mysqlpp::quote << nr->nick << ", ";
+ query << mysqlpp::quote << nr->passcode << ", " << mysqlpp::quote << nr->password << ", " << mysqlpp::quote << nr->email << ", '";
+ query << nr->requested << "')";
+ ExecuteQuery(query);
+ }
+
+ void OnDelNickRequest(NickRequest *nr)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_ns_request` WHERE `nick` = " << mysqlpp::quote << nr->nick;
+ ExecuteQuery(query);
+ }
+
+ void OnNickRegister(NickAlias *na)
+ {
+ std::string flags = BuildFlagsList(na);
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_ns_alias` (nick, last_quit, last_realname, last_usermask, time_registered, last_seen, flags, display) VALUES(";
+ query << mysqlpp::quote << na->nick << ", " << mysqlpp::quote << (na->last_quit ? na->last_quit : "") << ", ";
+ query << mysqlpp::quote << (na->last_realname ? na->last_realname : "") << ", ";
+ query << mysqlpp::quote << (na->last_usermask ? na->last_usermask : "") << ", " << na->time_registered << ", " << na->last_seen;
+ query << ", '" << (!flags.empty() ? flags : "") << "', " << mysqlpp::quote << na->nc->display << ") ";
+ query << "ON DUPLICATE KEY UPDATE last_quit=VALUES(last_quit), last_realname=VALUES(last_realname), last_usermask=VALUES(last_usermask), time_registered=VALUES(time_registered), last_seen=VALUES(last_seen), flags=VALUES(flags), display=VALUES(display)";
+ ExecuteQuery(query);
+
+ flags = BuildFlagsList(na->nc);
+ query << "INSERT DELAYED INTO `anope_ns_core` (display, pass, email, greet, icq, url, flags, language, channelcount, memomax) VALUES(";
+ query << mysqlpp::quote << na->nc->display << ", " << mysqlpp::quote << na->nc->pass << ", ";
+ query << mysqlpp::quote << (na->nc->email ? na->nc->email : "") << ", " << mysqlpp::quote << (na->nc->greet ? na->nc->greet : "");
+ query << ", " << na->nc->icq << ", " << mysqlpp::quote << (na->nc->url ? na->nc->url : "");
+ query << ", '" << (!flags.empty() ? flags : "") << "', " << na->nc->language << ", " << na->nc->channelcount << ", ";
+ query << na->nc->memos.memomax << ") ";
+ query << "ON DUPLICATE KEY UPDATE pass=VALUES(pass), email=VALUES(email), greet=VALUES(greet), icq=VALUES(icq), flags=VALUES(flags), language=VALUES(language), ";
+ query << "channelcount=VALUES(channelcount), memomax=VALUES(memomax)";
+ ExecuteQuery(query);
+ }
+
+ void OnChangeCoreDisplay(NickCore *nc, const std::string &newdisplay)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_ns_core` SET `display` = " << mysqlpp::quote << newdisplay << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_ns_alias` SET `display` = " << mysqlpp::quote << newdisplay << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_ns_access` SET `display` = " << mysqlpp::quote << newdisplay << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_access` SET `display` = " << mysqlpp::quote << newdisplay << " WHERE `display` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `founder` = " << mysqlpp::quote << newdisplay << " WHERE `founder` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `successor` = " << mysqlpp::quote << newdisplay << " WHERE `successor` = " << mysqlpp::quote << nc->display;
+ ExecuteQuery(query);
+ }
+
+ void OnNickSuspend(NickAlias *na)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_ns_core` SET `flags` = '" << BuildFlagsList(na->nc) << "' WHERE `display` = " << mysqlpp::quote << na->nc->display;
+ ExecuteQuery(query);
+ }
+
+ void OnAccessAdd(ChannelInfo *ci, User *u, NickAlias *na, int level)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_cs_access` (level, display, channel, last_seen, creator) VALUES (" << level << ", " << mysqlpp::quote << na->nc->display << ", " << mysqlpp::quote << ci->name << ", " << time(NULL) << ", " << mysqlpp::quote << u->nick << ")";
+ ExecuteQuery(query);
+ }
+
+ void OnAccessDel(ChannelInfo *ci, User *u, NickCore *nc)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_cs_access` WHERE `display` = " << mysqlpp::quote << nc->display << " AND `channel` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+
+ void OnAccessChange(ChannelInfo *ci, User *u, NickAlias *na, int level)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_cs_access` (level, display, channel, last_seen, creator) VALUES (" << level << ", " << mysqlpp::quote << na->nc->display << ", " << mysqlpp::quote << ci->name << ", " << time(NULL) << ", " << mysqlpp::quote << u->nick << ") ON DUPLICATE KEY UPDATE level=VALUES(level), display=VALUES(display), channel=VALUES(channel), last_seen=VALUES(last_seen), creator=VALUES(creator)";
+ ExecuteQuery(query);
+ }
+
+ void OnAccessClear(ChannelInfo *ci, User *u)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_cs_access` WHERE `channel` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+
+ void OnChanForbidden(ChannelInfo *ci)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_cs_info` (name, time_registered, last_used, flags, forbidby, forbidreason) VALUES (";
+ query << mysqlpp::quote << ci->name << ", " << ci->time_registered << ", " << ci->last_used << ", '" << BuildFlagsList(ci) << "', " << mysqlpp::quote << ci->forbidby << ", " << mysqlpp::quote << ci->forbidreason << ")";
+ ExecuteQuery(query);
+ }
+
+ void OnDelChan(ChannelInfo *ci)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_cs_access` WHERE `channel` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "DELETE FROM `anope_cs_info` WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "DELETE FROM `anope_cs_levels` WHERE `channel` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+
+ void OnChanRegistered(ChannelInfo *ci)
+ {
+ mysqlpp::Query query(Me->Con);
+ std::string flags = BuildFlagsList(ci), mlockon = GetMLockOn(ci), mlockoff = GetMLockOff(ci), mlockparams = GetMLockParams(ci);
+ query << "INSERT DELAYED INTO `anope_cs_info` (name, founder, successor, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, forbidby, forbidreason, bantype, mlock_on, mlock_off, mlock_params, entry_message, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES(";
+ query << mysqlpp::quote << ci->name << ", " << mysqlpp::quote << (ci->founder ? ci->founder->display : "") << ", ";
+ query << mysqlpp::quote << (ci->successor ? ci->successor->display : "") << ", " << mysqlpp::quote << ci->desc << ", ";
+ query << mysqlpp::quote << (ci->url ? ci->url : "") << ", " << mysqlpp::quote << (ci->email ? ci->email : "") << ", ";
+ query << ci->time_registered << ", " << ci->last_used << ", " << mysqlpp::quote << (ci->last_topic ? ci->last_topic : "");
+ query << ", " << mysqlpp::quote << (!ci->last_topic_setter.empty() ? ci->last_topic_setter : "");
+ query << ", " << ci->last_topic_time << ", '" << (!flags.empty() ? flags : "") << "', ";
+ query << mysqlpp::quote << (ci->forbidby ? ci->forbidby : "") << ", " << mysqlpp::quote << (ci->forbidreason ? ci->forbidreason : "") << ", " << ci->bantype << ", '";
+ query << mlockon << "', '" << mlockoff << "', '";
+ query << mlockparams << "', " << mysqlpp::quote << (ci->entry_message ? ci->entry_message : "") << ", ";
+ query << ci->memos.memomax << ", " << mysqlpp::quote << (ci->bi ? ci->bi->nick : "") << ", '" << GetBotFlags(ci->botflags);
+ query << "', " << ci->capsmin << ", " << ci->capspercent << ", " << ci->floodlines;
+ query << ", " << ci->floodsecs << ", " << ci->repeattimes << ") ";
+ query << "ON DUPLICATE KEY UPDATE founder=VALUES(founder), successor=VALUES(successor), descr=VALUES(descr), url=VALUES(url), email=VALUES(email), time_registered=VALUES(time_registered), last_used=VALUES(last_used), last_topic=VALUES(last_topic), last_topic_setter=VALUES(last_topic_setter), last_topic_time=VALUES(last_topic_time), flags=VALUES(flags), forbidby=VALUES(forbidby), forbidreason=VALUES(forbidreason), bantype=VALUES(bantype), mlock_on=VALUES(mlock_on), mlock_off=VALUES(mlock_off), mlock_params=VALUES(mlock_params), entry_message=VALUES(entry_message), memomax=VALUES(memomax), botnick=VALUES(botnick), botflags=VALUES(botflags), capsmin=VALUES(capsmin), capspercent=VALUES(capspercent), floodlines=VALUES(floodlines), floodsecs=VALUES(floodsecs), repeattimes=VALUES(repeattimes)";
+ ExecuteQuery(query);
+ }
+
+ void OnChanSuspend(ChannelInfo *ci)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_cs_info` SET `flags` = '" << BuildFlagsList(ci) << "' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `forbidby` = " << mysqlpp::quote << ci->forbidby << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `forbidreason` = " << mysqlpp::quote << ci->forbidreason << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ }
+
+ void OnBotCreate(BotInfo *bi)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "INSERT DELAYED INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(";
+ query << mysqlpp::quote << bi->nick << ", " << mysqlpp::quote << bi->user << ", " << mysqlpp::quote << bi->host << ", ";
+ query << mysqlpp::quote << bi->real << ", '" << GetBotServFlags(bi) << "', " << bi->created << ", " << bi->chancount << ") ";
+ query << "ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)";
+ ExecuteQuery(query);
+ }
+
+ void OnBotChange(BotInfo *bi)
+ {
+ OnBotCreate(bi);
+ }
+
+ void OnBotDelete(BotInfo *bi)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "DELETE FROM `anope_bs_core` WHERE `nick` = " << mysqlpp::quote << bi->nick;
+ ExecuteQuery(query);
+ query << "UPDATE `anope_cs_info` SET `botnick` = '' WHERE `botnick` = " << mysqlpp::quote << bi->nick;
+ ExecuteQuery(query);
+ }
+
+ EventReturn OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_cs_info` SET `botnick` = " << mysqlpp::quote << bi->nick << " WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ return EVENT_CONTINUE;
+ }
+
+ EventReturn OnBotUnAssign(User *sender, ChannelInfo *ci)
+ {
+ mysqlpp::Query query(Me->Con);
+ query << "UPDATE `anope_cs_info` SET `botnick` = '' WHERE `name` = " << mysqlpp::quote << ci->name;
+ ExecuteQuery(query);
+ return EVENT_CONTINUE;
+ }
+};
+
+MODULE_INIT(DBMySQLWrite)
+
diff --git a/src/nickcore.cpp b/src/nickcore.cpp
index fc46cd6d4..84761ed79 100644
--- a/src/nickcore.cpp
+++ b/src/nickcore.cpp
@@ -62,6 +62,9 @@ NickCore::~NickCore()
/* Log .. */
Alog() << Config.s_NickServ << ": deleting nickname group " << this->display;
+ /* Clear access before deleting display name, we want to be able to use the display name in the clear access event */
+ this->ClearAccess();
+
/* Now we can safely free it. */
delete [] this->display;
@@ -72,8 +75,6 @@ NickCore::~NickCore()
if (this->url)
delete [] this->url;
- this->ClearAccess();
-
if (!this->memos.memos.empty())
{
for (unsigned i = 0; i < this->memos.memos.size(); ++i)
@@ -119,6 +120,7 @@ bool NickCore::HasPriv(const std::string &privstr) const
void NickCore::AddAccess(const std::string &entry)
{
access.push_back(entry);
+ FOREACH_MOD(I_OnNickAddAccess, OnNickAddAccess(this, entry));
}
std::string NickCore::GetAccess(unsigned entry)