Merge branch 'development'
[NeonServV5.git] / src / modules / NeonServ.mod / cmd_neonserv_search.c
1 /* cmd_neonserv_search.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
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.
8  * 
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.
13  * 
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/>. 
16  */
17
18 #include "cmd_neonserv.h"
19
20 #define CMD_SEARCH_FLAG_HAS_NODELETE 0x001
21 #define CMD_SEARCH_FLAG_NOT_NODELETE 0x002
22 #define CMD_SEARCH_FLAG_HAS_SUSPENDED 0x004
23 #define CMD_SEARCH_FLAG_NOT_SUSPENDED 0x008
24 #define CMD_SEARCH_FLAG_IS_JOINED  0x010 /* state */
25 #define CMD_SEARCH_FLAG_NOT_JOINED 0x020 /* state */
26 #define CMD_SEARCH_FLAG_IS_OPPED   0x040 /* state */
27 #define CMD_SEARCH_FLAG_NOT_OPPED  0x080 /* state */
28 #define CMD_SEARCH_FLAG_IS_VOICED  0x100 /* state */
29 #define CMD_SEARCH_FLAG_NOT_VOICED 0x200 /* state */
30 #define CMD_SEARCH_FLAG_IS_ZOMBIE  0x400
31 #define CMD_SEARCH_FLAG_NOT_ZOMBIE 0x800
32
33 #define CMD_SEARCH_FLAG_STATES     0x3f0
34
35 struct neonserv_cmd_search_criteria {
36     char *name;
37     char *registrar;
38     char *onchan;
39     unsigned int flags : 16;
40     unsigned int unvisited;
41     unsigned int registered;
42     unsigned int limit : 16;
43 };
44
45 static char neonserv_cmd_search_zombie = 0;
46
47 CMD_BIND(neonserv_cmd_search) {
48     //ok parse the criterias
49     struct neonserv_cmd_search_criteria criteria;
50     memset(&criteria, 0, sizeof(criteria));
51     criteria.limit = 50;
52     int i, show_chans = 0, positive;
53     if(!stricmp(argv[0], "print")) {
54         show_chans = 1;
55     }
56     for(i = 1; i < argc; i += 2) {
57         if(argc <= i+1) {
58             reply(textclient, user, "MODCMD_LESS_PARAM_COUNT");
59             return;
60         }
61         if(!stricmp(argv[i], "name")) criteria.name = argv[i+1];
62         else if(!stricmp(argv[i], "registrar")) criteria.registrar = argv[i+1];
63         else if(!stricmp(argv[i], "onchan")) criteria.onchan = argv[i+1];
64         else if(!stricmp(argv[i], "unvisited")) criteria.unvisited = strToTime(user, argv[i+1]);
65         else if(!stricmp(argv[i], "registered")) criteria.registered = strToTime(user, argv[i+1]);
66         else if(!stricmp(argv[i], "flags")) {
67             if(argv[i+1][0] == '+') {
68                 positive = 1;
69                 argv[i+1]++;
70             } else if(argv[i+1][0] == '-') {
71                 positive = 0;
72                 argv[i+1]++;
73             } else
74                 positive = 1;
75             if(!stricmp(argv[i+1], "nodelete")) {
76                 if(positive)
77                     criteria.flags |= CMD_SEARCH_FLAG_HAS_NODELETE;
78                 else
79                     criteria.flags |= CMD_SEARCH_FLAG_NOT_NODELETE;
80             } else if(!stricmp(argv[i+1], "suspended")) {
81                 if(positive)
82                     criteria.flags |= CMD_SEARCH_FLAG_HAS_SUSPENDED;
83                 else
84                     criteria.flags |= CMD_SEARCH_FLAG_NOT_SUSPENDED;
85             } else if(!stricmp(argv[i+1], "zombie")) {
86                 if(positive)
87                     criteria.flags |= CMD_SEARCH_FLAG_IS_ZOMBIE;
88                 else
89                     criteria.flags |= CMD_SEARCH_FLAG_NOT_ZOMBIE;
90             }
91         }
92         else if(!stricmp(argv[i], "state")) {
93             if(argv[i+1][0] == '+') {
94                 positive = 1;
95                 argv[i+1]++;
96             } else if(argv[i+1][0] == '-') {
97                 positive = 0;
98                 argv[i+1]++;
99             } else
100                 positive = 1;
101             if(!stricmp(argv[i+1], "joined")) {
102                 if(positive)
103                     criteria.flags |= CMD_SEARCH_FLAG_IS_JOINED;
104                 else
105                     criteria.flags |= CMD_SEARCH_FLAG_NOT_JOINED;
106             } else if(!stricmp(argv[i+1], "opped")) {
107                 if(positive)
108                     criteria.flags |= CMD_SEARCH_FLAG_IS_OPPED;
109                 else
110                     criteria.flags |= CMD_SEARCH_FLAG_NOT_OPPED;
111             } else if(!stricmp(argv[i+1], "voiced")) {
112                 if(positive)
113                     criteria.flags |= CMD_SEARCH_FLAG_IS_VOICED;
114                 else
115                     criteria.flags |= CMD_SEARCH_FLAG_NOT_VOICED;
116             }
117         }
118         else if(!stricmp(argv[i], "limit")) {
119             criteria.limit = atoi(argv[i+1]);
120         }
121     }
122     int matches = 0;
123     if((criteria.flags & (CMD_SEARCH_FLAG_IS_ZOMBIE | CMD_SEARCH_FLAG_NOT_ZOMBIE))) {
124         if(neonserv_cmd_search_zombie) {
125             reply(textclient, user, "NS_SEARCH_ZOMBIE_SCAN_IN_PROGRESS");
126             return;
127         }
128         neonserv_cmd_search_zombie = 1;
129     }
130     
131     reply(textclient, user, "NS_SEARCH_HEADER");
132     MYSQL_RES *res, *res2;
133     MYSQL_ROW row, row2;
134     printf_mysql_query("SELECT `channel_name`, `user_user`, `channel_registered`, `channel_nodelete`, `suspended`, `channel_id` FROM `bot_channels` LEFT JOIN `bots` ON `bots`.`id` = `botid` LEFT JOIN `channels` ON `chanid` = `channel_id` LEFT JOIN `users` ON `channel_registrator` = `user_id` WHERE `botclass` = '%d' AND `active` = '1'", client->botid);
135     res = mysql_use();
136     struct ChanNode *channel;
137     while ((row = mysql_fetch_row(res)) != NULL) {
138         if((criteria.flags & (CMD_SEARCH_FLAG_IS_ZOMBIE | CMD_SEARCH_FLAG_NOT_ZOMBIE))) {
139             channel = getChanByName(row[0]);
140             if(channel)
141                 channel->flags |= CHANFLAG_SCRIPTFLAG1;
142             if(show_chans && matches == criteria.limit) {
143                 //too many
144                 continue;
145             }
146         } else {
147             if(show_chans && matches == criteria.limit) {
148                 //too many
149                 break;
150             }
151         }
152         if((criteria.flags & CMD_SEARCH_FLAG_IS_ZOMBIE)) continue;
153         if(criteria.name && match(criteria.name, row[0])) continue;
154         if(criteria.registrar && row[1] && match(criteria.registrar, row[1])) continue;
155         if(criteria.unvisited) {
156             printf_mysql_query("SELECT `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%s' ORDER BY `chanuser_seen` DESC LIMIT 1", row[5]);
157             res2 = mysql_use();
158             row2 = mysql_fetch_row(res2);
159             if(!row2) continue;
160             if((time(0) - atoi(row2[0])) < criteria.unvisited) continue;
161         }
162         if(criteria.registered && (time(0) - atoi(row[2])) < criteria.registered) continue;
163         
164         if((criteria.flags & CMD_SEARCH_FLAG_HAS_NODELETE) && strcmp(row[3], "1")) continue;
165         if((criteria.flags & CMD_SEARCH_FLAG_NOT_NODELETE) && strcmp(row[3], "0")) continue;
166         if((criteria.flags & CMD_SEARCH_FLAG_HAS_SUSPENDED) && strcmp(row[4], "1")) continue;
167         if((criteria.flags & CMD_SEARCH_FLAG_NOT_SUSPENDED) && strcmp(row[4], "0")) continue;
168         if((criteria.flags & CMD_SEARCH_FLAG_STATES) || criteria.onchan) {
169             if(!(criteria.flags & (CMD_SEARCH_FLAG_IS_ZOMBIE | CMD_SEARCH_FLAG_NOT_ZOMBIE)))
170                 channel = getChanByName(row[0]);
171             if(criteria.onchan) {
172                 if(!channel) continue;
173                 struct ChanUser *chanuser = NULL;
174                 for(chanuser = getChannelUsers(channel, NULL); chanuser; chanuser = getChannelUsers(channel, chanuser)) {
175                     if(!match(criteria.onchan, chanuser->user->nick)) break;
176                 }
177                 if(!chanuser) continue;
178             }
179             if((criteria.flags & CMD_SEARCH_FLAG_IS_JOINED) && !channel) continue;
180             if((criteria.flags & CMD_SEARCH_FLAG_NOT_JOINED) && channel) continue;
181             if(channel && (criteria.flags & (CMD_SEARCH_FLAG_IS_OPPED | CMD_SEARCH_FLAG_NOT_OPPED | CMD_SEARCH_FLAG_IS_VOICED | CMD_SEARCH_FLAG_NOT_VOICED))) {
182                 int flags = 0;
183                 struct ClientSocket *bot;
184                 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
185                     if(bot->botid == client->botid) {
186                         struct ChanUser *chanuser = getChanUser(bot->user, channel);
187                         if(chanuser) {
188                             flags = chanuser->flags;
189                             break;
190                         }
191                     }
192                 }
193                 if((criteria.flags & CMD_SEARCH_FLAG_IS_OPPED) && !(flags & CHANUSERFLAG_OPPED)) continue;
194                 if((criteria.flags & CMD_SEARCH_FLAG_NOT_OPPED) && (flags & CHANUSERFLAG_OPPED)) continue;
195                 if((criteria.flags & CMD_SEARCH_FLAG_IS_VOICED) && !(flags & CHANUSERFLAG_VOICED)) continue;
196                 if((criteria.flags & CMD_SEARCH_FLAG_NOT_VOICED) && (flags & CHANUSERFLAG_VOICED)) continue;
197             }
198         }
199         matches++;
200         //output
201         if(show_chans) {
202             reply(textclient, user, "%s", row[0]);
203         }
204     }
205     if((criteria.flags & (CMD_SEARCH_FLAG_IS_ZOMBIE | CMD_SEARCH_FLAG_NOT_ZOMBIE))) {
206         struct ChanUser *chanuser;
207         for(chanuser = getUserChannels(client->user, NULL); chanuser; chanuser = getUserChannels(client->user, chanuser)) {
208             channel = chanuser->chan;
209             if(channel->flags & CHANFLAG_SCRIPTFLAG1) {
210                 channel->flags &= ~CHANFLAG_SCRIPTFLAG1;
211             } else if((criteria.flags & CMD_SEARCH_FLAG_IS_ZOMBIE)) {
212                 matches++;
213                 if(show_chans) {
214                     reply(textclient, user, "%s", channel->name);
215                 }
216             }
217         }
218     }
219     neonserv_cmd_search_zombie = 0;
220     reply(textclient, user, "NS_TABLE_COUNT", matches);
221 }