made cmd_kick checking invisible users
[NeonServV5.git] / cmd_neonserv_kick.c
1
2 /*
3 * argv[0]    nick[,*auth[,*!*@mask[...]]]
4 * argv[1-*]  reason
5 */
6 static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup);
7 static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nicks, char *reason);
8
9 struct neonserv_cmd_kick_cache {
10     struct ClientSocket *client, *textclient;
11     struct UserNode *user;
12     char *nicks;
13     char *reason;
14 };
15
16 static CMD_BIND(neonserv_cmd_kick) {
17     struct neonserv_cmd_kick_cache *cache = malloc(sizeof(*cache));
18     if (!cache) {
19         perror("malloc() failed");
20         return;
21     }
22     cache->client = client;
23     cache->textclient = getTextBot();
24     cache->user = user;
25     cache->nicks = strdup(argv[0]);
26     if(argc > 1) {
27         cache->reason = strdup(merge_argv(argv, 1, argc));
28     } else
29         cache->reason = NULL;
30     get_userlist_with_invisible(chan, neonserv_cmd_kick_userlist_lookup, cache);
31 }
32
33 static USERLIST_CALLBACK(neonserv_cmd_kick_userlist_lookup) {
34     struct neonserv_cmd_kick_cache *cache = data;
35     neonserv_cmd_kick_async1(cache->client, cache->textclient, cache->user, chan, cache->nicks, (cache->reason ? cache->reason : "Bye."));
36     free(cache->nicks);
37     if(cache->reason)
38         free(cache->reason);
39     free(cache);
40 }
41
42 static void neonserv_cmd_kick_async1(struct ClientSocket *client, struct ClientSocket *textclient, struct UserNode *user, struct ChanNode *chan, char *nicks, char *reason) {
43     int i, kicked_users = 0, provided_nicks = 0;
44     char *nick, *nextnick;
45     struct UserNode *cuser;
46     struct ChanUser *chanuser;
47     nextnick = nicks;
48     while((nick = nextnick)) {
49         nextnick = strstr(nick, ",");
50         if(nextnick) {
51             *nextnick = '\0';
52             nextnick++;
53         }
54         if(!*nick) continue;
55         if(is_ircmask(nick)) {
56             //KICK HOSTMASK
57             char usermask[NICKLEN+USERLEN+HOSTLEN+3];
58             struct ChanUser *kick_chanuser[chan->usercount];
59             int kick_chanuser_pos = 0;
60             for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
61                 cuser = chanuser->user;
62                 sprintf(usermask, "%s!%s@%s", cuser->nick, cuser->ident, cuser->host);
63                 if(!match(nick, usermask)) {
64                     provided_nicks++;
65                     if(isNetworkService(chanuser->user)) {
66                         reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
67                         continue;
68                     }
69                     if(isUserProtected(chan, cuser, user)) {
70                         reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
71                         continue;
72                     }
73                     kick_chanuser[kick_chanuser_pos++] = chanuser;
74                     if(kick_chanuser_pos > 4 && (kick_chanuser_pos * 3) > chan->usercount && !isGodMode(user)) {
75                         kick_chanuser_pos = 0;
76                         reply(textclient, user, "NS_LAME_MASK", nick);
77                         break;
78                     }
79                 }
80             }
81             for(i = 0; i < kick_chanuser_pos; i++) {
82                 kicked_users++;
83                 putsock(client, "KICK %s %s :%s", chan->name, kick_chanuser[i]->user->nick, reason);
84             }
85         } else if(*nick == '*') {
86             //KICK AUTH
87             nick++;
88             cuser = NULL;
89             for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
90                 if((chanuser->user->flags & USERFLAG_ISAUTHED) && !stricmp(chanuser->user->auth, nick)) {
91                     provided_nicks++;
92                     if(isNetworkService(chanuser->user)) {
93                         reply(textclient, user, "NS_SERVICE_IMMUNE", chanuser->user->nick);
94                         continue;
95                     }
96                     if(!cuser) {
97                         //check if the user is protected
98                         if(isUserProtected(chan, chanuser->user, user)) {
99                             reply(textclient, user, "NS_USER_PROTECTED", chanuser->user->nick);
100                             break; //all other users are also protected...
101                         }
102                         cuser = chanuser->user;
103                     }
104                     kicked_users++;
105                     putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
106                 }
107             }
108         } else {
109             provided_nicks++;
110             cuser = NULL;
111             for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
112                 if(!stricmp(chanuser->user->nick, nick)) {
113                     cuser = chanuser->user;
114                 }
115             }
116             if(!cuser) continue;
117             if(isNetworkService(cuser)) {
118                 reply(textclient, user, "NS_SERVICE_IMMUNE", cuser->nick);
119                 continue;
120             }
121             if(isUserProtected(chan, cuser, user)) {
122                 reply(textclient, user, "NS_USER_PROTECTED", cuser->nick);
123                 continue;
124             }
125             kicked_users++;
126             putsock(client, "KICK %s %s :%s", chan->name, cuser->nick, reason);
127         }
128     }
129     if(kicked_users == provided_nicks)
130         reply(getTextBot(), user, "NS_KICK_DONE", kicked_users, chan->name);
131     else
132         reply(getTextBot(), user, "NS_KICK_FAIL", client->user->nick);
133 }