added full half-op support
authorpk910 <philipp@zoelle1.de>
Thu, 12 Jan 2012 14:07:20 +0000 (15:07 +0100)
committerpk910 <philipp@zoelle1.de>
Thu, 12 Jan 2012 14:12:36 +0000 (15:12 +0100)
20 files changed:
Makefile.am
database.sql
database.upgrade.sql
neonserv.example.conf
src/bot_NeonServ.c
src/cmd_neonserv.h
src/cmd_neonserv_dehalfop.c [new file with mode: 0644]
src/cmd_neonserv_dehalfopall.c [new file with mode: 0644]
src/cmd_neonserv_halfop.c [new file with mode: 0644]
src/cmd_neonserv_halfopall.c [new file with mode: 0644]
src/cmd_neonserv_peek.c
src/cmd_neonserv_resync.c
src/cmd_neonserv_set.c
src/commands.c
src/event_neonserv_join.c
src/event_neonserv_mode.c
src/event_neonserv_topic.c
src/main.h
src/mysqlConn.c
src/tools.h

index 1f7d907f521ef3e41d68054cf84f7b8996308ef6..ea2f28645c226ba7fd6d025ec8f777aa5e01daf0 100644 (file)
@@ -129,6 +129,10 @@ neonserv_SOURCES = src/version.c \
       src/cmd_neonhelp_next.c \
       src/cmd_neonhelp_delete.c \
       src/cmd_neonhelp_requests.c \
       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
 
       src/cmd_funcmds.c \
       src/ConfigParser.c
 
index 9f3ee1c39b023b01abb3925d0dd06b2dcd7d56bf..2047290e00d50e71b17c93a5d5722052ac532916 100644 (file)
@@ -102,8 +102,10 @@ CREATE TABLE IF NOT EXISTS `channels` (
   `channel_staticban` smallint(3) DEFAULT NULL,
   `channel_protect` tinyint(1) DEFAULT NULL,
   `channel_canop` smallint(3) DEFAULT NULL,
   `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_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,
   `channel_getvoice` smallint(3) DEFAULT NULL,
   `channel_greeting` varchar(512) NOT NULL,
   `channel_usergreeting` varchar(512) NOT NULL,
index fcbb93685347553a7cf3f40d69cd3a98624eff9a..4f4697dccf9da46b841813e021034bb701aa7eda 100644 (file)
@@ -127,3 +127,10 @@ ALTER TABLE `helpserv_requests` ADD `botid` INT( 11 ) NOT NULL AFTER `id`;
 ALTER TABLE `helpserv_settings` ADD `helpserv_intern_announce` TINYINT( 1 ) NOT NULL;
 
 -- version: 13
 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
index 99775aec371723f75d0a28264640742fd9836b4e..abb149d5338bcf56cd356d69a40233273fa74369 100644 (file)
@@ -8,4 +8,8 @@
     "user" = "neonserv";
     "pass" = "password";
     "base" = "neonserv";
     "user" = "neonserv";
     "pass" = "password";
     "base" = "neonserv";
+};
+"General" {
+    "alertchan" = "";
+    "have_halfop" = 0;
 };
\ No newline at end of file
 };
\ No newline at end of file
index 3700d4bb03bc5de11aac2f8840fd8dbed1b3a200..00b87c2c6ed1da3acec1e1ca947435b18797e0ef 100644 (file)
@@ -34,6 +34,7 @@
 #include "timeq.h"
 #include "EventLogger.h"
 #include "cmd_neonserv.h"
 #include "timeq.h"
 #include "EventLogger.h"
 #include "cmd_neonserv.h"
+#include "ConfigParser.h"
 
 #define BOTID 1
 #define BOTALIAS "NeonServ"
 
 #define BOTID 1
 #define BOTALIAS "NeonServ"
@@ -115,16 +116,22 @@ static const struct default_language_entry msgtab[] = {
     {"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_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_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_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_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_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"} */
@@ -244,6 +251,7 @@ static const struct default_language_entry msgtab[] = {
     {"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_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"},
     {"NS_PEEK_OPS", "Ops:"},
     {"NS_USET_GLOBAL", "$b--- Global ---$b"},
     {"NS_USET_CHANNEL", "$b--- User options (channel) ---$b"},
index ac3fa5413970562793003bea9e1f25921cbff39c..0df1a7baf638edb542e71dc1acfa9f513599bfd5 100644 (file)
@@ -37,6 +37,7 @@
 #include "EventLogger.h"
 #include "bots.h"
 #include "bot_NeonServ.h"
 #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_access);
 CMD_BIND(neonserv_cmd_addban);
@@ -50,6 +51,8 @@ CMD_BIND(neonserv_cmd_chanservsync);
 CMD_BIND(neonserv_cmd_clvl);
 CMD_BIND(neonserv_cmd_csuspend);
 CMD_BIND(neonserv_cmd_cunsuspend);
 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_delban);
 CMD_BIND(neonserv_cmd_delme);
 CMD_BIND(neonserv_cmd_delrank);
@@ -63,6 +66,8 @@ CMD_BIND(neonserv_cmd_downall);
 CMD_BIND(neonserv_cmd_events);
 CMD_BIND(neonserv_cmd_extscript);
 CMD_BIND(neonserv_cmd_giveowner);
 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);
 CMD_BIND(neonserv_cmd_help);
 CMD_BIND(neonserv_cmd_info);
 CMD_BIND(neonserv_cmd_invite);
diff --git a/src/cmd_neonserv_dehalfop.c b/src/cmd_neonserv_dehalfop.c
new file mode 100644 (file)
index 0000000..2253797
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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);
+}
diff --git a/src/cmd_neonserv_dehalfopall.c b/src/cmd_neonserv_dehalfopall.c
new file mode 100644 (file)
index 0000000..8dd8d61
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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);
+}
diff --git a/src/cmd_neonserv_halfop.c b/src/cmd_neonserv_halfop.c
new file mode 100644 (file)
index 0000000..ba684cb
--- /dev/null
@@ -0,0 +1,93 @@
+/* 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);
+}
diff --git a/src/cmd_neonserv_halfopall.c b/src/cmd_neonserv_halfopall.c
new file mode 100644 (file)
index 0000000..a52ad6d
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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);
+}
index f32ce6cde4fec8b1b0daf0eb77c3beea2c38558c..51de508c12d535381a2d271bc359bd3f1e378bed 100644 (file)
@@ -53,10 +53,13 @@ static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientS
     getModeString(chan->modes, tmpStr);
     reply(textclient, user, "NS_PEEK_MODES", tmpStr);
     struct ChanUser *chanuser;
     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++;
     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 if(chanuser->flags & CHANUSERFLAG_VOICED)
             voice_count++;
         else if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
@@ -64,7 +67,10 @@ static void neonserv_cmd_peek_async1(struct ClientSocket *client, struct ClientS
         else
             normal_count++;
     }
         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)) {
     int tmpStrPos = 0;
     int headerlen = 10 + strlen(user->nick);
     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
index f2ee0905cc48982dd2a1a8066d744d34812326c5..7c60a6eb044d6265d2db0735e52f8675dae49da5 100644 (file)
@@ -77,26 +77,36 @@ static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct Clien
     MYSQL_ROW row, defaults = NULL;
     int i;
     int resync_op = 1;
     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] == '@') {
     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_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;
         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) {
     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]));
         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)];
     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)];
@@ -130,14 +140,23 @@ static void neonserv_cmd_resync_async1(struct ClientSocket *client, struct Clien
         if(caccess >= db_enfops) {
             if(!(chanuser->flags & CHANUSERFLAG_OPPED) && resync_op && (override_noautoop || !(cflags & DB_CHANUSER_NOAUTOOP)))
                 modeBufferOp(modeBuf, chanuser->user->nick);
         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);
         } 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_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);
         }
             if((chanuser->flags & CHANUSERFLAG_VOICED) && resync_voice && !(chanuser->user->flags & (USERFLAG_ISBOT | USERFLAG_ISIRCOP)))
                 modeBufferDevoice(modeBuf, chanuser->user->nick);
         }
index f35dee91a7c05cab266065e85d67f509f473b58a..2b3ddab2f868ff5b19f2a5fdde69cfc164666149 100644 (file)
@@ -31,6 +31,7 @@ static char* neonserv_cmd_set_nodelete(struct ClientSocket *client, struct UserN
 #define NS_VALID_OPTIONS  0x10
 #define NS_VALID_NUMERIC  0x20
 #define NS_VALID_BOOLEAN  0x40
 #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 */
 
 #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 */
@@ -52,8 +53,10 @@ static const struct {
     {"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},
     {"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},
     {"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},
     {"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},
@@ -125,8 +128,9 @@ CMD_BIND(neonserv_cmd_set) {
         i = 0;
         j = 0;
         char *args = (argc > 1 ? merge_argv(argv, 1, argc) : 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) {
         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;
                 //setting found
                 if(channel_settings[i].valid & NS_VALID_FUNCTION) {
                     neonserv_cmd_set_function *func = channel_settings[i].parameter;
@@ -150,13 +154,19 @@ CMD_BIND(neonserv_cmd_set) {
         MYSQL_ROW row, defaults;
         struct Table *table;
         char *content[2];
         MYSQL_ROW row, defaults;
         struct Table *table;
         char *content[2];
+        int with_halfops = get_int_field("General.have_halfop");
         i = 0;
         i = 0;
+        j = 0;
         while(channel_settings[i].setting) {
         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++;
         }
             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();
         table_set_bold(table, 0, 1);
         printf_mysql_query("SELECT `channel_id` %s FROM `channels` WHERE `channel_name` = 'defaults'", query);
         defaults_res = mysql_use();
@@ -168,6 +178,10 @@ CMD_BIND(neonserv_cmd_set) {
         j = 0;
         reply(getTextBot(), user, "NS_SET_HEADER", chan->name);
         while(channel_settings[i].setting) {
         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]);
             if(channel_settings[i].chanfield) {
                 j++;
                 org_value = (row[j] ? row[j] : defaults[j]);
index c7978d15ba3b8bdd71f54be3492e2df74f6274bf..64128000d151a0fd59cc2ab890afdbcceef6f15e 100644 (file)
@@ -21,6 +21,7 @@
 #include "cmd_funcmds.h"
 #include "cmd_neonhelp.h"
 #include "modcmd.h"
 #include "cmd_funcmds.h"
 #include "cmd_neonhelp.h"
 #include "modcmd.h"
+#include "ConfigParser.h"
 
 void register_commands() {
     
 
 void register_commands() {
     
@@ -88,6 +89,12 @@ 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);
     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);
     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);
index 84845f3d9266f0626ff7e58c53d6d0e11b66e158..77d5de7519a200df297dbe939b3b691b405e8c03 100644 (file)
@@ -77,13 +77,14 @@ static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanU
     struct ChanNode *chan = chanuser->chan;
     struct UserNode *user = chanuser->user;
     struct ModeBuffer *modeBuf;
     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;
     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;
     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);
     }
         res = mysql_use();
         defaultrow = mysql_fetch_row(res);
     }
@@ -143,10 +144,13 @@ static void neonserv_event_join_async1(struct ClientSocket *client, struct ChanU
     //USER RIGHTS
     if(!(userflags & DB_CHANUSER_NOAUTOOP)) {
         int getop = atoi((row[3] ? row[3] : defaultrow[0]));
     //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);
         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);
         }
         } else if(uaccess >= getvoice) {
             modeBufferVoice(modeBuf, user->nick);
         }
index 5c87873d430d6d073884b00e065fb0a7c36f274a..68138530b2b5b4381c5922882194cc9e4e48a5a0 100644 (file)
@@ -76,16 +76,17 @@ static void neonserv_event_mode_async1(struct ClientSocket *client, struct UserN
     MYSQL_ROW row, defaults = NULL;
     int i, arg, add = 1, skip = 0;
     unsigned int modetype;
     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;
     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);
     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());
     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]));
         defaults = mysql_fetch_row(mysql_use());
     }
     db_canop = atoi((row[0] ? row[0] : defaults[0]));
@@ -94,6 +95,8 @@ static void neonserv_event_mode_async1(struct ClientSocket *client, struct UserN
     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_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])
     if(row[4])
         parseModeString(modelock, row[4]);
     else if(defaults[4])
@@ -114,6 +117,7 @@ static void neonserv_event_mode_async1(struct ClientSocket *client, struct UserN
                 add = 0;
                 break;
             case 'o':
                 add = 0;
                 break;
             case 'o':
+            case 'h':
             case 'v':
                 if(arg == argc) {
                     break;
             case 'v':
                 if(arg == argc) {
                     break;
@@ -128,7 +132,7 @@ static void neonserv_event_mode_async1(struct ClientSocket *client, struct UserN
                     //someone deopped the bot???
                     requestOp(client->user, chan);
                 }
                     //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;
                     if(uaccess < db_canop) {
                         reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
                         db_canop = -1;
@@ -140,7 +144,19 @@ static void neonserv_event_mode_async1(struct ClientSocket *client, struct UserN
                             modeBufferSet(modeBuf, !add, modes[i], carg);
                         break;
                     }
                             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;
                     if(uaccess < db_canvoice) {
                         reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
                         db_canvoice = -1;
@@ -301,13 +317,14 @@ static int neonserv_cmd_mode_botwar_detect(struct ClientSocket *client, struct U
             //BOTWAR!
             chanuser->changeTime = time(0);
             if(chanuser->chageEvents > 0) {
             //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;
                     struct ClientSocket *alertclient;
-                    if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+                    if(alertchan_chan && (alertclient = getBotForChannel(chan)) != NULL) {
                         char msgBuf[MAXLEN];
                         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));
                     }
                 }
             }
                     }
                 }
             }
index 304ebeac612717878c944ba926bba9760b4659ef..577e0a349d3a45beb2fe6fafa7a8f0d2b882eaa2 100644 (file)
@@ -90,13 +90,14 @@ static void neonserv_event_topic_async1(struct ClientSocket *client, struct User
                 //BOTWAR!
                 chanuser->changeTime = time(0);
                 if(chanuser->chageEvents > 0) {
                 //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;
                         struct ClientSocket *alertclient;
-                        if(alertchan && (alertclient = getBotForChannel(chan)) != NULL) {
+                        if(alertchan_chan && (alertclient = getBotForChannel(chan)) != NULL) {
                             char msgBuf[MAXLEN];
                             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));
                         }
                     }
                 }
                         }
                     }
                 }
index 21a978c65ad9e2809ea5b0412ce44ee1763d3c71..bc2ff722008eca00ca162f4261f2c48b6de69d24 100644 (file)
 #define NEONSERV_VERSION "5.3"
 #define VERSION_PATCHLEVEL 543
 
 #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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index a651b1682bb9fcdefbbf5f6b2c73f72d645e4a44..b82d317cc4a5770ffd6a3c8af6812bd9e8ec6ecc 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include "mysqlConn.h"
  */
 
 #include "mysqlConn.h"
-#define DATABASE_VERSION "13"
+#define DATABASE_VERSION "14"
 
 struct used_result {
     MYSQL_RES *result;
 
 struct used_result {
     MYSQL_RES *result;
index 29cd337697c6e5347640b0c2d6d17cd63ce288d9..7be2e0d233088efb3f5ea0cbcaa7ff0ed73a8788 100644 (file)
@@ -68,6 +68,8 @@ struct ModeBuffer* initModeBuffer(struct ClientSocket *client, struct ChanNode *
 #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 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) 
 #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)