]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/message.cpp
Remove TODO, we just did it.
[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  * The old algorithm in 1.0 for this was relatively inefficient, iterating over
55  * the first users channels then the second users channels within the outer loop,
56  * therefore it was a maximum of x*y iterations (upon returning 0 and checking
57  * all possible iterations). However this new function instead checks against the
58  * channel's userlist in the inner loop which is a std::map<userrec*,userrec*>
59  * and saves us time as we already know what pointer value we are after.
60  * Don't quote me on the maths as i am not a mathematician or computer scientist,
61  * but i believe this algorithm is now x+(log y) maximum iterations instead.
62  */
63 int common_channels(userrec *u, userrec *u2)
64 {
65         if ((!u) || (!u2) || (u->registered != REG_ALL) || (u2->registered != REG_ALL))
66                 return 0;
67
68         /* Outer loop */
69         for (std::vector<ucrec*>::const_iterator i = u->chans.begin(); i != u->chans.end(); i++)
70         {
71                 /* Fetch the channel from the user */
72                 ucrec* user_channel = (ucrec*)(*i);
73
74                 if (user_channel->channel)
75                 {
76                         /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
77                          * by replacing it with a map::find which *should* be more efficient
78                          */
79                         CUList* channel_user_map = user_channel->channel->GetUsers();
80                         if (channel_user_map->find(u2) != channel_user_map->end())
81                                 return 1;
82                 }
83         }
84         return 0;
85 }
86
87 void Blocking(int s)
88 {
89         int flags = fcntl(s, F_GETFL, 0);
90         fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
91 }
92
93 void NonBlocking(int s)
94 {
95         int flags = fcntl(s, F_GETFL, 0);
96         fcntl(s, F_SETFL, flags | O_NONBLOCK);
97 }
98
99 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost, bool forward)
100 {
101         bool ok;
102         std::string ipaddr;
103
104         DNS d(Config->DNSServer);
105         if (forward)
106                 ok = d.ForwardLookup(unresolvedHost, false);
107         else
108                 ok = d.ReverseLookup(unresolvedHost, false);
109         if (!ok)
110                 return 0;
111         time_t T = time(NULL)+1;
112         while ((!d.HasResult()) && (time(NULL)<T));
113         if (forward)
114                 ipaddr = d.GetResultIP();
115         else
116                 ipaddr = d.GetResult();
117         strlcpy(resolvedHost,ipaddr.c_str(),MAXBUF);
118         return (ipaddr != "");
119 }
120
121 int c_count(userrec* u)
122 {
123         int z = 0;
124         for (std::vector<ucrec*>::const_iterator i = u->chans.begin(); i != u->chans.end(); i++)
125                 if (((ucrec*)(*i))->channel)
126                         z++;
127         return z;
128
129 }
130
131 void ChangeName(userrec* user, const char* gecos)
132 {
133         if (user->fd > -1)
134         {
135                 int MOD_RESULT = 0;
136                 FOREACH_RESULT(I_OnChangeLocalUserGECOS,OnChangeLocalUserGECOS(user,gecos));
137                 if (MOD_RESULT)
138                         return;
139                 FOREACH_MOD(I_OnChangeName,OnChangeName(user,gecos));
140         }
141         strlcpy(user->fullname,gecos,MAXGECOS+1);
142 }
143
144 void ChangeDisplayedHost(userrec* user, const char* host)
145 {
146         if (user->fd > -1)
147         {
148                 int MOD_RESULT = 0;
149                 FOREACH_RESULT(I_OnChangeLocalUserHost,OnChangeLocalUserHost(user,host));
150                 if (MOD_RESULT)
151                         return;
152                 FOREACH_MOD(I_OnChangeHost,OnChangeHost(user,host));
153         }
154         strlcpy(user->dhost,host,63);
155         WriteServ(user->fd,"396 %s %s :is now your hidden host",user->nick,user->dhost);
156 }
157
158 /* verify that a user's ident and nickname is valid */
159
160 int isident(const char* n)
161 {
162         if (!n || !*n)
163         {
164                 return 0;
165         }
166         for (char* i = (char*)n; *i; i++)
167         {
168                 if ((*i >= 'A') && (*i <= '}'))
169                 {
170                         continue;
171                 }
172                 if (strchr(".-0123456789",*i))
173                 {
174                         continue;
175                 }
176                 return 0;
177         }
178         return 1;
179 }
180
181
182 int isnick(const char* n)
183 {
184         if (!n || !*n)
185         {
186                 return 0;
187         }
188         int p = 0;
189         for (char* i = (char*)n; *i; i++, p++)
190         {
191                 /* can occur anywhere in a nickname */
192                 if ((*i >= 'A') && (*i <= '}'))
193                 {
194                         continue;
195                 }
196                 /* can occur anywhere BUT the first char of a nickname */
197                 if ((strchr("-0123456789",*i)) && (i > n))
198                 {
199                         continue;
200                 }
201                 /* invalid character! abort */
202                 return 0;
203         }
204         return (p < NICKMAX - 1);
205 }
206
207 /* returns the status character for a given user on a channel, e.g. @ for op,
208  * % for halfop etc. If the user has several modes set, the highest mode
209  * the user has must be returned. */
210
211 const char* cmode(userrec *user, chanrec *chan)
212 {
213         if ((!user) || (!chan))
214         {
215                 log(DEFAULT,"*** BUG *** cmode was given an invalid parameter");
216                 return "";
217         }
218
219         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
220         {
221                 if (((ucrec*)(*i))->channel == chan)
222                 {
223                         if ((((ucrec*)(*i))->uc_modes & UCMODE_OP) > 0)
224                         {
225                                 return "@";
226                         }
227                         if ((((ucrec*)(*i))->uc_modes & UCMODE_HOP) > 0)
228                         {
229                                 return "%";
230                         }
231                         if ((((ucrec*)(*i))->uc_modes & UCMODE_VOICE) > 0)
232                         {
233                                 return "+";
234                         }
235                         return "";
236                 }
237         }
238         return "";
239 }
240
241 int cflags(userrec *user, chanrec *chan)
242 {
243         if ((!chan) || (!user))
244                 return 0;
245
246         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
247         {
248                 if (((ucrec*)(*i))->channel == chan)
249                 {
250                         return ((ucrec*)(*i))->uc_modes;
251                 }
252         }
253         return 0;
254 }
255
256 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
257  * op, STATUS_VOICE for voice etc. If the user has several modes set, the
258  * highest mode the user has must be returned. */
259
260 int cstatus(userrec *user, chanrec *chan)
261 {
262         if ((!chan) || (!user))
263         {
264                 log(DEFAULT,"*** BUG *** cstatus was given an invalid parameter");
265                 return 0;
266         }
267
268         if (is_uline(user->server))
269                 return STATUS_OP;
270
271         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
272         {
273                 if (((ucrec*)(*i))->channel == chan)
274                 {
275                         if ((((ucrec*)(*i))->uc_modes & UCMODE_OP) > 0)
276                         {
277                                 return STATUS_OP;
278                         }
279                         if ((((ucrec*)(*i))->uc_modes & UCMODE_HOP) > 0)
280                         {
281                                 return STATUS_HOP;
282                         }
283                         if ((((ucrec*)(*i))->uc_modes & UCMODE_VOICE) > 0)
284                         {
285                                 return STATUS_VOICE;
286                         }
287                         return STATUS_NORMAL;
288                 }
289         }
290         return STATUS_NORMAL;
291 }
292
293 void TidyBan(char *ban)
294 {
295         if (!ban) {
296                 log(DEFAULT,"*** BUG *** TidyBan was given an invalid parameter");
297                 return;
298         }
299         
300         char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
301
302         strlcpy(temp,ban,MAXBUF);
303
304         char* pos_of_pling = strchr(temp,'!');
305         char* pos_of_at = strchr(temp,'@');
306
307         pos_of_pling[0] = '\0';
308         pos_of_at[0] = '\0';
309         pos_of_pling++;
310         pos_of_at++;
311
312         strlcpy(NICK,temp,NICKMAX-1);
313         strlcpy(IDENT,pos_of_pling,IDENTMAX+1);
314         strlcpy(HOST,pos_of_at,63);
315
316         snprintf(ban,MAXBUF,"%s!%s@%s",NICK,IDENT,HOST);
317 }
318
319 char lst[MAXBUF];
320
321 std::string chlist(userrec *user,userrec* source)
322 {
323         std::string list;
324         
325         if (!user || !source)
326                 return "";
327         
328         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
329         {
330                 ucrec* rec = *i;
331                 
332                 if(rec->channel && rec->channel->name)
333                 {
334                         /* XXX - Why does this check need to be here at all? :< */
335                         /* Commenting this out until someone finds a case where we need it */
336                         //if (lst.find(rec->channel->name) == std::string::npos)
337                         //{
338                         
339                                 /*
340                                  * If the target is the same as the sender, let them see all their channels.
341                                  * If the channel is NOT private/secret AND the user is not invisible.
342                                  * If the user is an oper, and the <options:operspywhois> option is set.
343                                  */
344                                 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))))
345                                 {
346                                         list.append(cmode(user, rec->channel)).append(rec->channel->name).append(" ");
347                                 }
348                         //}
349                 }
350         }
351         
352         return list;
353 }