Another year is about to end... So we have to update these damn copyright information :P
[NeonServV5.git] / src / cmd_neonserv_search.c
1 /* cmd_neonserv_search.c - NeonServ v5.3
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
25 #define CMD_SEARCH_FLAG_NOT_JOINED 0x020
26 #define CMD_SEARCH_FLAG_IS_OPPED   0x040
27 #define CMD_SEARCH_FLAG_NOT_OPPED  0x080
28 #define CMD_SEARCH_FLAG_IS_VOICED  0x100
29 #define CMD_SEARCH_FLAG_NOT_VOICED 0x200
30 #define CMD_SEARCH_FLAG_STATES     0x3f0
31
32 struct neonserv_cmd_search_criteria {
33     char *name;
34     char *registrar;
35     char *onchan;
36     unsigned int flags : 16;
37     unsigned int unvisited;
38     unsigned int registered;
39     unsigned int limit : 16;
40 };
41
42 CMD_BIND(neonserv_cmd_search) {
43     //ok parse the criterias
44     struct neonserv_cmd_search_criteria *criteria = malloc(sizeof(*criteria));
45     if (!criteria) {
46         perror("malloc() failed");
47         return;
48     }
49     memset(criteria, 0, sizeof(*criteria));
50     criteria->limit = 50;
51     int i, show_chans = 0, positive;
52     if(!stricmp(argv[0], "print")) {
53         show_chans = 1;
54     }
55     for(i = 1; i < argc; i += 2) {
56         if(argc <= i+1) {
57             reply(getTextBot(), user, "MODCMD_LESS_PARAM_COUNT");
58             return;
59         }
60         if(!stricmp(argv[i], "name")) criteria->name = argv[i+1];
61         else if(!stricmp(argv[i], "registrar")) criteria->registrar = argv[i+1];
62         else if(!stricmp(argv[i], "onchan")) criteria->onchan = argv[i+1];
63         else if(!stricmp(argv[i], "unvisited")) criteria->unvisited = strToTime(user, argv[i+1]);
64         else if(!stricmp(argv[i], "registered")) criteria->registered = strToTime(user, argv[i+1]);
65         else if(!stricmp(argv[i], "flags")) {
66             if(argv[i+1][0] == '+') {
67                 positive = 1;
68                 argv[i+1]++;
69             } else if(argv[i+1][0] == '-') {
70                 positive = 0;
71                 argv[i+1]++;
72             } else
73                 positive = 1;
74             if(!stricmp(argv[i+1], "nodelete")) {
75                 if(positive)
76                     criteria->flags |= CMD_SEARCH_FLAG_HAS_NODELETE;
77                 else
78                     criteria->flags |= CMD_SEARCH_FLAG_NOT_NODELETE;
79             } else if(!stricmp(argv[i+1], "suspended")) {
80                 if(positive)
81                     criteria->flags |= CMD_SEARCH_FLAG_HAS_SUSPENDED;
82                 else
83                     criteria->flags |= CMD_SEARCH_FLAG_NOT_SUSPENDED;
84             }
85         }
86         else if(!stricmp(argv[i], "state")) {
87             if(argv[i+1][0] == '+') {
88                 positive = 1;
89                 argv[i+1]++;
90             } else if(argv[i+1][0] == '-') {
91                 positive = 0;
92                 argv[i+1]++;
93             } else
94                 positive = 1;
95             if(!stricmp(argv[i+1], "joined")) {
96                 if(positive)
97                     criteria->flags |= CMD_SEARCH_FLAG_IS_JOINED;
98                 else
99                     criteria->flags |= CMD_SEARCH_FLAG_NOT_JOINED;
100             } else if(!stricmp(argv[i+1], "opped")) {
101                 if(positive)
102                     criteria->flags |= CMD_SEARCH_FLAG_IS_OPPED;
103                 else
104                     criteria->flags |= CMD_SEARCH_FLAG_NOT_OPPED;
105             } else if(!stricmp(argv[i+1], "voiced")) {
106                 if(positive)
107                     criteria->flags |= CMD_SEARCH_FLAG_IS_VOICED;
108                 else
109                     criteria->flags |= CMD_SEARCH_FLAG_NOT_VOICED;
110             }
111         }
112         else if(!stricmp(argv[i], "limit")) {
113             criteria->limit = atoi(argv[i+1]);
114         }
115     }
116     int matches = 0;
117     reply(getTextBot(), user, "NS_SEARCH_HEADER");
118     MYSQL_RES *res, *res2;
119     MYSQL_ROW row, row2;
120     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);
121     res = mysql_use();
122     while ((row = mysql_fetch_row(res)) != NULL) {
123         if(show_chans && matches == criteria->limit) {
124             //too many
125             break;
126         }
127         if(criteria->name && match(criteria->name, row[0])) continue;
128         if(criteria->registrar && row[1] && match(criteria->registrar, row[1])) continue;
129         if(criteria->unvisited) {
130             printf_mysql_query("SELECT `chanuser_seen` FROM `chanusers` WHERE `chanuser_cid` = '%s' ORDER BY `chanuser_seen` DESC LIMIT 1", row[5]);
131             res2 = mysql_use();
132             row2 = mysql_fetch_row(res2);
133             if(!row2) continue;
134             if((time(0) - atoi(row2[0])) < criteria->unvisited) continue;
135         }
136         if(criteria->registered && (time(0) - atoi(row[2])) < criteria->registered) continue;
137         
138         if((criteria->flags & CMD_SEARCH_FLAG_HAS_NODELETE) && strcmp(row[3], "1")) continue;
139         if((criteria->flags & CMD_SEARCH_FLAG_NOT_NODELETE) && strcmp(row[3], "0")) continue;
140         if((criteria->flags & CMD_SEARCH_FLAG_HAS_SUSPENDED) && strcmp(row[4], "1")) continue;
141         if((criteria->flags & CMD_SEARCH_FLAG_NOT_SUSPENDED) && strcmp(row[4], "0")) continue;
142         if((criteria->flags & CMD_SEARCH_FLAG_STATES) || criteria->onchan) {
143             struct ChanNode *channel = getChanByName(row[0]);
144             if(criteria->onchan) {
145                 if(!channel) continue;
146                 struct ChanUser *chanuser = NULL;
147                 for(chanuser = getChannelUsers(channel, NULL); chanuser; chanuser = getChannelUsers(channel, chanuser)) {
148                     if(!match(criteria->onchan, chanuser->user->nick)) break;
149                 }
150                 if(!chanuser) continue;
151             }
152             if((criteria->flags & CMD_SEARCH_FLAG_IS_JOINED) && !channel) continue;
153             if((criteria->flags & CMD_SEARCH_FLAG_NOT_JOINED) && channel) continue;
154             if(channel && (criteria->flags & (CMD_SEARCH_FLAG_IS_OPPED | CMD_SEARCH_FLAG_NOT_OPPED | CMD_SEARCH_FLAG_IS_VOICED | CMD_SEARCH_FLAG_NOT_VOICED))) {
155                 int flags = 0;
156                 struct ClientSocket *bot;
157                 for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
158                     if(bot->botid == client->botid) {
159                         struct ChanUser *chanuser = getChanUser(bot->user, channel);
160                         if(chanuser) {
161                             flags = chanuser->flags;
162                             break;
163                         }
164                     }
165                 }
166                 if((criteria->flags & CMD_SEARCH_FLAG_IS_OPPED) && !(flags & CHANUSERFLAG_OPPED)) continue;
167                 if((criteria->flags & CMD_SEARCH_FLAG_NOT_OPPED) && (flags & CHANUSERFLAG_OPPED)) continue;
168                 if((criteria->flags & CMD_SEARCH_FLAG_IS_VOICED) && !(flags & CHANUSERFLAG_VOICED)) continue;
169                 if((criteria->flags & CMD_SEARCH_FLAG_NOT_VOICED) && (flags & CHANUSERFLAG_VOICED)) continue;
170             }
171         }
172         matches++;
173         //output
174         if(show_chans) {
175             reply(getTextBot(), user, "%s", row[0]);
176         }
177     }
178     reply(getTextBot(), user, "NS_TABLE_COUNT", matches);
179 }