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