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