1 /* cmd_neonserv_mode.c - NeonServ v5.3
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "cmd_neonserv.h"
22 * argv[1-*] - parameters
24 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup);
25 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode);
27 struct neonserv_cmd_mode_cache {
28 struct ClientSocket *client, *textclient;
29 struct UserNode *user;
34 CMD_BIND(neonserv_cmd_mode) {
35 struct neonserv_cmd_mode_cache *cache = malloc(sizeof(*cache));
37 perror("malloc() failed");
40 cache->client = client;
41 cache->textclient = getTextBot();
44 cache->mode = strdup(merge_argv(argv, 0, argc));
45 get_userlist_with_invisible(chan, neonserv_cmd_mode_userlist_lookup, cache);
48 static USERLIST_CALLBACK(neonserv_cmd_mode_userlist_lookup) {
49 struct neonserv_cmd_mode_cache *cache = data;
50 neonserv_cmd_mode_async1(cache->client, cache->textclient, cache->user, chan, cache->event, cache->mode);
55 static void neonserv_cmd_mode_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, struct Event *event, char *mode) {
56 MYSQL_ROW row, defaults = NULL;
57 int i, arg, add = 1, skip = 0;
58 unsigned int modetype;
59 int db_canop, db_canvoice, db_canban, db_enfmodes;
60 struct ModeNode *modelock = createModeNode(NULL), *changemodes = createModeNode(NULL);
61 struct ModeBuffer *modeBuf;
62 struct UserNode *cuser;
63 struct ChanUser *chanuser;
64 modeBuf = initModeBuffer(client, chan);
65 printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id);
66 row = mysql_fetch_row(mysql_use());
67 if(row[0] == NULL || row[1] == NULL || row[2] == NULL || row[3] == NULL) {
68 printf_mysql_query("SELECT `channel_canop`, `channel_canvoice`, `channel_canban`, `channel_enfmodes`, `channel_modes` FROM `channels` WHERE `channel_name` = 'defaults'");
69 defaults = mysql_fetch_row(mysql_use());
71 db_canop = atoi((row[0] ? row[0] : defaults[0]));
72 db_canvoice = atoi((row[1] ? row[1] : defaults[1]));
73 db_canban = atoi((row[2] ? row[2] : defaults[2]));
74 db_enfmodes = atoi((row[3] ? row[3] : defaults[3]));
76 parseModeString(modelock, row[4]);
78 parseModeString(modelock, defaults[4]);
79 int uaccess = getChannelAccess(user, chan);
81 char *argv[MAXNUMPARAMS];
89 if(argc == MAXNUMPARAMS) break;
94 char *modeStr = argv[arg++];
95 for(i = 0; i < strlen(modeStr); i++) {
106 reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
110 if(modeStr[i] == 'o') {
111 if(uaccess < db_canop) {
112 reply(textclient, user, "NS_MODE_ENFOPS", chan->name);
116 if(db_canop == -1) break;
118 if(uaccess < db_canvoice) {
119 reply(textclient, user, "NS_MODE_ENFVOICE", chan->name);
123 if(db_canvoice == -1) break;
125 cuser = searchUserByNick(carg);
127 //check for an invisible user
128 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
129 if(!stricmp(chanuser->user->nick, carg)) {
130 cuser = chanuser->user;
136 chanuser = getChanUser(cuser, chan);
139 if(!(add ^ (chanuser->flags & (modeStr[i] == 'o' ? CHANUSERFLAG_OPPED : CHANUSERFLAG_VOICED)))) break;
142 if(modeStr[i] == 'o' && isNetworkService(cuser)) {
143 reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
146 if(isUserProtected(chan, cuser, user)) {
147 reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
151 modeBufferSet(modeBuf, add, modeStr[i], carg);
155 reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
159 if(uaccess < db_canban) {
160 reply(textclient, user, "NS_MODE_CANBAN", chan->name);
164 if(db_canban == -1) break;
165 char hostmask_buffer[NICKLEN+USERLEN+HOSTLEN+3];
166 char usermask[NICKLEN+USERLEN+HOSTLEN+3];
169 carg = make_banmask(carg, hostmask_buffer);
171 for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
172 cuser = chanuser->user;
173 sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
174 if(!match(carg, usermask)) {
175 if(isNetworkService(chanuser->user)) {
176 reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
180 if(isUserProtected(chan, cuser, user)) {
181 reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
186 if(match_count > 4 && (match_count * 3) > chan->usercount && !isGodMode(user)) {
188 reply(textclient, user, "NS_LAME_MASK", carg);
195 for(ban = chan->bans; ban; ban = ban->next) {
196 if(!match(carg, ban->mask)) {
203 modeBufferSet(modeBuf, add, 'b', carg);
207 modetype = getModeType(modelock, modeStr[i]);
209 reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
212 if(isModeAffected(modelock, modeStr[i]) && add == !isModeSet(modelock, modeStr[i]) && uaccess < db_enfmodes) {
214 event->flags |= CMDFLAG_OPLOG;
216 getFullModeString(modelock, tmp);
217 reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
221 if(add && (modetype & CHANNEL_MODE_TYPE) != CHANNEL_MODE_TYPE_D) {
223 reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
227 if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
228 char *modelock_val = getModeValue(modelock, modeStr[i]);
229 if(stricmp(carg, modelock_val)) {
231 event->flags |= CMDFLAG_OPLOG;
233 getFullModeString(modelock, tmp);
234 reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
239 if((modetype & CHANNEL_MODE_VALUE) == CHANNEL_MODE_VALUE_STRING && isModeSet(modelock, modeStr[i])) {
240 int *modelock_val = getModeValue(modelock, modeStr[i]);
241 if(atoi(carg) != *modelock_val) {
243 event->flags |= CMDFLAG_OPLOG;
245 getFullModeString(modelock, tmp);
246 reply(textclient, user, "NS_MODE_LOCKED", tmp, chan->name);
253 if((modetype & CHANNEL_MODE_TYPE) == CHANNEL_MODE_TYPE_D && isModeSet(chan->modes, modeStr[i]) == add)
255 if(!isModeAffected(changemodes, modeStr[i])) {
256 if(!add && (modetype & CHANNEL_MODE_KEY)) {
257 if(isModeSet(chan->modes, modeStr[i])) {
258 char *current_val = getModeValue(chan->modes, modeStr[i]);
262 if(parseMode(changemodes, add, modeStr[i], carg)) {
264 if(add && (modetype & CHANNEL_MODE_KEY) && isModeSet(chan->modes, modeStr[i])) {
265 char *current_val = getModeValue(chan->modes, modeStr[i]);
266 modeBufferSet(modeBuf, 0, modeStr[i], current_val);
267 flushModeBuffer(modeBuf);
269 if(!add && !isModeSet(chan->modes, modeStr[i])) break;
270 modeBufferSet(modeBuf, add, modeStr[i], carg);
272 modeBufferSimpleMode(modeBuf, add, modeStr[i]);
275 reply(textclient, user, "NS_MODE_INVALID", modeStr[i]);
283 getFullModeString(changemodes, tmp);
284 freeModeBuffer(modeBuf);
286 reply(textclient, user, "NS_MODE_DONE", tmp);
289 freeModeNode(modelock);
290 freeModeNode(changemodes);