]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/message.cpp
This should be faster, we read it like a stream now with GetToken until GetToken...
[user/henk/code/inspircd.git] / src / message.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 "configreader.h"
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/errno.h>
25 #include <sys/utsname.h>
26 #include <time.h>
27 #include <string>
28 #include <ext/hash_map>
29 #include <map>
30 #include <sstream>
31 #include <vector>
32 #include <deque>
33 #include "users.h"
34 #include "ctables.h"
35 #include "globals.h"
36 #include "modules.h"
37 #include "dynamic.h"
38 #include "wildcard.h"
39 #include "commands.h"
40 #include "message.h"
41 #include "inspstring.h"
42 #include "dns.h"
43 #include "helperfuncs.h"
44
45 extern int MODCOUNT;
46 extern std::vector<Module*> modules;
47 extern std::vector<ircd_module*> factory;
48 extern time_t TIME;
49 extern ServerConfig* Config;
50
51 /* return 0 or 1 depending if users u and u2 share one or more common channels
52  * (used by QUIT, NICK etc which arent channel specific notices) */
53
54 int common_channels(userrec *u, userrec *u2)
55 {
56         if ((!u) || (!u2) || (u->registered != 7) || (u2->registered != 7))
57         {
58                 return 0;
59         }
60         for (std::vector<ucrec*>::const_iterator i = u->chans.begin(); i != u->chans.end(); i++)
61         {
62                 for (std::vector<ucrec*>::const_iterator z = u2->chans.begin(); z != u2->chans.end(); z++)
63                 {
64                         if ((((ucrec*)(*i))->channel != NULL) && (((ucrec*)(*z))->channel != NULL))
65                         {
66                                 if ((((ucrec*)(*i))->channel == ((ucrec*)(*z))->channel))
67                                 {
68                                         if ((c_count(u)) && (c_count(u2)))
69                                         {
70                                                 return 1;
71                                         }
72                                 }
73                         }
74                 }
75         }
76         return 0;
77 }
78
79 void tidystring(char* str)
80 {
81         // strips out double spaces before a : parameter
82
83         char temp[MAXBUF];
84         bool go_again = true;
85
86         if (!str)
87                 return;
88
89         // pointer voodoo++ --w00t
90         while ((*str) && (*str == ' '))
91                 str++;
92
93         while (go_again)
94         {
95                 bool noparse = false;
96                 int t = 0, a = 0;
97                 go_again = false;
98                 const int lenofstr = strlen(str);
99
100                 /*
101                  * by caching strlen() of str, we theoretically avoid 3 expensive calls each time this loop
102                  * rolls around.. should speed things up a nanosecond or two. ;)
103                  */
104
105                 while (a < lenofstr)
106                 {
107                         if ((a < lenofstr - 1) && (noparse == false))
108                         {
109                                 if ((str[a] == ' ') && (str[a+1] == ' '))
110                                 {
111                                         log(DEBUG,"Tidied extra space out of string: %s",str);
112                                         go_again = true;
113                                         a++;
114                                 }
115                         }
116
117                         if (a < lenofstr - 1)
118                         {
119                                 if ((str[a] == ' ') && (str[a+1] == ':'))
120                                 {
121                                         noparse = true;
122                                 }
123                         }
124
125                         temp[t++] = str[a++];
126                 }
127
128                 temp[t] = '\0';
129                 strlcpy(str,temp,MAXBUF);
130         }
131 }
132
133 /* chop a string down to 512 characters and preserve linefeed (irc max
134  * line length) */
135
136 void chop(char* str)
137 {
138         if (!str)
139         {
140                 log(DEBUG,"ERROR! Null string passed to chop()!");
141                 return;
142         }
143         if (strlen(str) >= 511)
144         {
145                 str[510] = '\r';
146                 str[511] = '\n';
147                 str[512] = '\0';
148                 log(DEBUG,"Excess line chopped.");
149         }
150 }
151
152
153 void Blocking(int s)
154 {
155         int flags = fcntl(s, F_GETFL, 0);
156         fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
157 }
158
159 void NonBlocking(int s)
160 {
161         int flags = fcntl(s, F_GETFL, 0);
162         fcntl(s, F_SETFL, flags | O_NONBLOCK);
163 }
164
165 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost, bool forward)
166 {
167         bool ok;
168         std::string ipaddr;
169
170         DNS d(Config->DNSServer);
171         if (forward)
172                 ok = d.ForwardLookup(unresolvedHost, false);
173         else
174                 ok = d.ReverseLookup(unresolvedHost, false);
175         if (!ok)
176                 return 0;
177         time_t T = time(NULL)+1;
178         while ((!d.HasResult()) && (time(NULL)<T));
179         if (forward)
180                 ipaddr = d.GetResultIP();
181         else
182                 ipaddr = d.GetResult();
183         strlcpy(resolvedHost,ipaddr.c_str(),MAXBUF);
184         return (ipaddr != "");
185 }
186
187 int c_count(userrec* u)
188 {
189         int z = 0;
190         for (std::vector<ucrec*>::const_iterator i = u->chans.begin(); i != u->chans.end(); i++)
191                 if (((ucrec*)(*i))->channel)
192                         z++;
193         return z;
194
195 }
196
197 void ChangeName(userrec* user, const char* gecos)
198 {
199         if (user->fd > -1)
200         {
201                 int MOD_RESULT = 0;
202                 FOREACH_RESULT(I_OnChangeLocalUserGECOS,OnChangeLocalUserGECOS(user,gecos));
203                 if (MOD_RESULT)
204                         return;
205                 FOREACH_MOD(I_OnChangeName,OnChangeName(user,gecos));
206         }
207         strlcpy(user->fullname,gecos,MAXGECOS+1);
208 }
209
210 void ChangeDisplayedHost(userrec* user, const char* host)
211 {
212         if (user->fd > -1)
213         {
214                 int MOD_RESULT = 0;
215                 FOREACH_RESULT(I_OnChangeLocalUserHost,OnChangeLocalUserHost(user,host));
216                 if (MOD_RESULT)
217                         return;
218                 FOREACH_MOD(I_OnChangeHost,OnChangeHost(user,host));
219         }
220         strlcpy(user->dhost,host,63);
221         WriteServ(user->fd,"396 %s %s :is now your hidden host",user->nick,user->dhost);
222 }
223
224 /* verify that a user's ident and nickname is valid */
225
226 int isident(const char* n)
227 {
228         if (!n || !*n)
229         {
230                 return 0;
231         }
232         for (char* i = (char*)n; *i; i++)
233         {
234                 if ((*i >= 'A') && (*i <= '}'))
235                 {
236                         continue;
237                 }
238                 if (strchr(".-0123456789",*i))
239                 {
240                         continue;
241                 }
242                 return 0;
243         }
244         return 1;
245 }
246
247
248 int isnick(const char* n)
249 {
250         if (!n || !*n)
251         {
252                 return 0;
253         }
254         int p = 0;
255         for (char* i = (char*)n; *i; i++, p++)
256         {
257                 /* can occur anywhere in a nickname */
258                 if ((*i >= 'A') && (*i <= '}'))
259                 {
260                         continue;
261                 }
262                 /* can occur anywhere BUT the first char of a nickname */
263                 if ((strchr("-0123456789",*i)) && (i > n))
264                 {
265                         continue;
266                 }
267                 /* invalid character! abort */
268                 return 0;
269         }
270         return (p < NICKMAX - 1);
271 }
272
273 /* returns the status character for a given user on a channel, e.g. @ for op,
274  * % for halfop etc. If the user has several modes set, the highest mode
275  * the user has must be returned. */
276
277 const char* cmode(userrec *user, chanrec *chan)
278 {
279         if ((!user) || (!chan))
280         {
281                 log(DEFAULT,"*** BUG *** cmode was given an invalid parameter");
282                 return "";
283         }
284
285         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
286         {
287                 if (((ucrec*)(*i))->channel == chan)
288                 {
289                         if ((((ucrec*)(*i))->uc_modes & UCMODE_OP) > 0)
290                         {
291                                 return "@";
292                         }
293                         if ((((ucrec*)(*i))->uc_modes & UCMODE_HOP) > 0)
294                         {
295                                 return "%";
296                         }
297                         if ((((ucrec*)(*i))->uc_modes & UCMODE_VOICE) > 0)
298                         {
299                                 return "+";
300                         }
301                         return "";
302                 }
303         }
304         return "";
305 }
306
307 int cflags(userrec *user, chanrec *chan)
308 {
309         if ((!chan) || (!user))
310                 return 0;
311
312         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
313         {
314                 if (((ucrec*)(*i))->channel == chan)
315                 {
316                         return ((ucrec*)(*i))->uc_modes;
317                 }
318         }
319         return 0;
320 }
321
322 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
323  * op, STATUS_VOICE for voice etc. If the user has several modes set, the
324  * highest mode the user has must be returned. */
325
326 int cstatus(userrec *user, chanrec *chan)
327 {
328         if ((!chan) || (!user))
329         {
330                 log(DEFAULT,"*** BUG *** cstatus was given an invalid parameter");
331                 return 0;
332         }
333
334         if (is_uline(user->server))
335                 return STATUS_OP;
336
337         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
338         {
339                 if (((ucrec*)(*i))->channel == chan)
340                 {
341                         if ((((ucrec*)(*i))->uc_modes & UCMODE_OP) > 0)
342                         {
343                                 return STATUS_OP;
344                         }
345                         if ((((ucrec*)(*i))->uc_modes & UCMODE_HOP) > 0)
346                         {
347                                 return STATUS_HOP;
348                         }
349                         if ((((ucrec*)(*i))->uc_modes & UCMODE_VOICE) > 0)
350                         {
351                                 return STATUS_VOICE;
352                         }
353                         return STATUS_NORMAL;
354                 }
355         }
356         return STATUS_NORMAL;
357 }
358
359 void TidyBan(char *ban)
360 {
361         if (!ban) {
362                 log(DEFAULT,"*** BUG *** TidyBan was given an invalid parameter");
363                 return;
364         }
365         
366         char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
367
368         strlcpy(temp,ban,MAXBUF);
369
370         char* pos_of_pling = strchr(temp,'!');
371         char* pos_of_at = strchr(temp,'@');
372
373         pos_of_pling[0] = '\0';
374         pos_of_at[0] = '\0';
375         pos_of_pling++;
376         pos_of_at++;
377
378         strlcpy(NICK,temp,NICKMAX-1);
379         strlcpy(IDENT,pos_of_pling,IDENTMAX+1);
380         strlcpy(HOST,pos_of_at,63);
381
382         snprintf(ban,MAXBUF,"%s!%s@%s",NICK,IDENT,HOST);
383 }
384
385 char lst[MAXBUF];
386
387 std::string chlist(userrec *user,userrec* source)
388 {
389         /* Should this be a stringstream? Not sure if it would be faster as streams are more oriented at appending stuff, which is all we do */
390         std::ostringstream list;
391         
392         if (!user || !source)
393                 return "";
394         
395         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
396         {
397                 ucrec* rec = *i;
398                 
399                 if(rec->channel && rec->channel->name)
400                 {
401                         /* XXX - Why does this check need to be here at all? :< */
402                         /* Commenting this out until someone finds a case where we need it */
403                         //if (lst.find(rec->channel->name) == std::string::npos)
404                         //{
405                         
406                                 /*
407                                  * If the target is the same as the sender, let them see all their channels.
408                                  * If the channel is NOT private/secret AND the user is not invisible.
409                                  * If the user is an oper, and the <options:operspywhois> option is set.
410                                  */
411                                 if ((source == user) || (*source->oper && Config->OperSpyWhois) || (((!rec->channel->modes[CM_PRIVATE]) && (!rec->channel->modes[CM_SECRET]) && !(user->modes[UM_INVISIBLE])) || (rec->channel->HasUser(source))))
412                                 {
413                                         list << cmode(user, rec->channel) << rec->channel->name << " ";
414                                 }
415                         //}
416                 }
417         }
418         
419         return list.str();
420 }