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