]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands.cpp
move do_whois to cmd_whois, i'm stopping now. really.
[user/henk/code/inspircd.git] / src / commands.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include "inspircd_config.h"
20 #include "inspircd.h"
21 #include "inspircd_io.h"
22 #include <unistd.h>
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
26 #include <cstdio>
27 #include <time.h>
28 #include <string>
29 #ifdef GCC3
30 #include <ext/hash_map>
31 #else
32 #include <hash_map>
33 #endif
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <deque>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #ifdef THREADED_DNS
42 #include <pthread.h>
43 #endif
44 #ifndef RUSAGE_SELF
45 #define   RUSAGE_SELF     0
46 #define   RUSAGE_CHILDREN     -1
47 #endif
48 #include "users.h"
49 #include "ctables.h"
50 #include "globals.h"
51 #include "modules.h"
52 #include "dynamic.h"
53 #include "wildcard.h"
54 #include "message.h"
55 #include "commands.h"
56 #include "mode.h"
57 #include "xline.h"
58 #include "inspstring.h"
59 #include "dnsqueue.h"
60 #include "helperfuncs.h"
61 #include "hashcomp.h"
62 #include "socketengine.h"
63 #include "typedefs.h"
64 #include "command_parse.h"
65
66 extern ServerConfig* Config;
67 extern InspIRCd* ServerInstance;
68
69 extern int MODCOUNT;
70 extern std::vector<Module*> modules;
71 extern std::vector<ircd_module*> factory;
72 extern time_t TIME;
73
74 const long duration_m = 60;
75 const long duration_h = duration_m * 60;
76 const long duration_d = duration_h * 24;
77 const long duration_w = duration_d * 7;
78 const long duration_y = duration_w * 52;
79
80 extern user_hash clientlist;
81 extern chan_hash chanlist;
82
83 extern std::vector<userrec*> all_opers;
84 extern std::vector<userrec*> local_users;
85
86 // This table references users by file descriptor.
87 // its an array to make it VERY fast, as all lookups are referenced
88 // by an integer, meaning there is no need for a scan/search operation.
89 extern userrec* fd_ref_table[MAX_DESCRIPTORS];
90
91
92 void split_chlist(userrec* user, userrec* dest, const std::string &cl)
93 {
94         std::string line;
95         std::ostringstream prefix;
96         std::string::size_type start, pos, length;
97         
98         prefix << ":" << Config->ServerName << " 319 " << user->nick << " " << dest->nick << " :";
99         line = prefix.str();
100         
101         for (start = 0; pos = cl.find(' ', start); start = pos+1)
102         {
103                 length = (pos == std::string::npos) ? cl.length() : pos;
104                 
105                 if (line.length() + length - start > 510)
106                 {
107                         Write_NoFormat(user->fd, line.c_str());
108                         line = prefix.str();
109                 }
110                 
111                 if(pos == std::string::npos)
112                 {
113                         line += cl.substr(start, length - start);
114                         break;
115                 }
116                 else
117                 {
118                         line += cl.substr(start, length - start + 1);
119                 }
120         }
121         
122         if (line.length())
123         {
124                 Write_NoFormat(user->fd, line.c_str());
125         }
126 }
127
128 /* XXX - these really belong in helperfuncs perhaps -- w00t */
129 bool is_uline(const char* server)
130 {
131         if (!server)
132                 return false;
133         if (!*server)
134                 return true;
135
136         return (find(Config->ulines.begin(),Config->ulines.end(),server) != Config->ulines.end());
137 }
138
139 int operstrcmp(char* data,char* input)
140 {
141         int MOD_RESULT = 0;
142         FOREACH_RESULT(I_OnOperCompare,OnOperCompare(data,input))
143         log(DEBUG,"operstrcmp: %d",MOD_RESULT);
144         if (MOD_RESULT == 1)
145                 return 0;
146         if (MOD_RESULT == -1)
147                 return 1;
148         log(DEBUG,"strcmp fallback: '%s' '%s' %d",data,input,strcmp(data,input));
149         return strcmp(data,input);
150 }
151
152 long duration(const char* str)
153 {
154         char n_field[MAXBUF];
155         long total = 0;
156         n_field[0] = 0;
157
158         if ((!strchr(str,'s')) && (!strchr(str,'m')) && (!strchr(str,'h')) && (!strchr(str,'d')) && (!strchr(str,'w')) && (!strchr(str,'y')))
159         {
160                 std::string n = str;
161                 n += 's';
162                 return duration(n.c_str());
163         }
164         
165         for (char* i = (char*)str; *i; i++)
166         {
167                 // if we have digits, build up a string for the value in n_field,
168                 // up to 10 digits in size.
169                 if ((*i >= '0') && (*i <= '9'))
170                 {
171                         strlcat(n_field,i,10);
172                 }
173                 else
174                 {
175                         // we dont have a digit, check for numeric tokens
176                         switch (tolower(*i))
177                         {
178                                 case 's':
179                                         total += atoi(n_field);
180                                 break;
181
182                                 case 'm':
183                                         total += (atoi(n_field)*duration_m);
184                                 break;
185
186                                 case 'h':
187                                         total += (atoi(n_field)*duration_h);
188                                 break;
189
190                                 case 'd':
191                                         total += (atoi(n_field)*duration_d);
192                                 break;
193
194                                 case 'w':
195                                         total += (atoi(n_field)*duration_w);
196                                 break;
197
198                                 case 'y':
199                                         total += (atoi(n_field)*duration_y);
200                                 break;
201                         }
202                         n_field[0] = 0;
203                 }
204         }
205         // add trailing seconds
206         total += atoi(n_field);
207         
208         return total;
209 }
210
211 /* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
212
213 bool host_matches_everyone(const std::string &mask, userrec* user)
214 {
215         char insanemasks[MAXBUF];
216         char buffer[MAXBUF];
217         char itrigger[MAXBUF];
218         Config->ConfValue(Config->config_data, "insane","hostmasks", 0, insanemasks, MAXBUF);
219         Config->ConfValue(Config->config_data, "insane","trigger", 0, itrigger, MAXBUF);
220         if (*itrigger == 0)
221                 strlcpy(itrigger,"95.5",MAXBUF);
222         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
223                 return false;
224         long matches = 0;
225         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
226         {
227                 strlcpy(buffer,u->second->ident,MAXBUF);
228                 charlcat(buffer,'@',MAXBUF);
229                 strlcat(buffer,u->second->host,MAXBUF);
230                 if (match(buffer,mask.c_str()))
231                         matches++;
232         }
233         float percent = ((float)matches / (float)clientlist.size()) * 100;
234         if (percent > (float)atof(itrigger))
235         {
236                 WriteOpers("*** \2WARNING\2: %s tried to set a G/K/E line mask of %s, which covers %.2f%% of the network!",user->nick,mask.c_str(),percent);
237                 return true;
238         }
239         return false;
240 }
241
242 bool ip_matches_everyone(const std::string &ip, userrec* user)
243 {
244         char insanemasks[MAXBUF];
245         char itrigger[MAXBUF];
246         Config->ConfValue(Config->config_data, "insane","ipmasks",0,insanemasks,MAXBUF);
247         Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF);
248         if (*itrigger == 0)
249                 strlcpy(itrigger,"95.5",MAXBUF);
250         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
251                 return false;
252         long matches = 0;
253         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
254         {
255                 if (match((char*)inet_ntoa(u->second->ip4),ip.c_str()))
256                         matches++;
257         }
258         float percent = ((float)matches / (float)clientlist.size()) * 100;
259         if (percent > (float)atof(itrigger))
260         {
261                 WriteOpers("*** \2WARNING\2: %s tried to set a Z line mask of %s, which covers %.2f%% of the network!",user->nick,ip.c_str(),percent);
262                 return true;
263         }
264         return false;
265 }
266
267 bool nick_matches_everyone(const std::string &nick, userrec* user)
268 {
269         char insanemasks[MAXBUF];
270         char itrigger[MAXBUF];
271         Config->ConfValue(Config->config_data, "insane","nickmasks",0,insanemasks,MAXBUF);
272         Config->ConfValue(Config->config_data, "insane","trigger",0,itrigger,MAXBUF);
273         if (*itrigger == 0)
274                 strlcpy(itrigger,"95.5",MAXBUF);
275         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
276                 return false;
277         long matches = 0;
278         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
279         {
280                 if (match(u->second->nick,nick.c_str()))
281                         matches++;
282         }
283         float percent = ((float)matches / (float)clientlist.size()) * 100;
284         if (percent > (float)atof(itrigger))
285         {
286                 WriteOpers("*** \2WARNING\2: %s tried to set a Q line mask of %s, which covers %.2f%% of the network!",user->nick,nick.c_str(),percent);
287                 return true;
288         }
289         return false;
290 }