diff options
author | sjaz <sjaz@5417fbe8-f217-4b02-8779-1006273d7864> | 2009-01-01 12:00:20 +0000 |
---|---|---|
committer | sjaz <sjaz@5417fbe8-f217-4b02-8779-1006273d7864> | 2009-01-01 12:00:20 +0000 |
commit | c777c8d9aa7cd5c2e9a399727a7fa9985a77fb1c (patch) | |
tree | 9e996ae4a1bbb833cec036c5cd4d87a590149e85 /src/mysql.c |
Anope Stable Branch
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/stable@1902 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src/mysql.c')
-rw-r--r-- | src/mysql.c | 2058 |
1 files changed, 2058 insertions, 0 deletions
diff --git a/src/mysql.c b/src/mysql.c new file mode 100644 index 000000000..c4db94252 --- /dev/null +++ b/src/mysql.c @@ -0,0 +1,2058 @@ + +/* MySQL functions. + * + * (C) 2003-2008 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * $Id$ + * + */ +#include "services.h" + +/*************************************************************************/ + +/* Database Global Variables */ +MYSQL *mysql; /* MySQL Handler */ +MYSQL_RES *mysql_res; /* MySQL Result */ +MYSQL_FIELD *mysql_fields; /* MySQL Fields */ +MYSQL_ROW mysql_row; /* MySQL Row */ + +int mysql_is_connected = 0; /* Are we currently connected? */ + +/*************************************************************************/ + +/* Throw a mysql error into the logs. If severity is MYSQL_ERROR, we + * also exit Anope... + */ +void db_mysql_error(int severity, char *msg) +{ + static char buf[512]; + + if (mysql_error(mysql)) { + snprintf(buf, sizeof(buf), "MySQL %s %s: %s", msg, + severity == MYSQL_WARNING ? "warning" : "error", + mysql_error(mysql)); + } else { + snprintf(buf, sizeof(buf), "MySQL %s %s", msg, + severity == MYSQL_WARNING ? "warning" : "error"); + } + + log_perror(buf); + + if (severity == MYSQL_ERROR) { + log_perror("MySQL FATAL error... aborting."); + exit(0); + } + +} + +/*************************************************************************/ + +/* Initialize the MySQL code */ +int db_mysql_init() +{ + + /* If the host is not defined, assume we don't want MySQL */ + if (!MysqlHost) { + do_mysql = 0; + alog("MySQL: has been disabled."); + return 0; + } else { + do_mysql = 1; + alog("MySQL: has been enabled."); + alog("MySQL: client version %s.", mysql_get_client_info()); + } + + /* The following configuration options are required. + * If missing disable MySQL to avoid any problems. + */ + + if ((do_mysql) && (!MysqlName || !MysqlUser)) { + do_mysql = 0; + alog("MySQL Error: Set all required configuration options."); + return 0; + } + + if (!db_mysql_open()) { + do_mysql = 0; + return 0; + } + + return 1; +} + +/*************************************************************************/ + +/* Open a connection to the mysql database. Return 0 on failure, or + * 1 on success. If this succeeds, we're guaranteed of a working + * mysql connection (unless something unexpected happens ofcourse...) + */ +int db_mysql_open() +{ + /* If MySQL is disabled, return 0 */ + if (!do_mysql) + return 0; + + /* If we are reported to be connected, ping MySQL to see if we really are + * still connected. (yes mysql_ping() returns 0 on success) + */ + if (mysql_is_connected && !mysql_ping(mysql)) + return 1; + + mysql_is_connected = 0; + + mysql = mysql_init(NULL); + if (mysql == NULL) { + db_mysql_error(MYSQL_WARNING, "Unable to create mysql object"); + return 0; + } + + if (!MysqlPort) + MysqlPort = MYSQL_DEFAULT_PORT; + + if (!mysql_real_connect(mysql, MysqlHost, MysqlUser, MysqlPass, MysqlName, MysqlPort, MysqlSock, 0)) { + log_perror("MySQL Error: Cant connect to MySQL: %s\n", mysql_error(mysql)); + return 0; + } + + mysql_is_connected = 1; + + return 1; + +} + + +/*************************************************************************/ + +/* Perform a MySQL query. Return 1 if the query succeeded and 0 if the + * query failed. Before returning failure, re-try the query a few times + * and die if it still fails. + */ +int db_mysql_query(char *sql) +{ + int lcv; + + if (!do_mysql) + return 0; + + if (debug) + alog("debug: MySQL: %s", sql); + + /* Try as many times as configured in MysqlRetries */ + for (lcv = 0; lcv < MysqlRetries; lcv++) { + if (db_mysql_open() && (mysql_query(mysql, sql) == 0)) + return 1; + + /* If we get here, we could not run the query */ + log_perror("Unable to run query: %s\n", mysql_error(mysql)); + + /* Wait for MysqlRetryGap seconds and try again */ + sleep(MysqlRetryGap); + } + + /* Unable to run the query even after MysqlRetries tries */ + db_mysql_error(MYSQL_WARNING, "query"); + + return 0; + +} + +/*************************************************************************/ + +/* Quote a string to be safely included in a query. The result of this + * function is allocated; it MUST be freed by the caller. + */ +char *db_mysql_quote(char *sql) +{ + int slen; + char *quoted; + + + if (!sql) + return sstrdup(""); + + slen = strlen(sql); + quoted = malloc((1 + (slen * 2)) * sizeof(char)); + + mysql_real_escape_string(mysql, quoted, sql, slen); + + return quoted; + +} + +/** + * Quote a buffer to be safely included in a query. + * The result is allocated and needs to be freed by caller. + **/ +char *db_mysql_quote_buffer(char *sql, int size) +{ + char *ret; + ret = scalloc((1 + 2 * size), sizeof(char)); + + mysql_real_escape_string(mysql, ret, sql, size); + + return ret; +} + +/*************************************************************************/ + +/* Close the MySQL database connection. */ +int db_mysql_close() +{ + mysql_close(mysql); + + mysql_is_connected = 0; + + return 1; +} + +/*************************************************************************/ + +/* Try to execute a query and issue a warning when failed. Return 1 on + * success and 0 on failure. + */ +int db_mysql_try(const char *fmt, ...) +{ + va_list args; + static char sql[MAX_SQL_BUF]; + + va_start(args, fmt); + vsnprintf(sql, MAX_SQL_BUF, fmt, args); + va_end(args); + + if (!db_mysql_query(sql)) { + log_perror("Can't create sql query: %s", sql); + db_mysql_error(MYSQL_WARNING, "query"); + return 0; + } + + return 1; +} + +/*************************************************************************/ + +/** + * Returns a string (buffer) to insert into a SQL query. + * The string will, once evaluated by MySQL, result in the given pass + * encoded in the encryption type selected for MysqlSecure + * + * This should be removed since Rob properly did encryption modules... -GD + * + * @param dest Destination buffer to store the password/ encryption string in. Needs to be at least size+14. + * @param pass The buffer containing the password to secure. + * @param bufsize The size of the destination buffer. + * @param size The size of the password-to-secure buffer. + * @return Returns -1 on failure, 1 if the result needs to be made MySQL safe (hash), 0 if it s ready. + **/ +int db_mysql_secure(char *dest, char *pass, int bufsize, int size) +{ + char tmp_pass[PASSMAX]; + + if (bufsize < size+14) + return -1; + + /* Initialize the buffer. Bug #86 */ + memset(tmp_pass, 0, PASSMAX); + memset(dest, 0, bufsize); + + /* Return all zeros if no pass is set. */ + if (!pass) + return 1; + + /* We couldnt decrypt the pass... */ + if (enc_decrypt(pass, tmp_pass, PASSMAX - 1) != 1) { + memcpy(dest, pass, size); + return 1; + } else { /* if we could decrypt the pass */ + if ((!MysqlSecure) || (strcmp(MysqlSecure, "") == 0)) { + snprintf(dest, bufsize, "'%s'", tmp_pass); + } else if (strcmp(MysqlSecure, "des") == 0) { + snprintf(dest, bufsize, "ENCRYPT('%s')", tmp_pass); + } else if (strcmp(MysqlSecure, "md5") == 0) { + snprintf(dest, bufsize, "MD5('%s')", tmp_pass); + } else if (strcmp(MysqlSecure, "sha") == 0) { + snprintf(dest, bufsize, "SHA('%s')", tmp_pass); + } else { + snprintf(dest, bufsize, "ENCODE('%s','%s')", tmp_pass, + MysqlSecure); + } + } + + return 0; +} + +/*************************************************************************/ + +/* + * NickServ Specific Secion + */ + +/*************************************************************************/ + +/* Save the given NickRequest into the database + * Return 1 on success, 0 on failure + * These tables are tagged and will be cleaned: + * - anope_ns_request + */ +int db_mysql_save_ns_req(NickRequest * nr) +{ + int ret; + char *q_nick, *q_passcode, *q_password, *q_email; + + q_nick = db_mysql_quote(nr->nick); + q_passcode = db_mysql_quote(nr->passcode); + q_password = db_mysql_quote_buffer(nr->password, PASSMAX); + q_email = db_mysql_quote(nr->email); + + ret = db_mysql_try("UPDATE anope_ns_request " + "SET passcode = '%s', password = '%s', email = '%s', requested = %d, active = 1 " + "WHERE nick = '%s'", + q_passcode, q_password, q_email, (int) nr->requested, + q_nick); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_ns_request " + "(nick, passcode, password, email, requested, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, 1)", + q_nick, q_passcode, q_password, q_email, + (int) nr->requested); + } + + free(q_nick); + free(q_passcode); + free(q_password); + free(q_email); + + return ret; +} + +/*************************************************************************/ + +/* Save the given NickCore into the database + * Also save the access list and memo's for this user + * Return 1 on success, 0 on failure + * These tables are tagged and will be cleaned: + * - anope_ns_core + * - anope_ns_alias + * - anope_ns_access + * - anope_ms_info (serv='NICK') + */ +int db_mysql_save_ns_core(NickCore * nc) +{ + int ret, res; + int i; + char epass[PASSMAX+15]; + char *q_display, *q_pass = NULL, *q_email, *q_greet, *q_url, + *q_access, *q_sender, *q_text; + + q_display = db_mysql_quote(nc->display); + q_email = db_mysql_quote(nc->email); + q_greet = db_mysql_quote(nc->greet); + q_url = db_mysql_quote(nc->url); + + /* First secure the pass, then make it MySQL safe.. - Viper */ + res = db_mysql_secure(epass, nc->pass, PASSMAX+15, PASSMAX); + if (res < 0) + fatal("Unable to encrypt password for MySQL"); + else if (res) + q_pass = db_mysql_quote_buffer(epass, PASSMAX+15); + else { + q_pass = scalloc(PASSMAX+15,sizeof(char)); + memcpy(q_pass, epass, PASSMAX+15); + } + + /* If it has been made MySQL safe, it still needs the 's. + * I know it s an ugly solution, but it works without breaking anything.. - Viper */ + /* Let's take care of the core itself */ + /* Update the existing records */ + if (res) + ret = db_mysql_try("UPDATE anope_ns_core " + "SET pass = '%s', email = '%s', greet = '%s', icq = %d, url = '%s', flags = %d, language = %d, accesscount = %d, memocount = %d, " + " memomax = %d, channelcount = %d, channelmax = %d, active = 1 " + "WHERE display = '%s'", + q_pass, q_email, q_greet, nc->icq, q_url, nc->flags, + nc->language, nc->accesscount, nc->memos.memocount, + nc->memos.memomax, nc->channelcount, nc->channelmax, + q_display); + else + ret = db_mysql_try("UPDATE anope_ns_core " + "SET pass = %s, email = '%s', greet = '%s', icq = %d, url = '%s', flags = %d, language = %d, accesscount = %d, memocount = %d, " + " memomax = %d, channelcount = %d, channelmax = %d, active = 1 " + "WHERE display = '%s'", + q_pass, q_email, q_greet, nc->icq, q_url, nc->flags, + nc->language, nc->accesscount, nc->memos.memocount, + nc->memos.memomax, nc->channelcount, nc->channelmax, + q_display); + + /* Our previous UPDATE affected no rows, therefore this is a new record */ + if (ret && (mysql_affected_rows(mysql) == 0)) { + if (res) + ret = db_mysql_try("INSERT DELAYED INTO anope_ns_core " + "(display, pass, email, greet, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, %d, %d, 1)", + q_display, q_pass, q_email, q_greet, nc->icq, q_url, + nc->flags, nc->language, nc->accesscount, + nc->memos.memocount, nc->memos.memomax, + nc->channelcount, nc->channelmax); + else + ret = db_mysql_try("INSERT DELAYED INTO anope_ns_core " + "(display, pass, email, greet, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, active) " + "VALUES ('%s', %s, '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, %d, %d, 1)", + q_display, q_pass, q_email, q_greet, nc->icq, q_url, + nc->flags, nc->language, nc->accesscount, + nc->memos.memocount, nc->memos.memomax, + nc->channelcount, nc->channelmax); + } + + /* Now let's do the access */ + for (i = 0; ret && (i < nc->accesscount); i++) { + q_access = db_mysql_quote(nc->access[i]); +/** + ret = db_mysql_try("UPDATE anope_ns_access " + "SET access = '%s' " + "WHERE display = '%s'", + q_access, q_display); + + if (ret && (mysql_affected_rows(mysql) == 0)) {**/ + + ret = db_mysql_try("INSERT DELAYED INTO anope_ns_access " + "(display, access) " + "VALUES ('%s','%s')", + q_display, q_access); +/* } */ + + free(q_access); + } + + /* Memos */ + for (i = 0; ret && (i < nc->memos.memocount); i++) { + q_sender = db_mysql_quote(nc->memos.memos[i].sender); + q_text = db_mysql_quote(nc->memos.memos[i].text); + + ret = db_mysql_try("UPDATE anope_ms_info " + "SET receiver = '%s', number = %d, flags = %d, time = %d, sender = '%s', text = '%s', active = 1 " + "WHERE nm_id = %d AND serv = 'NICK'", + q_display, nc->memos.memos[i].number, + nc->memos.memos[i].flags, + (int) nc->memos.memos[i].time, q_sender, q_text, + nc->memos.memos[i].id); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT INTO anope_ms_info " + "(receiver, number, flags, time, sender, text, serv, active) " + "VALUES ('%s', %d, %d, %d, '%s', '%s', 'NICK', 1)", + q_display, nc->memos.memos[i].number, + nc->memos.memos[i].flags, + (int) nc->memos.memos[i].time, q_sender, + q_text); + + /* This is to make sure we can UPDATE memos instead of TRUNCATE + * the table each time and then INSERT them all again. Ideally + * everything in core would have it's dbase-id stored, but that's + * something for phase 3. -GD + */ + if (ret) + nc->memos.memos[i].id = mysql_insert_id(mysql); + } + + free(q_sender); + free(q_text); + } + + free(q_display); + free(q_pass); + free(q_email); + free(q_greet); + free(q_url); + + return ret; +} + + +/*************************************************************************/ + +/* Save the given NickAlias into the database + * Return 1 on success, 0 on failure + * These tables are tagged and will be cleaned: + * - anope_ns_core + * - anope_ns_alias + * - anope_ns_access + * - anope_ms_info (serv='NICK') + */ +int db_mysql_save_ns_alias(NickAlias * na) +{ + int ret; + char *q_nick, *q_lastmask, *q_lastrname, *q_lastquit, *q_display; + + q_nick = db_mysql_quote(na->nick); + q_lastmask = db_mysql_quote(na->last_usermask); + q_lastrname = db_mysql_quote(na->last_realname); + q_lastquit = db_mysql_quote(na->last_quit); + q_display = db_mysql_quote(na->nc->display); + + ret = db_mysql_try("UPDATE anope_ns_alias " + "SET last_usermask = '%s', last_realname = '%s', last_quit = '%s', time_registered = %d, last_seen = %d, status = %d, " + " display = '%s', active = 1 " + "WHERE nick = '%s'", + q_lastmask, q_lastrname, q_lastquit, + (int) na->time_registered, (int) na->last_seen, + (int) na->status, q_display, q_nick); + + /* Our previous UPDATE affected no rows, therefore this is a new record */ + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_ns_alias " + "(nick, last_usermask, last_realname, last_quit, time_registered, last_seen, status, display, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, '%s', 1)", + q_nick, q_lastmask, q_lastrname, q_lastquit, + (int) na->time_registered, (int) na->last_seen, + (int) na->status, q_display); + } + + free(q_nick); + free(q_lastmask); + free(q_lastrname); + free(q_lastquit); + free(q_display); + + return ret; +} + +/*************************************************************************/ + +/* + * ChanServ Specific Secion + */ + +/*************************************************************************/ + +/* Save the given ChannelInfo into the database + * Also save the access list, levels, akicks, badwords, ttb, and memo's for this channel + * Return 1 on success, 0 on failure + * These tables are tagged and will be cleaned: + * - anope_cs_info + * - anope_cs_access + * - anope_cs_levels + * - anope_cs_akicks + * - anope_cs_badwords + * - anope_cs_ttb + * - anope_ms_info (serv='CHAN') + */ +int db_mysql_save_cs_info(ChannelInfo * ci) +{ + int ret, res, i; + char epass[PASSMAX+15]; + char *q_name; + char *q_founder; + char *q_successor; + char *q_pass = NULL; + char *q_desc; + char *q_url; + char *q_email; + char *q_lasttopic; + char *q_lasttopicsetter; + char *q_forbidby; + char *q_forbidreason; + char *q_mlock_key; + char *q_mlock_flood; + char *q_mlock_redirect; + char *q_entrymsg; + char *q_botnick; + char *q_sender; + char *q_text; + char *q_accessdisp; + char *q_akickdisp; + char *q_akickreason; + char *q_akickcreator; + char *q_badwords; + + q_name = db_mysql_quote(ci->name); + if (ci->founder) { + q_founder = db_mysql_quote(ci->founder->display); + } else { + q_founder = db_mysql_quote(""); + } + if (ci->successor) { + q_successor = db_mysql_quote(ci->successor->display); + } else { + q_successor = db_mysql_quote(""); + } + q_desc = db_mysql_quote(ci->desc); + q_url = db_mysql_quote(ci->url); + q_email = db_mysql_quote(ci->email); + q_lasttopic = db_mysql_quote(ci->last_topic); + q_lasttopicsetter = db_mysql_quote(ci->last_topic_setter); + q_forbidby = db_mysql_quote(ci->forbidby); + q_forbidreason = db_mysql_quote(ci->forbidreason); + q_mlock_key = db_mysql_quote(ci->mlock_key); + q_mlock_flood = db_mysql_quote(ci->mlock_flood); + q_mlock_redirect = db_mysql_quote(ci->mlock_redirect); + q_entrymsg = db_mysql_quote(ci->entry_message); + if (ci->bi) { + q_botnick = db_mysql_quote(ci->bi->nick); + } else { + q_botnick = db_mysql_quote(""); + } + + /* First secure the pass, then make it MySQL safe.. - Viper */ + res = db_mysql_secure(epass, ci->founderpass, PASSMAX+15, PASSMAX); + if (res < 0) + fatal("Unable to encrypt password for MySQL"); + else if (res) + q_pass = db_mysql_quote_buffer(epass, PASSMAX+15); + else { + q_pass = scalloc(PASSMAX+15,sizeof(char)); + memcpy(q_pass, epass, PASSMAX+15); + } + + /* If it has been made MySQL safe, it still needs the 's. + * I know it s an ugly solution, but it works without breaking anything.. - Viper */ + /* Let's take care of the core itself */ + if (res) + ret = db_mysql_try("UPDATE anope_cs_info " + "SET founder = '%s', successor = '%s', founderpass = '%s', descr = '%s', url = '%s', email = '%s', time_registered = %d, " + " last_used = %d, last_topic = '%s', last_topic_setter = '%s', last_topic_time = %d, flags = %d, forbidby = '%s', " + " forbidreason = '%s', bantype = %d, accesscount = %d, akickcount = %d, mlock_on = %d, mlock_off = %d, mlock_limit = %d, " + " mlock_key = '%s', mlock_flood = '%s', mlock_redirect = '%s', entry_message = '%s', memomax = %d, botnick = '%s', botflags = %d, " + " bwcount = %d, capsmin = %d, capspercent = %d, floodlines = %d, floodsecs = %d, repeattimes = %d, active = 1 " + "WHERE name = '%s'", + q_founder, q_successor, q_pass, q_desc, q_url, q_email, + (int) ci->time_registered, (int) ci->last_used, + q_lasttopic, q_lasttopicsetter, + (int) ci->last_topic_time, (int) ci->flags, q_forbidby, + q_forbidreason, (int) ci->bantype, + (int) ci->accesscount, (int) ci->akickcount, + (int) ci->mlock_on, (int) ci->mlock_off, + (int) ci->mlock_limit, q_mlock_key, q_mlock_flood, + q_mlock_redirect, q_entrymsg, (int) ci->memos.memomax, + q_botnick, (int) ci->botflags, (int) ci->bwcount, + (int) ci->capsmin, (int) ci->capspercent, + (int) ci->floodlines, (int) ci->floodsecs, + (int) ci->repeattimes, q_name); + else + ret = db_mysql_try("UPDATE anope_cs_info " + "SET founder = '%s', successor = '%s', founderpass = %s, descr = '%s', url = '%s', email = '%s', time_registered = %d, " + " last_used = %d, last_topic = '%s', last_topic_setter = '%s', last_topic_time = %d, flags = %d, forbidby = '%s', " + " forbidreason = '%s', bantype = %d, accesscount = %d, akickcount = %d, mlock_on = %d, mlock_off = %d, mlock_limit = %d, " + " mlock_key = '%s', mlock_flood = '%s', mlock_redirect = '%s', entry_message = '%s', memomax = %d, botnick = '%s', botflags = %d, " + " bwcount = %d, capsmin = %d, capspercent = %d, floodlines = %d, floodsecs = %d, repeattimes = %d, active = 1 " + "WHERE name = '%s'", + q_founder, q_successor, q_pass, q_desc, q_url, q_email, + (int) ci->time_registered, (int) ci->last_used, + q_lasttopic, q_lasttopicsetter, + (int) ci->last_topic_time, (int) ci->flags, q_forbidby, + q_forbidreason, (int) ci->bantype, + (int) ci->accesscount, (int) ci->akickcount, + (int) ci->mlock_on, (int) ci->mlock_off, + (int) ci->mlock_limit, q_mlock_key, q_mlock_flood, + q_mlock_redirect, q_entrymsg, (int) ci->memos.memomax, + q_botnick, (int) ci->botflags, (int) ci->bwcount, + (int) ci->capsmin, (int) ci->capspercent, + (int) ci->floodlines, (int) ci->floodsecs, + (int) ci->repeattimes, q_name); + + /* Our previous UPDATE affected no rows, therefore this is a new record */ + if (ret && (mysql_affected_rows(mysql) == 0)) { + if (res) + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_info " + "(name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, " + " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, " + " mlock_key, mlock_flood, mlock_redirect, entry_message, botnick, botflags, bwcount, capsmin, capspercent, floodlines, " + " floodsecs, repeattimes, active) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', %d, %d, %d, %d, %d, %d, '%s', '%s', " + " '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d, 1)", + q_name, q_founder, q_successor, q_pass, q_desc, + q_url, q_email, (int) ci->time_registered, + (int) ci->last_used, q_lasttopic, + q_lasttopicsetter, (int) ci->last_topic_time, + (int) ci->flags, q_forbidby, q_forbidreason, + (int) ci->bantype, (int) ci->accesscount, + (int) ci->akickcount, (int) ci->mlock_on, + (int) ci->mlock_off, (int) ci->mlock_limit, + q_mlock_key, q_mlock_flood, q_mlock_redirect, + q_entrymsg, q_botnick, (int) ci->botflags, + (int) ci->bwcount, (int) ci->capsmin, + (int) ci->capspercent, (int) ci->floodlines, + (int) ci->floodsecs, (int) ci->repeattimes); + else + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_info " + "(name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, " + " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, " + " mlock_key, mlock_flood, mlock_redirect, entry_message, botnick, botflags, bwcount, capsmin, capspercent, floodlines, " + " floodsecs, repeattimes, active) " + "VALUES ('%s', '%s', '%s', %s, '%s', '%s', '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', %d, %d, %d, %d, %d, %d, '%s', '%s', " + " '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d, 1)", + q_name, q_founder, q_successor, q_pass, q_desc, + q_url, q_email, (int) ci->time_registered, + (int) ci->last_used, q_lasttopic, + q_lasttopicsetter, (int) ci->last_topic_time, + (int) ci->flags, q_forbidby, q_forbidreason, + (int) ci->bantype, (int) ci->accesscount, + (int) ci->akickcount, (int) ci->mlock_on, + (int) ci->mlock_off, (int) ci->mlock_limit, + q_mlock_key, q_mlock_flood, q_mlock_redirect, + q_entrymsg, q_botnick, (int) ci->botflags, + (int) ci->bwcount, (int) ci->capsmin, + (int) ci->capspercent, (int) ci->floodlines, + (int) ci->floodsecs, (int) ci->repeattimes); + } + + /* Memos */ + for (i = 0; ret && (i < ci->memos.memocount); i++) { + q_sender = db_mysql_quote(ci->memos.memos[i].sender); + q_text = db_mysql_quote(ci->memos.memos[i].text); + + ret = db_mysql_try("UPDATE anope_ms_info " + "SET receiver = '%s', number = %d, flags = %d, time = %d, sender = '%s', text = '%s', active = 1 " + "WHERE nm_id = %d AND serv = 'CHAN'", + q_name, ci->memos.memos[i].number, + ci->memos.memos[i].flags, + (int) ci->memos.memos[i].time, q_sender, q_text, + ci->memos.memos[i].id); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT INTO anope_ms_info " + "(receiver, number,flags, time, sender, text, serv, active) " + "VALUES ('%s', %d, %d, %d, '%s', '%s', 'CHAN', 1)", + q_name, ci->memos.memos[i].number, + ci->memos.memos[i].flags, + (int) ci->memos.memos[i].time, q_sender, + q_text); + + /* See comment at db_mysql_save_ns_core */ + if (ret) + ci->memos.memos[i].id = mysql_insert_id(mysql); + } + + free(q_sender); + free(q_text); + } + + /* Access */ + for (i = 0; ret && (i < ci->accesscount); i++) { + if (ci->access[i].in_use) { + q_accessdisp = db_mysql_quote(ci->access[i].nc->display); + + ret = db_mysql_try("UPDATE anope_cs_access " + "SET in_use = %d, level = %d, last_seen = %d, active = 1 " + "WHERE channel = '%s' AND display = '%s'", + (int) ci->access[i].in_use, + (int) ci->access[i].level, + (int) ci->access[i].last_seen, + q_name, q_accessdisp); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_access " + "(channel, display, in_use, level, last_seen, active) " + "VALUES ('%s', '%s', %d, %d, %d, 1)", + q_name, q_accessdisp, + (int) ci->access[i].in_use, + (int) ci->access[i].level, + (int) ci->access[i].last_seen); + } + + free(q_accessdisp); + } + } + + /* Levels */ + for (i = 0; ret && (i < CA_SIZE); i++) { + ret = db_mysql_try("UPDATE anope_cs_levels " + "SET level = %d, active = 1 " + "WHERE channel = '%s' AND position = %d", + (int) ci->levels[i], q_name, i); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_levels " + "(channel, position, level, active) " + "VALUES ('%s', %d, %d, 1)", + q_name, i, (int) ci->levels[i]); + } + } + + /* Akicks */ + for (i = 0; ret && (i < ci->akickcount); i++) { + if (ci->akick[i].flags & AK_USED) { + if (ci->akick[i].flags & AK_ISNICK) + q_akickdisp = db_mysql_quote(ci->akick[i].u.nc->display); + else + q_akickdisp = db_mysql_quote(ci->akick[i].u.mask); + + q_akickreason = db_mysql_quote(ci->akick[i].reason); + q_akickcreator = db_mysql_quote(ci->akick[i].creator); + } else { + q_akickdisp = ""; + q_akickreason = ""; + q_akickcreator = ""; + } + + ret = db_mysql_try("UPDATE anope_cs_akicks " + "SET flags = %d, reason = '%s', creator = '%s', addtime = %d, active = 1 " + "WHERE channel = '%s' AND dmask = '%s'", + (int) ci->akick[i].flags, q_akickreason, + q_akickcreator, (ci->akick[i].flags & AK_USED ? + (int) ci->akick[i].addtime : 0), + q_name, q_akickdisp); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_akicks " + "(channel, dmask, flags, reason, creator, addtime, active) " + "VALUES ('%s', '%s', %d, '%s', '%s', %d, 1)", + q_name, q_akickdisp, (int) ci->akick[i].flags, + q_akickreason, q_akickcreator, + (ci->akick[i].flags & AK_USED ? + (int) ci->akick[i].addtime : 0)); + } + + if (ci->akick[i].flags & AK_USED) { + free(q_akickdisp); + free(q_akickreason); + free(q_akickcreator); + } + } + + /* Bad Words */ + for (i = 0; ret && (i < ci->bwcount); i++) { + if (ci->badwords[i].in_use) { + q_badwords = db_mysql_quote(ci->badwords[i].word); + + ret = db_mysql_try("UPDATE anope_cs_badwords " + "SET type = %d, active = 1 " + "WHERE channel = '%s' AND word = '%s'", + (int) ci->badwords[i].type, q_name, + q_badwords); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_badwords " + "(channel, word, type, active) " + "VALUES ('%s', '%s', %d, 1)", + q_name, q_badwords, + (int) ci->badwords[i].type); + } + + free(q_badwords); + } + } + + /* TTB's */ + for (i = 0; ret && (i < TTB_SIZE); i++) { + ret = db_mysql_try("UPDATE anope_cs_ttb " + "SET value = %d, active = 1 " + "WHERE channel = '%s' AND ttb_id = %d", + ci->ttb[i], q_name, i); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_cs_ttb " + "(channel, ttb_id, value, active) " + "VALUES ('%s', %d, %d, 1)", + q_name, i, ci->ttb[i]); + } + } + + free(q_name); + free(q_founder); + free(q_successor); + free(q_pass); + free(q_desc); + free(q_url); + free(q_email); + free(q_lasttopic); + free(q_lasttopicsetter); + free(q_mlock_key); + free(q_mlock_flood); + free(q_mlock_redirect); + free(q_entrymsg); + free(q_botnick); + free(q_forbidby); + free(q_forbidreason); + + return ret; +} + +/*************************************************************************/ + + +/* + * OperServ Specific Section + */ + +/*************************************************************************/ + +/* Save the OperServ database into MySQL + * Return 1 on success, 0 on failure + * These tables are tagged and will be cleaned: + * - anope_os_akills + * - anope_os_sglines + * - anope_os_sqlines + * - anope_os_szlines + * These tables are emptied: + * - anope_os_core + */ + +int db_mysql_save_os_db(unsigned int maxucnt, unsigned int maxutime, + SList * ak, SList * sgl, SList * sql, SList * szl) +{ + int ret; + int i; + Akill *akl; + SXLine *sl; + char *q_user; + char *q_host; + char *q_mask; + char *q_by; + char *q_reason; + + + /* First save the core info */ + ret = db_mysql_try("INSERT DELAYED INTO anope_os_core " + "(maxusercnt, maxusertime, akills_count, sglines_count, sqlines_count, szlines_count) " + "VALUES (%d, %d, %d, %d, %d, %d)", + maxucnt, maxutime, ak->count, sgl->count, sql->count, + szl->count); + + /* Next save all AKILLs */ + for (i = 0; ret && (i < ak->count); i++) { + akl = ak->list[i]; + q_user = db_mysql_quote(akl->user); + q_host = db_mysql_quote(akl->host); + q_by = db_mysql_quote(akl->by); + q_reason = db_mysql_quote(akl->reason); + + ret = db_mysql_try("UPDATE anope_os_akills " + "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 " + "WHERE user = '%s' AND host = '%s'", + q_by, q_reason, (int) akl->seton, + (int) akl->expires, q_user, q_host); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_akills " + "(user, host, xby, reason, seton, expire, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, %d, 1)", + q_user, q_host, q_by, q_reason, + (int) akl->seton, (int) akl->expires); + } + + free(q_user); + free(q_host); + free(q_by); + free(q_reason); + } + + /* Time to save the SGLINEs */ + for (i = 0; ret && (i < sgl->count); i++) { + sl = sgl->list[i]; + q_mask = db_mysql_quote(sl->mask); + q_by = db_mysql_quote(sl->by); + q_reason = db_mysql_quote(sl->reason); + + ret = db_mysql_try("UPDATE anope_os_sglines " + "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 " + "WHERE mask = '%s'", + q_by, q_reason, (int) sl->seton, (int) sl->expires, + q_mask); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_sglines " + "(mask, xby, reason, seton, expire, active) " + "VALUES ('%s', '%s', '%s', %d, %d, 1)", + q_mask, q_by, q_reason, (int) sl->seton, + (int) sl->expires); + } + + free(q_mask); + free(q_by); + free(q_reason); + } + + /* Save the SQLINEs */ + for (i = 0; ret && (i < sql->count); i++) { + sl = sql->list[i]; + + q_mask = db_mysql_quote(sl->mask); + q_by = db_mysql_quote(sl->by); + q_reason = db_mysql_quote(sl->reason); + + ret = db_mysql_try("UPDATE anope_os_sqlines " + "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 " + "WHERE mask = '%s'", + q_by, q_reason, (int) sl->seton, (int) sl->expires, + q_mask); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_sqlines " + "(mask, xby, reason, seton, expire, active) " + "VALUES ('%s', '%s', '%s', %d, %d, 1)", + q_mask, q_by, q_reason, (int) sl->seton, + (int) sl->expires); + } + + free(q_mask); + free(q_by); + free(q_reason); + } + + /* Now save the SZLINEs */ + for (i = 0; ret && (i < szl->count); i++) { + sl = szl->list[i]; + + q_mask = db_mysql_quote(sl->mask); + q_by = db_mysql_quote(sl->by); + q_reason = db_mysql_quote(sl->reason); + + ret = db_mysql_try("UPDATE anope_os_szlines " + "SET xby = '%s', reason = '%s', seton = %d, expire = %d, active = 1 " + "WHERE mask = '%s'", + q_by, q_reason, (int) sl->seton, (int) sl->expires, + q_mask); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_szlines " + "(mask, xby, reason, seton, expire, active) " + "VALUES ('%s', '%s', '%s', %d, %d, 1)", + q_mask, q_by, q_reason, (int) sl->seton, + (int) sl->expires); + } + + free(q_mask); + free(q_by); + free(q_reason); + } + + return ret; +} + +/*************************************************************************/ + +/* Save the given NewsItem + * These tables are tagged and will be cleaned: + * - anope_os_news + */ +int db_mysql_save_news(NewsItem * ni) +{ + int ret; + char *q_text; + char *q_who; + + q_text = db_mysql_quote(ni->text); + q_who = db_mysql_quote(ni->who); + + ret = db_mysql_try("UPDATE anope_os_news " + "SET ntext = '%s', who = '%s', active = 1 " + "WHERE type = %d AND num = %d AND `time` = %d", + q_text, q_who, ni->type, ni->num, (int) ni->time); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_news " + "(type, num, ntext, who, `time`, active) " + "VALUES (%d, %d, '%s', '%s', %d, 1)", + ni->type, ni->num, q_text, q_who, (int) ni->time); + } + + free(q_text); + free(q_who); + + return ret; +} + +/*************************************************************************/ + +/* Save the given Exception + * These tables are tagged and will be cleaned: + * - anope_os_exceptions + */ + +int db_mysql_save_exceptions(Exception * e) +{ + int ret; + char *q_mask; + char *q_who; + char *q_reason; + + q_mask = db_mysql_quote(e->mask); + q_who = db_mysql_quote(e->who); + q_reason = db_mysql_quote(e->reason); + + ret = db_mysql_try("UPDATE anope_os_exceptions " + "SET lim = %d, who = '%s', reason = '%s', `time` = %d, expires = %d, active = 1 " + "WHERE mask = '%s'", + e->limit, q_who, q_reason, (int) e->time, + (int) e->expires, q_mask); + + if (ret && (mysql_affected_rows(mysql)) == 0) { + ret = db_mysql_try("INSERT DELAYED INTO anope_os_exceptions " + "(mask, lim, who, reason, `time`, expires, active) " + "VALUES ('%s', %d, '%s', '%s', %d, %d, 1)", + q_mask, e->limit, q_who, q_reason, (int) e->time, + (int) e->expires); + } + + free(q_mask); + free(q_who); + free(q_reason); + + return ret; +} + +/*************************************************************************/ + + +/* + * HostServ Specific Section + */ + +/*************************************************************************/ + +/* Save the given HostCore + * These tables are tagged and will be cleaned: + * - anope_hs_core + */ + +int db_mysql_save_hs_core(HostCore * hc) +{ + int ret; + char *q_nick; + char *q_ident; + char *q_host; + char *q_creator; + + q_nick = db_mysql_quote(hc->nick); + q_ident = db_mysql_quote(hc->vIdent); + q_host = db_mysql_quote(hc->vHost); + q_creator = db_mysql_quote(hc->creator); + + ret = db_mysql_try("UPDATE anope_hs_core " + "SET vident = '%s', vhost = '%s', creator = '%s', `time` = %d, active = 1 " + "WHERE nick = '%s'", + q_ident, q_host, q_creator, (int) hc->time, q_nick); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_hs_core " + "(nick, vident, vhost, creator, `time`, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, 1)", + q_nick, q_ident, q_host, q_creator, + (int) hc->time); + } + + free(q_nick); + free(q_ident); + free(q_host); + free(q_creator); + + return ret; +} + +/*************************************************************************/ + +/* + * BotServ Specific Section + */ + +/*************************************************************************/ + +int db_mysql_save_bs_core(BotInfo * bi) +{ + int ret; + char *q_nick; + char *q_user; + char *q_host; + char *q_real; + + q_nick = db_mysql_quote(bi->nick); + q_user = db_mysql_quote(bi->user); + q_host = db_mysql_quote(bi->host); + q_real = db_mysql_quote(bi->real); + + ret = db_mysql_try("UPDATE anope_bs_core " + "SET user = '%s', host = '%s', rname = '%s', flags = %d, created = %d, chancount = %d, active = 1 " + "WHERE nick = '%s'", + q_user, q_host, q_real, bi->flags, (int) bi->created, + bi->chancount, q_nick); + + if (ret && (mysql_affected_rows(mysql) == 0)) { + ret = db_mysql_try("INSERT DELAYED INTO anope_bs_core " + "(nick, user, host, rname, flags, created, chancount, active) " + "VALUES ('%s', '%s', '%s', '%s', %d, %d, %d, 1)", + q_nick, q_user, q_host, q_real, bi->flags, + (int) bi->created, bi->chancount); + } + + free(q_nick); + free(q_user); + free(q_host); + free(q_real); + + return ret; +} + +/*************************************************************************/ +/*************************************************************************/ + +/* Some loading code! */ + +/*************************************************************************/ +/*************************************************************************/ + +int db_mysql_load_bs_dbase(void) +{ + int ret; + BotInfo *bi; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT nick, user, host, rname, flags, created, chancount " + "FROM anope_bs_core " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + bi = makebot(mysql_row[0]); + bi->user = sstrdup(mysql_row[1]); + bi->host = sstrdup(mysql_row[2]); + bi->real = sstrdup(mysql_row[3]); + bi->flags = strtol(mysql_row[4], (char **) NULL, 10); + bi->created = strtol(mysql_row[5], (char **) NULL, 10); + bi->chancount = strtol(mysql_row[6], (char **) NULL, 10); + } + + mysql_free_result(mysql_res); + + return 1; +} + +int db_mysql_load_hs_dbase(void) +{ + int ret; + int32 time; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT nick, vident, vhost, creator, `time` " + "FROM anope_hs_core " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + time = strtol(mysql_row[4], (char **) NULL, 10); + addHostCore(mysql_row[0], mysql_row[1], mysql_row[2], mysql_row[3], + time); + } + + mysql_free_result(mysql_res); + + return 1; +} + +int db_mysql_load_news(void) +{ + int ret; + int i; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT type, num, ntext, who, `time` " + "FROM anope_os_news " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_store_result(mysql); + + nnews = mysql_num_rows(mysql_res); + if (nnews < 8) /* 2^3 */ + news_size = 16; /* 2^4 */ + else if (nnews >= 16384) /* 2^14 */ + news_size = 32767; /* 2^15 - 1 */ + else + news_size = 2 * nnews; + + news = scalloc(news_size, sizeof(*news)); + + i = 0; + while ((mysql_row = mysql_fetch_row(mysql_res))) { + news[i].type = strtol(mysql_row[0], (char **) NULL, 10); + news[i].num = strtol(mysql_row[1], (char **) NULL, 10); + news[i].text = sstrdup(mysql_row[2]); + snprintf(news[i].who, NICKMAX, "%s", mysql_row[3]); + news[i].time = strtol(mysql_row[4], (char **) NULL, 10); + i++; + } + + mysql_free_result(mysql_res); + + return 1; +} + +int db_mysql_load_exceptions(void) +{ + int ret; + int i; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT mask, lim, who, reason, `time`, expires " + "FROM anope_os_exceptions " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_store_result(mysql); + nexceptions = mysql_num_rows(mysql_res); + exceptions = scalloc(nexceptions, sizeof(Exception)); + + i = 0; + while ((mysql_row = mysql_fetch_row(mysql_res))) { + exceptions[i].mask = sstrdup(mysql_row[0]); + exceptions[i].limit = strtol(mysql_row[1], (char **) NULL, 10); + snprintf(exceptions[i].who, NICKMAX, "%s", mysql_row[2]); + exceptions[i].reason = sstrdup(mysql_row[3]); + exceptions[i].time = strtol(mysql_row[4], (char **) NULL, 10); + exceptions[i].expires = strtol(mysql_row[5], (char **) NULL, 10); + i++; + } + + mysql_free_result(mysql_res); + + return 1; +} + +int db_mysql_load_os_dbase(void) +{ + int ret; + Akill *ak; + SXLine *sl; + int akc, sglc, sqlc, szlc; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT maxusercnt, maxusertime, akills_count, sglines_count, sqlines_count, szlines_count " + "FROM anope_os_core"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + + if ((mysql_row = mysql_fetch_row(mysql_res))) { + maxusercnt = strtol(mysql_row[0], (char **) NULL, 10); + maxusertime = strtol(mysql_row[1], (char **) NULL, 10); + /* I'm not too happy with the idea of storing thse counts in a field + * instead of just using mysql_num_rows on the actual tables when + * filling the data. For now this will do, but it's bound to give + * problems sooner or later... (it probably does if you are looking + * at this) -GD + */ + akc = strtol(mysql_row[2], (char **) NULL, 10); + sglc = strtol(mysql_row[3], (char **) NULL, 10); + sqlc = strtol(mysql_row[4], (char **) NULL, 10); + szlc = strtol(mysql_row[5], (char **) NULL, 10); + } else { + maxusercnt = 0; + maxusertime = time(NULL); + akc = 0; + sglc = 0; + sqlc = 0; + szlc = 0; + } + + mysql_free_result(mysql_res); + + + /* Load the AKILLs */ + + ret = db_mysql_try("SELECT user, host, xby, reason, seton, expire " + "FROM anope_os_akills " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + slist_setcapacity(&akills, akc); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + ak = scalloc(1, sizeof(Akill)); + ak->user = sstrdup(mysql_row[0]); + ak->host = sstrdup(mysql_row[1]); + ak->by = sstrdup(mysql_row[2]); + ak->reason = sstrdup(mysql_row[3]); + ak->seton = strtol(mysql_row[4], (char **) NULL, 10); + ak->expires = strtol(mysql_row[5], (char **) NULL, 10); + slist_add(&akills, ak); + } + + mysql_free_result(mysql_res); + + + /* Load the SGLINEs */ + + ret = db_mysql_try("SELECT mask, xby, reason, seton, expire " + "FROM anope_os_sglines " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + slist_setcapacity(&sglines, sglc); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + sl = scalloc(1, sizeof(SXLine)); + sl->mask = sstrdup(mysql_row[0]); + sl->by = sstrdup(mysql_row[1]); + sl->reason = sstrdup(mysql_row[2]); + sl->seton = strtol(mysql_row[3], (char **) NULL, 10); + sl->expires = strtol(mysql_row[4], (char **) NULL, 10); + slist_add(&sglines, sl); + } + + mysql_free_result(mysql_res); + + + /* Load the SQLINEs */ + + ret = db_mysql_try("SELECT mask, xby, reason, seton, expire " + "FROM anope_os_sqlines " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + slist_setcapacity(&sqlines, sqlc); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + sl = scalloc(1, sizeof(SXLine)); + sl->mask = sstrdup(mysql_row[0]); + sl->by = sstrdup(mysql_row[1]); + sl->reason = sstrdup(mysql_row[2]); + sl->seton = strtol(mysql_row[3], (char **) NULL, 10); + sl->expires = strtol(mysql_row[4], (char **) NULL, 10); + slist_add(&sqlines, sl); + } + + mysql_free_result(mysql_res); + + + /* Load the SZLINEs */ + + ret = db_mysql_try("SELECT mask, xby, reason, seton, expire " + "FROM anope_os_szlines " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + slist_setcapacity(&szlines, szlc); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + sl = scalloc(1, sizeof(SXLine)); + sl->mask = sstrdup(mysql_row[0]); + sl->by = sstrdup(mysql_row[1]); + sl->reason = sstrdup(mysql_row[2]); + sl->seton = strtol(mysql_row[3], (char **) NULL, 10); + sl->expires = strtol(mysql_row[4], (char **) NULL, 10); + slist_add(&szlines, sl); + } + + mysql_free_result(mysql_res); + + return 1; +} + +int db_mysql_load_cs_dbase(void) +{ + int ret; + char *q_name; + ChannelInfo *ci; + int i; + MYSQL_RES *res; + MYSQL_ROW row; + unsigned long *lengths; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT name, founder, successor, founderpass, descr, url, email, time_registered, last_used, last_topic, last_topic_setter, " + " last_topic_time, flags, forbidby, forbidreason, bantype, accesscount, akickcount, mlock_on, mlock_off, mlock_limit, " + " mlock_key, mlock_flood, mlock_redirect, entry_message, memomax, botnick, botflags, bwcount, capsmin, capspercent, floodlines, " + " floodsecs, repeattimes " + "FROM anope_cs_info " + "WHERE active = 1"); + + if (!ret) + return 0; + + /* I'd really like to use mysql_use_result here, but it'd tie up with + * all the queries being run inside each iteration... -GD + */ + mysql_res = mysql_store_result(mysql); + + while (ret && (mysql_row = mysql_fetch_row(mysql_res))) { + /* We need to get the length of the password.. - Viper */ + lengths = mysql_fetch_lengths(mysql_res); + ci = scalloc(1, sizeof(ChannelInfo)); + + /* Name, founder, successor, password */ + snprintf(ci->name, CHANMAX, "%s", mysql_row[0]); + ci->founder = findcore(mysql_row[1]); + if (mysql_row[2] && *(mysql_row[2])) + ci->successor = findcore(mysql_row[2]); + else + ci->successor = NULL; + + /* Copy the password from what we got back from the DB and + * keep in mind that lengths may vary. We should never + * use more than we have. - Viper */ + memset(ci->founderpass, 0, PASSMAX); + if (lengths[3] >= PASSMAX) + memcpy(ci->founderpass, mysql_row[3], PASSMAX - 1); + else + memcpy(ci->founderpass, mysql_row[3], lengths[3]); + + /* Description, URL, email -- scalloc() initializes to 0/NULL */ + ci->desc = sstrdup(mysql_row[4]); + if (mysql_row[5] && *(mysql_row[5])) + ci->url = sstrdup(mysql_row[5]); + if (mysql_row[6] && *(mysql_row[6])) + ci->email = sstrdup(mysql_row[6]); + + /* Time registered, last used, last topic, last topic setter + time */ + ci->time_registered = strtol(mysql_row[7], (char **) NULL, 10); + ci->last_used = strtol(mysql_row[8], (char **) NULL, 10); + if (mysql_row[9] && *(mysql_row[9])) { + ci->last_topic = sstrdup(mysql_row[9]); + snprintf(ci->last_topic_setter, NICKMAX, "%s", mysql_row[10]); + ci->last_topic_time = strtol(mysql_row[11], (char **) NULL, 10); + } + + /* Flags, forbidden by, forbid reason, bantype + * NOTE: CI_INHABIT will be disabled in flags!! + */ + ci->flags = + strtol(mysql_row[12], (char **) NULL, 10) & ~CI_INHABIT; + + if (mysql_row[13] && *(mysql_row[13])) { + ci->forbidby = sstrdup(mysql_row[13]); + if (mysql_row[14] && *(mysql_row[14])) + ci->forbidreason = sstrdup(mysql_row[14]); + } + + ci->bantype = strtol(mysql_row[15], (char **) NULL, 10); + + /* Accesscount, akickcount */ + ci->accesscount = strtol(mysql_row[16], (char **) NULL, 10); + ci->akickcount = strtol(mysql_row[17], (char **) NULL, 10); + + /* Mlock: on, off, limit, key, flood, redirect */ + ci->mlock_on = strtol(mysql_row[18], (char **) NULL, 10); + ci->mlock_off = strtol(mysql_row[19], (char **) NULL, 10); + ci->mlock_limit = strtol(mysql_row[20], (char **) NULL, 10); + if (mysql_row[21] && *(mysql_row[21])) { + ci->mlock_key = sstrdup(mysql_row[21]); + if (mysql_row[22] && *(mysql_row[22])) { + ci->mlock_flood = sstrdup(mysql_row[22]); + } + if (mysql_row[23] && *(mysql_row[23])) { + ci->mlock_redirect = sstrdup(mysql_row[23]); + } + } + + /* MemoMax, entrymessage, botinfo, botflags, badwordcount */ + ci->memos.memomax = strtol(mysql_row[25], (char **) NULL, 10); + if (mysql_row[24] && *(mysql_row[24])) + ci->entry_message = sstrdup(mysql_row[24]); + ci->bi = findbot(mysql_row[26]); + ci->botflags = strtol(mysql_row[27], (char **) NULL, 10); + ci->bwcount = strtol(mysql_row[28], (char **) NULL, 10); + + /* Capsmin, capspercent, floodlines, floodsecs, repeattimes */ + ci->capsmin = strtol(mysql_row[29], (char **) NULL, 10); + ci->capspercent = strtol(mysql_row[30], (char **) NULL, 10); + ci->floodlines = strtol(mysql_row[31], (char **) NULL, 10); + ci->floodsecs = strtol(mysql_row[32], (char **) NULL, 10); + ci->repeattimes = strtol(mysql_row[33], (char **) NULL, 10); + + + /* Get info from other tables; we'll need the channel name */ + q_name = db_mysql_quote(ci->name); + + /* Get the LEVELS list */ + ret = db_mysql_try("SELECT position, level " + "FROM anope_cs_levels " + "WHERE channel = '%s' AND active = 1", + q_name); + + if (ret) { + res = mysql_use_result(mysql); + ci->levels = scalloc(CA_SIZE, sizeof(*ci->levels)); + reset_levels(ci); + + while ((row = mysql_fetch_row(res))) { + i = strtol(row[0], (char **) NULL, 10); + ci->levels[i] = strtol(row[1], (char **) NULL, 10); + } + + mysql_free_result(res); + } + + /* Get the channel ACCESS list */ + if (ret && (ci->accesscount > 0)) { + ci->access = scalloc(ci->accesscount, sizeof(ChanAccess)); + + ret = db_mysql_try("SELECT level, display, last_seen " + "FROM anope_cs_access " + "WHERE channel = '%s' AND in_use = 1 AND active = 1", + q_name); + + if (ret) { + res = mysql_store_result(mysql); + + i = 0; + while ((row = mysql_fetch_row(res))) { + ci->access[i].in_use = 1; + ci->access[i].level = strtol(row[0], (char **) NULL, 10); + ci->access[i].nc = findcore(row[1]); + if (!(ci->access[i].nc)) + ci->access[i].in_use = 0; + ci->access[i].last_seen = + strtol(row[2], (char **) NULL, 10); + i++; + } + + mysql_free_result(res); + } + } + + /* Get the channel AKICK list */ + if (ret && (ci->akickcount > 0)) { + ci->akick = scalloc(ci->akickcount, sizeof(AutoKick)); + + ret = db_mysql_try("SELECT flags, dmask, reason, creator, addtime " + "FROM anope_cs_akicks " + "WHERE channel = '%s' AND active = 1 AND (flags & %d) <> 0", + q_name, AK_USED); + + if (ret) { + res = mysql_use_result(mysql); + + i = 0; + while ((row = mysql_fetch_row(res))) { + ci->akick[i].flags = strtol(row[0], (char **) NULL, 10); + if (ci->akick[i].flags & AK_ISNICK) { + ci->akick[i].u.nc = findcore(row[1]); + if (!(ci->akick[i].u.nc)) + ci->akick[i].flags &= ~AK_USED; + } else { + ci->akick[i].u.mask = sstrdup(row[1]); + } + if (row[2] && *(row[2])) { + ci->akick[i].reason = sstrdup(row[2]); + } + ci->akick[i].creator = sstrdup(row[3]); + ci->akick[i].addtime = strtol(row[4], (char **) NULL, 10); + i++; + } + + mysql_free_result(res); + } + } + + if (ret) { + /* Get the channel memos */ + ret = db_mysql_try("SELECT nm_id, number, flags, time, sender, text " + "FROM anope_ms_info " + "WHERE receiver = '%s' AND serv = 'CHAN' AND active = 1", + q_name); + + if (ret) { + res = mysql_store_result(mysql); + ci->memos.memocount = mysql_num_rows(res); + + if (ci->memos.memocount > 0) { + Memo *memos; + + memos = scalloc(ci->memos.memocount, sizeof(Memo)); + ci->memos.memos = memos; + + i = 0; + while ((row = mysql_fetch_row(res))) { + memos[i].id = strtol(row[0], (char **) NULL, 10); + memos[i].number = strtol(row[1], (char **) NULL, 10); + memos[i].flags = strtol(row[2], (char **) NULL, 10); + memos[i].time = strtol(row[3], (char **) NULL, 10); + snprintf(memos[i].sender, NICKMAX, "%s", row[4]); + memos[i].text = sstrdup(row[5]); + i++; + } + } + + mysql_free_result(res); + } + } + + /* Get the TTB data */ + if (ret) { + ci->ttb = scalloc(TTB_SIZE, sizeof(*ci->ttb)); + + ret = db_mysql_try("SELECT ttb_id, value " + "FROM anope_cs_ttb " + "WHERE channel = '%s' AND active = 1", + q_name); + + if (ret) { + res = mysql_use_result(mysql); + + while ((row = mysql_fetch_row(res))) { + i = strtol(row[0], (char **) NULL, 10); + /* Should we do a sanity check on the value of i? -GD */ + ci->ttb[i] = strtol(row[1], (char **) NULL, 10); + } + + mysql_free_result(res); + } + } + + /* Get the badwords */ + if (ret && (ci->bwcount > 0)) { + ci->badwords = scalloc(ci->bwcount, sizeof(BadWord)); + + ret = db_mysql_try("SELECT word, type " + "FROM anope_cs_badwords " + "WHERE channel = '%s' AND active = 1", + q_name); + + if (ret) { + res = mysql_use_result(mysql); + + i = 0; + while ((row = mysql_fetch_row(res))) { + ci->badwords[i].in_use = 1; + ci->badwords[i].word = sstrdup(row[0]); + ci->badwords[i].type = strtol(row[1], (char **) NULL, 10); + i++; + } + + mysql_free_result(res); + } + } + + /* YAY! all done; free q_name and insert the channel */ + free(q_name); + alpha_insert_chan(ci); + } + + mysql_free_result(mysql_res); + + /* Check to be sure that all channels still have a founder. If not, + * delete them. This code seems to be required in the old mysql code + * so i'll leave it in just to be sure. I also wonder why they didn't + * do that check up above immediately when it was known there was no + * founder... -GD + */ + for (i = 0; i < 256; i++) { + ChannelInfo *next; + for (ci = chanlists[i]; ci; ci = next) { + next = ci->next; + if (!(ci->flags & CI_VERBOTEN) && !ci->founder) { + alog("%s: database load: Deleting founderless channel %s", + s_ChanServ, ci->name); + delchan(ci); + } + } + } + + return ret; +} + +int db_mysql_load_ns_req_dbase(void) +{ + int ret; + NickRequest *nr; + unsigned long *lengths; + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT nick, passcode, password, email, requested " + "FROM anope_ns_request " + "WHERE active = 1"); + + if (ret) { + mysql_res = mysql_use_result(mysql); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + /* We need to get the length of the password.. - Viper */ + lengths = mysql_fetch_lengths(mysql_res); + nr = scalloc(1, sizeof(NickRequest)); + + nr->nick = sstrdup(mysql_row[0]); + nr->passcode = sstrdup(mysql_row[1]); + nr->email = sstrdup(mysql_row[3]); + nr->requested = strtol(mysql_row[4], (char **) NULL, 10); + + /* Copy the password from what we got back from the DB and + * keep in mind that lengths may vary. We should never + * use more than we have. - Viper */ + memset(nr->password, 0, PASSMAX); + if (lengths[2] >= PASSMAX) + memcpy(nr->password, mysql_row[2], PASSMAX - 1); + else + memcpy(nr->password, mysql_row[2], lengths[2]); + + + insert_requestnick(nr); + } + + mysql_free_result(mysql_res); + } + + return ret; +} + +int db_mysql_load_ns_dbase(void) +{ + int ret; + char *q_display; + NickCore *nc; + NickAlias *na; + MYSQL_RES *res; + MYSQL_ROW row; + int i; + unsigned long *lengths; + + + if (!do_mysql) + return 0; + + ret = db_mysql_try("SELECT display, pass, email, icq, url, flags, language, accesscount, memocount, memomax, channelcount, channelmax, greet " + "FROM anope_ns_core " + "WHERE active = 1"); + + if (!ret) + return 0; + + /* I'd really like to use mysql_use_result here, but it'd tie up with + * all the queries being run inside each iteration... -GD + */ + mysql_res = mysql_store_result(mysql); + + while (ret && (mysql_row = mysql_fetch_row(mysql_res))) { + /* We need to get the length of the password.. - Viper */ + lengths = mysql_fetch_lengths(mysql_res); + + nc = scalloc(1, sizeof(NickCore)); + + /* Display, password, email, ICQ, URL, flags */ + nc->display = sstrdup(mysql_row[0]); + if (mysql_row[2] && *(mysql_row[2])) { + nc->email = sstrdup(mysql_row[2]); + } + nc->icq = strtol(mysql_row[3], (char **) NULL, 10); + if (mysql_row[4] && *(mysql_row[4])) { + nc->url = sstrdup(mysql_row[4]); + } + nc->flags = strtol(mysql_row[5], (char **) NULL, 10); + + /* Copy the password from what we got back from the DB and + * keep in mind that lengths may vary. We should never + * use more than we have. - Viper */ + memset(nc->pass, 0, PASSMAX); + if (lengths[1] >= PASSMAX) + memcpy(nc->pass, mysql_row[1], PASSMAX - 1); + else + memcpy(nc->pass, mysql_row[1], lengths[1]); + + /* Language, accesscount, memocount, memomax */ + nc->language = strtol(mysql_row[6], (char **) NULL, 10); + nc->accesscount = strtol(mysql_row[7], (char **) NULL, 10); + nc->memos.memocount = strtol(mysql_row[8], (char **) NULL, 10); + nc->memos.memomax = strtol(mysql_row[9], (char **) NULL, 10); + + /* Channelcount, channelmax, greet */ + nc->channelcount = strtol(mysql_row[10], (char **) NULL, 10); + nc->channelmax = strtol(mysql_row[11], (char **) NULL, 10); + if (mysql_row[12] && *(mysql_row[12])) + nc->greet = sstrdup(mysql_row[12]); + + /* Don't allow KILL_IMMED if the config doesn't allow it */ + if (!NSAllowKillImmed) + nc->flags &= ~NI_KILL_IMMED; + + /* Check if the current user is important enough to be added to + * services admin or services oper lists + */ + if (nc->flags & NI_SERVICES_ADMIN) + slist_add(&servadmins, nc); + if (nc->flags & NI_SERVICES_OPER) + slist_add(&servopers, nc); + + /* Unset the SERVICES_ROOT flag; we will set it again later if this + * user is really a services root (checked per NickAlias) -GD + */ + nc->flags &= ~NI_SERVICES_ROOT; + + /* Get info from other tables; we'll need the display */ + q_display = db_mysql_quote(nc->display); + + /* Fill the accesslist */ + if (ret && (nc->accesscount > 0)) { + nc->access = scalloc(nc->accesscount, sizeof(char *)); + + ret = db_mysql_try("SELECT access " + "FROM anope_ns_access " + "WHERE display = '%s' AND active = 1", + q_display); + + if (ret) { + res = mysql_use_result(mysql); + + i = 0; + while ((row = mysql_fetch_row(res))) { + if (row[0] && *(row[0])) { + nc->access[i] = sstrdup(row[0]); + i++; + } + } + + mysql_free_result(res); + } + } + + /* Load the memos */ + if (ret && (nc->memos.memocount > 0)) { + nc->memos.memos = scalloc(nc->memos.memocount, sizeof(Memo)); + + ret = db_mysql_try("SELECT nm_id, number, flags, time, sender, text " + "FROM anope_ms_info " + "WHERE receiver = '%s' AND active = 1 AND serv = 'NICK' " + "ORDER BY number ASC", + q_display); + + if (ret) { + res = mysql_use_result(mysql); + + i = 0; + while ((row = mysql_fetch_row(res))) { + nc->memos.memos[i].id = strtol(row[0], (char **) NULL, 10); + nc->memos.memos[i].number = strtol(row[1], (char **) NULL, 10); + nc->memos.memos[i].flags = strtol(row[2], (char **) NULL, 10); + nc->memos.memos[i].time = strtol(row[3], (char **) NULL, 10); + snprintf(nc->memos.memos[i].sender, NICKMAX, "%s", row[4]); + nc->memos.memos[i].text = sstrdup(row[5]); + + i++; + } + + mysql_free_result(res); + } + } + + /* Done with the core; insert it */ + insert_core(nc); + } + + mysql_free_result(mysql_res); + + if (!ret) + return 0; + + /* Load the nickaliases */ + ret = db_mysql_try("SELECT nick, display, time_registered, last_seen, status, last_usermask, last_realname, last_quit " + "FROM anope_ns_alias " + "WHERE active = 1"); + + if (!ret) + return 0; + + mysql_res = mysql_use_result(mysql); + + while ((mysql_row = mysql_fetch_row(mysql_res))) { + /* First make sure this NickAlias has a NickCore; else we don't even + * bother adding it to the aliases at all... + */ + NickCore *nc; + + if (!(nc = findcore(mysql_row[1]))) + continue; + + na = scalloc(1, sizeof(NickAlias)); + + /* nick, time_registered, last_seen, status + * NOTE: remove NS_TEMPORARY from status on load + */ + na->nick = sstrdup(mysql_row[0]); + na->nc = nc; + na->time_registered = strtol(mysql_row[2], (char **) NULL, 10); + na->last_seen = strtol(mysql_row[3], (char **) NULL, 10); + na->status = + strtol(mysql_row[4], (char **) NULL, 10) & ~NS_TEMPORARY; + + /* last_usermask, last_realname, last_quit */ + na->last_usermask = sstrdup(mysql_row[5]); + na->last_realname = sstrdup(mysql_row[6]); + + if (mysql_row[7] && *(mysql_row[7])) { + na->last_quit = sstrdup(mysql_row[7]); + } + + /* Assign to the nickcore aliases */ + slist_add(&na->nc->aliases, na); + + /* Check if this user is a services root */ + for (i = 0; i < RootNumber; i++) { + if (stricmp(ServicesRoots[i], na->nick) == 0) + na->nc->flags |= NI_SERVICES_ROOT; + } + + /* Last, but not least: insert the alias! */ + alpha_insert_alias(na); + } + + mysql_free_result(mysql_res); + + return ret; +} + +/* get random mysql number for the generator */ +unsigned int mysql_rand(void) +{ + unsigned int num = 0; + + if (!do_mysql) + return 0; + + db_mysql_try("SELECT RAND()"); + + mysql_res = mysql_store_result(mysql); + + if (!(mysql_row = mysql_fetch_row(mysql_res))) { + mysql_free_result(mysql_res); + return 0; + } + + num = UserKey3 * strtol(mysql_row[0], (char **) NULL, 10); + + mysql_free_result(mysql_res); + + return num; +} |