]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands.cpp
Advanced to RC1
[user/henk/code/inspircd.git] / src / commands.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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 SocketEngine* SE;
67 extern ServerConfig* Config;
68 extern InspIRCd* ServerInstance;
69
70 extern int MODCOUNT;
71 extern std::vector<Module*> modules;
72 extern std::vector<ircd_module*> factory;
73 extern time_t TIME;
74
75 const long duration_m = 60;
76 const long duration_h = duration_m * 60;
77 const long duration_d = duration_h * 24;
78 const long duration_w = duration_d * 7;
79 const long duration_y = duration_w * 52;
80
81 extern user_hash clientlist;
82 extern chan_hash chanlist;
83 extern whowas_hash whowas;
84
85 extern std::vector<userrec*> all_opers;
86 extern std::vector<userrec*> local_users;
87
88 // This table references users by file descriptor.
89 // its an array to make it VERY fast, as all lookups are referenced
90 // by an integer, meaning there is no need for a scan/search operation.
91 extern userrec* fd_ref_table[65536];
92
93 char* CleanFilename(char* name)
94 {
95         char* p = name + strlen(name);
96         while ((p != name) && (*p != '/')) p--;
97         return (p != name ? ++p : p);
98 }
99
100 void split_chlist(userrec* user, userrec* dest, std::string &cl)
101 {
102         std::stringstream channels(cl);
103         std::string line = "";
104         std::string cname = "";
105         while (!channels.eof())
106         {
107                 channels >> cname;
108                 line = line + cname + " ";
109                 if (line.length() > 400)
110                 {
111                         WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
112                         line = "";
113                 }
114         }
115         if (line.length())
116         {
117                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, line.c_str());
118         }
119 }
120
121 void do_whois(userrec* user, userrec* dest,unsigned long signon, unsigned long idle, char* nick)
122 {
123         // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
124         if (dest->registered == 7)
125         {
126                 WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
127                 if ((user == dest) || (strchr(user->modes,'o')))
128                 {
129                         WriteServ(user->fd,"378 %s %s :is connecting from *@%s %s",user->nick, dest->nick, dest->host, dest->ip);
130                 }
131                 std::string cl = chlist(dest,user);
132                 if (cl.length())
133                 {
134                         if (cl.length() > 400)
135                         {
136                                 split_chlist(user,dest,cl);
137                         }
138                         else
139                         {
140                                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, cl.c_str());
141                         }
142                 }
143                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
144                 if (*dest->awaymsg)
145                 {
146                         WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
147                 }
148                 if (strchr(dest->modes,'o'))
149                 {
150                         if (*dest->oper)
151                         {
152                                 WriteServ(user->fd,"313 %s %s :is %s %s on %s",user->nick, dest->nick, (strchr("aeiou",dest->oper[0]) ? "an" : "a"),dest->oper, Config->Network);
153                         }
154                         else
155                         {
156                                 WriteServ(user->fd,"313 %s %s :is opered but has an unknown type",user->nick, dest->nick);
157                         }
158                 }
159                 if ((!signon) && (!idle))
160                 {
161                         FOREACH_MOD OnWhois(user,dest);
162                 }
163                 if (!strcasecmp(user->server,dest->server))
164                 {
165                         // idle time and signon line can only be sent if youre on the same server (according to RFC)
166                         WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-TIME), dest->signon);
167                 }
168                 else
169                 {
170                         if ((idle) || (signon))
171                                 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, idle, signon);
172                 }
173                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
174         }
175         else
176         {
177                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, nick);
178                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, nick);
179         }
180 }
181
182 bool is_uline(const char* server)
183 {
184         char ServName[MAXBUF];
185
186         if (!server)
187                 return false;
188         if (!(*server))
189                 return true;
190
191         for (int i = 0; i < Config->ConfValueEnum("uline",&Config->config_f); i++)
192         {
193                 Config->ConfValue("uline","server",i,ServName,&Config->config_f);
194                 if (!strcasecmp(server,ServName))
195                 {
196                         return true;
197                 }
198         }
199         return false;
200 }
201
202 int operstrcmp(char* data,char* input)
203 {
204         int MOD_RESULT = 0;
205         FOREACH_RESULT(OnOperCompare(data,input))
206         log(DEBUG,"operstrcmp: %d",MOD_RESULT);
207         if (MOD_RESULT == 1)
208                 return 0;
209         if (MOD_RESULT == -1)
210                 return 1;
211         log(DEBUG,"strcmp fallback: '%s' '%s' %d",data,input,strcmp(data,input));
212         return strcmp(data,input);
213 }
214
215 long duration(const char* str)
216 {
217         char n_field[MAXBUF];
218         long total = 0;
219         const char* str_end = str + strlen(str);
220         n_field[0] = 0;
221
222         if ((!strchr(str,'s')) && (!strchr(str,'m')) && (!strchr(str,'h')) && (!strchr(str,'d')) && (!strchr(str,'w')) && (!strchr(str,'y')))
223         {
224                 std::string n = str;
225                 n = n + "s";
226                 return duration(n.c_str());
227         }
228         
229         for (char* i = (char*)str; i < str_end; i++)
230         {
231                 // if we have digits, build up a string for the value in n_field,
232                 // up to 10 digits in size.
233                 if ((*i >= '0') && (*i <= '9'))
234                 {
235                         strlcat(n_field,i,10);
236                 }
237                 else
238                 {
239                         // we dont have a digit, check for numeric tokens
240                         switch (tolower(*i))
241                         {
242                                 case 's':
243                                         total += atoi(n_field);
244                                 break;
245
246                                 case 'm':
247                                         total += (atoi(n_field)*duration_m);
248                                 break;
249
250                                 case 'h':
251                                         total += (atoi(n_field)*duration_h);
252                                 break;
253
254                                 case 'd':
255                                         total += (atoi(n_field)*duration_d);
256                                 break;
257
258                                 case 'w':
259                                         total += (atoi(n_field)*duration_w);
260                                 break;
261
262                                 case 'y':
263                                         total += (atoi(n_field)*duration_y);
264                                 break;
265                         }
266                         n_field[0] = 0;
267                 }
268         }
269         // add trailing seconds
270         total += atoi(n_field);
271         
272         return total;
273 }
274
275 /* All other ircds when doing this check usually just look for a string of *@* or *. We're smarter than that, though. */
276
277 bool host_matches_everyone(std::string mask, userrec* user)
278 {
279         char insanemasks[MAXBUF];
280         char buffer[MAXBUF];
281         char itrigger[MAXBUF];
282         Config->ConfValue("insane","hostmasks",0,insanemasks,&Config->config_f);
283         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
284         if (*itrigger == 0)
285                 strlcpy(itrigger,"95.5",MAXBUF);
286         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
287                 return false;
288         long matches = 0;
289         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
290         {
291                 strlcpy(buffer,u->second->ident,MAXBUF);
292                 strlcat(buffer,"@",MAXBUF);
293                 strlcat(buffer,u->second->host,MAXBUF);
294                 if (match(buffer,mask.c_str()))
295                         matches++;
296         }
297         float percent = ((float)matches / (float)clientlist.size()) * 100;
298         if (percent > (float)atof(itrigger))
299         {
300                 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);
301                 return true;
302         }
303         return false;
304 }
305
306 bool ip_matches_everyone(std::string ip, userrec* user)
307 {
308         char insanemasks[MAXBUF];
309         char itrigger[MAXBUF];
310         Config->ConfValue("insane","ipmasks",0,insanemasks,&Config->config_f);
311         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
312         if (*itrigger == 0)
313                 strlcpy(itrigger,"95.5",MAXBUF);
314         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
315                 return false;
316         long matches = 0;
317         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
318         {
319                 if (match(u->second->ip,ip.c_str()))
320                         matches++;
321         }
322         float percent = ((float)matches / (float)clientlist.size()) * 100;
323         if (percent > (float)atof(itrigger))
324         {
325                 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);
326                 return true;
327         }
328         return false;
329 }
330
331 bool nick_matches_everyone(std::string nick, userrec* user)
332 {
333         char insanemasks[MAXBUF];
334         char itrigger[MAXBUF];
335         Config->ConfValue("insane","nickmasks",0,insanemasks,&Config->config_f);
336         Config->ConfValue("insane","trigger",0,itrigger,&Config->config_f);
337         if (*itrigger == 0)
338                 strlcpy(itrigger,"95.5",MAXBUF);
339         if ((*insanemasks == 'y') || (*insanemasks == 't') || (*insanemasks == '1'))
340                 return false;
341         long matches = 0;
342         for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
343         {
344                 if (match(u->second->nick,nick.c_str()))
345                         matches++;
346         }
347         float percent = ((float)matches / (float)clientlist.size()) * 100;
348         if (percent > (float)atof(itrigger))
349         {
350                 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);
351                 return true;
352         }
353         return false;
354 }