]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/message.cpp
Moved a ton of functions into helperfuncs.h to speed up recompiles
[user/henk/code/inspircd.git] / src / message.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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 #include "inspircd.h"
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
21 #include <unistd.h>
22 #include <fcntl.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 <errno.h>
38 #include <deque>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sched.h>
42 #include "connection.h"
43 #include "users.h"
44 #include "servers.h"
45 #include "ctables.h"
46 #include "globals.h"
47 #include "modules.h"
48 #include "dynamic.h"
49 #include "wildcard.h"
50 #include "message.h"
51 #include "inspstring.h"
52 #include "dns.h"
53 #include "helperfuncs.h"
54
55 using namespace std;
56
57 extern int MODCOUNT;
58 extern std::vector<Module*> modules;
59 extern std::vector<ircd_module*> factory;
60
61 extern char ServerName[MAXBUF];
62
63 extern time_t TIME;
64
65 extern FILE *log_file;
66 extern char DNSServer[MAXBUF];
67
68 /* return 0 or 1 depending if users u and u2 share one or more common channels
69  * (used by QUIT, NICK etc which arent channel specific notices) */
70
71 int common_channels(userrec *u, userrec *u2)
72 {
73         if ((!u) || (!u2))
74         {
75                 log(DEFAULT,"*** BUG *** common_channels was given an invalid parameter");
76                 return 0;
77         }
78         for (int i = 0; i != MAXCHANS; i++)
79         {
80                 for (int z = 0; z != MAXCHANS; z++)
81                 {
82                         if ((u->chans[i].channel != NULL) && (u2->chans[z].channel != NULL))
83                         {
84                                 if ((!strcasecmp(u->chans[i].channel->name,u2->chans[z].channel->name)) && (u->chans[i].channel) && (u2->chans[z].channel) && (u->registered == 7) && (u2->registered == 7))
85                                 {
86                                         if ((c_count(u)) && (c_count(u2)))
87                                         {
88                                                 return 1;
89                                         }
90                                 }
91                         }
92                 }
93         }
94         return 0;
95 }
96
97
98 void safedelete(userrec *p)
99 {
100         if (p)
101         {
102                 log(DEBUG,"deleting %s %s %s %s",p->nick,p->ident,p->dhost,p->fullname);
103                 log(DEBUG,"safedelete(userrec*): pointer is safe to delete");
104                 delete p;
105                 p = NULL;
106         }
107         else
108         {
109                 log(DEBUG,"safedelete(userrec*): unsafe pointer operation squished");
110         }
111 }
112
113 void safedelete(chanrec *p)
114 {
115         if (p)
116         {
117                 delete p;
118                 p = NULL;
119                 log(DEBUG,"safedelete(chanrec*): pointer is safe to delete");
120         }
121         else
122         {
123                 log(DEBUG,"safedelete(chanrec*): unsafe pointer operation squished");
124         }
125 }
126
127
128 void tidystring(char* str)
129 {
130         // strips out double spaces before a : parameter
131         
132         char temp[MAXBUF];
133         bool go_again = true;
134         
135         if (!str)
136         {
137                 return;
138         }
139         
140         while ((str[0] == ' ') && (strlen(str)>0))
141         {
142                 str++;
143         }
144         
145         while (go_again)
146         {
147                 bool noparse = false;
148                 int t = 0, a = 0;
149                 go_again = false;
150                 while (a < strlen(str))
151                 {
152                         if ((a<strlen(str)-1) && (noparse==false))
153                         {
154                                 if ((str[a] == ' ') && (str[a+1] == ' '))
155                                 {
156                                         log(DEBUG,"Tidied extra space out of string: %s",str);
157                                         go_again = true;
158                                         a++;
159                                 }
160                         }
161                         
162                         if (a<strlen(str)-1)
163                         {
164                                 if ((str[a] == ' ') && (str[a+1] == ':'))
165                                 {
166                                         noparse = true;
167                                 }
168                         }
169                         
170                         temp[t++] = str[a++];
171                 }
172                 temp[t] = '\0';
173                 strlcpy(str,temp,MAXBUF);
174         }
175 }
176
177 /* chop a string down to 512 characters and preserve linefeed (irc max
178  * line length) */
179
180 void chop(char* str)
181 {
182         if (!str)
183         {
184                 log(DEBUG,"ERROR! Null string passed to chop()!");
185                 return;
186         }
187         string temp = str;
188         FOREACH_MOD OnServerRaw(temp,false,NULL);
189         const char* str2 = temp.c_str();
190         snprintf(str,MAXBUF,"%s",str2);
191         if (strlen(str) >= 511)
192         {
193                 str[510] = '\r';
194                 str[511] = '\n';
195                 str[512] = '\0';
196                 log(DEBUG,"Excess line chopped.");
197         }
198 }
199
200
201 void Blocking(int s)
202 {
203         int flags;
204         log(DEBUG,"Blocking: %d",s);
205         flags = fcntl(s, F_GETFL, 0);
206         fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
207 }
208
209 void NonBlocking(int s)
210 {
211         int flags;
212         log(DEBUG,"NonBlocking: %d",s);
213         flags = fcntl(s, F_GETFL, 0);
214         fcntl(s, F_SETFL, flags | O_NONBLOCK);
215 }
216
217 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost)
218 {
219         DNS d(DNSServer);
220         int fd = d.ReverseLookup(unresolvedHost);
221         if (fd < 1)
222                 return 0;
223         time_t T = time(NULL)+1;
224         while ((!d.HasResult()) && (time(NULL)<T));
225         std::string ipaddr = d.GetResult();
226         strlcpy(resolvedHost,ipaddr.c_str(),MAXBUF);
227         return (ipaddr != "");
228 }
229
230 int c_count(userrec* u)
231 {
232         int z = 0;
233         for (int i =0; i != MAXCHANS; i++)
234                 if (u->chans[i].channel != NULL)
235                         z++;
236         return z;
237
238 }
239
240 bool hasumode(userrec* user, char mode)
241 {
242         if (user)
243         {
244                 return (strchr(user->modes,mode)>0);
245         }
246         else return false;
247 }
248
249
250 void ChangeName(userrec* user, const char* gecos)
251 {
252         if (!strcasecmp(user->server,ServerName))
253         {
254                 int MOD_RESULT = 0;
255                 FOREACH_RESULT(OnChangeLocalUserGECOS(user,gecos));
256                 if (MOD_RESULT)
257                         return;
258         }
259         strlcpy(user->fullname,gecos,MAXBUF);
260         char buffer[MAXBUF];
261         snprintf(buffer,MAXBUF,"a %s :%s",user->nick,gecos);
262         NetSendToAll(buffer);
263 }
264
265 void ChangeDisplayedHost(userrec* user, const char* host)
266 {
267         if (!strcasecmp(user->server,ServerName))
268         {
269                 int MOD_RESULT = 0;
270                 FOREACH_RESULT(OnChangeLocalUserHost(user,host));
271                 if (MOD_RESULT)
272                         return;
273         }
274         strlcpy(user->dhost,host,160);
275         char buffer[MAXBUF];
276         snprintf(buffer,MAXBUF,"b %s %s",user->nick,host);
277         NetSendToAll(buffer);
278 }
279
280 /* verify that a user's ident and nickname is valid */
281
282 int isident(const char* n)
283 {
284         if (!n)
285
286         {
287                 return 0;
288         }
289         if (!strcmp(n,""))
290         {
291                 return 0;
292         }
293         for (int i = 0; i != strlen(n); i++)
294         {
295                 if ((n[i] < 33) || (n[i] > 125))
296                 {
297                         return 0;
298                 }
299                 /* can't occur ANYWHERE in an Ident! */
300                 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
301                 {
302                         return 0;
303                 }
304         }
305         return 1;
306 }
307
308
309 int isnick(const char* n)
310 {
311         if (!n)
312         {
313                 return 0;
314         }
315         if (!strcmp(n,""))
316         {
317                 return 0;
318         }
319         if (strlen(n) > NICKMAX-1)
320         {
321                 return 0;
322         }
323         for (int i = 0; i != strlen(n); i++)
324         {
325                 if ((n[i] < 33) || (n[i] > 125))
326                 {
327                         return 0;
328                 }
329                 /* can't occur ANYWHERE in a nickname! */
330                 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
331                 {
332                         return 0;
333                 }
334                 /* can't occur as the first char of a nickname... */
335                 if ((strchr("0123456789",n[i])) && (!i))
336                 {
337                         return 0;
338                 }
339         }
340         return 1;
341 }
342
343 /* returns the status character for a given user on a channel, e.g. @ for op,
344  * % for halfop etc. If the user has several modes set, the highest mode
345  * the user has must be returned. */
346
347 char* cmode(userrec *user, chanrec *chan)
348 {
349         if ((!user) || (!chan))
350         {
351                 log(DEFAULT,"*** BUG *** cmode was given an invalid parameter");
352                 return "";
353         }
354         for (int i = 0; i != MAXCHANS; i++)
355         {
356                 if (user->chans[i].channel)
357                 {
358                         if ((!strcasecmp(user->chans[i].channel->name,chan->name)) && (chan != NULL))
359                         {
360                                 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
361                                 {
362                                         return "@";
363                                 }
364                                 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
365                                 {
366                                         return "%";
367                                 }
368                                 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
369                                 {
370                                         return "+";
371                                 }
372                                 return "";
373                         }
374                 }
375         }
376         return "";
377 }
378
379 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
380  * op, STATUS_VOICE for voice etc. If the user has several modes set, the
381  * highest mode the user has must be returned. */
382
383 int cstatus(userrec *user, chanrec *chan)
384 {
385         if ((!chan) || (!user))
386         {
387                 log(DEFAULT,"*** BUG *** cstatus was given an invalid parameter");
388                 return 0;
389         }
390
391         for (int i = 0; i != MAXCHANS; i++)
392         {
393                 if (user->chans[i].channel)
394                 {
395                         if ((!strcasecmp(user->chans[i].channel->name,chan->name)) && (chan != NULL))
396                         {
397                                 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
398                                 {
399                                         return STATUS_OP;
400                                 }
401                                 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
402                                 {
403                                         return STATUS_HOP;
404                                 }
405                                 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
406                                 {
407                                         return STATUS_VOICE;
408                                 }
409                                 return STATUS_NORMAL;
410                         }
411                 }
412         }
413         return STATUS_NORMAL;
414 }
415
416 /* returns 1 if user u has channel c in their record, 0 if not */
417
418 int has_channel(userrec *u, chanrec *c)
419 {
420         if ((!u) || (!c))
421         {
422                 log(DEFAULT,"*** BUG *** has_channel was given an invalid parameter");
423                 return 0;
424         }
425         for (int i =0; i != MAXCHANS; i++)
426         {
427                 if (u->chans[i].channel)
428                 {
429                         if (!strcasecmp(u->chans[i].channel->name,c->name))
430                         {
431                                 return 1;
432                         }
433                 }
434         }
435         return 0;
436 }
437
438
439 void TidyBan(char *ban)
440 {
441         if (!ban) {
442                 log(DEFAULT,"*** BUG *** TidyBan was given an invalid parameter");
443                 return;
444         }
445         
446         char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
447
448         strlcpy(temp,ban,MAXBUF);
449
450         char* pos_of_pling = strchr(temp,'!');
451         char* pos_of_at = strchr(temp,'@');
452
453         pos_of_pling[0] = '\0';
454         pos_of_at[0] = '\0';
455         pos_of_pling++;
456         pos_of_at++;
457
458         strlcpy(NICK,temp,NICKMAX);
459         strlcpy(IDENT,pos_of_pling,IDENTMAX+1);
460         strlcpy(HOST,pos_of_at,160);
461
462         snprintf(ban,MAXBUF,"%s!%s@%s",NICK,IDENT,HOST);
463 }
464
465 char lst[MAXBUF];
466
467 char* chlist(userrec *user,userrec* source)
468 {
469         char cmp[MAXBUF];
470         log(DEBUG,"chlist: %s",user->nick);
471         strcpy(lst,"");
472         if (!user)
473         {
474                 return lst;
475         }
476         for (int i = 0; i != MAXCHANS; i++)
477         {
478                 if (user->chans[i].channel != NULL)
479                 {
480                         if (user->chans[i].channel->name)
481                         {
482                                 strlcpy(cmp,user->chans[i].channel->name,MAXBUF);
483                                 strlcat(cmp," ",MAXBUF);
484                                 if (!strstr(lst,cmp))
485                                 {
486                                         // if the channel is NOT private/secret, OR the source user is on the channel
487                                         if (((!(user->chans[i].channel->binarymodes & CM_PRIVATE)) && (!(user->chans[i].channel->binarymodes & CM_SECRET))) || (has_channel(source,user->chans[i].channel)))
488                                         {
489                                                 strlcat(lst,cmode(user,user->chans[i].channel),MAXBUF);
490                                                 strlcat(lst,user->chans[i].channel->name,MAXBUF);
491                                                 strlcat(lst," ",MAXBUF);
492                                         }
493                                 }
494                         }
495                 }
496         }
497         if (strlen(lst))
498         {
499                 lst[strlen(lst)-1] = '\0'; // chop trailing space
500         }
501         return lst;
502 }
503
504
505 void send_network_quit(const char* nick, const char* reason)
506 {
507         char buffer[MAXBUF];
508         snprintf(buffer,MAXBUF,"Q %s :%s",nick,reason);
509         NetSendToAll(buffer);
510 }
511
512