`user_god` tinyint(1) NOT NULL,
`user_lang` varchar(6) NOT NULL,
`user_reply_privmsg` tinyint(1) NOT NULL,
+ `user_registered` INT(20) NOT NULL,
+ `user_lastcheck` INT(20) NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_user` (`user_user`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
`channel_gethalfop` = '150' WHERE `channel_name` = 'defaults';
-- version: 14
+
+ALTER TABLE `users` ADD `user_registered` INT( 20 ) NOT NULL ,
+ADD `user_lastcheck` INT( 20 ) NOT NULL;
+
+-- version: 15
+
*/
"MySQL" {
- "host" = "127.0.0.1 ";
+ "host" = "127.0.0.1";
"port" = 3306;
"user" = "neonserv";
"pass" = "password";
"General" {
"alertchan" = "";
"have_halfop" = 0;
+ "CheckAuths" {
+ "enabled" = 1;
+ "start_time" = 3; //24h format
+ "duration" = 180; //minutes
+ "interval" = 2; //seconds
+ "min_unckecked" = 172800; //check auth only if unchecked for x seconds
+ //180 miutes, every 2 seconds: 5400 auth checks
+ "alertchan" = "#krypton.intern";
+ };
};
"QServer" {
"enabled" = 1;
#ifdef HAVE_THREADS
static pthread_mutex_t synchronized;
static pthread_mutex_t synchronized_recv;
+
+struct ParseOrder {
+ unsigned long tid;
+ struct ParseOrder *next;
+};
+struct ParseOrder *parse_order = NULL;
#endif
//the magic list :P
return write_socket_force(client, msg, len);
}
+#if HAVE_THREADS
+static void clientsocket_start_of_recv(unsigned long tid) {
+ SYNCHRONIZE(whohandler_sync);
+ struct ParseOrder *entry, *last;
+ for(last = parse_order; last; last = last->next) {
+ if(last->next == NULL)
+ break;
+ }
+ entry = malloc(sizeof(*entry));
+ entry->tid = tid;
+ entry->next = NULL;
+ if(last)
+ last->next = entry;
+ else
+ parse_order = entry;
+ DESYNCHRONIZE(whohandler_sync);
+}
+
+static void clientsocket_end_of_recv(unsigned long tid) {
+ SYNCHRONIZE(whohandler_sync);
+ struct ParseOrder *entry, *last = NULL;
+ for(entry = parse_order; entry; entry = entry->next) {
+ if(entry->tid == tid) {
+ if(last)
+ last->next = entry->next;
+ else
+ parse_order = entry->next;
+ free(entry);
+ break;
+ } else
+ last = entry;
+ }
+ DESYNCHRONIZE(whohandler_sync);
+}
+
+int clientsocket_parseorder_top(unsigned long tid) {
+ if(parse_order && parse_order->tid == tid)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
void socket_loop(int timeout_seconds) {
if(sockets == NULL) return;
int is_synchronized = 1;
}
is_synchronized = 0;
unsigned long tid = syscall(SYS_gettid);
- whohandler_start_of_recv(sock, tid);
+ clientsocket_start_of_recv(tid);
DESYNCHRONIZE(synchronized_recv);
parse_lines(sock, linesbuf, used);
- whohandler_end_of_recv(sock, tid); //WHOHandler hack (unlock WHOQueue mutexes)
+ clientsocket_end_of_recv(tid);
#else
int used = parse_lines(sock, sock->buffer, sock->bufferpos);
if(used == sock->bufferpos + 1) {
int disconnect_socket(struct ClientSocket *client);
int write_socket_force(struct ClientSocket *client, char* msg, int len);
int write_socket(struct ClientSocket *client, char* msg, int len);
+#ifdef HAVE_THREADS
+int clientsocket_parseorder_top(unsigned long tid);
+#endif
void socket_loop(int timeout_seconds);
void putsock(struct ClientSocket *client, const char *text, ...) PRINTF_LIKE(2, 3);
struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot);
#include "tools.h"
#include "IRCEvents.h"
#include "HandleInfoHandler.h"
+#include "ClientSocket.h"
void _loadUserSettings(struct UserNode *user) {
SYNCHRONIZE(cache_sync);
free(cache->oldauth);
}
+void deleteUser(int userid) {
+ //simply delete the user
+ MYSQL_RES *res, *res2;
+ MYSQL_ROW row, row2;
+ printf_mysql_query("SELECT a.`chanuser_access`, a.`chanuser_cid`, (SELECT COUNT(*) FROM `chanusers` AS b WHERE b.`chanuser_cid` = a.`chanuser_cid` AND b.`chanuser_access` = 500) FROM `chanusers` AS a WHERE a.`chanuser_uid` = '%d'", userid);
+ res = mysql_use();
+ while((row = mysql_fetch_row(res))) {
+ if(!strcmp(row[0], "500") && !strcmp(row[2], "1")) {
+ //unregister channel
+ printf_mysql_query("SELECT `botid`, `channel_name` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `chanid` = '%s' AND `suspended` = '0'", row[1]);
+ res2 = mysql_use();
+ while((row2 = mysql_fetch_row(res))) {
+ struct ClientSocket *bot;
+ int clientid = atoi(row2[0]);
+ for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+ if(bot->clientid == clientid)
+ putsock(bot, "PART %s :Channel unregistered.", row2[1]);
+ }
+ }
+ printf_mysql_query("DELETE FROM `bot_channels` WHERE `chanid` = '%s'", row[1]);
+ }
+ }
+ printf_mysql_query("DELETE FROM `chanusers` WHERE `chanuser_uid` = '%d'", userid);
+ printf_mysql_query("UPDATE `bans` SET `ban_owner` = 0 WHERE `ban_owner` = '%d'", userid);
+ printf_mysql_query("UPDATE `donotregister` SET `dnr_user` = 0 WHERE `dnr_user` = '%d'", userid);
+ printf_mysql_query("UPDATE `bans` SET `ban_owner` = 0 WHERE `ban_owner` = '%d'", userid);
+ printf_mysql_query("UPDATE `godlog` SET `godlog_uid` = 0 WHERE `godlog_uid` = '%d'", userid);
+ printf_mysql_query("DELETE FROM `noinvite` WHERE `uid` = '%d'", userid);
+ printf_mysql_query("UPDATE `owner_history` SET `owner_history_to_uid` = 0 WHERE `owner_history_to_uid` = '%d'", userid);
+ printf_mysql_query("UPDATE `owner_history` SET `owner_history_from_uid` = 0 WHERE `owner_history_from_uid` = '%d'", userid);
+ printf_mysql_query("UPDATE `channels` SET `channel_registrator` = 0 WHERE `channel_registrator` = '%d'", userid);
+ printf_mysql_query("DELETE FROM `users` WHERE `user_id` = '%d'", userid);
+ struct UserNode *user;
+ for(user = getAllUsers(NULL); user; user = getAllUsers(user)) {
+ if(user->flags & USERFLAG_HAS_USERID)
+ user->flags &= ~USERFLAG_HAS_USERID;
+ }
+}
+
void init_DBHelper() {
bind_registered(event_user_registered);
}
int renameAccount(char *oldauth, char *newauth);
+void deleteUser(int userid);
+
void init_DBHelper();
#endif
\ No newline at end of file
char *auth = NULL;
int do_match = 0, exists = 0;
char *tmp;
+ time_t registered = time(0);
+ struct tm *timeinfo;
//messages to parse:
// Account * has not been registered.
// Account information for Skynet:
auth = tmp+1;
tmp = strstr(auth, "\002");
*tmp = '\0';
- }
- if(!match("Account information for *", message)) {
- do_match = 1;
+ } else if(!match("Account information for *", message)) {
+ do_match = 2;
exists = 1;
tmp = strstr(message, "\002");
auth = tmp+1;
tmp = strstr(auth, "\002");
*tmp = '\0';
+ } else if(!match(" Registered on: *", message)) {
+ do_match = 1;
+ exists = 1;
+ tmp = strstr(message, ": ");
+ tmp += 2;
+ timeinfo = localtime(®istered);
+ timeinfo->tm_year = 0;
+ //parse time
+ //Sat Nov 19 14:52:57 2011
+ tmp = strchr(tmp, ' ');
+ if(!tmp) goto errparse;
+ tmp++;
+ char *tmp2 = strchr(tmp, ' ');
+ if(!tmp2) goto errparse;
+ *tmp2 = '\0';
+ if(!stricmp(tmp, "Jan"))
+ timeinfo->tm_mon = 0;
+ else if(!stricmp(tmp, "Feb"))
+ timeinfo->tm_mon = 1;
+ else if(!stricmp(tmp, "Mar"))
+ timeinfo->tm_mon = 2;
+ else if(!stricmp(tmp, "Apr"))
+ timeinfo->tm_mon = 3;
+ else if(!stricmp(tmp, "May"))
+ timeinfo->tm_mon = 4;
+ else if(!stricmp(tmp, "Jun"))
+ timeinfo->tm_mon = 5;
+ else if(!stricmp(tmp, "Jul"))
+ timeinfo->tm_mon = 6;
+ else if(!stricmp(tmp, "Aug"))
+ timeinfo->tm_mon = 7;
+ else if(!stricmp(tmp, "Sep"))
+ timeinfo->tm_mon = 8;
+ else if(!stricmp(tmp, "Oct"))
+ timeinfo->tm_mon = 9;
+ else if(!stricmp(tmp, "Nov"))
+ timeinfo->tm_mon = 10;
+ else if(!stricmp(tmp, "Dec"))
+ timeinfo->tm_mon = 11;
+ tmp = tmp2 + 1;
+ tmp2 = strchr(tmp, ' ');
+ if(!tmp2) goto errparse;
+ *tmp2 = '\0';
+ timeinfo->tm_mday = atoi(tmp);
+ tmp = tmp2 + 1;
+ if(*tmp == ' ') tmp++;
+ tmp2 = strchr(tmp, ':');
+ if(!tmp2) goto errparse;
+ *tmp2 = '\0';
+ timeinfo->tm_hour = atoi(tmp);
+ tmp = tmp2 + 1;
+ tmp2 = strchr(tmp, ':');
+ if(!tmp2) goto errparse;
+ *tmp2 = '\0';
+ timeinfo->tm_min = atoi(tmp);
+ tmp = tmp2 + 1;
+ tmp2 = strchr(tmp, ' ');
+ if(!tmp2) goto errparse;
+ *tmp2 = '\0';
+ timeinfo->tm_sec = atoi(tmp);
+ tmp = tmp2 + 1;
+ timeinfo->tm_year = atoi(tmp) - 1900;
+ registered = mktime(timeinfo);
}
+ errparse:
+
if(do_match) {
- struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, 1);
+ #ifdef HAVE_THREADS
+ unsigned long tid = syscall(SYS_gettid);
+ while(!clientsocket_parseorder_top(tid)) {
+ usleep(1000); //1ms
+ }
+ #endif
+ struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, ((do_match != 2) ? 1 : 0));
if(entry) {
+ if(do_match == 2) {
+ free(entry->auth);
+ entry->auth = strdup(auth);
+ return;
+ }
authlookup_callback_t *callback;
int i;
for(i = 0; i < MAXCALLBACKS; i++) {
callback = entry->callback[i];
if(!callback) break;
- callback(auth, exists, entry->data[i]);
+ callback(entry->auth, exists, registered, entry->data[i]);
}
free(entry->auth);
free(entry);
struct ClientSocket;
struct UserNode;
-#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(void *data))
+#define AUTHLOOKUP_CALLBACK(NAME) void NAME(UNUSED_ARG(char *auth), UNUSED_ARG(int exists), UNUSED_ARG(time_t registered), UNUSED_ARG(void *data))
typedef AUTHLOOKUP_CALLBACK(authlookup_callback_t);
void clear_handleinfoqueue(struct ClientSocket *client);
void *data[MAXCALLBACKS];
};
-#ifdef HAVE_THREADS
-struct ParseOrder {
- unsigned long tid;
- struct ParseOrder *next;
-};
-struct ParseOrder *parse_order = NULL;
-#endif
-
static int checkWHOID(struct ClientSocket *client, int whoid) {
struct WHOQueueEntry *entry;
for(entry = client->whoqueue_first; entry; entry = entry->next) {
DESYNCHRONIZE(whohandler_sync);
}
-#if HAVE_THREADS
-void whohandler_start_of_recv(struct ClientSocket *client, unsigned long tid) {
- SYNCHRONIZE(whohandler_sync);
- struct ParseOrder *entry, *last;
- for(last = parse_order; last; last = last->next) {
- if(last->next == NULL)
- break;
- }
- entry = malloc(sizeof(*entry));
- entry->tid = tid;
- entry->next = NULL;
- if(last)
- last->next = entry;
- else
- parse_order = entry;
- DESYNCHRONIZE(whohandler_sync);
-}
-
-void whohandler_end_of_recv(struct ClientSocket *client, unsigned long tid) {
- SYNCHRONIZE(whohandler_sync);
- struct ParseOrder *entry, *last = NULL;
- for(entry = parse_order; entry; entry = entry->next) {
- if(entry->tid == tid) {
- if(last)
- last->next = entry->next;
- else
- parse_order = entry->next;
- free(entry);
- break;
- } else
- last = entry;
- }
- DESYNCHRONIZE(whohandler_sync);
-}
-#endif
-
void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
struct ClientSocket *bot;
for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
if(entry == NULL) return;
#ifdef HAVE_THREADS
unsigned long tid = syscall(SYS_gettid);
- while(parse_order->tid != tid) {
- usleep(5000); //5ms
+ while(!clientsocket_parseorder_top(tid)) {
+ usleep(1000); //1ms
}
#endif
if(entry->type & WHOQUEUETYPE_USERLIST) {
if(entry == NULL) return;
#ifdef HAVE_THREADS
unsigned long tid = syscall(SYS_gettid);
- while(parse_order->tid != tid) {
- usleep(5000); //5ms
+ while(!clientsocket_parseorder_top(tid)) {
+ usleep(1000); //1ms
}
#endif
getNextWHOQueueEntry(client, type, 1);
typedef USERAUTH_CALLBACK(userauth_callback_t);
void clear_whoqueue(struct ClientSocket *client);
-#if HAVE_THREADS
-void whohandler_start_of_recv(struct ClientSocket *client, unsigned long tid);
-void whohandler_end_of_recv(struct ClientSocket *client, unsigned long tid);
-#endif
void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc);
void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc);
void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data);
return;
}
if(client->botid == 0)
- printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended`, `bots`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '0' AND `botid` = '%d'", chanid, client->clientid);
+ printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '0' AND `botid` = '%d'", chanid, client->clientid);
else
- printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended`, `bots`.`id` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
+ printf_mysql_query("SELECT `botid`, `bot_channels`.`id`, `suspended` FROM `bot_channels` LEFT JOIN `bots` ON `bot_channels`.`botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chanid, client->botid);
res = mysql_use();
if ((row = mysql_fetch_row(res)) == NULL) {
reply(getTextBot(), user, "NS_UNREGISTER_NOT_REGISTERED", argv[0], client->user->nick);
return;
}
int botid = atoi(row[0]);
- int clientid = atoi(row[3]);
struct ClientSocket *bot;
for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
- if(bot->clientid == botid && (!botid || bot->clientid == clientid))
+ if(bot->clientid == botid)
break;
}
if(bot && strcmp(row[2], "1")) {
static int statistics_requested_lusers = 0;
int statistics_enabled;
TIMEQ_CALLBACK(main_statistics);
+TIMEQ_CALLBACK(main_checkauths);
#ifdef HAVE_THREADS
int running_threads;
pthread_mutex_t cache_sync;
if(!update_minutes) update_minutes = 2;
timeq_add(update_minutes * 60 + 10, main_statistics, NULL);
+ timeq_add(90, main_checkauths, NULL);
+
int worker_threads = get_int_field("General.worker_threads");
if(!worker_threads) worker_threads = 1;
loadConfig("neonserv.conf");
}
+static int getCurrentSecondsOfDay() {
+ time_t now = time(0);
+ struct tm *timeofday = localtime(&now);
+ int seconds = 0;
+ seconds += timeofday->tm_hour * 3600;
+ seconds += timeofday->tm_min * 60;
+ seconds += timeofday->tm_sec;
+ return seconds;
+}
+
+static AUTHLOOKUP_CALLBACK(main_checkauths_callback) {
+ //check if registered is still valid
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ printf_mysql_query("SELECT `user_id`, `user_registered` FROM `users` WHERE `user_user` = '%s'", escape_string(auth));
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) != NULL) {
+ if(!exists || (strcmp(row[1], "0") && registered != atoi(row[1]))) {
+ //User is no longer valid! Delete it...
+ deleteUser(atoi(row[0]));
+ char *alertchan = get_string_field("General.CheckAuths.alertchan");
+ if(alertchan) {
+ struct ChanNode *alertchan_chan = getChanByName(alertchan);
+ struct ClientSocket *alertclient;
+ if(alertchan_chan && (alertclient = getChannelBot(alertchan_chan, 0)) != NULL) {
+ putsock(alertclient, "PRIVMSG %s :Deleted User %s", alertchan_chan->name, auth);
+ }
+ }
+ } else if(exists && !strcmp(row[1], "0")) {
+ printf_mysql_query("UPDATE `users` SET `user_registered` = '%lu', `user_lastcheck` = UNIX_TIMESTAMP() WHERE `user_id` = '%s'", (unsigned long) registered, row[0]);
+ } else {
+ printf_mysql_query("UPDATE `users` SET `user_lastcheck` = UNIX_TIMESTAMP() WHERE `user_id` = '%s'", row[0]);
+ }
+ }
+}
+
+TIMEQ_CALLBACK(main_checkauths) {
+ int next_call = 600;
+ if(get_int_field("General.CheckAuths.enabled")) {
+ int check_start_time = get_int_field("General.CheckAuths.start_time") * 3600;
+ int duration = get_int_field("General.CheckAuths.duration") * 60;
+ int now = getCurrentSecondsOfDay();
+ if(now < check_start_time && check_start_time+duration >= 86400) {
+ check_start_time -= 86400;
+ }
+ if(now >= check_start_time && now < (check_start_time + duration)) {
+ next_call = get_int_field("General.CheckAuths.interval");
+ //get the "longest-unchecked-user"
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int lastcheck;
+ time_t unixtime = time(0);
+ int min_unckecked = get_int_field("General.CheckAuths.min_unckecked");
+ printf_mysql_query("SELECT `user_user`, `user_lastcheck` FROM `users` ORDER BY `user_lastcheck` ASC LIMIT 1");
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) != NULL) {
+ lastcheck = atoi(row[1]);
+ if(!lastcheck || unixtime - lastcheck >= min_unckecked) {
+ lookup_authname(row[0], main_checkauths_callback, NULL);
+ } else
+ next_call = 300;
+ }
+ } else {
+ int pending;
+ if(now > check_start_time)
+ pending = 86400 - now + check_start_time;
+ else
+ pending = check_start_time - now;
+ if(pending < 600)
+ next_call = pending;
+ }
+
+ }
+ timeq_add(next_call, main_checkauths, NULL);
+}
+
TIMEQ_CALLBACK(main_statistics) {
int update_minutes = get_int_field("statistics.frequency");
if(!update_minutes) update_minutes = 2;
*/
#include "mysqlConn.h"
-#define DATABASE_VERSION "14"
+#define DATABASE_VERSION "15"
struct mysql_conn_struct {
unsigned long tid;