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