]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspircd.cpp
6350bf659070a60f0e3d3dc8e4c0eca983107612
[user/henk/code/inspircd.git] / src / inspircd.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2003 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 /* Now with added unF! ;) */
18
19 #include "inspircd.h"
20 #include "inspircd_io.h"
21 #include "inspircd_util.h"
22 #include "inspircd_config.h"
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <sys/errno.h>
26 #include <sys/ioctl.h>
27 #include <sys/utsname.h>
28 #include <cstdio>
29 #include <time.h>
30 #include <string>
31 #ifdef GCC3
32 #include <ext/hash_map>
33 #else
34 #include <hash_map>
35 #endif
36 #include <map>
37 #include <sstream>
38 #include <vector>
39 #include <errno.h>
40 #include <deque>
41 #include "connection.h"
42 #include "users.h"
43 #include "servers.h"
44 #include "ctables.h"
45 #include "globals.h"
46 #include "modules.h"
47 #include "dynamic.h"
48 #include "wildcard.h"
49
50 using namespace std;
51
52 #ifdef GCC3
53 #define nspace __gnu_cxx
54 #else
55 #define nspace std
56 #endif
57
58 int LogLevel = DEFAULT;
59 char ServerName[MAXBUF];
60 char Network[MAXBUF];
61 char ServerDesc[MAXBUF];
62 char AdminName[MAXBUF];
63 char AdminEmail[MAXBUF];
64 char AdminNick[MAXBUF];
65 char diepass[MAXBUF];
66 char restartpass[MAXBUF];
67 char motd[MAXBUF];
68 char rules[MAXBUF];
69 char list[MAXBUF];
70 char PrefixQuit[MAXBUF];
71 char DieValue[MAXBUF];
72 int debugging =  0;
73 int WHOWAS_STALE = 48; // default WHOWAS Entries last 2 days before they go 'stale'
74 int WHOWAS_MAX = 100;  // default 100 people maximum in the WHOWAS list
75 int DieDelay  =  5;
76 time_t startup_time = time(NULL);
77
78 extern vector<Module*> modules;
79 extern vector<ircd_module*> factory;
80
81 extern int MODCOUNT;
82
83 namespace nspace
84 {
85         template<> struct nspace::hash<in_addr>
86         {
87                 size_t operator()(const struct in_addr &a) const
88                 {
89                         size_t q;
90                         memcpy(&q,&a,sizeof(size_t));
91                         return q;
92                 }
93         };
94
95         template<> struct nspace::hash<string>
96         {
97                 size_t operator()(const string &s) const
98                 {
99                         char a[MAXBUF];
100                         static struct hash<const char *> strhash;
101                         strcpy(a,s.c_str());
102                         strlower(a);
103                         return strhash(a);
104                 }
105         };
106 }       
107
108
109 struct StrHashComp
110 {
111
112         bool operator()(const string& s1, const string& s2) const
113         {
114                 char a[MAXBUF],b[MAXBUF];
115                 strcpy(a,s1.c_str());
116                 strcpy(b,s2.c_str());
117                 return (strcasecmp(a,b) == 0);
118         }
119
120 };
121
122 struct InAddr_HashComp
123 {
124
125         bool operator()(const in_addr &s1, const in_addr &s2) const
126         {
127                 size_t q;
128                 size_t p;
129                 
130                 memcpy(&q,&s1,sizeof(size_t));
131                 memcpy(&p,&s2,sizeof(size_t));
132                 
133                 return (q == p);
134         }
135
136 };
137
138
139 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
140 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
141 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
142 typedef std::deque<command_t> command_table;
143
144 serverrec* me[32];
145 server_list* servers;
146
147 user_hash clientlist;
148 chan_hash chanlist;
149 user_hash whowas;
150 command_table cmdlist;
151 file_cache MOTD;
152 file_cache RULES;
153 address_cache IP;
154
155 ClassVector Classes;
156
157 struct linger linger = { 0 };
158 char bannerBuffer[MAXBUF];
159 int boundPortCount = 0;
160 int portCount = 0, UDPportCount = 0, ports[MAXSOCKS];
161 int defaultRoute = 0;
162
163 /* prototypes */
164
165 int has_channel(userrec *u, chanrec *c);
166 int usercount(chanrec *c);
167 int usercount_i(chanrec *c);
168 void update_stats_l(int fd,int data_out);
169 char* Passwd(userrec *user);
170 bool IsDenied(userrec *user);
171 void AddWhoWas(userrec* u);
172
173
174 void safedelete(userrec *p)
175 {
176         if (p)
177         {
178                 log(DEBUG,"deleting %s %s %s %s",p->nick,p->ident,p->dhost,p->fullname);
179                 log(DEBUG,"safedelete(userrec*): pointer is safe to delete");
180                 delete p;
181         }
182         else
183         {
184                 log(DEBUG,"safedelete(userrec*): unsafe pointer operation squished");
185         }
186 }
187
188 void safedelete(chanrec *p)
189 {
190         if (p)
191         {
192                 delete p;
193                 log(DEBUG,"safedelete(chanrec*): pointer is safe to delete");
194         }
195         else
196         {
197                 log(DEBUG,"safedelete(chanrec*): unsafe pointer operation squished");
198         }
199 }
200
201
202 /* chop a string down to 512 characters and preserve linefeed (irc max
203  * line length) */
204
205 void chop(char* str)
206 {
207
208   string temp = str;
209   FOREACH_MOD OnServerRaw(temp,false);
210   const char* str2 = temp.c_str();
211   sprintf(str,"%s",str2);
212   
213
214   if (strlen(str) > 512)
215   {
216         str[510] = '\r';
217         str[511] = '\n';
218         str[512] = '\0';
219   }
220 }
221
222
223 std::string getservername()
224 {
225         return ServerName;
226 }
227
228 std::string getserverdesc()
229 {
230         return ServerDesc;
231 }
232
233 std::string getnetworkname()
234 {
235         return Network;
236 }
237
238 std::string getadminname()
239 {
240         return AdminName;
241 }
242
243 std::string getadminemail()
244 {
245         return AdminEmail;
246 }
247
248 std::string getadminnick()
249 {
250         return AdminNick;
251 }
252
253 void log(int level,char *text, ...)
254 {
255         char textbuffer[MAXBUF];
256         va_list argsPtr;
257         FILE *f;
258         time_t rawtime;
259         struct tm * timeinfo;
260         if (level < LogLevel)
261                 return;
262
263         time(&rawtime);
264         timeinfo = localtime (&rawtime);
265
266         f = fopen("ircd.log","a+");
267         if (f)
268         {
269                 char b[MAXBUF];
270                 va_start (argsPtr, text);
271                 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
272                 va_end(argsPtr);
273                 strcpy(b,asctime(timeinfo));
274                 b[strlen(b)-1] = ':';
275                 fprintf(f,"%s %s\n",b,textbuffer);
276                 fclose(f);
277         }
278         else
279         {
280                 printf("Can't write log file, bailing!!!");
281                 Exit(ERROR);
282         }
283 }
284
285 void readfile(file_cache &F, const char* fname)
286 {
287   FILE* file;
288   char linebuf[MAXBUF];
289
290   log(DEBUG,"readfile: loading %s",fname);
291   F.clear();
292   file =  fopen(fname,"r");
293   if (file)
294   {
295         while (!feof(file))
296         {
297                 fgets(linebuf,sizeof(linebuf),file);
298                 linebuf[strlen(linebuf)-1]='\0';
299                 if (!strcmp(linebuf,""))
300                 {
301                         strcpy(linebuf,"  ");
302                 }
303                 if (!feof(file))
304                 {
305                         F.push_back(linebuf);
306                 }
307         }
308         fclose(file);
309   }
310   else
311   {
312           log(DEBUG,"readfile: failed to load file: %s",fname);
313   }
314   log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
315 }
316
317 void ReadConfig(void)
318 {
319   char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF];
320   ConnectClass c;
321
322   ConfValue("server","name",0,ServerName);
323   ConfValue("server","description",0,ServerDesc);
324   ConfValue("server","network",0,Network);
325   ConfValue("admin","name",0,AdminName);
326   ConfValue("admin","email",0,AdminEmail);
327   ConfValue("admin","nick",0,AdminNick);
328   ConfValue("files","motd",0,motd);
329   ConfValue("files","rules",0,rules);
330   ConfValue("power","diepass",0,diepass);
331   ConfValue("power","pause",0,pauseval);
332   ConfValue("power","restartpass",0,restartpass);
333   ConfValue("options","prefixquit",0,PrefixQuit);
334   ConfValue("die","value",0,DieValue);
335   ConfValue("options","loglevel",0,dbg);
336   if (!strcmp(dbg,"debug"))
337         LogLevel = DEBUG;
338   if (!strcmp(dbg,"verbose"))
339         LogLevel = VERBOSE;
340   if (!strcmp(dbg,"default"))
341         LogLevel = DEFAULT;
342   if (!strcmp(dbg,"sparse"))
343         LogLevel = SPARSE;
344   if (!strcmp(dbg,"none"))
345         LogLevel = NONE;
346   readfile(RULES,rules);
347   log(DEBUG,"Reading connect classes");
348   Classes.clear();
349   for (int i = 0; i < ConfValueEnum("connect"); i++)
350   {
351         strcpy(Value,"");
352         ConfValue("connect","allow",i,Value);
353         if (strcmp(Value,""))
354         {
355                 strcpy(c.host,Value);
356                 c.type = CC_ALLOW;
357                 strcpy(Value,"");
358                 ConfValue("connect","password",i,Value);
359                 strcpy(c.pass,Value);
360                 Classes.push_back(c);
361                 log(DEBUG,"Read connect class type ALLOW, host=%s password=%s",c.host,c.pass);
362         }
363         else
364         {
365                 ConfValue("connect","deny",i,Value);
366                 strcpy(c.host,Value);
367                 c.type = CC_DENY;
368                 Classes.push_back(c);
369                 log(DEBUG,"Read connect class type DENY, host=%s",c.host);
370         }
371         
372   }
373 }
374
375 void Blocking(int s)
376 {
377   int flags;
378   log(DEBUG,"Blocking: %d",s);
379   flags = fcntl(s, F_GETFL, 0);
380   fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
381 }
382
383 void NonBlocking(int s)
384 {
385   int flags;
386   log(DEBUG,"NonBlocking: %d",s);
387   flags = fcntl(s, F_GETFL, 0);
388   fcntl(s, F_SETFL, flags | O_NONBLOCK);
389 }
390
391
392 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost)
393 {
394   struct hostent *hostPtr = NULL;
395   struct in_addr addr;
396
397   memset (resolvedHost, '\0',MAXBUF);
398   if(unresolvedHost == NULL)
399         return(ERROR);
400   if ((inet_aton(unresolvedHost,&addr)) == 0)
401         return(ERROR);
402   hostPtr = gethostbyaddr ((char *)&addr.s_addr,sizeof(addr.s_addr),AF_INET);
403   if (hostPtr != NULL)
404         snprintf(resolvedHost,MAXBUF,"%s",hostPtr->h_name);
405   else
406         snprintf(resolvedHost,MAXBUF,"%s",unresolvedHost);
407   return (TRUE);
408 }
409
410 /* write formatted text to a socket, in same format as printf */
411
412 void Write(int sock,char *text, ...)
413 {
414   char textbuffer[MAXBUF];
415   va_list argsPtr;
416   char tb[MAXBUF];
417
418   va_start (argsPtr, text);
419   vsnprintf(textbuffer, MAXBUF, text, argsPtr);
420   va_end(argsPtr);
421   sprintf(tb,"%s\r\n",textbuffer);
422   chop(tb);
423   write(sock,tb,strlen(tb));
424   update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
425 }
426
427 /* write a server formatted numeric response to a single socket */
428
429 void WriteServ(int sock, char* text, ...)
430 {
431   char textbuffer[MAXBUF],tb[MAXBUF];
432   va_list argsPtr;
433   va_start (argsPtr, text);
434
435   vsnprintf(textbuffer, MAXBUF, text, argsPtr);
436   va_end(argsPtr);
437   sprintf(tb,":%s %s\r\n",ServerName,textbuffer);
438   chop(tb);
439   write(sock,tb,strlen(tb));
440   update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
441 }
442
443 /* write text from an originating user to originating user */
444
445 void WriteFrom(int sock, userrec *user,char* text, ...)
446 {
447   char textbuffer[MAXBUF],tb[MAXBUF];
448   va_list argsPtr;
449   va_start (argsPtr, text);
450
451   vsnprintf(textbuffer, MAXBUF, text, argsPtr);
452   va_end(argsPtr);
453   sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
454   chop(tb);
455   write(sock,tb,strlen(tb));
456   update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
457 }
458
459 /* write text to an destination user from a source user (e.g. user privmsg) */
460
461 void WriteTo(userrec *source, userrec *dest,char *data, ...)
462 {
463         char textbuffer[MAXBUF],tb[MAXBUF];
464         va_list argsPtr;
465         va_start (argsPtr, data);
466         if ((!dest) || (!source))
467         {
468                 return;
469         }
470         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
471         va_end(argsPtr);
472         chop(tb);
473         WriteFrom(dest->fd,source,"%s",textbuffer);
474 }
475
476 /* write formatted text from a source user to all users on a channel
477  * including the sender (NOT for privmsg, notice etc!) */
478
479 void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...)
480 {
481         char textbuffer[MAXBUF];
482         va_list argsPtr;
483         va_start (argsPtr, text);
484         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
485         va_end(argsPtr);
486         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
487         {
488                 if (has_channel(i->second,Ptr))
489                 {
490                         WriteTo(user,i->second,"%s",textbuffer);
491                 }
492         }
493 }
494
495 /* write formatted text from a source user to all users on a channel except
496  * for the sender (for privmsg etc) */
497
498 void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...)
499 {
500         char textbuffer[MAXBUF];
501         va_list argsPtr;
502         va_start (argsPtr, text);
503         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
504         va_end(argsPtr);
505
506         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
507         {
508                 if (has_channel(i->second,Ptr) && (user != i->second))
509                 {
510                         WriteTo(user,i->second,"%s",textbuffer);
511                 }
512         }
513 }
514
515 int c_count(userrec* u)
516 {
517         int z = 0;
518         for (int i =0; i != MAXCHANS; i++)
519                 if (u->chans[i].channel)
520                         z++;
521         return z;
522
523 }
524
525 /* return 0 or 1 depending if users u and u2 share one or more common channels
526  * (used by QUIT, NICK etc which arent channel specific notices) */
527
528 int common_channels(userrec *u, userrec *u2)
529 {
530         int i = 0;
531         int z = 0;
532
533         if ((!u) || (!u2))
534         {
535                 return 0;
536         }
537         for (i = 0; i != MAXCHANS; i++)
538         {
539                 for (z = 0; z != MAXCHANS; z++)
540                 {
541                         if ((u->chans[i].channel == u2->chans[z].channel) && (u->chans[i].channel) && (u2->chans[z].channel) && (u->registered == 7) && (u2->registered == 7))
542                         {
543                                 if ((c_count(u)) && (c_count(u2)))
544                                 {
545                                         return 1;
546                                 }
547                         }
548                 }
549         }
550         return 0;
551 }
552
553 /* write a formatted string to all users who share at least one common
554  * channel, including the source user e.g. for use in NICK */
555
556 void WriteCommon(userrec *u, char* text, ...)
557 {
558         char textbuffer[MAXBUF];
559         va_list argsPtr;
560         va_start (argsPtr, text);
561         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
562         va_end(argsPtr);
563
564         WriteFrom(u->fd,u,"%s",textbuffer);
565
566         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
567         {
568                 if (common_channels(u,i->second) && (i->second != u))
569                 {
570                         WriteFrom(i->second->fd,u,"%s",textbuffer);
571                 }
572         }
573 }
574
575 /* write a formatted string to all users who share at least one common
576  * channel, NOT including the source user e.g. for use in QUIT */
577
578 void WriteCommonExcept(userrec *u, char* text, ...)
579 {
580         char textbuffer[MAXBUF];
581         va_list argsPtr;
582         va_start (argsPtr, text);
583         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
584         va_end(argsPtr);
585
586         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
587         {
588                 if ((common_channels(u,i->second)) && (u != i->second))
589                 {
590                         WriteFrom(i->second->fd,u,"%s",textbuffer);
591                 }
592         }
593 }
594
595 void WriteOpers(char* text, ...)
596 {
597         char textbuffer[MAXBUF];
598         va_list argsPtr;
599         va_start (argsPtr, text);
600         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
601         va_end(argsPtr);
602
603         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
604         {
605                 if (strchr(i->second->modes,'o'))
606                 {
607                         if (strchr(i->second->modes,'s'))
608                         {
609                                 // send server notices to all with +s
610                                 // (TODO: needs SNOMASKs)
611                                 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
612                         }
613                 }
614         }
615 }
616
617 void WriteWallOps(userrec *source, char* text, ...)  
618 {  
619         int i = 0;  
620         char textbuffer[MAXBUF];  
621         va_list argsPtr;  
622         va_start (argsPtr, text);  
623         vsnprintf(textbuffer, MAXBUF, text, argsPtr);  
624         va_end(argsPtr);  
625   
626         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
627         {  
628                 if (strchr(i->second->modes,'w'))
629                 {  
630                         WriteTo(source,i->second,"WALLOPS %s",textbuffer);
631                 }
632         }
633 }  
634
635 /* convert a string to lowercase. Note following special circumstances
636  * taken from RFC 1459. Many "official" server branches still hold to this
637  * rule so i will too;
638  *
639  *  Because of IRC's scandanavian origin, the characters {}| are
640  *  considered to be the lower case equivalents of the characters []\,
641  *  respectively. This is a critical issue when determining the
642  *  equivalence of two nicknames.
643  */
644
645 void strlower(char *n)
646 {
647         if (!n)
648         {
649                 return;
650         }
651         for (int i = 0; i != strlen(n); i++)
652         {
653                 n[i] = tolower(n[i]);
654                 if (n[i] == '[')
655                         n[i] = '{';
656                 if (n[i] == ']')
657                         n[i] = '}';
658                 if (n[i] == '\\')
659                         n[i] = '|';
660         }
661 }
662
663 /* verify that a user's ident and nickname is valid */
664
665 int isident(const char* n)
666 {
667         int i = 0;
668         char v[MAXBUF];
669         if (!n)
670
671         {
672                 return 0;
673         }
674         if (!strcmp(n,""))
675         {
676                 return 0;
677         }
678         for (i = 0; i != strlen(n); i++)
679         {
680                 if ((n[i] < 33) || (n[i] > 125))
681                 {
682                         return 0;
683                 }
684                 /* can't occur ANYWHERE in an Ident! */
685                 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
686                 {
687                         return 0;
688                 }
689         }
690         return 1;
691 }
692
693
694 int isnick(const char* n)
695 {
696         int i = 0;
697         char v[MAXBUF];
698         if (!n)
699         {
700                 return 0;
701         }
702         if (!strcmp(n,""))
703         {
704                 return 0;
705         }
706         if (strlen(n) > NICKMAX-1)
707         {
708                 return 0;
709         }
710         for (i = 0; i != strlen(n); i++)
711         {
712                 if ((n[i] < 33) || (n[i] > 125))
713                 {
714                         return 0;
715                 }
716                 /* can't occur ANYWHERE in a nickname! */
717                 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
718                 {
719                         return 0;
720                 }
721                 /* can't occur as the first char of a nickname... */
722                 if ((strchr("0123456789",n[i])) && (!i))
723                 {
724                         return 0;
725                 }
726         }
727         return 1;
728 }
729
730 /* Find a user record by nickname and return a pointer to it */
731
732 userrec* Find(string nick)
733 {
734         user_hash::iterator iter = clientlist.find(nick);
735
736         if (iter == clientlist.end())
737                 /* Couldn't find it */
738                 return NULL;
739
740         return iter->second;
741 }
742
743 void update_stats_l(int fd,int data_out) /* add one line-out to stats L for this fd */
744 {
745         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
746         {
747                 if (i->second->fd == fd)
748                 {
749                         i->second->bytes_out+=data_out;
750                         i->second->cmds_out++;
751                 }
752         }
753 }
754
755
756 /* find a channel record by channel name and return a pointer to it */
757
758 chanrec* FindChan(const char* chan)
759 {
760         chan_hash::iterator iter = chanlist.find(chan);
761
762         if (iter == chanlist.end())
763                 /* Couldn't find it */
764                 return NULL;
765
766         return iter->second;
767 }
768
769
770 void purge_empty_chans(void)
771 {
772         int go_again = 1, purge = 0;
773         
774         while (go_again)
775         {
776                 go_again = 0;
777                 for (chan_hash::iterator i = chanlist.begin(); i != chanlist.end(); i++)
778                 {
779                         if (i->second) {
780                                 if (!usercount(i->second))
781                                 {
782                                         /* kill the record */
783                                         if (i != chanlist.end())
784                                         {
785                                                 log(DEBUG,"del_channel: destroyed: %s",i->second->name);
786                                                 delete i->second;
787                                                 chanlist.erase(i);
788                                                 go_again = 1;
789                                                 purge++;
790                                                 break;
791                                         }
792                                 }
793                         }
794                 }
795         }
796         log(DEBUG,"completed channel purge, killed %d",purge);
797 }
798
799 /* returns the status character for a given user on a channel, e.g. @ for op,
800  * % for halfop etc. If the user has several modes set, the highest mode
801  * the user has must be returned. */
802
803 char* cmode(userrec *user, chanrec *chan)
804 {
805         int i;
806         for (i = 0; i != MAXCHANS; i++)
807         {
808                 if ((user->chans[i].channel == chan) && (chan != NULL))
809                 {
810                         if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
811                         {
812                                 return "@";
813                         }
814                         if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
815                         {
816                                 return "%";
817                         }
818                         if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
819                         {
820                                 return "+";
821                         }
822                         return "";
823                 }
824         }
825 }
826
827 char scratch[MAXMODES];
828
829 char* chanmodes(chanrec *chan)
830 {
831         strcpy(scratch,"");
832         if (chan->noexternal)
833         {
834                 strcat(scratch,"n");
835         }
836         if (chan->topiclock)
837         {
838                 strcat(scratch,"t");
839         }
840         if (strcmp(chan->key,""))
841         {
842                 strcat(scratch,"k");
843         }
844         if (chan->limit)
845         {
846                 strcat(scratch,"l");
847         }
848         if (chan->inviteonly)
849         {
850                 strcat(scratch,"i");
851         }
852         if (chan->moderated)
853         {
854                 strcat(scratch,"m");
855         }
856         if (chan->secret)
857         {
858                 strcat(scratch,"s");
859         }
860         if (chan->c_private)
861         {
862                 strcat(scratch,"p");
863         }
864         if (strcmp(chan->key,""))
865         {
866                 strcat(scratch," ");
867                 strcat(scratch,chan->key);
868         }
869         if (chan->limit)
870         {
871                 char foo[24];
872                 sprintf(foo," %d",chan->limit);
873                 strcat(scratch,foo);
874         }
875         log(DEBUG,"chanmodes: %s %s",chan->name,scratch);
876         return scratch;
877 }
878
879 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
880  * op, STATUS_VOICE for voice etc. If the user has several modes set, the
881  * highest mode the user has must be returned. */
882
883 int cstatus(userrec *user, chanrec *chan)
884 {
885         int i;
886         for (i = 0; i != MAXCHANS; i++)
887         {
888                 if ((user->chans[i].channel == chan) && (chan != NULL))
889                 {
890                         if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
891                         {
892                                 return STATUS_OP;
893                         }
894                         if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
895                         {
896                                 return STATUS_HOP;
897                         }
898                         if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
899                         {
900                                 return STATUS_VOICE;
901                         }
902                         return STATUS_NORMAL;
903                 }
904         }
905 }
906
907
908 /* compile a userlist of a channel into a string, each nick seperated by
909  * spaces and op, voice etc status shown as @ and + */
910
911 void userlist(userrec *user,chanrec *c)
912 {
913         sprintf(list,"353 %s = %s :", user->nick, c->name);
914         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
915         {
916                 if (has_channel(i->second,c))
917                 {
918                         if (isnick(i->second->nick))
919                         {
920                                 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
921                                 {
922                                         /* user is +i, and source not on the channel, does not show
923                                          * nick in NAMES list */
924                                         continue;
925                                 }
926                                 strcat(list,cmode(i->second,c));
927                                 strcat(list,i->second->nick);
928                                 strcat(list," ");
929                                 if (strlen(list)>(480-NICKMAX))
930                                 {
931                                         /* list overflowed into
932                                          * multiple numerics */
933                                         WriteServ(user->fd,list);
934                                         sprintf(list,"353 %s = %s :", user->nick, c->name);
935                                 }
936                         }
937                 }
938         }
939         /* if whats left in the list isnt empty, send it */
940         if (list[strlen(list)-1] != ':')
941         {
942                 WriteServ(user->fd,list);
943         }
944 }
945
946 /* return a count of the users on a specific channel accounting for
947  * invisible users who won't increase the count. e.g. for /LIST */
948
949 int usercount_i(chanrec *c)
950 {
951         int i = 0;
952         int count = 0;
953
954         strcpy(list,"");
955         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
956         {
957                 if (has_channel(i->second,c))
958                 {
959                         if (isnick(i->second->nick))
960                         {
961                                 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
962                                 {
963                                         /* user is +i, and source not on the channel, does not show
964                                          * nick in NAMES list */
965                                         continue;
966                                 }
967                                 count++;
968                         }
969                 }
970         }
971         log(DEBUG,"usercount_i: %s %d",c->name,count);
972         return count;
973 }
974
975
976 int usercount(chanrec *c)
977 {
978         int i = 0;
979         int count = 0;
980
981         strcpy(list,"");
982         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
983         {
984                 if (has_channel(i->second,c))
985                 {
986                         if (isnick(i->second->nick))
987                         {
988                                 count++;
989                         }
990                 }
991         }
992         log(DEBUG,"usercount: %s %d",c->name,count);
993         return count;
994 }
995
996
997 /* add a channel to a user, creating the record for it if needed and linking
998  * it to the user record */
999
1000 chanrec* add_channel(userrec *user, char* cname, char* key)
1001 {
1002         int i = 0;
1003         chanrec* Ptr;
1004         int created = 0;
1005
1006         if ((!cname) || (!user))
1007         {
1008                 return NULL;
1009         }
1010         if (strlen(cname) > CHANMAX-1)
1011         {
1012                 cname[CHANMAX-1] = '\0';
1013         }
1014
1015         log(DEBUG,"add_channel: %s %s",user->nick,cname);
1016         
1017         if ((has_channel(user,FindChan(cname))) && (FindChan(cname)))
1018         {
1019                 return NULL; // already on the channel!
1020         }
1021         
1022         if (!FindChan(cname))
1023         {
1024                 /* create a new one */
1025                 log(DEBUG,"add_channel: creating: %s",cname);
1026                 {
1027                         chanlist[cname] = new chanrec();
1028
1029                         strcpy(chanlist[cname]->name, cname);
1030                         chanlist[cname]->topiclock = 1;
1031                         chanlist[cname]->noexternal = 1;
1032                         chanlist[cname]->created = time(NULL);
1033                         strcpy(chanlist[cname]->topic, "");
1034                         strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
1035                         chanlist[cname]->topicset = 0;
1036                         Ptr = chanlist[cname];
1037                         log(DEBUG,"add_channel: created: %s",cname);
1038                         /* set created to 2 to indicate user
1039                          * is the first in the channel
1040                          * and should be given ops */
1041                         created = 2;
1042                 }
1043         }
1044         else
1045         {
1046                 /* channel exists, just fish out a pointer to its struct */
1047                 Ptr = FindChan(cname);
1048                 if (Ptr)
1049                 {
1050                         log(DEBUG,"add_channel: joining to: %s",Ptr->name);
1051                         if (strcmp(Ptr->key,""))
1052                         {
1053                                 log(DEBUG,"add_channel: %s has key %s",Ptr->name,Ptr->key);
1054                                 if (!key)
1055                                 {
1056                                         log(DEBUG,"add_channel: no key given in JOIN");
1057                                         WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
1058                                         return NULL;
1059                                 }
1060                                 else
1061                                 {
1062                                         log(DEBUG,"key at %p is %s",key,key);
1063                                         if (strcasecmp(key,Ptr->key))
1064                                         {
1065                                                 log(DEBUG,"add_channel: bad key given in JOIN");
1066                                                 WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
1067                                                 return NULL;
1068                                         }
1069                                 }
1070                         }
1071
1072                         if (Ptr->inviteonly)
1073                         {
1074                                 if (user->IsInvited(Ptr->name))
1075                                 {
1076                                         /* user was invited to channel */
1077                                         /* there may be an optional channel NOTICE here */
1078                                 }
1079                                 else
1080                                 {
1081                                         WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
1082                                         return NULL;
1083                                 }
1084                         }
1085
1086                         if (Ptr->limit)
1087                         {
1088                                 if (usercount(Ptr) == Ptr->limit)
1089                                 {
1090                                         WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
1091                                         return NULL;
1092                                 }
1093                         }
1094                         
1095                         /* check user against the channel banlist */
1096                         for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1097                         {
1098                                 if (match(user->GetFullHost(),i->data))
1099                                 {
1100                                         WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
1101                                         return NULL;
1102                                 }
1103                         }
1104
1105                         user->RemoveInvite(Ptr->name);
1106                         
1107                 }
1108                 created = 1;
1109         }
1110
1111         
1112         for (i =0; i != MAXCHANS; i++)
1113         {
1114                 if (user->chans[i].channel == NULL)
1115                 {
1116                         if (created == 2) 
1117                         {
1118                                 /* first user in is given ops */
1119                                 user->chans[i].uc_modes = UCMODE_OP;
1120                         }
1121                         else
1122                         {
1123                                 user->chans[i].uc_modes = 0;
1124                         }
1125                         user->chans[i].channel = Ptr;
1126                         WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
1127                         if (Ptr->topicset)
1128                         {
1129                                 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
1130                                 WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
1131                         }
1132                         userlist(user,Ptr);
1133                         WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
1134                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr));
1135                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1136                         FOREACH_MOD OnUserJoin(user,Ptr);
1137                         return Ptr;
1138                 }
1139         }
1140         log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
1141         WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
1142         return NULL;
1143 }
1144
1145 /* remove a channel from a users record, and remove the record from memory
1146  * if the channel has become empty */
1147
1148 chanrec* del_channel(userrec *user, char* cname, char* reason)
1149 {
1150         int i = 0;
1151         chanrec* Ptr;
1152         int created = 0;
1153
1154         if ((!cname) || (!user))
1155         {
1156                 return NULL;
1157         }
1158
1159         Ptr = FindChan(cname);
1160         
1161         if (!Ptr)
1162         {
1163                 return NULL;
1164         }
1165
1166         FOREACH_MOD OnUserPart(user,Ptr);
1167         log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
1168         
1169         for (i =0; i != MAXCHANS; i++)
1170         {
1171                 /* zap it from the channel list of the user */
1172                 if (user->chans[i].channel == Ptr)
1173                 {
1174                         if (reason)
1175                         {
1176                                 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
1177                         }
1178                         else
1179                         {
1180                                 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
1181                         }
1182                         user->chans[i].uc_modes = 0;
1183                         user->chans[i].channel = NULL;
1184                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
1185                         break;
1186                 }
1187         }
1188         
1189         /* if there are no users left on the channel */
1190         if (!usercount(Ptr))
1191         {
1192                 chan_hash::iterator iter = chanlist.find(Ptr->name);
1193
1194                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
1195
1196                 /* kill the record */
1197                 if (iter != chanlist.end())
1198                 {
1199                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
1200                         delete iter->second;
1201                         chanlist.erase(iter);
1202                 }
1203         }
1204 }
1205
1206
1207 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
1208 {
1209         int i = 0;
1210         int created = 0;
1211
1212         if ((!Ptr) || (!user) || (!src))
1213         {
1214                 return;
1215         }
1216
1217         log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
1218
1219         if (!has_channel(user,Ptr))
1220         {
1221                 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
1222                 return;
1223         }
1224         if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
1225         {
1226                 if (cstatus(src,Ptr) == STATUS_HOP)
1227                 {
1228                         WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
1229                 }
1230                 else
1231                 {
1232                         WriteServ(src->fd,"482 %s %s :You must be at least a half-operator",src->nick, Ptr->name);
1233                 }
1234                 
1235                 return;
1236         }
1237         
1238         for (i =0; i != MAXCHANS; i++)
1239         {
1240                 /* zap it from the channel list of the user */
1241                 if (user->chans[i].channel == Ptr)
1242                 {
1243                         WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
1244                         user->chans[i].uc_modes = 0;
1245                         user->chans[i].channel = NULL;
1246                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
1247                         break;
1248                 }
1249         }
1250         
1251         /* if there are no users left on the channel */
1252         if (!usercount(Ptr))
1253         {
1254                 chan_hash::iterator iter = chanlist.find(Ptr->name);
1255
1256                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
1257
1258                 /* kill the record */
1259                 if (iter != chanlist.end())
1260                 {
1261                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
1262                         delete iter->second;
1263                         chanlist.erase(iter);
1264                 }
1265         }
1266 }
1267
1268
1269 /* returns 1 if user u has channel c in their record, 0 if not */
1270
1271 int has_channel(userrec *u, chanrec *c)
1272 {
1273         int i = 0;
1274
1275         if (!u)
1276         {
1277                 return 0;
1278         }
1279         for (i =0; i != MAXCHANS; i++)
1280         {
1281                 if (u->chans[i].channel == c)
1282                 {
1283                         return 1;
1284                 }
1285         }
1286         return 0;
1287 }
1288
1289 int give_ops(userrec *user,char *dest,chanrec *chan,int status)
1290 {
1291         userrec *d;
1292         int i;
1293         
1294         if ((!user) || (!dest) || (!chan))
1295         {
1296                 return 0;
1297         }
1298         if (status != STATUS_OP)
1299         {
1300                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1301                 return 0;
1302         }
1303         else
1304         {
1305                 if (!isnick(dest))
1306                 {
1307                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1308                         return 0;
1309                 }
1310                 d = Find(dest);
1311                 if (!d)
1312                 {
1313                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1314                         return 0;
1315                 }
1316                 else
1317                 {
1318                         for (i = 0; i != MAXCHANS; i++)
1319                         {
1320                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1321                                 {
1322                                         if (d->chans[i].uc_modes & UCMODE_OP)
1323                                         {
1324                                                 /* mode already set on user, dont allow multiple */
1325                                                 return 0;
1326                                         }
1327                                         d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
1328                                         log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
1329                                 }
1330                         }
1331                 }
1332         }
1333         return 1;
1334 }
1335
1336 int give_hops(userrec *user,char *dest,chanrec *chan,int status)
1337 {
1338         userrec *d;
1339         int i;
1340         
1341         if ((!user) || (!dest) || (!chan))
1342         {
1343                 return 0;
1344         }
1345         if (status != STATUS_OP)
1346         {
1347                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1348                 return 0;
1349         }
1350         else
1351         {
1352                 d = Find(dest);
1353                 if (!isnick(dest))
1354                 {
1355                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1356                         return 0;
1357                 }
1358                 if (!d)
1359                 {
1360                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1361                         return 0;
1362                 }
1363                 else
1364                 {
1365                         for (i = 0; i != MAXCHANS; i++)
1366                         {
1367                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1368                                 {
1369                                         if (d->chans[i].uc_modes & UCMODE_HOP)
1370                                         {
1371                                                 /* mode already set on user, dont allow multiple */
1372                                                 return 0;
1373                                         }
1374                                         d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
1375                                         log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
1376                                 }
1377                         }
1378                 }
1379         }
1380         return 1;
1381 }
1382
1383 int give_voice(userrec *user,char *dest,chanrec *chan,int status)
1384 {
1385         userrec *d;
1386         int i;
1387         
1388         if ((!user) || (!dest) || (!chan))
1389         {
1390                 return 0;
1391         }
1392         if (status < STATUS_HOP)
1393         {
1394                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1395                 return 0;
1396         }
1397         else
1398         {
1399                 d = Find(dest);
1400                 if (!isnick(dest))
1401                 {
1402                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1403                         return 0;
1404                 }
1405                 if (!d)
1406                 {
1407                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1408                         return 0;
1409                 }
1410                 else
1411                 {
1412                         for (i = 0; i != MAXCHANS; i++)
1413                         {
1414                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1415                                 {
1416                                         if (d->chans[i].uc_modes & UCMODE_VOICE)
1417                                         {
1418                                                 /* mode already set on user, dont allow multiple */
1419                                                 return 0;
1420                                         }
1421                                         d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
1422                                         log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
1423                                 }
1424                         }
1425                 }
1426         }
1427         return 1;
1428 }
1429
1430 int take_ops(userrec *user,char *dest,chanrec *chan,int status)
1431 {
1432         userrec *d;
1433         int i;
1434         
1435         if ((!user) || (!dest) || (!chan))
1436         {
1437                 return 0;
1438         }
1439         if (status != STATUS_OP)
1440         {
1441                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1442                 return 0;
1443         }
1444         else
1445         {
1446                 d = Find(dest);
1447                 if (!isnick(dest))
1448                 {
1449                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1450                         return 0;
1451                 }
1452                 if (!d)
1453                 {
1454                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1455                         return 0;
1456                 }
1457                 else
1458                 {
1459                         for (i = 0; i != MAXCHANS; i++)
1460                         {
1461                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1462                                 {
1463                                         if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
1464                                         {
1465                                                 /* mode already set on user, dont allow multiple */
1466                                                 return 0;
1467                                         }
1468                                         d->chans[i].uc_modes ^= UCMODE_OP;
1469                                         log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
1470                                 }
1471                         }
1472                 }
1473         }
1474         return 1;
1475 }
1476
1477 int take_hops(userrec *user,char *dest,chanrec *chan,int status)
1478 {
1479         userrec *d;
1480         int i;
1481         
1482         if ((!user) || (!dest) || (!chan))
1483         {
1484                 return 0;
1485         }
1486         if (status != STATUS_OP)
1487         {
1488                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1489                 return 0;
1490         }
1491         else
1492         {
1493                 d = Find(dest);
1494                 if (!isnick(dest))
1495                 {
1496                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1497                         return 0;
1498                 }
1499                 if (!d)
1500                 {
1501                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1502                         return 0;
1503                 }
1504                 else
1505                 {
1506                         for (i = 0; i != MAXCHANS; i++)
1507                         {
1508                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1509                                 {
1510                                         if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
1511                                         {
1512                                                 /* mode already set on user, dont allow multiple */
1513                                                 return 0;
1514                                         }
1515                                         d->chans[i].uc_modes ^= UCMODE_HOP;
1516                                         log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
1517                                 }
1518                         }
1519                 }
1520         }
1521         return 1;
1522 }
1523
1524 int take_voice(userrec *user,char *dest,chanrec *chan,int status)
1525 {
1526         userrec *d;
1527         int i;
1528         
1529         if ((!user) || (!dest) || (!chan))
1530         {
1531                 return 0;
1532         }
1533         if (status < STATUS_HOP)
1534         {
1535                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1536                 return 0;
1537         }
1538         else
1539         {
1540                 d = Find(dest);
1541                 if (!isnick(dest))
1542                 {
1543                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1544                         return 0;
1545                 }
1546                 if (!d)
1547                 {
1548                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1549                         return 0;
1550                 }
1551                 else
1552                 {
1553                         for (i = 0; i != MAXCHANS; i++)
1554                         {
1555                                 if ((d->chans[i].channel == chan) && (chan != NULL))
1556                                 {
1557                                         if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
1558                                         {
1559                                                 /* mode already set on user, dont allow multiple */
1560                                                 return 0;
1561                                         }
1562                                         d->chans[i].uc_modes ^= UCMODE_VOICE;
1563                                         log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
1564                                 }
1565                         }
1566                 }
1567         }
1568         return 1;
1569 }
1570
1571 void TidyBan(char *ban)
1572 {
1573         char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
1574
1575         strcpy(temp,ban);
1576
1577         char* pos_of_pling = strchr(temp,'!');
1578         char* pos_of_at = strchr(temp,'@');
1579
1580         pos_of_pling[0] = '\0';
1581         pos_of_at[0] = '\0';
1582         pos_of_pling++;
1583         pos_of_at++;
1584
1585         strncpy(NICK,temp,NICKMAX);
1586         strncpy(IDENT,pos_of_pling,IDENTMAX+1);
1587         strncpy(HOST,pos_of_at,160);
1588
1589         sprintf(ban,"%s!%s@%s",NICK,IDENT,HOST);
1590 }
1591
1592 int add_ban(userrec *user,char *dest,chanrec *chan,int status)
1593 {
1594         BanItem b;
1595         if ((!user) || (!dest) || (!chan))
1596                 return 0;
1597         if (strchr(dest,'!')==0)
1598                 return 0;
1599         if (strchr(dest,'@')==0)
1600                 return 0;
1601         for (int i = 0; i < strlen(dest); i++)
1602                 if (dest[i] < 32)
1603                         return 0;
1604         for (int i = 0; i < strlen(dest); i++)
1605                 if (dest[i] > 126)
1606                         return 0;
1607         int c = 0;
1608         for (int i = 0; i < strlen(dest); i++)
1609                 if (dest[i] == '!')
1610                         c++;
1611         if (c>1)
1612                 return 0;
1613         c = 0;
1614         for (int i = 0; i < strlen(dest); i++)
1615                 if (dest[i] == '@')
1616                         c++;
1617         if (c>1)
1618                 return 0;
1619         log(DEBUG,"add_ban: %s %s",chan->name,user->nick);
1620
1621         TidyBan(dest);
1622         for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1623         {
1624                 if (!strcasecmp(i->data,dest))
1625                 {
1626                         // dont allow a user to set the same ban twice
1627                         return 0;
1628                 }
1629         }
1630
1631         b.set_time = time(NULL);
1632         strncpy(b.data,dest,MAXBUF);
1633         strncpy(b.set_by,user->nick,NICKMAX);
1634         chan->bans.push_back(b);
1635         return 1;
1636 }
1637
1638 int take_ban(userrec *user,char *dest,chanrec *chan,int status)
1639 {
1640         if ((!user) || (!dest) || (!chan))
1641         {
1642                 return 0;
1643         }
1644
1645         log(DEBUG,"del_ban: %s %s",chan->name,user->nick);
1646         for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1647         {
1648                 if (!strcasecmp(i->data,dest))
1649                 {
1650                         chan->bans.erase(i);
1651                         return 1;
1652                 }
1653         }
1654         return 0;
1655 }
1656
1657 void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt)
1658 {
1659         char modelist[MAXBUF];
1660         char outlist[MAXBUF];
1661         char outstr[MAXBUF];
1662         char outpars[32][MAXBUF];
1663         int param = 2;
1664         int pc = 0;
1665         int ptr = 0;
1666         int mdir = 1;
1667         int r = 0;
1668         bool k_set = false, l_set = false;
1669
1670         if (pcnt < 2)
1671         {
1672                 return;
1673         }
1674
1675         log(DEBUG,"process_modes: start");
1676
1677         strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
1678                                         /* parameters[2] onwards are parameters for
1679                                          * modes that require them :) */
1680         strcpy(outlist,"+");
1681         mdir = 1;
1682
1683         log(DEBUG,"process_modes: modelist: %s",modelist);
1684
1685         for (ptr = 0; ptr < strlen(modelist); ptr++)
1686         {
1687                 r = 0;
1688
1689                 {
1690                         log(DEBUG,"process_modes: modechar: %c",modelist[ptr]);
1691                         char modechar = modelist[ptr];
1692                         switch (modelist[ptr])
1693                         {
1694                                 case '-':
1695                                         if (mdir != 0)
1696                                         {
1697                                                 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1698                                                 {
1699                                                         outlist[strlen(outlist)-1] = '-';
1700                                                 }
1701                                                 else
1702                                                 {
1703                                                         strcat(outlist,"-");
1704                                                 }
1705                                         }
1706                                         mdir = 0;
1707                                         
1708                                 break;                  
1709
1710                                 case '+':
1711                                         if (mdir != 1)
1712                                         {
1713                                                 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1714                                                 {
1715                                                         outlist[strlen(outlist)-1] = '+';
1716                                                 }
1717                                                 else
1718                                                 {
1719                                                         strcat(outlist,"+");
1720                                                 }
1721                                         }
1722                                         mdir = 1;
1723                                 break;
1724
1725                                 case 'o':
1726                                         if ((param >= pcnt)) break;
1727                                         if (mdir == 1)
1728                                         {
1729                                                 r = give_ops(user,parameters[param++],chan,status);
1730                                         }
1731                                         else
1732                                         {
1733                                                 r = take_ops(user,parameters[param++],chan,status);
1734                                         }
1735                                         if (r)
1736                                         {
1737                                                 strcat(outlist,"o");
1738                                                 strcpy(outpars[pc++],parameters[param-1]);
1739                                         }
1740                                 break;
1741                         
1742                                 case 'h':
1743                                         if ((param >= pcnt)) break;
1744                                         if (mdir == 1)
1745                                         {
1746                                                 r = give_hops(user,parameters[param++],chan,status);
1747                                         }
1748                                         else
1749                                         {
1750                                                 r = take_hops(user,parameters[param++],chan,status);
1751                                         }
1752                                         if (r)
1753                                         {
1754                                                 strcat(outlist,"h");
1755                                                 strcpy(outpars[pc++],parameters[param-1]);
1756                                         }
1757                                 break;
1758                         
1759                                 
1760                                 case 'v':
1761                                         if ((param >= pcnt)) break;
1762                                         if (mdir == 1)
1763                                         {
1764                                                 r = give_voice(user,parameters[param++],chan,status);
1765                                         }
1766                                         else
1767                                         {
1768                                                 r = take_voice(user,parameters[param++],chan,status);
1769                                         }
1770                                         if (r)
1771                                         {
1772                                                 strcat(outlist,"v");
1773                                                 strcpy(outpars[pc++],parameters[param-1]);
1774                                         }
1775                                 break;
1776                                 
1777                                 case 'b':
1778                                         if ((param >= pcnt)) break;
1779                                         if (mdir == 1)
1780                                         {
1781                                                 r = add_ban(user,parameters[param++],chan,status);
1782                                         }
1783                                         else
1784                                         {
1785                                                 r = take_ban(user,parameters[param++],chan,status);
1786                                         }
1787                                         if (r)
1788                                         {
1789                                                 strcat(outlist,"b");
1790                                                 strcpy(outpars[pc++],parameters[param-1]);
1791                                         }
1792                                 break;
1793
1794                                 case 'k':
1795                                         if ((param >= pcnt))
1796                                                 break;
1797
1798                                         if (mdir == 1)
1799                                         {
1800                                                 if (k_set)
1801                                                         break;
1802                                                 
1803                                                 if (!strcmp(chan->key,""))
1804                                                 {
1805                                                         strcat(outlist,"k");
1806                                                         strcpy(outpars[pc++],parameters[param++]);
1807                                                         strcpy(chan->key,parameters[param-1]);
1808                                                         k_set = true;
1809                                                 }
1810                                         }
1811                                         else
1812                                         {
1813                                                 /* only allow -k if correct key given */
1814                                                 if (strcmp(chan->key,""))
1815                                                 {
1816                                                         strcat(outlist,"k");
1817                                                         strcpy(chan->key,"");
1818                                                 }
1819                                         }
1820                                 break;
1821                                 
1822                                 case 'l':
1823                                         if (mdir == 0)
1824                                         {
1825                                                 if (chan->limit)
1826                                                 {
1827                                                         strcat(outlist,"l");
1828                                                         chan->limit = 0;
1829                                                 }
1830                                         }
1831                                         
1832                                         if ((param >= pcnt)) break;
1833                                         if (mdir == 1)
1834                                         {
1835                                                 if (l_set)
1836                                                         break;
1837                                                 
1838                                                 bool invalid = false;
1839                                                 for (int i = 0; i < strlen(parameters[param]); i++)
1840                                                 {
1841                                                         if ((parameters[param][i] < '0') || (parameters[param][i] > '9'))
1842                                                         {
1843                                                                 invalid = true;
1844                                                         }
1845                                                 }
1846                                                 if (atoi(parameters[param]) < 1)
1847                                                 {
1848                                                         invalid = true;
1849                                                 }
1850
1851                                                 if (invalid)
1852                                                         break;
1853                                                 
1854                                                 chan->limit = atoi(parameters[param]);
1855                                                 if (chan->limit)
1856                                                 {
1857                                                         strcat(outlist,"l");
1858                                                         strcpy(outpars[pc++],parameters[param++]);
1859                                                         l_set = true;
1860                                                 }
1861                                         }
1862                                 break;
1863                                 
1864                                 case 'i':
1865                                         if (chan->inviteonly != mdir)
1866                                         {
1867                                                 strcat(outlist,"i");
1868                                         }
1869                                         chan->inviteonly = mdir;
1870                                 break;
1871                                 
1872                                 case 't':
1873                                         if (chan->topiclock != mdir)
1874                                         {
1875                                                 strcat(outlist,"t");
1876                                         }
1877                                         chan->topiclock = mdir;
1878                                 break;
1879                                 
1880                                 case 'n':
1881                                         if (chan->noexternal != mdir)
1882                                         {
1883                                                 strcat(outlist,"n");
1884                                         }
1885                                         chan->noexternal = mdir;
1886                                 break;
1887                                 
1888                                 case 'm':
1889                                         if (chan->moderated != mdir)
1890                                         {
1891                                                 strcat(outlist,"m");
1892                                         }
1893                                         chan->moderated = mdir;
1894                                 break;
1895                                 
1896                                 case 's':
1897                                         if (chan->secret != mdir)
1898                                         {
1899                                                 strcat(outlist,"s");
1900                                                 if (chan->c_private)
1901                                                 {
1902                                                         chan->c_private = 0;
1903                                                         if (mdir)
1904                                                         {
1905                                                                 strcat(outlist,"-p+");
1906                                                         }
1907                                                         else
1908                                                         {
1909                                                                 strcat(outlist,"+p-");
1910                                                         }
1911                                                 }
1912                                         }
1913                                         chan->secret = mdir;
1914                                 break;
1915                                 
1916                                 case 'p':
1917                                         if (chan->c_private != mdir)
1918                                         {
1919                                                 strcat(outlist,"p");
1920                                                 if (chan->secret)
1921                                                 {
1922                                                         chan->secret = 0;
1923                                                         if (mdir)
1924                                                         {
1925                                                                 strcat(outlist,"-s+");
1926                                                         }
1927                                                         else
1928                                                         {
1929                                                                 strcat(outlist,"+s-");
1930                                                         }
1931                                                 }
1932                                         }
1933                                         chan->c_private = mdir;
1934                                 break;
1935                                 
1936                                 default:
1937                                         string_list p;
1938                                         p.clear();
1939                                         if (ModeDefined(modelist[ptr],MT_CHANNEL))
1940                                         {
1941                                                 if ((ModeDefinedOn(modelist[ptr],MT_CHANNEL)>0) && (mdir))
1942                                                 {
1943                                                 p.push_back(parameters[param]);
1944                                                 }
1945                                                 if ((ModeDefinedOff(modelist[ptr],MT_CHANNEL)>0) && (!mdir))
1946                                                 {
1947                                                 p.push_back(parameters[param]);
1948                                                 }
1949                                                 for (int i = 0; i <= MODCOUNT; i++)
1950                                                 {
1951                                                         if (modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p))
1952                                                         {
1953                                                                 char app[] = {modechar, 0};
1954                                                                 strcat(outlist, app);
1955                                                                 chan->SetCustomMode(modelist[ptr],mdir);
1956                                                                 // include parameters in output if mode has them
1957                                                                 if ((ModeDefinedOn(modelist[ptr],MT_CHANNEL)>0) || (ModeDefinedOff(modelist[ptr],MT_CHANNEL)>0))
1958                                                                 {
1959                                                                         chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
1960                                                                         strcpy(outpars[pc++],parameters[param++]);
1961                                                                 }
1962                                                 }
1963                                         }
1964                                 }
1965                                 break;
1966                                 
1967                         }
1968                 }
1969         }
1970
1971         /* this ensures only the *valid* modes are sent out onto the network */
1972         while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
1973         {
1974                 outlist[strlen(outlist)-1] = '\0';
1975         }
1976         if (strcmp(outlist,""))
1977         {
1978                 strcpy(outstr,outlist);
1979                 for (ptr = 0; ptr < pc; ptr++)
1980                 {
1981                         strcat(outstr," ");
1982                         strcat(outstr,outpars[ptr]);
1983                 }
1984                 WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
1985         }
1986 }
1987
1988 void handle_mode(char **parameters, int pcnt, userrec *user)
1989 {
1990         chanrec* Ptr;
1991         userrec* dest;
1992         int can_change,i;
1993         int direction = 1;
1994         char outpars[MAXBUF];
1995
1996         dest = Find(parameters[0]);
1997
1998         if ((dest) && (pcnt == 1))
1999         {
2000                 WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes);
2001                 return;
2002         }
2003         if ((dest) && (pcnt > 1))
2004         {
2005                 can_change = 0;
2006                 if (user != dest)
2007                 {
2008                         if (strchr(user->modes,'o'))
2009                         {
2010                                 can_change = 1;
2011                         }
2012                 }
2013                 else
2014                 {
2015                         can_change = 1;
2016                 }
2017                 if (!can_change)
2018                 {
2019                         WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
2020                         return;
2021                 }
2022                 
2023                 strcpy(outpars,"+");
2024                 direction = 1;
2025
2026                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
2027                         return;
2028
2029                 for (i = 0; i < strlen(parameters[1]); i++)
2030                 {
2031                         if (parameters[1][i] == '+')
2032                         {
2033                                 if (direction != 1)
2034                                 {
2035                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
2036                                         {
2037                                                 outpars[strlen(outpars)-1] = '+';
2038                                         }
2039                                         else
2040                                         {
2041                                                 strcat(outpars,"+");
2042                                         }
2043                                 }
2044                                 direction = 1;
2045                         }
2046                         else
2047                         if (parameters[1][i] == '-')
2048                         {
2049                                 if (direction != 0)
2050                                 {
2051                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
2052                                         {
2053                                                 outpars[strlen(outpars)-1] = '-';
2054                                         }
2055                                         else
2056                                         {
2057                                                 strcat(outpars,"-");
2058                                         }
2059                                 }
2060                                 direction = 0;
2061                         }
2062                         else
2063                         {
2064                                 can_change = 0;
2065                                 if (strchr(user->modes,'o'))
2066                                 {
2067                                         can_change = 1;
2068                                 }
2069                                 else
2070                                 {
2071                                         if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's'))
2072                                         {
2073                                                 can_change = 1;
2074                                         }
2075                                 }
2076                                 if (can_change)
2077                                 {
2078                                         if (direction == 1)
2079                                         {
2080                                                 if (!strchr(dest->modes,parameters[1][i]))
2081                                                 {
2082                                                         dest->modes[strlen(dest->modes)+1]='\0';
2083                                                         dest->modes[strlen(dest->modes)] = parameters[1][i];
2084                                                         outpars[strlen(outpars)+1]='\0';
2085                                                         outpars[strlen(outpars)] = parameters[1][i];
2086                                                 }
2087                                         }
2088                                         else
2089                                         {
2090                                                 int q = 0;
2091                                                 char temp[MAXBUF];
2092                                                 char moo[MAXBUF];
2093
2094                                                 outpars[strlen(outpars)+1]='\0';
2095                                                 outpars[strlen(outpars)] = parameters[1][i];
2096                                                 
2097                                                 strcpy(temp,"");
2098                                                 for (q = 0; q < strlen(user->modes); q++)
2099                                                 {
2100                                                         if (user->modes[q] != parameters[1][i])
2101                                                         {
2102                                                                 moo[0] = user->modes[q];
2103                                                                 moo[1] = '\0';
2104                                                                 strcat(temp,moo);
2105                                                         }
2106                                                 }
2107                                                 strcpy(user->modes,temp);
2108                                         }
2109                                 }
2110                         }
2111                 }
2112                 if (strlen(outpars))
2113                 {
2114                         char b[MAXBUF];
2115                         strcpy(b,"");
2116                         int z = 0;
2117                         int i = 0;
2118                         while (i < strlen (outpars))
2119                         {
2120                                 b[z++] = outpars[i++];
2121                                 b[z] = '\0';
2122                                 if (i<strlen(outpars)-1)
2123                                 {
2124                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
2125                                         {
2126                                                 // someones playing silly buggers and trying
2127                                                 // to put a +- or -+ into the line...
2128                                                 i++;
2129                                         }
2130                                 }
2131                                 if (i == strlen(outpars)-1)
2132                                 {
2133                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
2134                                         {
2135                                                 i++;
2136                                         }
2137                                 }
2138                         }
2139
2140                         z = strlen(b)-1;
2141                         if ((b[z] == '-') || (b[z] == '+'))
2142                                 b[z] == '\0';
2143
2144                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
2145                                 return;
2146
2147                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
2148                 }
2149                 return;
2150         }
2151         
2152         Ptr = FindChan(parameters[0]);
2153         if (Ptr)
2154         {
2155                 if (pcnt == 1)
2156                 {
2157                         /* just /modes #channel */
2158                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
2159                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
2160                         return;
2161                 }
2162                 else
2163                 if (pcnt == 2)
2164                 {
2165                         if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b")))
2166                         {
2167
2168                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
2169                                 {
2170                                         WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
2171                                 }
2172                                 WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
2173                         }
2174                 }
2175
2176                 if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
2177                 {
2178                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, Ptr->name);
2179                         return;
2180                 }
2181
2182                 process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt);
2183         }
2184         else
2185         {
2186                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2187         }
2188 }
2189
2190 /* This function pokes and hacks at a parameter list like the following:
2191  *
2192  * PART #winbot, #darkgalaxy :m00!
2193  *
2194  * to turn it into a series of individual calls like this:
2195  *
2196  * PART #winbot :m00!
2197  * PART #darkgalaxy :m00!
2198  *
2199  * The seperate calls are sent to a callback function provided by the caller
2200  * (the caller will usually call itself recursively). The callback function
2201  * must be a command handler. Calling this function on a line with no list causes
2202  * no action to be taken. You must provide a starting and ending parameter number
2203  * where the range of the list can be found, useful if you have a terminating
2204  * parameter as above which is actually not part of the list, or parameters
2205  * before the actual list as well. This code is used by many functions which
2206  * can function as "one to list" (see the RFC) */
2207
2208 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
2209 {
2210         char plist[MAXBUF];
2211         char *param;
2212         char *pars[32];
2213         char blog[32][MAXBUF];
2214         char blog2[32][MAXBUF];
2215         int i = 0, j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
2216         char keystr[MAXBUF];
2217         char moo[MAXBUF];
2218
2219         for (i = 0; i <32; i++)
2220                 strcpy(blog[i],"");
2221
2222         for (i = 0; i <32; i++)
2223                 strcpy(blog2[i],"");
2224
2225         strcpy(moo,"");
2226         for (i = 0; i <10; i++)
2227         {
2228                 if (!parameters[i])
2229                 {
2230                         parameters[i] = moo;
2231                 }
2232         }
2233         if (joins)
2234         {
2235                 if (pcnt > 1) /* we have a key to copy */
2236                 {
2237                         strcpy(keystr,parameters[1]);
2238                 }
2239         }
2240
2241         if (!parameters[start])
2242         {
2243                 return 0;
2244         }
2245         if (!strchr(parameters[start],','))
2246         {
2247                 return 0;
2248         }
2249         strcpy(plist,"");
2250         for (i = start; i <= end; i++)
2251         {
2252                 if (parameters[i])
2253                 {
2254                         strcat(plist,parameters[i]);
2255                 }
2256         }
2257         
2258         j = 0;
2259         param = plist;
2260
2261         t = strlen(plist);
2262         for (i = 0; i < t; i++)
2263         {
2264                 if (plist[i] == ',')
2265                 {
2266                         plist[i] = '\0';
2267                         strcpy(blog[j++],param);
2268                         param = plist+i+1;
2269                 }
2270         }
2271         strcpy(blog[j++],param);
2272         total = j;
2273
2274         if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
2275         {
2276                 strcat(keystr,",");
2277         }
2278         
2279         if ((joins) && (keystr))
2280         {
2281                 if (strchr(keystr,','))
2282                 {
2283                         j = 0;
2284                         param = keystr;
2285                         t2 = strlen(keystr);
2286                         for (i = 0; i < t2; i++)
2287                         {
2288                                 if (keystr[i] == ',')
2289                                 {
2290                                         keystr[i] = '\0';
2291                                         strcpy(blog2[j++],param);
2292                                         param = keystr+i+1;
2293                                 }
2294                         }
2295                         strcpy(blog2[j++],param);
2296                         total2 = j;
2297                 }
2298         }
2299
2300         for (j = 0; j < total; j++)
2301         {
2302                 if (blog[j])
2303                 {
2304                         pars[0] = blog[j];
2305                 }
2306                 for (q = end; q < pcnt-1; q++)
2307                 {
2308                         if (parameters[q+1])
2309                         {
2310                                 pars[q-end+1] = parameters[q+1];
2311                         }
2312                 }
2313                 if ((joins) && (parameters[1]))
2314                 {
2315                         if (pcnt > 1)
2316                         {
2317                                 pars[1] = blog2[j];
2318                         }
2319                         else
2320                         {
2321                                 pars[1] = NULL;
2322                         }
2323                 }
2324                 /* repeatedly call the function with the hacked parameter list */
2325                 if ((joins) && (pcnt > 1))
2326                 {
2327                         if (pars[1])
2328                         {
2329                                 // pars[1] already set up and containing key from blog2[j]
2330                                 fn(pars,2,u);
2331                         }
2332                         else
2333                         {
2334                                 pars[1] = parameters[1];
2335                                 fn(pars,2,u);
2336                         }
2337                 }
2338                 else
2339                 {
2340                         fn(pars,pcnt-(end-start),u);
2341                 }
2342         }
2343
2344         return 1;
2345 }
2346
2347 void handle_join(char **parameters, int pcnt, userrec *user)
2348 {
2349         chanrec* Ptr;
2350         int i = 0;
2351         
2352         if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
2353                 return;
2354         if (parameters[0][0] == '#')
2355         {
2356                 Ptr = add_channel(user,parameters[0],parameters[1]);
2357         }
2358 }
2359
2360
2361 void handle_part(char **parameters, int pcnt, userrec *user)
2362 {
2363         chanrec* Ptr;
2364
2365         if (pcnt > 1)
2366         {
2367                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
2368                         return;
2369                 del_channel(user,parameters[0],parameters[1]);
2370         }
2371         else
2372         {
2373                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
2374                         return;
2375                 del_channel(user,parameters[0],NULL);
2376         }
2377 }
2378
2379 void handle_kick(char **parameters, int pcnt, userrec *user)
2380 {
2381         chanrec* Ptr = FindChan(parameters[0]);
2382         userrec* u   = Find(parameters[1]);
2383
2384         if ((!u) || (!Ptr))
2385         {
2386                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2387                 return;
2388         }
2389         
2390         if (!has_channel(u,Ptr))
2391         {
2392                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
2393                 return;
2394         }
2395         
2396         if (pcnt > 2)
2397         {
2398                 kick_channel(user,u,Ptr,parameters[2]);
2399         }
2400         else
2401         {
2402                 kick_channel(user,u,Ptr,user->nick);
2403         }
2404 }
2405
2406
2407 void handle_die(char **parameters, int pcnt, userrec *user)
2408 {
2409         log(DEBUG,"die: %s",user->nick);
2410         if (!strcmp(parameters[0],diepass))
2411         {
2412                 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
2413                 sleep(DieDelay);
2414                 Exit(ERROR);
2415         }
2416         else
2417         {
2418                 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
2419         }
2420 }
2421
2422 void handle_restart(char **parameters, int pcnt, userrec *user)
2423 {
2424         log(DEBUG,"restart: %s",user->nick);
2425         if (!strcmp(parameters[0],restartpass))
2426         {
2427                 WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host);
2428                 sleep(DieDelay);
2429                 Exit(ERROR);
2430                 /* Will finish this later when i can be arsed :) */
2431         }
2432         else
2433         {
2434                 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
2435         }
2436 }
2437
2438
2439 void kill_link(userrec *user,char* reason)
2440 {
2441         user_hash::iterator iter = clientlist.find(user->nick);
2442
2443         log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
2444         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
2445         fdatasync(user->fd);
2446         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
2447         FOREACH_MOD OnUserQuit(user);
2448         log(DEBUG,"closing fd %d",user->fd);
2449         /* bugfix, cant close() a nonblocking socket (sux!) */
2450         WriteCommonExcept(user,"QUIT :%s",reason);
2451         Blocking(user->fd);
2452         close(user->fd);
2453         NonBlocking(user->fd);
2454         AddWhoWas(user);
2455
2456         if (iter != clientlist.end())
2457         {
2458                 log(DEBUG,"deleting user hash value %p",iter->second);
2459                 delete iter->second;
2460                 clientlist.erase(iter);
2461         }
2462         
2463         purge_empty_chans();
2464 }
2465
2466
2467 void handle_kill(char **parameters, int pcnt, userrec *user)
2468 {
2469         userrec *u = Find(parameters[0]);
2470         char killreason[MAXBUF];
2471         
2472         log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
2473         if (u)
2474         {
2475                 WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
2476                 sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]);
2477                 kill_link(u,killreason);
2478         }
2479         else
2480         {
2481                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2482         }
2483 }
2484
2485 void handle_summon(char **parameters, int pcnt, userrec *user)
2486 {
2487         WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
2488 }
2489
2490 void handle_users(char **parameters, int pcnt, userrec *user)
2491 {
2492         WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
2493 }
2494
2495
2496 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
2497
2498 char* Passwd(userrec *user)
2499 {
2500         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2501         {
2502                 if (match(user->host,i->host) && (i->type == CC_ALLOW))
2503                 {
2504                         return i->pass;
2505                 }
2506         }
2507         return "";
2508 }
2509
2510 bool IsDenied(userrec *user)
2511 {
2512         for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2513         {
2514                 if (match(user->host,i->host) && (i->type == CC_DENY))
2515                 {
2516                         return true;
2517                 }
2518         }
2519         return false;
2520 }
2521
2522
2523 void handle_pass(char **parameters, int pcnt, userrec *user)
2524 {
2525         if (!strcasecmp(parameters[0],Passwd(user)))
2526         {
2527                 user->haspassed = true;
2528         }
2529 }
2530
2531 void handle_invite(char **parameters, int pcnt, userrec *user)
2532 {
2533         userrec* u = Find(parameters[0]);
2534         chanrec* c = FindChan(parameters[1]);
2535
2536         if ((!c) || (!u))
2537         {
2538                 if (!c)
2539                 {
2540                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[1]);
2541                 }
2542                 else
2543                 {
2544                         if (c->inviteonly)
2545                         {
2546                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
2547                         }
2548                 }
2549
2550                 return;
2551         }
2552
2553         if (c->inviteonly)
2554         {
2555                 if (cstatus(user,c) < STATUS_HOP)
2556                 {
2557                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, c->name);
2558                         return;
2559                 }
2560
2561                 u->InviteTo(c->name);
2562                 WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
2563                 WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
2564         }
2565 }
2566
2567 void handle_topic(char **parameters, int pcnt, userrec *user)
2568 {
2569         chanrec* Ptr;
2570
2571         if (pcnt == 1)
2572         {
2573                 if (strlen(parameters[0]) <= CHANMAX)
2574                 {
2575                         Ptr = FindChan(parameters[0]);
2576                         if (Ptr)
2577                         {
2578                                 if (Ptr->topicset)
2579                                 {
2580                                         WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
2581                                         WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
2582                                 }
2583                                 else
2584                                 {
2585                                         WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2586                                 }
2587                         }
2588                         else
2589                         {
2590                                 WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2591                         }
2592                 }
2593         }
2594         else if (pcnt>1)
2595         {
2596                 if (loop_call(handle_topic,parameters,pcnt,user,0,pcnt-2,0))
2597                         return;
2598                 if (strlen(parameters[0]) <= CHANMAX)
2599                 {
2600                         Ptr = FindChan(parameters[0]);
2601                         if (Ptr)
2602                         {
2603                                 if ((Ptr->topiclock) && (cstatus(user,Ptr)<STATUS_HOP))
2604                                 {
2605                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator", user->nick, Ptr->name);
2606                                         return;
2607                                 }
2608                                 strcpy(Ptr->topic,parameters[1]);
2609                                 strcpy(Ptr->setby,user->nick);
2610                                 Ptr->topicset = time(NULL);
2611                                 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
2612                         }
2613                         else
2614                         {
2615                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2616                         }
2617                 }
2618         }
2619 }
2620
2621 /* sends out an error notice to all connected clients (not to be used
2622  * lightly!) */
2623
2624 void send_error(char *s)
2625 {
2626         log(DEBUG,"send_error: %s",s);
2627         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
2628         {
2629                 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
2630         }
2631 }
2632
2633 void Error(int status)
2634 {
2635         signal (SIGALRM, SIG_IGN);
2636         signal (SIGPIPE, SIG_IGN);
2637         signal (SIGTERM, SIG_IGN);
2638         signal (SIGABRT, SIG_IGN);
2639         signal (SIGSEGV, SIG_IGN);
2640         signal (SIGURG, SIG_IGN);
2641         signal (SIGKILL, SIG_IGN);
2642         log(DEBUG,"*** fell down a pothole in the road to perfection ***");
2643         send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
2644         exit(status);
2645 }
2646
2647 int main (int argc, char *argv[])
2648 {
2649         Start();
2650         log(DEBUG,"*** InspIRCd starting up!");
2651         if (!CheckConfig())
2652         {
2653                 log(DEBUG,"main: no config");
2654                 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
2655                 Exit(ERROR);
2656         }
2657         if (InspIRCd() == ERROR)
2658         {
2659                 log(DEBUG,"main: daemon function bailed");
2660                 printf("ERROR: could not initialise. Shutting down.\n");
2661                 Exit(ERROR);
2662         }
2663         Exit(TRUE);
2664         return 0;
2665 }
2666
2667 template<typename T> inline string ConvToStr(const T &in)
2668 {
2669         stringstream tmp;
2670         if (!(tmp << in)) return string();
2671         return tmp.str();
2672 }
2673
2674 /* re-allocates a nick in the user_hash after they change nicknames,
2675  * returns a pointer to the new user as it may have moved */
2676
2677 userrec* ReHashNick(char* Old, char* New)
2678 {
2679         user_hash::iterator newnick;
2680         user_hash::iterator oldnick = clientlist.find(Old);
2681
2682         log(DEBUG,"ReHashNick: %s %s",Old,New);
2683         
2684         if (!strcasecmp(Old,New))
2685         {
2686                 log(DEBUG,"old nick is new nick, skipping");
2687                 return oldnick->second;
2688         }
2689         
2690         if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
2691
2692         log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
2693
2694         clientlist[New] = new userrec();
2695         clientlist[New] = oldnick->second;
2696         /*delete oldnick->second; */
2697         clientlist.erase(oldnick);
2698
2699         log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
2700         
2701         return clientlist[New];
2702 }
2703
2704 /* adds or updates an entry in the whowas list */
2705 void AddWhoWas(userrec* u)
2706 {
2707         user_hash::iterator iter = whowas.find(u->nick);
2708         userrec *a = new userrec();
2709         strcpy(a->nick,u->nick);
2710         strcpy(a->ident,u->ident);
2711         strcpy(a->dhost,u->dhost);
2712         strcpy(a->host,u->host);
2713         strcpy(a->fullname,u->fullname);
2714         strcpy(a->server,u->server);
2715         a->signon = u->signon;
2716
2717         /* MAX_WHOWAS:   max number of /WHOWAS items
2718          * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
2719          *               can be replaced by a newer one
2720          */
2721         
2722         if (iter == whowas.end())
2723         {
2724                 if (whowas.size() == WHOWAS_MAX)
2725                 {
2726                         for (user_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
2727                         {
2728                                 // 3600 seconds in an hour ;)
2729                                 if ((i->second->signon)<(time(NULL)-(WHOWAS_STALE*3600)))
2730                                 {
2731                                         delete i->second;
2732                                         i->second = a;
2733                                         log(DEBUG,"added WHOWAS entry, purged an old record");
2734                                         return;
2735                                 }
2736                         }
2737                 }
2738                 else
2739                 {
2740                         log(DEBUG,"added fresh WHOWAS entry");
2741                         whowas[a->nick] = a;
2742                 }
2743         }
2744         else
2745         {
2746                 log(DEBUG,"updated WHOWAS entry");
2747                 delete iter->second;
2748                 iter->second = a;
2749         }
2750 }
2751
2752
2753 /* add a client connection to the sockets list */
2754 void AddClient(int socket, char* host, int port, bool iscached)
2755 {
2756         int i;
2757         int blocking = 1;
2758         char resolved[MAXBUF];
2759         string tempnick;
2760         char tn2[MAXBUF];
2761         user_hash::iterator iter;
2762
2763         tempnick = ConvToStr(socket) + "-unknown";
2764         sprintf(tn2,"%d-unknown",socket);
2765
2766         iter = clientlist.find(tempnick);
2767
2768         if (iter != clientlist.end()) return;
2769
2770         /*
2771          * It is OK to access the value here this way since we know
2772          * it exists, we just created it above.
2773          *
2774          * At NO other time should you access a value in a map or a
2775          * hash_map this way.
2776          */
2777         clientlist[tempnick] = new userrec();
2778
2779         NonBlocking(socket);
2780         log(DEBUG,"AddClient: %d %s %d",socket,host,port);
2781
2782
2783         clientlist[tempnick]->fd = socket;
2784         strncpy(clientlist[tempnick]->nick, tn2,NICKMAX);
2785         strncpy(clientlist[tempnick]->host, host,160);
2786         strncpy(clientlist[tempnick]->dhost, host,160);
2787         strncpy(clientlist[tempnick]->server, ServerName,256);
2788         clientlist[tempnick]->registered = 0;
2789         clientlist[tempnick]->signon = time(NULL);
2790         clientlist[tempnick]->nping = time(NULL)+240;
2791         clientlist[tempnick]->lastping = 1;
2792         clientlist[tempnick]->port = port;
2793
2794         if (iscached)
2795         {
2796                 WriteServ(socket,"NOTICE Auth :Found your hostname (cached)...");
2797         }
2798         else
2799         {
2800                 WriteServ(socket,"NOTICE Auth :Looking up your hostname...");
2801         }
2802
2803         if (clientlist.size() == MAXCLIENTS)
2804                 kill_link(clientlist[tempnick],"No more connections allowed in this class");
2805 }
2806
2807 void handle_names(char **parameters, int pcnt, userrec *user)
2808 {
2809         chanrec* c;
2810
2811         if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
2812                 return;
2813         c = FindChan(parameters[0]);
2814         if (c)
2815         {
2816                 /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
2817                 userlist(user,c);
2818                 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
2819         }
2820         else
2821         {
2822                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2823         }
2824 }
2825
2826
2827 void handle_privmsg(char **parameters, int pcnt, userrec *user)
2828 {
2829         userrec *dest;
2830         chanrec *chan;
2831         
2832         if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
2833                 return;
2834         if (parameters[0][0] == '#')
2835         {
2836                 chan = FindChan(parameters[0]);
2837                 if (chan)
2838                 {
2839                         if ((chan->noexternal) && (!has_channel(user,chan)))
2840                         {
2841                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2842                                 return;
2843                         }
2844                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2845                         {
2846                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2847                                 return;
2848                         }
2849                         ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
2850                 }
2851                 else
2852                 {
2853                         /* no such nick/channel */
2854                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2855                 }
2856                 return;
2857         }
2858         
2859         dest = Find(parameters[0]);
2860         if (dest)
2861         {
2862                 if (strcmp(dest->awaymsg,""))
2863                 {
2864                         /* auto respond with aweh msg */
2865                         WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
2866                 }
2867                 WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
2868         }
2869         else
2870         {
2871                 /* no such nick/channel */
2872                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2873         }
2874 }
2875
2876 void handle_notice(char **parameters, int pcnt, userrec *user)
2877 {
2878         userrec *dest;
2879         chanrec *chan;
2880
2881         if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
2882                 return;
2883         if (parameters[0][0] == '#')
2884         {
2885                 chan = FindChan(parameters[0]);
2886                 if (chan)
2887                 {
2888                         if ((chan->noexternal) && (!has_channel(user,chan)))
2889                         {
2890                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2891                                 return;
2892                         }
2893                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2894                         {
2895                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2896                                 return;
2897                         }
2898                         WriteChannel(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
2899                 }
2900                 else
2901                 {
2902                         /* no such nick/channel */
2903                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2904                 }
2905                 return;
2906         }
2907         
2908         dest = Find(parameters[0]);
2909         if (dest)
2910         {
2911                 WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
2912         }
2913         else
2914         {
2915                 /* no such nick/channel */
2916                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2917         }
2918 }
2919
2920 char lst[MAXBUF];
2921
2922 char* chlist(userrec *user)
2923 {
2924         int i = 0;
2925         char cmp[MAXBUF];
2926
2927         log(DEBUG,"chlist: %s",user->nick);
2928         strcpy(lst,"");
2929         if (!user)
2930         {
2931                 return lst;
2932         }
2933         for (i = 0; i != MAXCHANS; i++)
2934         {
2935                 if (user->chans[i].channel != NULL)
2936                 {
2937                         if (user->chans[i].channel->name)
2938                         {
2939                                 strcpy(cmp,user->chans[i].channel->name);
2940                                 strcat(cmp," ");
2941                                 if (!strstr(lst,cmp))
2942                                 {
2943                                         if ((!user->chans[i].channel->c_private) && (!user->chans[i].channel->secret))
2944                                         {
2945                                                 strcat(lst,cmode(user,user->chans[i].channel));
2946                                                 strcat(lst,user->chans[i].channel->name);
2947                                                 strcat(lst," ");
2948                                         }
2949                                 }
2950                         }
2951                 }
2952         }
2953         return lst;
2954 }
2955
2956 void handle_info(char **parameters, int pcnt, userrec *user)
2957 {
2958         WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick);
2959         WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick);
2960         WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick);
2961         WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
2962 }
2963
2964 void handle_time(char **parameters, int pcnt, userrec *user)
2965 {
2966         time_t rawtime;
2967         struct tm * timeinfo;
2968
2969         time ( &rawtime );
2970         timeinfo = localtime ( &rawtime );
2971         WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
2972   
2973 }
2974
2975 void handle_whois(char **parameters, int pcnt, userrec *user)
2976 {
2977         userrec *dest;
2978         char *t;
2979
2980         if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
2981                 return;
2982         dest = Find(parameters[0]);
2983         if (dest)
2984         {
2985                 WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
2986                 if ((user == dest) || (strchr(user->modes,'o')))
2987                 {
2988                         WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host);
2989                 }
2990                 if (strcmp(chlist(dest),""))
2991                 {
2992                         WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest));
2993                 }
2994                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, ServerDesc);
2995                 if (strcmp(dest->awaymsg,""))
2996                 {
2997                         WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
2998                 }
2999                 if (strchr(dest->modes,'o'))
3000                 {
3001                         WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick);
3002                 }
3003                 //WriteServ(user->fd,"310 %s %s :is available for help.",user->nick, dest->nick);
3004                 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon);
3005                 
3006                 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
3007         }
3008         else
3009         {
3010                 /* no such nick/channel */
3011                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
3012         }
3013 }
3014
3015 void handle_quit(char **parameters, int pcnt, userrec *user)
3016 {
3017         user_hash::iterator iter = clientlist.find(user->nick);
3018
3019         /* theres more to do here, but for now just close the socket */
3020         if (pcnt == 1)
3021         {
3022                 if (parameters[0][0] == ':')
3023                 {
3024                         *parameters[0]++;
3025                 }
3026                 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]);
3027                 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]);
3028                 WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
3029         }
3030         else
3031         {
3032                 Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
3033                 WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
3034                 WriteCommonExcept(user,"QUIT :Client exited");
3035         }
3036
3037         FOREACH_MOD OnUserQuit(user);
3038
3039         /* confucious say, he who close nonblocking socket, get nothing! */
3040         Blocking(user->fd);
3041         close(user->fd);
3042         NonBlocking(user->fd);
3043         AddWhoWas(user);
3044
3045         if (iter != clientlist.end())
3046         {
3047                 log(DEBUG,"deleting user hash value");
3048                 delete iter->second;
3049                 clientlist.erase(iter);
3050         }
3051         
3052         purge_empty_chans();
3053 }
3054
3055 void handle_who(char **parameters, int pcnt, userrec *user)
3056 {
3057         chanrec* Ptr = NULL;
3058         
3059         /* theres more to do here, but for now just close the socket */
3060         if (pcnt == 1)
3061         {
3062                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
3063                 {
3064                         if (user->chans[0].channel)
3065                         {
3066                                 Ptr = user->chans[0].channel;
3067                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3068                                 {
3069                                         if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
3070                                         {
3071                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname);
3072                                         }
3073                                 }
3074                         }
3075                         if (Ptr)
3076                         {
3077                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3078                         }
3079                         else
3080                         {
3081                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
3082                         }
3083                         return;
3084                 }
3085                 if (parameters[0][0] = '#')
3086                 {
3087                         Ptr = FindChan(parameters[0]);
3088                         if (Ptr)
3089                         {
3090                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3091                                 {
3092                                         if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
3093                                         {
3094                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname);
3095                                         }
3096                                 }
3097                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3098                         }
3099                         else
3100                         {
3101                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
3102                         }
3103                 }
3104         }
3105         if (pcnt == 2)
3106         {
3107                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
3108                 {
3109                         Ptr = user->chans[0].channel;
3110                         printf(user->chans[0].channel->name);
3111                         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3112                         {
3113                                 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
3114                                 {
3115                                         if (strchr(i->second->modes,'o'))
3116                                         {
3117                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname);
3118                                         }
3119                                 }
3120                         }
3121                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3122                         return;
3123                 }
3124         }
3125 }
3126
3127 void handle_wallops(char **parameters, int pcnt, userrec *user)
3128 {
3129         WriteWallOps(user,"%s",parameters[0]);
3130 }
3131
3132 void handle_list(char **parameters, int pcnt, userrec *user)
3133 {
3134         chanrec* Ptr;
3135         
3136         WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
3137         for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
3138         {
3139                 if ((!i->second->c_private) && (!i->second->secret))
3140                 {
3141                         WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
3142                 }
3143         }
3144         WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
3145 }
3146
3147
3148 void handle_rehash(char **parameters, int pcnt, userrec *user)
3149 {
3150         WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CONFIG_FILE);
3151         ReadConfig();
3152         FOREACH_MOD OnRehash();
3153         WriteOpers("%s is rehashing config file %s",user->nick,CONFIG_FILE);
3154 }
3155
3156
3157 int usercnt(void)
3158 {
3159         return clientlist.size();
3160 }
3161
3162 int usercount_invisible(void)
3163 {
3164         int c = 0;
3165
3166         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3167         {
3168                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
3169         }
3170         return c;
3171 }
3172
3173 int usercount_opers(void)
3174 {
3175         int c = 0;
3176
3177         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3178         {
3179                 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
3180         }
3181         return c;
3182 }
3183
3184 int usercount_unknown(void)
3185 {
3186         int c = 0;
3187
3188         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3189         {
3190                 if ((i->second->fd) && (i->second->registered != 7))
3191                         c++;
3192         }
3193         return c;
3194 }
3195
3196 int chancount(void)
3197 {
3198         return chanlist.size();
3199 }
3200
3201 int servercount(void)
3202 {
3203         return 1;
3204 }
3205
3206 void handle_lusers(char **parameters, int pcnt, userrec *user)
3207 {
3208         WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
3209         WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
3210         WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
3211         WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
3212         WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,usercnt());
3213 }
3214
3215 void handle_admin(char **parameters, int pcnt, userrec *user)
3216 {
3217         WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
3218         WriteServ(user->fd,"257 %s :Name     - %s",user->nick,AdminName);
3219         WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
3220         WriteServ(user->fd,"258 %s :E-Mail   - %s",user->nick,AdminEmail);
3221 }
3222
3223 void ShowMOTD(userrec *user)
3224 {
3225         if (!MOTD.size())
3226         {
3227                 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
3228                 return;
3229         }
3230         WriteServ(user->fd,"375 %s :- %s message of the day",user->nick,ServerName);
3231         for (int i = 0; i != MOTD.size(); i++)
3232         {
3233                                 WriteServ(user->fd,"372 %s :- %s",user->nick,MOTD[i].c_str());
3234         }
3235         WriteServ(user->fd,"376 %s :End of %s message of the day.",user->nick,ServerName);
3236 }
3237
3238 void ShowRULES(userrec *user)
3239 {
3240         if (!RULES.size())
3241         {
3242                 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
3243                 return;
3244         }
3245         WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
3246         for (int i = 0; i != RULES.size(); i++)
3247         {
3248                                 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
3249         }
3250         WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
3251 }
3252
3253 /* shows the message of the day, and any other on-logon stuff */
3254 void ConnectUser(userrec *user)
3255 {
3256         user->registered = 7;
3257         user->idle_lastmsg = time(NULL);
3258         log(DEBUG,"ConnectUser: %s",user->nick);
3259
3260         if (strcmp(Passwd(user),"") && (!user->haspassed))
3261         {
3262                 Write(user->fd,"ERROR :Closing link: Invalid password");
3263                 fdatasync(user->fd);
3264                 kill_link(user,"Invalid password");
3265                 return;
3266         }
3267         if (IsDenied(user))
3268         {
3269                 Write(user->fd,"ERROR :Closing link: Unauthorized connection");
3270                 fdatasync(user->fd);
3271                 kill_link(user,"Unauthorised connection");
3272         }
3273
3274         WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
3275         WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
3276         WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
3277         WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
3278         WriteServ(user->fd,"004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
3279         WriteServ(user->fd,"005 %s :MAP KNOCK SAFELIST HCN MAXCHANNELS=20 MAXBANS=60 NICKLEN=30 TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 :are supported by this server",user->nick);
3280         WriteServ(user->fd,"005 %s :WALLCHOPS WATCH=128 SILENCE=5 MODES=13 CHANTYPES=# PREFIX=(ohv)@%c+ CHANMODES=ohvbeqa,kfL,l,psmntirRcOAQKVHGCuzN NETWORK=%s :are supported by this server",user->nick,'%',Network);
3281         ShowMOTD(user);
3282         FOREACH_MOD OnUserConnect(user);
3283         WriteOpers("*** Client connecting on port %d: %s!%s@%s",user->port,user->nick,user->ident,user->host);
3284 }
3285
3286 void handle_version(char **parameters, int pcnt, userrec *user)
3287 {
3288         WriteServ(user->fd,"351 %s :%s %s :%s",user->nick,VERSION,ServerName,SYSTEM);
3289 }
3290
3291 void handle_ping(char **parameters, int pcnt, userrec *user)
3292 {
3293         WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
3294 }
3295
3296 void handle_pong(char **parameters, int pcnt, userrec *user)
3297 {
3298         // set the user as alive so they survive to next ping
3299         user->lastping = 1;
3300 }
3301
3302 void handle_motd(char **parameters, int pcnt, userrec *user)
3303 {
3304         ShowMOTD(user);
3305 }
3306
3307 void handle_rules(char **parameters, int pcnt, userrec *user)
3308 {
3309         ShowRULES(user);
3310 }
3311
3312 void handle_user(char **parameters, int pcnt, userrec *user)
3313 {
3314         if (user->registered < 3)
3315         {
3316                 if (isident(parameters[0]) == 0) {
3317                         // This kinda Sucks, According to the RFC thou, its either this,
3318                         // or "You have already registered" :p -- Craig
3319                         WriteServ(user->fd,"461 %s USER :Not enough parameters",user->nick);
3320                 }
3321                 else {
3322                         WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~");
3323                         strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */
3324                         strncat(user->ident,parameters[0],IDENTMAX);
3325                         strncpy(user->fullname,parameters[3],128);
3326                         user->registered = (user->registered | 1);
3327                 }
3328         }
3329         else
3330         {
3331                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
3332                 return;
3333         }
3334         /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
3335         if (user->registered == 3)
3336         {
3337                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3338                 ConnectUser(user);
3339         }
3340 }
3341
3342 void handle_userhost(char **parameters, int pcnt, userrec *user)
3343 {
3344         char Return[MAXBUF],junk[MAXBUF];
3345         sprintf(Return,"302 %s :",user->nick);
3346         for (int i = 0; i < pcnt; i++)
3347         {
3348                 userrec *u = Find(parameters[i]);
3349                 if (u)
3350                 {
3351                         if (strchr(u->modes,'o'))
3352                         {
3353                                 sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host);
3354                                 strcat(Return,junk);
3355                         }
3356                         else
3357                         {
3358                                 sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host);
3359                                 strcat(Return,junk);
3360                         }
3361                 }
3362         }
3363         WriteServ(user->fd,Return);
3364 }
3365
3366
3367 void handle_ison(char **parameters, int pcnt, userrec *user)
3368 {
3369         char Return[MAXBUF];
3370         sprintf(Return,"303 %s :",user->nick);
3371         for (int i = 0; i < pcnt; i++)
3372         {
3373                 userrec *u = Find(parameters[i]);
3374                 if (u)
3375                 {
3376                         strcat(Return,u->nick);
3377                         strcat(Return," ");
3378                 }
3379         }
3380         WriteServ(user->fd,Return);
3381 }
3382
3383
3384 void handle_away(char **parameters, int pcnt, userrec *user)
3385 {
3386         if (pcnt)
3387         {
3388                 strcpy(user->awaymsg,parameters[0]);
3389                 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
3390         }
3391         else
3392         {
3393                 strcpy(user->awaymsg,"");
3394                 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
3395         }
3396 }
3397
3398 void handle_whowas(char **parameters, int pcnt, userrec* user)
3399 {
3400         user_hash::iterator i = whowas.find(parameters[0]);
3401
3402         if (i == whowas.end())
3403         {
3404                 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
3405                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3406         }
3407         else
3408         {
3409                 time_t rawtime = i->second->signon;
3410                 tm *timeinfo;
3411                 char b[MAXBUF];
3412                 
3413                 timeinfo = localtime(&rawtime);
3414                 strcpy(b,asctime(timeinfo));
3415                 b[strlen(b)-1] = '\0';
3416                 
3417                 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
3418                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
3419                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3420         }
3421
3422 }
3423
3424 void handle_trace(char **parameters, int pcnt, userrec *user)
3425 {
3426         for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3427         {
3428                 if (i->second)
3429                 {
3430                         if (isnick(i->second->nick))
3431                         {
3432                                 if (strchr(i->second->modes,'o'))
3433                                 {
3434                                         WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
3435                                 }
3436                                 else
3437                                 {
3438                                         WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
3439                                 }
3440                         }
3441                         else
3442                         {
3443                                 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
3444                         }
3445                 }
3446         }
3447 }
3448
3449 void handle_stats(char **parameters, int pcnt, userrec *user)
3450 {
3451         if (pcnt != 1)
3452         {
3453                 return;
3454         }
3455         if (strlen(parameters[0])>1)
3456         {
3457                 /* make the stats query 1 character long */
3458                 parameters[0][1] = '\0';
3459         }
3460
3461         /* stats m (list number of times each command has been used, plus bytecount) */
3462         if (!strcasecmp(parameters[0],"m"))
3463         {
3464                 for (int i = 0; i < cmdlist.size(); i++)
3465                 {
3466                         if (cmdlist[i].handler_function)
3467                         {
3468                                 if (cmdlist[i].use_count)
3469                                 {
3470                                         /* RPL_STATSCOMMANDS */
3471                                         WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
3472                                 }
3473                         }
3474                 }
3475                         
3476         }
3477
3478         /* stats z (debug and memory info) */
3479         if (!strcasecmp(parameters[0],"z"))
3480         {
3481                 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
3482                 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
3483                 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
3484                 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
3485                 WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
3486                 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
3487                 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
3488                 WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount);
3489         }
3490         
3491         /* stats o */
3492         if (!strcasecmp(parameters[0],"o"))
3493         {
3494                 for (int i = 0; i < ConfValueEnum("oper"); i++)
3495                 {
3496                         char LoginName[MAXBUF];
3497                         char HostName[MAXBUF];
3498                         char OperType[MAXBUF];
3499                         ConfValue("oper","name",i,LoginName);
3500                         ConfValue("oper","host",i,HostName);
3501                         ConfValue("oper","type",i,OperType);
3502                         WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
3503                 }
3504         }
3505         
3506         /* stats l (show user I/O stats) */
3507         if (!strcasecmp(parameters[0],"l"))
3508         {
3509                 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
3510                 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3511                 {
3512                         if (isnick(i->second->nick))
3513                         {
3514                                 WriteServ(user->fd,"211 %s :%s:%d %s %d %d %d %d",user->nick,ServerName,i->second->port,i->second->nick,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
3515                         }
3516                         else
3517                         {
3518                                 WriteServ(user->fd,"211 %s :%s:%d (unknown@%d) %d %d %d %d",user->nick,ServerName,i->second->port,i->second->fd,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
3519                         }
3520                         
3521                 }
3522         }
3523         
3524         /* stats u (show server uptime) */
3525         if (!strcasecmp(parameters[0],"u"))
3526         {
3527                 time_t current_time = 0;
3528                 current_time = time(NULL);
3529                 time_t server_uptime = current_time - startup_time;
3530                 struct tm* stime;
3531                 stime = gmtime(&server_uptime);
3532                 /* i dont know who the hell would have an ircd running for over a year nonstop, but
3533                  * Craig suggested this, and it seemed a good idea so in it went */
3534                 if (stime->tm_year > 70)
3535                 {
3536                         WriteServ(user->fd,"242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
3537                 }
3538                 else
3539                 {
3540                         WriteServ(user->fd,"242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
3541                 }
3542         }
3543
3544         WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
3545         WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
3546         
3547 }
3548
3549 void handle_connect(char **parameters, int pcnt, userrec *user)
3550 {
3551         WriteServ(user->fd,"NOTICE %s :*** Connecting to %s port %s...",user->nick,parameters[0],parameters[1]);
3552         if (!me[defaultRoute]->BeginLink(parameters[0],atoi(parameters[1]),"password"))
3553         {
3554                 WriteServ(user->fd,"NOTICE %s :*** Failed to send auth packet to %s!",user->nick,parameters[0]);
3555         }
3556 }
3557
3558 void handle_squit(char **parameters, int pcnt, userrec *user)
3559 {
3560 }
3561
3562 void handle_oper(char **parameters, int pcnt, userrec *user)
3563 {
3564         char LoginName[MAXBUF];
3565         char Password[MAXBUF];
3566         char OperType[MAXBUF];
3567         char TypeName[MAXBUF];
3568         char Hostname[MAXBUF];
3569         int i,j;
3570
3571         for (i = 0; i < ConfValueEnum("oper"); i++)
3572         {
3573                 ConfValue("oper","name",i,LoginName);
3574                 ConfValue("oper","password",i,Password);
3575                 if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1])))
3576                 {
3577                         /* correct oper credentials */
3578                         ConfValue("oper","type",i,OperType);
3579                         WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
3580                         WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
3581                         WriteServ(user->fd,"MODE %s :+o",user->nick);
3582                         for (j =0; j < ConfValueEnum("type"); j++)
3583                         {
3584                                 ConfValue("type","name",j,TypeName);
3585                                 if (!strcmp(TypeName,OperType))
3586                                 {
3587                                         /* found this oper's opertype */
3588                                         ConfValue("type","host",j,Hostname);
3589                                         strncpy(user->dhost,Hostname,256);
3590                                 }
3591                         }
3592                         if (!strchr(user->modes,'o'))
3593                         {
3594                                 strcat(user->modes,"o");
3595                         }
3596                         return;
3597                 }
3598         }
3599         /* no such oper */
3600         WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
3601         WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
3602 }
3603                                 
3604 void handle_nick(char **parameters, int pcnt, userrec *user)
3605 {
3606         if (pcnt < 1) 
3607         {
3608                 log(DEBUG,"not enough params for handle_nick");
3609                 return;
3610         }
3611         if (!parameters[0])
3612         {
3613                 log(DEBUG,"invalid parameter passed to handle_nick");
3614                 return;
3615         }
3616         if (!strlen(parameters[0]))
3617         {
3618                 log(DEBUG,"zero length new nick passed to handle_nick");
3619                 return;
3620         }
3621         if (!user)
3622         {
3623                 log(DEBUG,"invalid user passed to handle_nick");
3624                 return;
3625         }
3626         if (!user->nick)
3627         {
3628                 log(DEBUG,"invalid old nick passed to handle_nick");
3629                 return;
3630         }
3631         if (!strcasecmp(user->nick,parameters[0]))
3632         {
3633                 log(DEBUG,"old nick is new nick, skipping");
3634                 return;
3635         }
3636         else
3637         {
3638                 if (strlen(parameters[0]) > 1)
3639                 {
3640                         if (parameters[0][0] == ':')
3641                         {
3642                                 *parameters[0]++;
3643                         }
3644                 }
3645                 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
3646                 {
3647                         WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
3648                         return;
3649                 }
3650         }
3651         if (isnick(parameters[0]) == 0)
3652         {
3653                 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
3654                 return;
3655         }
3656
3657         if (user->registered == 7)
3658         {
3659                 WriteCommon(user,"NICK %s",parameters[0]);
3660         }
3661         
3662         /* change the nick of the user in the users_hash */
3663         user = ReHashNick(user->nick, parameters[0]);
3664         /* actually change the nick within the record */
3665         if (!user) return;
3666         if (!user->nick) return;
3667
3668         strncpy(user->nick, parameters[0],NICKMAX);
3669
3670         log(DEBUG,"new nick set: %s",user->nick);
3671         
3672         if (user->registered < 3)
3673                 user->registered = (user->registered | 2);
3674         if (user->registered == 3)
3675         {
3676                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3677                 ConnectUser(user);
3678         }
3679         log(DEBUG,"exit nickchange: %s",user->nick);
3680 }
3681
3682 int process_parameters(char **command_p,char *parameters)
3683 {
3684         int i = 0;
3685         int j = 0;
3686         int q = 0;
3687         q = strlen(parameters);
3688         if (!q)
3689         {
3690                 /* no parameters, command_p invalid! */
3691                 return 0;
3692         }
3693         if (parameters[0] == ':')
3694         {
3695                 command_p[0] = parameters+1;
3696                 return 1;
3697         }
3698         if (q)
3699         {
3700                 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
3701                 {
3702                         /* only one parameter */
3703                         command_p[0] = parameters;
3704                         if (parameters[0] == ':')
3705                         {
3706                                 if (strchr(parameters,' ') != NULL)
3707                                 {
3708                                         command_p[0]++;
3709                                 }
3710                         }
3711                         return 1;
3712                 }
3713         }
3714         command_p[j++] = parameters;
3715         for (i = 0; i <= q; i++)
3716         {
3717                 if (parameters[i] == ' ')
3718                 {
3719                         command_p[j++] = parameters+i+1;
3720                         parameters[i] = '\0';
3721                         if (command_p[j-1][0] == ':')
3722                         {
3723                                 *command_p[j-1]++; /* remove dodgy ":" */
3724                                 break;
3725                                 /* parameter like this marks end of the sequence */
3726                         }
3727                 }
3728         }
3729         return j; /* returns total number of items in the list */
3730 }
3731
3732 void process_command(userrec *user, char* cmd)
3733 {
3734         char *parameters;
3735         char *command;
3736         char *command_p[127];
3737         char p[MAXBUF], temp[MAXBUF];
3738         int i, j, items, cmd_found;
3739
3740         for (int i = 0; i < 127; i++)
3741                 command_p[i] = NULL;
3742
3743         if (!user)
3744         {
3745                 return;
3746         }
3747         if (!cmd)
3748         {
3749                 return;
3750         }
3751         if (!strcmp(cmd,""))
3752         {
3753                 return;
3754         }
3755         strcpy(temp,cmd);
3756
3757         string tmp = cmd;
3758         FOREACH_MOD OnServerRaw(tmp,true);
3759         const char* cmd2 = tmp.c_str();
3760         snprintf(cmd,512,"%s",cmd2);
3761
3762         if (!strchr(cmd,' '))
3763         {
3764                 /* no parameters, lets skip the formalities and not chop up
3765                  * the string */
3766                 items = 0;
3767                 command_p[0] = NULL;
3768                 parameters = NULL;
3769                 for (int i = 0; i <= strlen(cmd); i++)
3770                 {
3771                         cmd[i] = toupper(cmd[i]);
3772                 }
3773         }
3774         else
3775         {
3776                 strcpy(cmd,"");
3777                 j = 0;
3778                 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
3779                 for (i = 0; i < strlen(temp); i++)
3780                 {
3781                         if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
3782                         {
3783                                 cmd[j++] = temp[i];
3784                                 cmd[j] = 0;
3785                         }
3786                 }
3787                 /* split the full string into a command plus parameters */
3788                 parameters = p;
3789                 strcpy(p," ");
3790                 command = cmd;
3791                 if (strchr(cmd,' '))
3792                 {
3793                         for (i = 0; i <= strlen(cmd); i++)
3794                         {
3795                                 /* capitalise the command ONLY, leave params intact */
3796                                 cmd[i] = toupper(cmd[i]);
3797                                 /* are we nearly there yet?! :P */
3798                                 if (cmd[i] == ' ')
3799                                 {
3800                                         command = cmd;
3801                                         parameters = cmd+i+1;
3802                                         cmd[i] = '\0';
3803                                         break;
3804                                 }
3805                         }
3806                 }
3807                 else
3808                 {
3809                         for (i = 0; i <= strlen(cmd); i++)
3810                         {
3811                                 cmd[i] = toupper(cmd[i]);
3812                         }
3813                 }
3814
3815         }
3816         
3817         cmd_found = 0;
3818
3819         for (i = 0; i != cmdlist.size(); i++)
3820         {
3821                 if (strcmp(cmdlist[i].command,""))
3822                 {
3823                         if (!strcmp(command, cmdlist[i].command))
3824                         {
3825                                 if (parameters)
3826                                 {
3827                                         if (strcmp(parameters,""))
3828                                         {
3829                                                 items = process_parameters(command_p,parameters);
3830                                         }
3831                                         else
3832                                         {
3833                                                 items = 0;
3834                                                 command_p[0] = NULL;
3835                                         }
3836                                 }
3837                                 else
3838                                 {
3839                                         items = 0;
3840                                         command_p[0] = NULL;
3841                                 }
3842                                 
3843                                 if (user)
3844                                 {
3845                                         user->idle_lastmsg = time(NULL);
3846                                         /* activity resets the ping pending timer */
3847                                         user->nping = time(NULL) + 120;
3848                                         if ((items) < cmdlist[i].min_params)
3849                                         {
3850                                                 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
3851                                                 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
3852                                                 return;
3853                                         }
3854                                         if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
3855                                         {
3856                                                 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
3857                                                 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
3858                                                 cmd_found = 1;
3859                                                 return;
3860                                         }
3861                 /* if the command isnt USER, PASS, or NICK, and nick is empty,
3862                  * deny command! */
3863                                         if ((strcmp(command,"USER")) && (strcmp(command,"NICK")) && (strcmp(command,"PASS")))
3864                                         {
3865                                                 if ((!isnick(user->nick)) || (user->registered != 7))
3866                                                 {
3867                                                         log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3868                                                         WriteServ(user->fd,"451 %s :You have not registered",command);
3869                                                         return;
3870                                                 }
3871                                         }
3872                                         if ((user->registered == 7) || (!strcmp(command,"USER")) || (!strcmp(command,"NICK")) || (!strcmp(command,"PASS")))
3873                                         {
3874                                                 log(DEBUG,"process_command: handler: %s %s %d",user->nick,command,items);
3875                                                 if (cmdlist[i].handler_function)
3876                                                 {
3877                                                         /* ikky /stats counters */
3878                                                         if (temp)
3879                                                         {
3880                                                                 if (user)
3881                                                                 {
3882                                                                         user->bytes_in += strlen(temp);
3883                                                                         user->cmds_in++;
3884                                                                 }
3885                                                                 cmdlist[i].use_count++;
3886                                                                 cmdlist[i].total_bytes+=strlen(temp);
3887                                                         }
3888
3889                                                         /* WARNING: nothing may come after the
3890                                                          * command handler call, as the handler
3891                                                          * may free the user structure! */
3892
3893                                                         cmdlist[i].handler_function(command_p,items,user);
3894                                                 }
3895                                                 return;
3896                                         }
3897                                         else
3898                                         {
3899                                                 log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3900                                                 WriteServ(user->fd,"451 %s :You have not registered",command);
3901                                                 return;
3902                                         }
3903                                 }
3904                                 cmd_found = 1;
3905                         }
3906                 }
3907         }
3908         if ((!cmd_found) && (user))
3909         {
3910                 log(DEBUG,"process_command: not in table: %s %s",user->nick,command);
3911                 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
3912         }
3913 }
3914
3915
3916 void createcommand(char* cmd, handlerfunc f, char flags, int minparams)
3917 {
3918         command_t comm;
3919         /* create the command and push it onto the table */     
3920         strcpy(comm.command,cmd);
3921         comm.handler_function = f;
3922         comm.flags_needed = flags;
3923         comm.min_params = minparams;
3924         comm.use_count = 0;
3925         comm.total_bytes = 0;
3926         cmdlist.push_back(comm);
3927 }
3928
3929 void SetupCommandTable(void)
3930 {
3931   createcommand("USER",handle_user,0,4);
3932   createcommand("NICK",handle_nick,0,1);
3933   createcommand("QUIT",handle_quit,0,0);
3934   createcommand("VERSION",handle_version,0,0);
3935   createcommand("PING",handle_ping,0,1);
3936   createcommand("PONG",handle_pong,0,1);
3937   createcommand("ADMIN",handle_admin,0,0);
3938   createcommand("PRIVMSG",handle_privmsg,0,2);
3939   createcommand("INFO",handle_info,0,0);
3940   createcommand("TIME",handle_time,0,0);
3941   createcommand("WHOIS",handle_whois,0,1);
3942   createcommand("WALLOPS",handle_wallops,'o',1);
3943   createcommand("NOTICE",handle_notice,0,2);
3944   createcommand("JOIN",handle_join,0,1);
3945   createcommand("NAMES",handle_names,0,1);
3946   createcommand("PART",handle_part,0,1);
3947   createcommand("KICK",handle_kick,0,2);
3948   createcommand("MODE",handle_mode,0,1);
3949   createcommand("TOPIC",handle_topic,0,1);
3950   createcommand("WHO",handle_who,0,1);
3951   createcommand("MOTD",handle_motd,0,0);
3952   createcommand("RULES",handle_join,0,0);
3953   createcommand("OPER",handle_oper,0,2);
3954   createcommand("LIST",handle_list,0,0);
3955   createcommand("DIE",handle_die,'o',1);
3956   createcommand("RESTART",handle_restart,'o',1);
3957   createcommand("KILL",handle_kill,'o',2);
3958   createcommand("REHASH",handle_rehash,'o',0);
3959   createcommand("LUSERS",handle_lusers,0,0);
3960   createcommand("STATS",handle_stats,0,1);
3961   createcommand("USERHOST",handle_userhost,0,1);
3962   createcommand("AWAY",handle_away,0,0);
3963   createcommand("ISON",handle_ison,0,0);
3964   createcommand("SUMMON",handle_summon,0,0);
3965   createcommand("USERS",handle_users,0,0);
3966   createcommand("INVITE",handle_invite,0,2);
3967   createcommand("PASS",handle_pass,0,1);
3968   createcommand("TRACE",handle_trace,'o',0);
3969   createcommand("WHOWAS",handle_whowas,0,1);
3970   createcommand("CONNECT",handle_connect,'o',2);
3971   createcommand("SQUIT",handle_squit,'o',1);
3972 }
3973
3974 void process_buffer(userrec *user)
3975 {
3976         char cmd[MAXBUF];
3977         int i;
3978         if (!user->inbuf)
3979         {
3980                 return;
3981         }
3982         if (!strcmp(user->inbuf,""))
3983         {
3984                 return;
3985         }
3986         strncpy(cmd,user->inbuf,MAXBUF);
3987         if (!strcmp(cmd,""))
3988         {
3989                 return;
3990         }
3991         if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
3992         {
3993                 cmd[strlen(cmd)-1] = '\0';
3994         }
3995         if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
3996         {
3997                 cmd[strlen(cmd)-1] = '\0';
3998         }
3999         strcpy(user->inbuf,"");
4000         if (!strcmp(cmd,""))
4001         {
4002                 return;
4003         }
4004         log(DEBUG,"InspIRCd: processing: %s %s",user->nick,cmd);
4005         process_command(user,cmd);
4006 }
4007
4008 void handle_link_packet(char* udp_msg, char* udp_host, int udp_port, serverrec *serv)
4009 {
4010 }
4011
4012 int InspIRCd(void)
4013 {
4014   struct sockaddr_in client, server;
4015   char addrs[MAXBUF][255];
4016   int openSockfd[MAXSOCKS], incomingSockfd, result = TRUE;
4017   socklen_t length;
4018   int count = 0, scanDetectTrigger = TRUE, showBanner = FALSE;
4019   int selectResult = 0;
4020   char *temp, configToken[MAXBUF], stuff[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
4021   char resolvedHost[MAXBUF];
4022   fd_set selectFds;
4023   struct timeval tv;
4024
4025   log(DEBUG,"InspIRCd: startup: begin");
4026   log(DEBUG,"$Id$");
4027   if (geteuid() == 0)
4028   {
4029         printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
4030         Exit(ERROR);
4031         log(DEBUG,"InspIRCd: startup: not starting with UID 0!");
4032   }
4033   SetupCommandTable();
4034   log(DEBUG,"InspIRCd: startup: default command table set up");
4035
4036   ReadConfig();
4037   if (strcmp(DieValue,"")) 
4038   { 
4039         printf("WARNING: %s\n\n",DieValue);
4040         exit(0); 
4041   }  
4042   log(DEBUG,"InspIRCd: startup: read config");
4043   
4044   int count2 = 0, count3 = 0;
4045   for (count = 0; count < ConfValueEnum("bind"); count++)
4046   {
4047         ConfValue("bind","port",count,configToken);
4048         ConfValue("bind","address",count,Addr);
4049         ConfValue("bind","type",count,Type);
4050         if (!strcmp(Type,"servers"))
4051         {
4052                 char Default[MAXBUF];
4053                 strcpy(Default,"no");
4054                 ConfValue("bind","default",count,Default);
4055                 if (strchr(Default,'y'))
4056                 {
4057                                 defaultRoute = count3;
4058                                 log(DEBUG,"InspIRCd: startup: binding '%s:%s' is default server route",Addr,configToken);
4059                 }
4060                 me[count3] = new serverrec(ServerName,100L,false);
4061                 me[count3]->CreateListener(Addr,atoi(configToken));
4062                 count3++;
4063         }
4064         else
4065         {
4066                 ports[count2] = atoi(configToken);
4067                 strcpy(addrs[count2],Addr);
4068                 count2++;
4069         }
4070         log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
4071   }
4072   portCount = count2;
4073   UDPportCount = count3;
4074   
4075   log(DEBUG,"InspIRCd: startup: read %d total client ports and %d total server ports",portCount,UDPportCount);
4076
4077   log(DEBUG,"InspIRCd: startup: InspIRCd is now running!");
4078
4079   printf("\n");
4080
4081   /* BugFix By Craig! :p */
4082   count2 = 0;
4083   for (count = 0; count2 < ConfValueEnum("module"); count2++)
4084   {
4085         char modfile[MAXBUF];
4086         ConfValue("module","name",count,configToken);
4087         sprintf(modfile,"%s/%s",MOD_PATH,configToken);
4088         printf("Loading module... \033[1;37m%s\033[0;37m\n",modfile);
4089         log(DEBUG,"InspIRCd: startup: Loading module: %s",modfile);
4090         /* If The File Doesnt exist, Trying to load it
4091          * Will Segfault the IRCd.. So, check to see if
4092          * it Exists, Before Proceeding. */
4093         if (CheckModule(modfile))
4094         {
4095                 factory[count] = new ircd_module(modfile);
4096                 if (factory[count]->LastError())
4097                 {
4098                         log(DEBUG,"Unable to load %s: %s",modfile,factory[count]->LastError());
4099                         sprintf("Unable to load %s: %s\nExiting...\n",modfile,factory[count]->LastError());
4100                         Exit(ERROR);
4101                 }
4102                 if (factory[count]->factory)
4103                 {
4104                         modules[count] = factory[count]->factory->CreateModule();
4105                         /* save the module and the module's classfactory, if
4106                          * this isnt done, random crashes can occur :/ */
4107                 }
4108                 else
4109                 {
4110                         log(DEBUG,"Unable to load %s",modfile);
4111                         sprintf("Unable to load %s\nExiting...\n",modfile);
4112                         Exit(ERROR);
4113                 }
4114                 /* Increase the Count */
4115                 count++;
4116         }
4117         else
4118         {
4119                 log(DEBUG,"InspIRCd: startup: Module Not Found %s",modfile);
4120                 printf("Module Not Found: \033[1;37m%s\033[0;37m, Skipping\n",modfile);
4121         }
4122   }
4123   MODCOUNT = count - 1;
4124   log(DEBUG,"Total loaded modules: %d",MODCOUNT+1);
4125
4126   servers = new server_list;
4127   servers->clear();
4128
4129   printf("\nInspIRCd is now running!\n");
4130
4131   startup_time = time(NULL);
4132   
4133   if (DaemonSeed() == ERROR)
4134   {
4135      log(DEBUG,"InspIRCd: startup: can't daemonise");
4136      printf("ERROR: could not go into daemon mode. Shutting down.\n");
4137      Exit(ERROR);
4138   }
4139   
4140   
4141   /* setup select call */
4142   FD_ZERO(&selectFds);
4143   log(DEBUG,"InspIRCd: startup: zero selects");
4144   log(VERBOSE,"InspIRCd: startup: portCount = %d", portCount);
4145
4146   for (count = 0; count < portCount; count++)
4147   {
4148           if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
4149       {
4150                 log(DEBUG,"InspIRCd: startup: bad fd %d",openSockfd[boundPortCount]);
4151                 return(ERROR);
4152       }
4153       if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR)
4154       {
4155                 log(DEBUG,"InspIRCd: startup: failed to bind port %d",ports[count]);
4156       }
4157       else                      /* well we at least bound to one socket so we'll continue */
4158       {
4159                 boundPortCount++;
4160       }
4161   }
4162
4163   log(DEBUG,"InspIRCd: startup: total bound ports %d",boundPortCount);
4164   
4165   /* if we didn't bind to anything then abort */
4166   if (boundPortCount == 0)
4167   {
4168      log(DEBUG,"InspIRCd: startup: no ports bound, bailing!");
4169      return (ERROR);
4170   }
4171
4172   length = sizeof (client);
4173   int flip_flop = 0, udp_port = 0;
4174   char udp_msg[MAXBUF], udp_host[MAXBUF];
4175   
4176   /* main loop for multiplexing/resetting */
4177   for (;;)
4178   {
4179       /* set up select call */
4180       for (count = 0; count < boundPortCount; count++)
4181       {
4182                 FD_SET (openSockfd[count], &selectFds);
4183       }
4184         
4185       /* added timeout! select was waiting forever... wank... :/ */
4186       tv.tv_usec = 0;
4187
4188       flip_flop++;
4189       if (flip_flop > 20)
4190       {
4191               tv.tv_usec = 1;
4192               flip_flop = 0;
4193       }
4194       
4195       tv.tv_sec = 0;
4196       selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv);
4197
4198       for (int x = 0; x != UDPportCount; x++)
4199       {
4200                 if (me[x]->RecvPacket(udp_msg, udp_host, udp_port))
4201                 {
4202                     FOREACH_MOD OnPacketReceive(udp_msg);
4203                         WriteOpers("UDP Link Packet: '%s' from %s:%d:%d [route%d]",udp_msg,udp_host,udp_port,me[x]->port,x);
4204                         // Packets must go back via the route they arrived on :)
4205                         handle_link_packet(udp_msg, udp_host, udp_port, me[x]);
4206             }
4207       }
4208
4209         for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++)
4210         {
4211                 char data[MAXBUF];
4212
4213                 if (!count2->second) break;
4214                 
4215                 if (count2->second)
4216                 if (count2->second->fd)
4217                 {
4218                         if (((time(NULL)) > count2->second->nping) && (isnick(count2->second->nick)) && (count2->second->registered == 7))
4219                         {
4220                                 if (!count2->second->lastping) 
4221                                 {
4222                                         log(DEBUG,"InspIRCd: ping timeout: %s",count2->second->nick);
4223                                         kill_link(count2->second,"Ping timeout");
4224                                         break;
4225                                 }
4226                                 Write(count2->second->fd,"PING :%s",ServerName);
4227                                 log(DEBUG,"InspIRCd: pinging: %s",count2->second->nick);
4228                                 count2->second->lastping = 0;
4229                                 count2->second->nping = time(NULL)+120;
4230                         }
4231                         
4232                         result = read(count2->second->fd, data, 1);
4233                         // result EAGAIN means nothing read
4234                         if (result == EAGAIN)
4235                         {
4236                         }
4237                         else
4238                         if (result == 0)
4239                         {
4240                                 log(DEBUG,"InspIRCd: Exited: %s",count2->second->nick);
4241                                 kill_link(count2->second,"Client exited");
4242                         }
4243                         else if (result > 0)
4244                         {
4245                                 strncat(count2->second->inbuf, data, result);
4246                                 if (strchr(count2->second->inbuf, '\n') || strchr(count2->second->inbuf, '\r'))
4247                                 {
4248                                         /* at least one complete line is waiting to be processed */
4249                                         if (!count2->second->fd)
4250                                                 break;
4251                                         else
4252                                         {
4253                                                 process_buffer(count2->second);
4254                                                 break;
4255                                         }
4256                                 }
4257                         }
4258                 }
4259         }
4260
4261       /* select is reporting a waiting socket. Poll them all to find out which */
4262       if (selectResult > 0)
4263       {
4264         char target[MAXBUF], resolved[MAXBUF];
4265         for (count = 0; count < boundPortCount; count++)                
4266         {
4267             if (FD_ISSET (openSockfd[count], &selectFds))
4268             {
4269               incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
4270               
4271               address_cache::iterator iter = IP.find(client.sin_addr);
4272               bool iscached = false;
4273               if (iter == IP.end())
4274               {
4275                         /* ip isn't in cache, add it */
4276                         strncpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF);
4277                         if(CleanAndResolve(resolved, target) != TRUE)
4278                         {
4279                                 strncpy(resolved,target,MAXBUF);
4280                         }
4281                         /* hostname now in 'target' */
4282                         IP[client.sin_addr] = new string(resolved);
4283               /* hostname in cache */
4284               }
4285               else
4286               {
4287               /* found ip (cached) */
4288               strncpy(resolved, iter->second->c_str(), MAXBUF);
4289               iscached = true;
4290            }
4291
4292               if (incomingSockfd < 0)
4293               {
4294                         WriteOpers("*** WARNING: Accept failed on port %d (%s)", ports[count],target);
4295                         log(DEBUG,"InspIRCd: accept failed: %d",ports[count]);
4296                         break;
4297               }
4298
4299               AddClient(incomingSockfd, resolved, ports[count], iscached);
4300               log(DEBUG,"InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd);
4301               break;
4302             }
4303
4304            }
4305       }
4306   }
4307
4308   /* not reached */
4309   close (incomingSockfd);
4310 }
4311