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