{"NS_UNREGISTER_DONE", "\002%s\002 unregistered."},
{"NS_RECOVER_DONE", "\002%s\002 has been recovered."},
{"NS_RESYNC_DONE", "Synchronized users in \002%s\002 with the userlist."},
+ {"NS_TIMEBAN_DURATION_TOO_SHORT", "You must specify a ban duration of at least %d seconds."},
+ {"NS_TIMEBAN_DONE", "Banned \002%s\002 from %s for %s. (matching %d users)"},
{NULL, NULL}
};
+//define some usefull functions :D
+static TIMEQ_CALLBACK(channel_ban_timeout);
+
/*
INCLUDE ALL CMD's HERE
*/
#include "cmd_neonserv_unsuspend.c"
#include "cmd_neonserv_wipeinfo.c"
#include "cmd_neonserv_addban.c"
-//#include "cmd_neonserv_addtimeban.c"
+#include "cmd_neonserv_addtimeban.c"
#include "cmd_neonserv_delban.c"
#include "cmd_neonserv_bans.c"
//#include "cmd_neonserv_open.c"
}
}
}
+
+ //load all timed bans
+ printf_mysql_query("SELECT `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_timeout` > 0");
+ res = mysql_use();
+ char nameBuf[20];
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ if(atol(row[1]) - time(0) > 0) {
+ sprintf(nameBuf, "ban_%s", row[0]);
+ timeq_add_name(nameBuf, atol(row[1]) - time(0), channel_ban_timeout, strdup(row[0]));
+ } else {
+ //timed out
+ printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[0]);
+ }
+ }
+}
+
+static TIMEQ_CALLBACK(channel_ban_timeout) {
+ char *str_banid = data;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ printf_mysql_query("SELECT `ban_mask` FROM `bans` WHERE `ban_id` = '%s'", str_banid);
+ res = mysql_use();
+ if((row = mysql_fetch_row(res)) != NULL) {
+ //TODO: unban if mask is still banned
+ printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", str_banid);
+ }
+ free(str_banid);
}
void init_NeonServ() {
register_command(BOTID, "topic", neonserv_cmd_topic, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "#channel_changetopic", 0);
register_command(BOTID, "chanservsync", neonserv_cmd_chanservsync, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH,"500", 0);
register_command(BOTID, "resync", neonserv_cmd_resync, 0, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "#channel_canresync", 0);
+ register_command(BOTID, "addtimeban", neonserv_cmd_addtimeban,2, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, "#channel_staticban", 0);
register_command(BOTID, "trace", neonserv_cmd_trace, 1, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH, NULL, 400);
register_command(BOTID, "register", neonserv_cmd_register, 2, CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_CHAN_PARAM | CMDFLAG_OPLOG, NULL, 100);
--- /dev/null
+
+/*
+* argv[0] nick|*auth|*!*@mask
+* argv[1] time
+* argv[2-*] reason
+*/
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup);
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason);
+
+struct neonserv_cmd_addtimeban_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct Event *event;
+ char *mask;
+ int duration;
+ char *reason;
+};
+
+static CMD_BIND(neonserv_cmd_addtimeban) {
+ int duration = strToTime(user, argv[1]);
+ if(duration < 30) {
+ reply(getTextBot(), user, "NS_TIMEBAN_DURATION_TOO_SHORT", 30);
+ return;
+ }
+ struct neonserv_cmd_addtimeban_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->event = event;
+ cache->mask = strdup(argv[0]);
+ cache->duration = duration;
+ if(argc > 2) {
+ cache->reason = strdup(merge_argv(argv, 2, argc));
+ } else
+ cache->reason = NULL;
+ get_userlist(chan, neonserv_cmd_addtimeban_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_addtimeban_userlist_lookup) {
+ struct neonserv_cmd_addtimeban_cache *cache = data;
+ neonserv_cmd_addtimeban_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mask, cache->duration, (cache->reason ? cache->reason : "Bye."));
+ free(cache->mask);
+ if(cache->reason)
+ free(cache->reason);
+ free(cache);
+}
+
+static void neonserv_cmd_addtimeban_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mask, int duration, char *reason) {
+ int match_count = 0;
+ char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
+ char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+ struct UserNode *cuser;
+ struct ChanUser *chanuser;
+ mask = make_banmask(mask, hostmask_buffer);
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ cuser = chanuser->user;
+ sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+ if(!match(mask, usermask)) {
+ if(isNetworkService(chanuser->user)) {
+ reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
+ return;
+ }
+ if(isUserProtected(chan, cuser, user)) {
+ reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+ return;
+ }
+ match_count++;
+ if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
+ reply(textclient, user, "NS_LAME_MASK", mask);
+ return;
+ }
+ }
+ }
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ //check if the provided mask is already banned by another ban
+ char *ban = getBanAffectingMask(chan, mask);
+ if(ban != NULL) {
+ reply(textclient, user, "NS_BAN_ALREADY_ADDED", mask, chan->name);
+ return;
+ }
+ //check if the provided mask affects any existing bans
+ printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+ res = mysql_use();
+ while ((row = mysql_fetch_row(res)) != NULL) {
+ if(!match(mask, row[0])) {
+ //remove the ban
+ printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
+ }
+ }
+ printf_mysql_query("SELECT `user_id` FROM `users` WHERE `user_user` = '%s'", escape_string(user->auth));
+ int userid;
+ res = mysql_use();
+ if ((row = mysql_fetch_row(res)) != NULL)
+ userid = atoi(row[0]);
+ else
+ return;
+ //add the ban
+ printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chan->channel_id, escape_string(mask), (unsigned long) (time(0) + duration), userid, escape_string(reason));
+ int banid = (int) mysql_insert_id(mysql_conn);
+ putsock(client, "MODE %s +b %s", chan->name, mask);
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ cuser = chanuser->user;
+ sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
+ if(!match(mask, usermask)) {
+ putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
+ }
+ }
+ char nameBuf[MAXLEN];
+ char banidBuf[20];
+ sprintf(nameBuf, "ban_%d", banid);
+ sprintf(banidBuf, "%d", banid);
+ timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf));
+ reply(textclient, user, "NS_ADDTIMEBAN_DONE", mask, chan->name, timeToStr(user, duration, 2, nameBuf), match_count);
+ logEvent(event);
+}
return;
}
//check if the provided mask affects any existing bans
- printf_mysql_query("SELECT `ban_mask`, `ban_id` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
+ char nameBuf[20];
+ printf_mysql_query("SELECT `ban_mask`, `ban_id`, `ban_timeout` FROM `bans` WHERE `ban_channel` = '%d'", chan->channel_id);
res = mysql_use();
while ((row = mysql_fetch_row(res)) != NULL) {
if(!match(mask, row[0])) {
//remove the ban
+ if(strcmp(row[2], "0")) {
+ sprintf(nameBuf, "ban_%s", row[1]);
+ timeq_del_name(nameBuf);
+ }
printf_mysql_query("DELETE FROM `bans` WHERE `ban_id` = '%s'", row[1]);
matching_bans++;
}
entry->execute = now + seconds;
entry->callback = callback;
entry->data = data;
+ entry->name = NULL;
struct timeq_entry *next, *prev = NULL;
for(next = timeq_events; next; next = next->next) {
if(next->execute >= entry->execute)
return entry;
}
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data) {
+ struct timeq_entry *entry = timeq_add(seconds, callback, data);
+ entry->name = strdup(name);
+ return entry;
+}
+
int timeq_del(struct timeq_entry* entry) {
struct timeq_entry *centry, *last = NULL;
for(centry = timeq_events; centry; centry = centry->next) {
last->next = centry->next;
else
timeq_events = centry->next;
+ if(centry->name)
+ free(centry->name);
+ free(centry);
+ return 1;
+ } else {
+ last = centry;
+ }
+ }
+ return 0;
+}
+
+int timeq_del_name(char *name) {
+ struct timeq_entry *centry, *last = NULL;
+ for(centry = timeq_events; centry; centry = centry->next) {
+ if(centry->name && !stricmp(centry->name, name)) {
+ if(last)
+ last->next = centry->next;
+ else
+ timeq_events = centry->next;
+ free(centry->name);
free(centry);
return 1;
} else {
#include "main.h"
-#define TIMEQ_CALLBACK(NAME) int NAME(UNUSED_ARG(void *data))
+#define TIMEQ_CALLBACK(NAME) void NAME(UNUSED_ARG(void *data))
typedef TIMEQ_CALLBACK(timeq_callback_t);
struct timeq_entry {
+ char *name;
time_t execute;
timeq_callback_t *callback;
void *data;
void timeq_tick();
struct timeq_entry* timeq_add(int seconds, timeq_callback_t *callback, void *data);
+struct timeq_entry* timeq_add_name(char *name, int seconds, timeq_callback_t *callback, void *data);
int timeq_del(struct timeq_entry* entry);
+int timeq_del_name(char *name);
#endif
\ No newline at end of file