src/cmd_neonhelp_next.c \
src/cmd_neonhelp_delete.c \
src/cmd_neonhelp_requests.c \
+ src/cmd_neonserv_halfop.c \
+ src/cmd_neonserv_dehalfop.c \
+ src/cmd_neonserv_halfopall.c \
+ src/cmd_neonserv_dehalfopall.c \
src/cmd_funcmds.c \
src/ConfigParser.c
`channel_staticban` smallint(3) DEFAULT NULL,
`channel_protect` tinyint(1) DEFAULT NULL,
`channel_canop` smallint(3) DEFAULT NULL,
+ `channel_canhalfop` smallint(3) DEFAULT NULL,
`channel_canvoice` smallint(3) DEFAULT NULL,
`channel_getop` smallint(3) DEFAULT NULL,
+ `channel_gethalfop` smallint(3) DEFAULT NULL,
`channel_getvoice` smallint(3) DEFAULT NULL,
`channel_greeting` varchar(512) NOT NULL,
`channel_usergreeting` varchar(512) NOT NULL,
ALTER TABLE `helpserv_settings` ADD `helpserv_intern_announce` TINYINT( 1 ) NOT NULL;
-- version: 13
+
+ALTER TABLE `channels` ADD `channel_canhalfop` SMALLINT( 3 ) NULL AFTER `channel_canop`;
+ALTER TABLE `channels` ADD `channel_gethalfop` SMALLINT( 3 ) NULL AFTER `channel_getop`;
+UPDATE `channels` SET `channel_canhalfop` = '150',
+`channel_gethalfop` = '150' WHERE `channel_name` = 'defaults';
+
+-- version: 14
"user" = "neonserv";
"pass" = "password";
"base" = "neonserv";
+};
+"General" {
+ "alertchan" = "";
+ "have_halfop" = 0;
};
\ No newline at end of file
#include "timeq.h"
#include "EventLogger.h"
#include "cmd_neonserv.h"
+#include "ConfigParser.h"
#define BOTID 1
#define BOTALIAS "NeonServ"
{"NS_GIVEOWNER_DONE", "Ownership of $b%s$b has been transferred to account $b%s$b."}, /* {ARGS: "#TestChan", "TestUser"} */
{"NS_OP_FAIL", "$b%s$b could not op some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
{"NS_OP_DONE", "Opped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+ {"NS_HALFOP_FAIL", "$b%s$b could not halfop some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+ {"NS_HALFOP_DONE", "Half-Opped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
{"NS_VOICE_FAIL", "$b%s$b could not voice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
{"NS_VOICE_DONE", "Voiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
{"NS_DEOP_FAIL", "$b%s$b could not deop some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
{"NS_DEOP_DONE", "Deopped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
+ {"NS_DEHALFOP_FAIL", "$b%s$b could not dehalfop some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
+ {"NS_DEHALFOP_DONE", "Dehalfopped users in $b%s$b."}, /* {ARGS: "#TestChan"} */
{"NS_DEVOICE_FAIL", "$b%s$b could not devoice some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
{"NS_DEVOICE_DONE", "Devoiced users in $b%s$b."}, /* {ARGS: "#TestChan"} */
{"NS_OPALL_SECURITY", "$bWARNING$b: Opping all users on a channel is very insecure! If you still want do op all users on %s use: '$bopall FORCE$b [nick mask]'"},
{"NS_OPALL_DONE", "Opped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+ {"NS_HALFOPALL_DONE", "Half-Opped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
{"NS_VOICEALL_DONE", "Voiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
{"NS_DEOPALL_DONE", "Deopped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
+ {"NS_DEHALFOPALL_DONE", "Dehalfopped $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
{"NS_DEVOICEALL_DONE", "Devoiced $b%d$b users in %s."}, /* {ARGS: 20, "#TestChan"} */
{"NS_KICK_DONE", "Kicked $b%d$b users from %s"}, /* {ARGS: 20, "#TestChan"} */
{"NS_KICK_FAIL", "$b%s$b could not kick some of the nicks you provided."}, /* {ARGS: "NeonServ"} */
{"NS_PEEK_TOPIC", "Topic: %s"}, /* {ARGS: "TOPIC"} */
{"NS_PEEK_MODES", "Modes: %s"}, /* {ARGS: "+xyz"} */
{"NS_PEEK_USERS", "Total Users: %d (%d ops, %d voices, %d regulars, %d invisible)"}, /* {ARGS: 20, 4, 6, 8, 2} */
+ {"NS_PEEK_USERS_HALFOP", "Total Users: %d (%d ops, %d halfops, %d voices, %d regulars, %d invisible)"}, /* {ARGS: 25, 5, 4, 6, 8, 2} */
{"NS_PEEK_OPS", "Ops:"},
{"NS_USET_GLOBAL", "$b--- Global ---$b"},
{"NS_USET_CHANNEL", "$b--- User options (channel) ---$b"},
#include "EventLogger.h"
#include "bots.h"
#include "bot_NeonServ.h"
+#include "ConfigParser.h"
CMD_BIND(neonserv_cmd_access);
CMD_BIND(neonserv_cmd_addban);
CMD_BIND(neonserv_cmd_clvl);
CMD_BIND(neonserv_cmd_csuspend);
CMD_BIND(neonserv_cmd_cunsuspend);
+CMD_BIND(neonserv_cmd_dehalfop);
+CMD_BIND(neonserv_cmd_dehalfopall);
CMD_BIND(neonserv_cmd_delban);
CMD_BIND(neonserv_cmd_delme);
CMD_BIND(neonserv_cmd_delrank);
CMD_BIND(neonserv_cmd_events);
CMD_BIND(neonserv_cmd_extscript);
CMD_BIND(neonserv_cmd_giveowner);
+CMD_BIND(neonserv_cmd_halfop);
+CMD_BIND(neonserv_cmd_halfopall);
CMD_BIND(neonserv_cmd_help);
CMD_BIND(neonserv_cmd_info);
CMD_BIND(neonserv_cmd_invite);
--- /dev/null
+/* cmd_neonserv_dehalfop.c - NeonServ v5.3
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*] nicks
+*/
+static USERLIST_CALLBACK(neonserv_cmd_dehalfop_userlist_lookup);
+static void neonserv_cmd_dehalfop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
+
+struct neonserv_cmd_dehalfop_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct Event *event;
+ char **argv;
+ int argc;
+};
+
+CMD_BIND(neonserv_cmd_dehalfop) {
+ struct neonserv_cmd_dehalfop_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->event = event;
+ cache->argv = calloc(argc, sizeof(char*));
+ int i;
+ for(i = 0; i < argc; i++) {
+ cache->argv[i] = strdup(argv[i]);
+ }
+ cache->argc = argc;
+ get_userlist(chan, neonserv_cmd_dehalfop_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_dehalfop_userlist_lookup) {
+ struct neonserv_cmd_dehalfop_cache *cache = data;
+ neonserv_cmd_dehalfop_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
+ int i;
+ for(i = 0; i < cache->argc; i++) {
+ free(cache->argv[i]);
+ }
+ free(cache);
+}
+
+static void neonserv_cmd_dehalfop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
+ int i, done_users = 0;
+ struct UserNode *cuser;
+ struct ChanUser *chanuser;
+ struct ModeBuffer *modeBuf;
+ modeBuf = initModeBuffer(client, chan);
+ for(i = 0; i < argc; i++) {
+ cuser = searchUserByNick(argv[i]);
+ if(!cuser) continue;
+ chanuser = getChanUser(cuser, chan);
+ if(!chanuser) continue;
+ if(isNetworkService(cuser)) {
+ reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
+ continue;
+ }
+ if(isUserProtected(chan, cuser, user)) {
+ reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
+ continue;
+ }
+ done_users++;
+ if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
+ modeBufferDehalfop(modeBuf, argv[i]);
+ }
+ freeModeBuffer(modeBuf);
+ if(done_users == argc)
+ reply(textclient, user, "NS_DEHALFOP_DONE", chan->name);
+ else
+ reply(textclient, user, "NS_DEHALFOP_FAIL", client->user->nick);
+ if(done_users)
+ logEvent(event);
+}
--- /dev/null
+/* cmd_neonserv_dehalfopall.c - NeonServ v5.3
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_dehalfopall_userlist_lookup);
+static void neonserv_cmd_dehalfopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc);
+
+struct neonserv_cmd_dehalfopall_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct Event *event;
+ char **argv;
+ int argc;
+};
+
+CMD_BIND(neonserv_cmd_dehalfopall) {
+ struct neonserv_cmd_dehalfopall_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->event = event;
+ cache->argv = calloc(argc, sizeof(char*));
+ int i;
+ for(i = 0; i < argc; i++) {
+ cache->argv[i] = strdup(argv[i]);
+ }
+ cache->argc = argc;
+ get_userlist(chan, neonserv_cmd_dehalfopall_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_dehalfopall_userlist_lookup) {
+ struct neonserv_cmd_dehalfopall_cache *cache = data;
+ neonserv_cmd_dehalfopall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->argv, cache->argc);
+ int i;
+ for(i = 0; i < cache->argc; i++) {
+ free(cache->argv[i]);
+ }
+ free(cache);
+}
+
+static void neonserv_cmd_dehalfopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char **argv, int argc) {
+ int issuer_access, victim_access, done_users = 0;
+ char *nickmask = NULL;
+ struct ChanUser *chanuser;
+ struct ModeBuffer *modeBuf;
+ if(argc > 0)
+ nickmask = argv[0];
+ modeBuf = initModeBuffer(client, chan);
+ issuer_access = getChannelAccess(user, chan);
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+ victim_access = getChannelAccess(chanuser->user, chan);
+ if(victim_access >= issuer_access || isNetworkService(chanuser->user)) continue;
+ if(!(chanuser->flags & CHANUSERFLAG_OPPED)) continue;
+ modeBufferDehalfop(modeBuf, chanuser->user->nick);
+ done_users++;
+ }
+ freeModeBuffer(modeBuf);
+ reply(getTextBot(), user, "NS_DEHALFOPALL_DONE", done_users, chan->name);
+ if(done_users)
+ logEvent(event);
+}
--- /dev/null
+/* cmd_neonserv_halfop.c - NeonServ v5.3
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*] nicks
+*/
+static USERLIST_CALLBACK(neonserv_cmd_halfop_userlist_lookup);
+static void neonserv_cmd_halfop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks);
+
+struct neonserv_cmd_halfop_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct Event *event;
+ char *nicks;
+};
+
+CMD_BIND(neonserv_cmd_halfop) {
+ struct neonserv_cmd_halfop_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->event = event;
+ cache->nicks = strdup(merge_argv(argv, 0, argc));
+ get_userlist_if_invisible(chan, neonserv_cmd_halfop_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_halfop_userlist_lookup) {
+ struct neonserv_cmd_halfop_cache *cache = data;
+ neonserv_cmd_halfop_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nicks);
+ free(cache->nicks);
+ free(cache);
+}
+
+static void neonserv_cmd_halfop_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nicks) {
+ int total_users = 0, done_users = 0;
+ struct UserNode *cuser;
+ struct ChanUser *chanuser;
+ struct ModeBuffer *modeBuf;
+ modeBuf = initModeBuffer(client, chan);
+ char *a, *b = nicks;
+ do {
+ a = strstr(b, " ");
+ if(a) *a = '\0';
+ total_users++;
+ cuser = searchUserByNick(b);
+ if(!cuser) {
+ //check for an invisible user
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if(!stricmp(chanuser->user->nick, b)) {
+ cuser = chanuser->user;
+ break;
+ }
+ }
+ if(!cuser) continue;
+ } else {
+ chanuser = getChanUser(cuser, chan);
+ if(!chanuser) continue;
+ }
+ done_users++;
+ if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
+ modeBufferHalfop(modeBuf, b);
+ if(a) {
+ b = a+1;
+ }
+ } while(a);
+ freeModeBuffer(modeBuf);
+ if(done_users == total_users)
+ reply(textclient, user, "NS_HALFOP_DONE", chan->name);
+ else
+ reply(textclient, user, "NS_HALFOP_FAIL", client->user->nick);
+ if(done_users)
+ logEvent(event);
+}
--- /dev/null
+/* cmd_neonserv_halfopall.c - NeonServ v5.3
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0] "force"
+* argv[1] (optional) nick mask
+*/
+static USERLIST_CALLBACK(neonserv_cmd_halfopall_userlist_lookup);
+static void neonserv_cmd_halfopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask);
+
+struct neonserv_cmd_halfopall_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct Event *event;
+ char *nickmask;
+};
+
+CMD_BIND(neonserv_cmd_halfopall) {
+ struct neonserv_cmd_halfopall_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->event = event;
+ if(argc) {
+ cache->nickmask = strdup(argv[0]);
+ } else
+ cache->nickmask = NULL;
+ get_userlist_if_invisible(chan, neonserv_cmd_halfopall_userlist_lookup, cache);
+}
+
+static USERLIST_CALLBACK(neonserv_cmd_halfopall_userlist_lookup) {
+ struct neonserv_cmd_halfopall_cache *cache = data;
+ neonserv_cmd_halfopall_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->nickmask);
+ if(cache->nickmask)
+ free(cache->nickmask);
+ free(cache);
+}
+
+static void neonserv_cmd_halfopall_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *nickmask) {
+ int done_users = 0;
+ struct ChanUser *chanuser;
+ struct ModeBuffer *modeBuf;
+ modeBuf = initModeBuffer(client, chan);
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if(nickmask && match(nickmask, chanuser->user->nick)) continue;
+ if(chanuser->flags & CHANUSERFLAG_OPPED) continue;
+ modeBufferHalfop(modeBuf, chanuser->user->nick);
+ done_users++;
+ }
+ freeModeBuffer(modeBuf);
+ reply(textclient, user, "NS_HALFOPALL_DONE", done_users, chan->name);
+ if(done_users)
+ logEvent(event);
+}
getModeString(chan->modes, tmpStr);
reply(textclient, user, "NS_PEEK_MODES", tmpStr);
struct ChanUser *chanuser;
- int op_count = 0, voice_count = 0, normal_count = 0, invi_count = 0;
+ int with_halfops = get_int_field("General.have_halfop");
+ int op_count = 0, halfop_count = 0, voice_count = 0, normal_count = 0, invi_count = 0;
for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
if(chanuser->flags & CHANUSERFLAG_OPPED)
op_count++;
+ else if(with_halfops && (chanuser->flags & CHANUSERFLAG_HALFOPPED))
+ halfop_count++;
else if(chanuser->flags & CHANUSERFLAG_VOICED)
voice_count++;
else if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
else
normal_count++;
}
- reply(textclient, user, "NS_PEEK_USERS", op_count+voice_count+invi_count+normal_count, op_count, voice_count, normal_count, invi_count);
+ if(with_halfops)
+ reply(textclient, user, "NS_PEEK_USERS_HALFOP", op_count+halfop_count+voice_count+invi_count+normal_count, op_count, halfop_count, voice_count, normal_count, invi_count);
+ else
+ reply(textclient, user, "NS_PEEK_USERS", op_count+voice_count+invi_count+normal_count, op_count, voice_count, normal_count, invi_count);
int tmpStrPos = 0;
int headerlen = 10 + strlen(user->nick);
for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
MYSQL_ROW row, defaults = NULL;
int i;
int resync_op = 1;
+ int with_halfop = get_int_field("General.have_halfop");
+ int resync_halfop = with_halfop;
int resync_voice = 1;
if(usermask && usermask[0] == '@') {
+ resync_voice = 0;
+ resync_halfop = 0;
+ usermask++;
+ if(!*usermask) usermask = NULL;
+ } else if(usermask && with_halfop && usermask[0] == 'h') {
+ resync_op = 0;
resync_voice = 0;
usermask++;
if(!*usermask) usermask = NULL;
} else if(usermask && usermask[0] == '+') {
resync_op = 0;
+ resync_halfop = 0;
usermask++;
if(!*usermask) usermask = NULL;
}
struct ChanUser *chanuser;
- int db_enfops, db_enfvoice;
- printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+ int db_enfops, db_enfhalfop, db_enfvoice;
+ printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_gethalfop` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
row = mysql_fetch_row(mysql_use());
if(row[0] == NULL || row[1] == NULL) {
- printf_mysql_query("SELECT `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+ printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_gethalfop` FROM `channels` WHERE `channel_name` = 'defaults'");
defaults = mysql_fetch_row(mysql_use());
}
db_enfops = atoi((row[0] ? row[0] : defaults[0]));
db_enfvoice = atoi((row[1] ? row[1] : defaults[1]));
+ db_enfhalfop = (with_halfop ? atoi((row[2] ? row[2] : defaults[2])) : 0);
printf_mysql_query("SELECT `chanuser_access`, `user_user`, `chanuser_flags` FROM `chanusers` LEFT JOIN `users` ON `chanuser_uid` = `user_id` WHERE `chanuser_cid` = '%d' ORDER BY `chanuser_access` DESC, `user_user` ASC", chan->channel_id);
res = mysql_use();
char *db_users[mysql_num_rows(res)];
if(caccess >= db_enfops) {
if(!(chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
modeBufferOp(modeBuf, chanuser->user->nick);
+ } else if(with_halfop && caccess >= db_enfhalfop) {
+ if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+ modeBufferDeop(modeBuf, chanuser->user->nick);
+ if(!(chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
+ modeBufferHalfop(modeBuf, chanuser->user->nick);
} else if(caccess >= db_enfvoice) {
if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
modeBufferDeop(modeBuf, chanuser->user->nick);
+ if((chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+ modeBufferDehalfop(modeBuf, chanuser->user->nick);
if(!(chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
modeBufferVoice(modeBuf, chanuser->user->nick);
} else {
if((chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
modeBufferDeop(modeBuf, chanuser->user->nick);
+ if((chanuser->flags & CHANUSERFLAG_HALFOPPED) && resync_halfop && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
+ modeBufferDehalfop(modeBuf, chanuser->user->nick);
if((chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
modeBufferDevoice(modeBuf, chanuser->user->nick);
}
#define NS_VALID_OPTIONS 0x10
#define NS_VALID_NUMERIC 0x20
#define NS_VALID_BOOLEAN 0x40
+#define NS_VALID_IF_HALFOP 0x80
#define NS_HAS_OPT 0x100 /* options (SET_OPTION_{NAME}_{VALUE}) */
#define NS_HAS_HELP 0x200 /* help (SET_HELP_{NAME}) - only shown if help is requested */
{"MODES", "channel_modes", NS_VALID_FUNCTION, neonserv_cmd_set_modes},
{"INVITEME", "channel_getinvite", NS_VALID_ACCESS, NULL},
{"GIVEOPS", "channel_getop", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
+ {"GIVEHALFOPS", "channel_gethalfop", NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
{"GIVEVOICE", "channel_getvoice", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
{"ENFOPS", "channel_canop", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
+ {"ENFHALFOPS", "channel_canhalfop", NS_VALID_ACCESS | NS_HAS_HELP | NS_VALID_IF_HALFOP, NULL},
{"ENFVOICE", "channel_canvoice", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
{"KICK", "channel_cankick", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
{"BAN", "channel_canban", NS_VALID_ACCESS | NS_HAS_HELP, NULL},
i = 0;
j = 0;
char *args = (argc > 1 ? merge_argv(argv, 1, argc) : NULL);
+ int with_halfops = get_int_field("General.have_halfop");
while(channel_settings[i].setting) {
- if(!stricmp(channel_settings[i].setting, argv[0])) {
+ if(!stricmp(channel_settings[i].setting, argv[0]) && (!(channel_settings[i].valid & NS_VALID_IF_HALFOP) || with_halfops)) {
//setting found
if(channel_settings[i].valid & NS_VALID_FUNCTION) {
neonserv_cmd_set_function *func = channel_settings[i].parameter;
MYSQL_ROW row, defaults;
struct Table *table;
char *content[2];
+ int with_halfops = get_int_field("General.have_halfop");
i = 0;
+ j = 0;
while(channel_settings[i].setting) {
+ if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
+ j++;
+ continue;
+ }
if(channel_settings[i].chanfield)
querypos += sprintf(query + querypos, ", `%s`", channel_settings[i].chanfield);
i++;
}
- table = table_init(2, i, 0);
+ table = table_init(2, i-j, 0);
table_set_bold(table, 0, 1);
printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
defaults_res = mysql_use();
j = 0;
reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
while(channel_settings[i].setting) {
+ if((channel_settings[i].valid & NS_VALID_IF_HALFOP) && !with_halfops) {
+ i++;
+ continue;
+ }
if(channel_settings[i].chanfield) {
j++;
org_value = (row[j] ? row[j] : defaults[j]);
#include "cmd_funcmds.h"
#include "cmd_neonhelp.h"
#include "modcmd.h"
+#include "ConfigParser.h"
void register_commands() {
USER_COMMAND("deopall", neonserv_cmd_deopall, 0, "@#channel_getop,#channel_canop", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
USER_COMMAND("voiceall", neonserv_cmd_voiceall, 0, "+#channel_getvoice,#channel_canvoice", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
USER_COMMAND("devoiceall", neonserv_cmd_devoiceall,0, "+#channel_getvoice,#channel_canvoice", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+ if(get_int_field("General.have_halfop")) {
+ USER_COMMAND("halfop", neonserv_cmd_halfop, 1, "%#channel_gethalfop,#channel_canhalfop", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+ USER_COMMAND("dehalfop", neonserv_cmd_dehalfop, 1, "%#channel_gethalfop,#channel_canhalfop", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+ USER_COMMAND("halfopall", neonserv_cmd_halfopall, 0, "%#channel_gethalfop,#channel_canhalfop", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+ USER_COMMAND("dehalfopall", neonserv_cmd_dehalfopall,0,"%#channel_gethalfop,#channel_canhalfop", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
+ }
USER_COMMAND("set", neonserv_cmd_set, 0, "#channel_setters", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
USER_COMMAND("kick", neonserv_cmd_kick, 1, "#channel_cankick", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
USER_COMMAND("kickban", neonserv_cmd_kickban, 1, "#channel_cankick,#channel_canban", CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN | CMDFLAG_REQUIRE_AUTH | CMDFLAG_CHECK_AUTH | CMDFLAG_LOG);
struct ChanNode *chan = chanuser->chan;
struct UserNode *user = chanuser->user;
struct ModeBuffer *modeBuf;
+ int with_halfops = get_int_field("General.have_halfop");
MYSQL_RES *res;
MYSQL_ROW row, chanuserrow, defaultrow = NULL;
- printf_mysql_query("SELECT `channel_maxusers`, `channel_greeting`, `channel_usergreeting`, `channel_getop`, `channel_getvoice`, `channel_userinfo`, `channel_dynlimit` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+ printf_mysql_query("SELECT `channel_maxusers`, `channel_greeting`, `channel_usergreeting`, `channel_getop`, `channel_getvoice`, `channel_userinfo`, `channel_dynlimit`, `channel_gethalfop` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
res = mysql_use();
if ((row = mysql_fetch_row(res)) == NULL) return;
- if(!row[3] || !row[4] || !row[5]) {
- printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_userinfo` FROM `channels` WHERE `channel_name` = 'defaults'");
+ if(!row[3] || !row[4] || !row[5] || (!row[7] && with_halfops)) {
+ printf_mysql_query("SELECT `channel_getop`, `channel_getvoice`, `channel_userinfo`, `channel_gethalfop` FROM `channels` WHERE `channel_name` = 'defaults'");
res = mysql_use();
defaultrow = mysql_fetch_row(res);
}
//USER RIGHTS
if(!(userflags & DB_CHANUSER_NOAUTOOP)) {
int getop = atoi((row[3] ? row[3] : defaultrow[0]));
+ int gethalfop = (with_halfops ? atoi((row[7] ? row[7] : defaultrow[3])) : 0);
int getvoice = atoi((row[4] ? row[4] : defaultrow[1]));
modeBuf = initModeBuffer(client, chan);
if(uaccess >= getop && uaccess != 0) { //we disallow auto op for all users
modeBufferOp(modeBuf, user->nick);
+ } else if(with_halfops && uaccess >= gethalfop) {
+ modeBufferHalfop(modeBuf, user->nick);
} else if(uaccess >= getvoice) {
modeBufferVoice(modeBuf, user->nick);
}
MYSQL_ROW row, defaults = NULL;
int i, arg, add = 1, skip = 0;
unsigned int modetype;
- int db_canop, db_canvoice, db_canban, db_enfmodes, db_getop, db_getvoice;
+ int db_canop, db_canhalfop, db_canvoice, db_canban, db_enfmodes, db_getop, db_gethalfop, db_getvoice;
struct ModeNode *modelock = createModeNode(NULL);
struct ModeBuffer *modeBuf;
struct UserNode *cuser;
struct ChanUser *chanuser;
+ int with_halfops = get_int_field("General.have_halfop");
modeBuf = initModeBuffer(client, chan);
- printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes`, `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
+ printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes`, `channel_getop`, `channel_getvoice`, `channel_gethalfop`, `channel_canhalfop` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
row = mysql_fetch_row(mysql_use());
- if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL || row[4] == NULL || row[5] == NULL || row[6] == NULL) {
- printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes`, `channel_getop`, `channel_getvoice` FROM `channels` WHERE `channel_name` = 'defaults'");
+ if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL || row[4] == NULL || row[5] == NULL || row[6] == NULL || (row[7] == NULL && with_halfops) || (row[8] == NULL && with_halfops)) {
+ printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes`, `channel_getop`, `channel_getvoice`, `channel_gethalfop`, `channel_canhalfop` FROM `channels` WHERE `channel_name` = 'defaults'");
defaults = mysql_fetch_row(mysql_use());
}
db_canop = atoi((row[0] ? row[0] : defaults[0]));
db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
db_getop = atoi((row[5] ? row[5] : defaults[5]));
db_getvoice = atoi((row[6] ? row[6] : defaults[6]));
+ db_gethalfop = (with_halfops ? atoi((row[7] ? row[7] : defaults[7])) : 0);
+ db_canhalfop = (with_halfops ? atoi((row[8] ? row[8] : defaults[8])) : 0);
if(row[4])
parseModeString(modelock, row[4]);
else if(defaults[4])
add = 0;
break;
case 'o':
+ case 'h':
case 'v':
if(arg == argc) {
break;
//someone deopped the bot???
requestOp(client->user, chan);
}
- if(modes[i] == 'o' && !(add && isBot(cuser))) {
+ if((modes[i] == 'o' || (modes[i] == 'h' && !with_halfops)) && !(add && isBot(cuser))) {
if(uaccess < db_canop) {
reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
db_canop = -1;
modeBufferSet(modeBuf, !add, modes[i], carg);
break;
}
- } else if(modes[i] == 'v') {
+ } else if(modes[i] == 'h' && with_halfops && !(add && isBot(cuser))) {
+ if(uaccess < db_canhalfop) {
+ reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
+ db_canhalfop = -1;
+ if(uaccess < db_gethalfop)
+ deop_user = 1;
+ }
+ if(db_canhalfop == -1 && caccess < db_gethalfop) {
+ if(!neonserv_cmd_mode_botwar_detect(client, user, chan))
+ modeBufferSet(modeBuf, !add, modes[i], carg);
+ break;
+ }
+ } else if(modes[i] == 'v' && !(add && isBot(cuser))) {
if(uaccess < db_canvoice) {
reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
db_canvoice = -1;
//BOTWAR!
chanuser->changeTime = time(0);
if(chanuser->chageEvents > 0) {
- putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (BOTWAR_ALERT_CHAN ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
- if(BOTWAR_ALERT_CHAN) {
- struct ChanNode *alertchan = getChanByName(BOTWAR_ALERT_CHAN);
+ char *alertchan = get_string_field("General.alertchan");
+ putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (alertchan ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
+ if(alertchan) {
+ struct ChanNode *alertchan_chan = getChanByName(alertchan);
struct ClientSocket *alertclient;
- if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+ if(alertchan_chan && (alertclient = getBotForChannel(chan)) != NULL) {
char msgBuf[MAXLEN];
- putsock(alertclient, "PRIVMSG %s :%s", alertchan->name, build_language_string(NULL, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
+ putsock(alertclient, "PRIVMSG %s :%s", alertchan_chan->name, build_language_string(NULL, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
}
}
}
//BOTWAR!
chanuser->changeTime = time(0);
if(chanuser->chageEvents > 0) {
- putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (BOTWAR_ALERT_CHAN ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
- if(BOTWAR_ALERT_CHAN) {
- struct ChanNode *alertchan = getChanByName(BOTWAR_ALERT_CHAN);
+ char *alertchan = get_string_field("General.alertchan");
+ putsock(client, "NOTICE @%s :%s %s", chan->name, get_language_string(user, "NS_BOTWAR_DETECTED"), (alertchan ? get_language_string(user, "NS_BOTWAR_REPORTED") : ""));
+ if(alertchan) {
+ struct ChanNode *alertchan_chan = getChanByName(alertchan);
struct ClientSocket *alertclient;
- if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+ if(alertchan_chan && (alertclient = getBotForChannel(chan)) != NULL) {
char msgBuf[MAXLEN];
- putsock(alertclient, "PRIVMSG %s :%s", alertchan->name, build_language_string(NULL, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
+ putsock(alertclient, "PRIVMSG %s :%s", alertchan_chan->name, build_language_string(NULL, msgBuf, "NS_BOTWAR_ALERT", chan->name, user->nick));
}
}
}
#define NEONSERV_VERSION "5.3"
#define VERSION_PATCHLEVEL 543
-#ifndef BOTWAR_ALERT_CHAN
-#define BOTWAR_ALERT_CHAN NULL
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
*/
#include "mysqlConn.h"
-#define DATABASE_VERSION "13"
+#define DATABASE_VERSION "14"
struct used_result {
MYSQL_RES *result;
#define modeBufferSimpleMode(MODEBUF,ADD,MODE) modeBufferSet(MODEBUF, ADD, MODE, NULL)
#define modeBufferOp(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'o', USER)
#define modeBufferDeop(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'o', USER)
+#define modeBufferHalfop(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'h', USER)
+#define modeBufferDehalfop(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'h', USER)
#define modeBufferVoice(MODEBUF,USER) modeBufferSet(MODEBUF, 1, 'v', USER)
#define modeBufferDevoice(MODEBUF,USER) modeBufferSet(MODEBUF, 0, 'v', USER)
#define modeBufferBan(MODEBUF,MASK) modeBufferSet(MODEBUF, 1, 'b', MASK)