1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * Inspire is copyright (C) 2002-2003 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
17 /* Now with added unF! ;) */
20 #include "inspircd_io.h"
21 #include "inspircd_util.h"
22 #include "inspircd_config.h"
25 #include <sys/errno.h>
26 #include <sys/ioctl.h>
27 #include <sys/utsname.h>
37 #include "connection.h"
48 int LogLevel = DEFAULT;
49 char ServerName[MAXBUF];
51 char ServerDesc[MAXBUF];
52 char AdminName[MAXBUF];
53 char AdminEmail[MAXBUF];
54 char AdminNick[MAXBUF];
56 char restartpass[MAXBUF];
60 char PrefixQuit[MAXBUF];
61 char DieValue[MAXBUF];
63 int WHOWAS_STALE = 48; // default WHOWAS Entries last 2 days before they go 'stale'
64 int WHOWAS_MAX = 100; // default 100 people maximum in the WHOWAS list
66 time_t startup_time = time(NULL);
68 extern vector<Module*> modules;
69 extern vector<ircd_module*> factory;
73 template<> struct hash<in_addr>
75 size_t operator()(const struct in_addr &a) const
78 memcpy(&q,&a,sizeof(size_t));
83 template<> struct hash<string>
85 size_t operator()(const string &s) const
88 static struct hash<const char *> strhash;
100 bool operator()(const string& s1, const string& s2) const
102 char a[MAXBUF],b[MAXBUF];
103 strcpy(a,s1.c_str());
104 strcpy(b,s2.c_str());
105 return (strcasecmp(a,b) == 0);
110 struct InAddr_HashComp
113 bool operator()(const in_addr &s1, const in_addr &s2) const
118 memcpy(&q,&s1,sizeof(size_t));
119 memcpy(&p,&s2,sizeof(size_t));
127 typedef hash_map<string, userrec*, hash<string>, StrHashComp> user_hash;
128 typedef hash_map<string, chanrec*, hash<string>, StrHashComp> chan_hash;
129 typedef hash_map<in_addr,string*, hash<in_addr>, InAddr_HashComp> address_cache;
130 typedef deque<command_t> command_table;
133 server_list* servers;
135 user_hash clientlist;
138 command_table cmdlist;
145 struct linger linger = { 0 };
146 char bannerBuffer[MAXBUF];
147 int boundPortCount = 0;
148 int portCount = 0, UDPportCount = 0, ports[MAXSOCKS];
149 int defaultRoute = 0;
153 int has_channel(userrec *u, chanrec *c);
154 int usercount(chanrec *c);
155 int usercount_i(chanrec *c);
156 void update_stats_l(int fd,int data_out);
157 char* Passwd(userrec *user);
158 bool IsDenied(userrec *user);
159 void AddWhoWas(userrec* u);
162 void safedelete(userrec *p)
166 log(DEBUG,"deleting %s %s %s %s",p->nick,p->ident,p->dhost,p->fullname);
167 log(DEBUG,"safedelete(userrec*): pointer is safe to delete");
172 log(DEBUG,"safedelete(userrec*): unsafe pointer operation squished");
176 void safedelete(chanrec *p)
181 log(DEBUG,"safedelete(chanrec*): pointer is safe to delete");
185 log(DEBUG,"safedelete(chanrec*): unsafe pointer operation squished");
190 /* chop a string down to 512 characters and preserve linefeed (irc max
197 FOREACH_MOD OnServerRaw(temp,false);
198 const char* str2 = temp.c_str();
199 sprintf(str,"%s",str2);
202 if (strlen(str) > 512)
211 string getservername()
216 string getserverdesc()
221 string getnetworkname()
226 string getadminname()
231 string getadminemail()
236 string getadminnick()
241 void log(int level,char *text, ...)
243 char textbuffer[MAXBUF];
247 struct tm * timeinfo;
249 if (level < LogLevel)
253 timeinfo = localtime (&rawtime);
255 f = fopen("ircd.log","a+");
259 va_start (argsPtr, text);
260 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
262 strcpy(b,asctime(timeinfo));
263 b[strlen(b)-1] = ':';
264 fprintf(f,"%s %s\n",b,textbuffer);
269 printf("Can't write log file, bailing!!!");
274 void readfile(file_cache &F, const char* fname)
277 char linebuf[MAXBUF];
279 log(DEBUG,"readfile: loading %s",fname);
281 file = fopen(fname,"r");
286 fgets(linebuf,sizeof(linebuf),file);
287 linebuf[strlen(linebuf)-1]='\0';
288 if (!strcmp(linebuf,""))
294 F.push_back(linebuf);
301 log(DEBUG,"readfile: failed to load file: %s",fname);
303 log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
306 void ReadConfig(void)
308 char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF];
311 ConfValue("server","name",0,ServerName);
312 ConfValue("server","description",0,ServerDesc);
313 ConfValue("server","network",0,Network);
314 ConfValue("admin","name",0,AdminName);
315 ConfValue("admin","email",0,AdminEmail);
316 ConfValue("admin","nick",0,AdminNick);
317 ConfValue("files","motd",0,motd);
318 ConfValue("files","rules",0,rules);
319 ConfValue("power","diepass",0,diepass);
320 ConfValue("power","pause",0,pauseval);
321 ConfValue("power","restartpass",0,restartpass);
322 ConfValue("options","prefixquit",0,PrefixQuit);
323 ConfValue("die","value",0,DieValue);
324 ConfValue("options","loglevel",0,dbg);
325 if (!strcmp(dbg,"debug"))
327 if (!strcmp(dbg,"verbose"))
329 if (!strcmp(dbg,"default"))
331 if (!strcmp(dbg,"sparse"))
333 if (!strcmp(dbg,"none"))
335 readfile(RULES,rules);
336 log(DEBUG,"Reading connect classes");
338 for (int i = 0; i < ConfValueEnum("connect"); i++)
341 ConfValue("connect","allow",i,Value);
342 if (strcmp(Value,""))
344 strcpy(c.host,Value);
347 ConfValue("connect","password",i,Value);
348 strcpy(c.pass,Value);
349 Classes.push_back(c);
350 log(DEBUG,"Read connect class type ALLOW, host=%s password=%s",c.host,c.pass);
354 ConfValue("connect","deny",i,Value);
355 strcpy(c.host,Value);
357 Classes.push_back(c);
358 log(DEBUG,"Read connect class type DENY, host=%s",c.host);
367 log(DEBUG,"Blocking: %d",s);
368 flags = fcntl(s, F_GETFL, 0);
369 fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
372 void NonBlocking(int s)
375 log(DEBUG,"NonBlocking: %d",s);
376 flags = fcntl(s, F_GETFL, 0);
377 fcntl(s, F_SETFL, flags | O_NONBLOCK);
381 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost)
383 struct hostent *hostPtr = NULL;
386 memset (resolvedHost, '\0',MAXBUF);
387 if(unresolvedHost == NULL)
389 if ((inet_aton(unresolvedHost,&addr)) == 0)
391 hostPtr = gethostbyaddr ((char *)&addr.s_addr,sizeof(addr.s_addr),AF_INET);
393 snprintf(resolvedHost,MAXBUF,"%s",hostPtr->h_name);
395 snprintf(resolvedHost,MAXBUF,"%s",unresolvedHost);
399 /* write formatted text to a socket, in same format as printf */
401 void Write(int sock,char *text, ...)
403 char textbuffer[MAXBUF];
407 va_start (argsPtr, text);
408 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
410 sprintf(tb,"%s\r\n",textbuffer);
412 write(sock,tb,strlen(tb));
413 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
416 /* write a server formatted numeric response to a single socket */
418 void WriteServ(int sock, char* text, ...)
420 char textbuffer[MAXBUF],tb[MAXBUF];
422 va_start (argsPtr, text);
424 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
426 sprintf(tb,":%s %s\r\n",ServerName,textbuffer);
428 write(sock,tb,strlen(tb));
429 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
432 /* write text from an originating user to originating user */
434 void WriteFrom(int sock, userrec *user,char* text, ...)
436 char textbuffer[MAXBUF],tb[MAXBUF];
438 va_start (argsPtr, text);
440 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
442 sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
444 write(sock,tb,strlen(tb));
445 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
448 /* write text to an destination user from a source user (e.g. user privmsg) */
450 void WriteTo(userrec *source, userrec *dest,char *data, ...)
452 char textbuffer[MAXBUF],tb[MAXBUF];
454 va_start (argsPtr, data);
455 if ((!dest) || (!source))
459 vsnprintf(textbuffer, MAXBUF, data, argsPtr);
462 WriteFrom(dest->fd,source,"%s",textbuffer);
465 /* write formatted text from a source user to all users on a channel
466 * including the sender (NOT for privmsg, notice etc!) */
468 void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...)
470 char textbuffer[MAXBUF];
472 va_start (argsPtr, text);
473 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
475 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
477 if (has_channel(i->second,Ptr))
479 WriteTo(user,i->second,"%s",textbuffer);
484 /* write formatted text from a source user to all users on a channel except
485 * for the sender (for privmsg etc) */
487 void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...)
489 char textbuffer[MAXBUF];
491 va_start (argsPtr, text);
492 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
495 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
497 if (has_channel(i->second,Ptr) && (user != i->second))
499 WriteTo(user,i->second,"%s",textbuffer);
504 int c_count(userrec* u)
507 for (int i =0; i != MAXCHANS; i++)
508 if (u->chans[i].channel)
514 /* return 0 or 1 depending if users u and u2 share one or more common channels
515 * (used by QUIT, NICK etc which arent channel specific notices) */
517 int common_channels(userrec *u, userrec *u2)
526 for (i = 0; i != MAXCHANS; i++)
528 for (z = 0; z != MAXCHANS; z++)
530 if ((u->chans[i].channel == u2->chans[z].channel) && (u->chans[i].channel) && (u2->chans[z].channel) && (u->registered == 7) && (u2->registered == 7))
532 if ((c_count(u)) && (c_count(u2)))
542 /* write a formatted string to all users who share at least one common
543 * channel, including the source user e.g. for use in NICK */
545 void WriteCommon(userrec *u, char* text, ...)
547 char textbuffer[MAXBUF];
549 va_start (argsPtr, text);
550 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
553 WriteFrom(u->fd,u,"%s",textbuffer);
555 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
557 if (common_channels(u,i->second) && (i->second != u))
559 WriteFrom(i->second->fd,u,"%s",textbuffer);
564 /* write a formatted string to all users who share at least one common
565 * channel, NOT including the source user e.g. for use in QUIT */
567 void WriteCommonExcept(userrec *u, char* text, ...)
569 char textbuffer[MAXBUF];
571 va_start (argsPtr, text);
572 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
575 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
577 if ((common_channels(u,i->second)) && (u != i->second))
579 WriteFrom(i->second->fd,u,"%s",textbuffer);
584 void WriteOpers(char* text, ...)
586 char textbuffer[MAXBUF];
588 va_start (argsPtr, text);
589 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
592 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
594 if (strchr(i->second->modes,'o'))
596 if (strchr(i->second->modes,'s'))
598 // send server notices to all with +s
599 // (TODO: needs SNOMASKs)
600 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
606 void WriteWallOps(userrec *source, char* text, ...)
609 char textbuffer[MAXBUF];
611 va_start (argsPtr, text);
612 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
615 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
617 if (strchr(i->second->modes,'w'))
619 WriteTo(source,i->second,"WALLOPS %s",textbuffer);
624 /* convert a string to lowercase. Note following special circumstances
625 * taken from RFC 1459. Many "official" server branches still hold to this
626 * rule so i will too;
628 * Because of IRC's scandanavian origin, the characters {}| are
629 * considered to be the lower case equivalents of the characters []\,
630 * respectively. This is a critical issue when determining the
631 * equivalence of two nicknames.
634 void strlower(char *n)
640 for (int i = 0; i != strlen(n); i++)
642 n[i] = tolower(n[i]);
652 /* verify that a user's nickname is valid */
654 int isnick(const char* n)
666 if (strlen(n) > NICKMAX-1)
670 for (i = 0; i != strlen(n); i++)
672 if ((n[i] < 33) || (n[i] > 125))
676 /* can't occur ANYWHERE in a nickname! */
677 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
681 /* can't occur as the first char of a nickname... */
682 if ((strchr("0123456789",n[i])) && (!i))
690 /* Find a user record by nickname and return a pointer to it */
692 userrec* Find(string nick)
694 user_hash::iterator iter = clientlist.find(nick);
696 if (iter == clientlist.end())
697 /* Couldn't find it */
703 void update_stats_l(int fd,int data_out) /* add one line-out to stats L for this fd */
705 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
707 if (i->second->fd == fd)
709 i->second->bytes_out+=data_out;
710 i->second->cmds_out++;
716 /* find a channel record by channel name and return a pointer to it */
718 chanrec* FindChan(const char* chan)
720 chan_hash::iterator iter = chanlist.find(chan);
722 if (iter == chanlist.end())
723 /* Couldn't find it */
730 void purge_empty_chans(void)
732 int go_again = 1, purge = 0;
737 for (chan_hash::iterator i = chanlist.begin(); i != chanlist.end(); i++)
740 if (!usercount(i->second))
742 /* kill the record */
743 if (i != chanlist.end())
745 log(DEBUG,"del_channel: destroyed: %s",i->second->name);
756 log(DEBUG,"completed channel purge, killed %d",purge);
759 /* returns the status character for a given user on a channel, e.g. @ for op,
760 * % for halfop etc. If the user has several modes set, the highest mode
761 * the user has must be returned. */
763 char* cmode(userrec *user, chanrec *chan)
766 for (i = 0; i != MAXCHANS; i++)
768 if ((user->chans[i].channel == chan) && (chan != NULL))
770 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
774 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
778 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
787 char scratch[MAXMODES];
789 char* chanmodes(chanrec *chan)
792 if (chan->noexternal)
800 if (strcmp(chan->key,""))
808 if (chan->inviteonly)
824 if (strcmp(chan->key,""))
827 strcat(scratch,chan->key);
832 sprintf(foo," %d",chan->limit);
835 log(DEBUG,"chanmodes: %s %s",chan->name,scratch);
839 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
840 * op, STATUS_VOICE for voice etc. If the user has several modes set, the
841 * highest mode the user has must be returned. */
843 int cstatus(userrec *user, chanrec *chan)
846 for (i = 0; i != MAXCHANS; i++)
848 if ((user->chans[i].channel == chan) && (chan != NULL))
850 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
854 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
858 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
862 return STATUS_NORMAL;
868 /* compile a userlist of a channel into a string, each nick seperated by
869 * spaces and op, voice etc status shown as @ and + */
871 void userlist(userrec *user,chanrec *c)
873 sprintf(list,"353 %s = %s :", user->nick, c->name);
874 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
876 if (has_channel(i->second,c))
878 if (isnick(i->second->nick))
880 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
882 /* user is +i, and source not on the channel, does not show
883 * nick in NAMES list */
886 strcat(list,cmode(i->second,c));
887 strcat(list,i->second->nick);
889 if (strlen(list)>(480-NICKMAX))
891 /* list overflowed into
892 * multiple numerics */
893 WriteServ(user->fd,list);
894 sprintf(list,"353 %s = %s :", user->nick, c->name);
899 /* if whats left in the list isnt empty, send it */
900 if (list[strlen(list)-1] != ':')
902 WriteServ(user->fd,list);
906 /* return a count of the users on a specific channel accounting for
907 * invisible users who won't increase the count. e.g. for /LIST */
909 int usercount_i(chanrec *c)
915 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
917 if (has_channel(i->second,c))
919 if (isnick(i->second->nick))
921 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
923 /* user is +i, and source not on the channel, does not show
924 * nick in NAMES list */
931 log(DEBUG,"usercount_i: %s %d",c->name,count);
936 int usercount(chanrec *c)
942 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
944 if (has_channel(i->second,c))
946 if (isnick(i->second->nick))
952 log(DEBUG,"usercount: %s %d",c->name,count);
957 /* add a channel to a user, creating the record for it if needed and linking
958 * it to the user record */
960 chanrec* add_channel(userrec *user, char* cname, char* key)
966 if ((!cname) || (!user))
970 if (strlen(cname) > CHANMAX-1)
972 cname[CHANMAX-1] = '\0';
975 log(DEBUG,"add_channel: %s %s",user->nick,cname);
977 if ((has_channel(user,FindChan(cname))) && (FindChan(cname)))
979 return NULL; // already on the channel!
982 if (!FindChan(cname))
984 /* create a new one */
985 log(DEBUG,"add_channel: creating: %s",cname);
987 chanlist[cname] = new chanrec();
989 strcpy(chanlist[cname]->name, cname);
990 chanlist[cname]->topiclock = 1;
991 chanlist[cname]->noexternal = 1;
992 chanlist[cname]->created = time(NULL);
993 strcpy(chanlist[cname]->topic, "");
994 strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
995 chanlist[cname]->topicset = 0;
996 Ptr = chanlist[cname];
997 log(DEBUG,"add_channel: created: %s",cname);
998 /* set created to 2 to indicate user
999 * is the first in the channel
1000 * and should be given ops */
1006 /* channel exists, just fish out a pointer to its struct */
1007 Ptr = FindChan(cname);
1010 log(DEBUG,"add_channel: joining to: %s",Ptr->name);
1011 if (strcmp(Ptr->key,""))
1013 log(DEBUG,"add_channel: %s has key %s",Ptr->name,Ptr->key);
1016 log(DEBUG,"add_channel: no key given in JOIN");
1017 WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
1022 log(DEBUG,"key at %p is %s",key,key);
1023 if (strcasecmp(key,Ptr->key))
1025 log(DEBUG,"add_channel: bad key given in JOIN");
1026 WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
1032 if (Ptr->inviteonly)
1034 if (user->IsInvited(Ptr->name))
1036 /* user was invited to channel */
1037 /* there may be an optional channel NOTICE here */
1041 WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
1048 if (usercount(Ptr) == Ptr->limit)
1050 WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
1055 /* check user against the channel banlist */
1056 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1058 if (match(user->GetFullHost(),i->data))
1060 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
1065 user->RemoveInvite(Ptr->name);
1072 for (i =0; i != MAXCHANS; i++)
1074 if (user->chans[i].channel == NULL)
1078 /* first user in is given ops */
1079 user->chans[i].uc_modes = UCMODE_OP;
1083 user->chans[i].uc_modes = 0;
1085 user->chans[i].channel = Ptr;
1086 WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
1089 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
1090 WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
1093 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
1094 WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr));
1095 WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1096 FOREACH_MOD OnUserJoin(user,Ptr);
1100 log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
1101 WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
1105 /* remove a channel from a users record, and remove the record from memory
1106 * if the channel has become empty */
1108 chanrec* del_channel(userrec *user, char* cname, char* reason)
1114 if ((!cname) || (!user))
1119 Ptr = FindChan(cname);
1126 FOREACH_MOD OnUserPart(user,Ptr);
1127 log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
1129 for (i =0; i != MAXCHANS; i++)
1131 /* zap it from the channel list of the user */
1132 if (user->chans[i].channel == Ptr)
1136 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
1140 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
1142 user->chans[i].uc_modes = 0;
1143 user->chans[i].channel = NULL;
1144 log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
1149 /* if there are no users left on the channel */
1150 if (!usercount(Ptr))
1152 chan_hash::iterator iter = chanlist.find(Ptr->name);
1154 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
1156 /* kill the record */
1157 if (iter != chanlist.end())
1159 log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
1160 delete iter->second;
1161 chanlist.erase(iter);
1167 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
1172 if ((!Ptr) || (!user) || (!src))
1177 log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
1179 if (!has_channel(user,Ptr))
1181 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
1184 if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
1186 if (cstatus(src,Ptr) == STATUS_HOP)
1188 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
1192 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator",src->nick, Ptr->name);
1198 for (i =0; i != MAXCHANS; i++)
1200 /* zap it from the channel list of the user */
1201 if (user->chans[i].channel == Ptr)
1203 WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
1204 user->chans[i].uc_modes = 0;
1205 user->chans[i].channel = NULL;
1206 log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
1211 /* if there are no users left on the channel */
1212 if (!usercount(Ptr))
1214 chan_hash::iterator iter = chanlist.find(Ptr->name);
1216 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
1218 /* kill the record */
1219 if (iter != chanlist.end())
1221 log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
1222 delete iter->second;
1223 chanlist.erase(iter);
1229 /* returns 1 if user u has channel c in their record, 0 if not */
1231 int has_channel(userrec *u, chanrec *c)
1239 for (i =0; i != MAXCHANS; i++)
1241 if (u->chans[i].channel == c)
1249 int give_ops(userrec *user,char *dest,chanrec *chan,int status)
1254 if ((!user) || (!dest) || (!chan))
1258 if (status != STATUS_OP)
1260 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1267 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1273 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1278 for (i = 0; i != MAXCHANS; i++)
1280 if ((d->chans[i].channel == chan) && (chan != NULL))
1282 if (d->chans[i].uc_modes & UCMODE_OP)
1284 /* mode already set on user, dont allow multiple */
1287 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
1288 log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
1296 int give_hops(userrec *user,char *dest,chanrec *chan,int status)
1301 if ((!user) || (!dest) || (!chan))
1305 if (status != STATUS_OP)
1307 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1315 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1320 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1325 for (i = 0; i != MAXCHANS; i++)
1327 if ((d->chans[i].channel == chan) && (chan != NULL))
1329 if (d->chans[i].uc_modes & UCMODE_HOP)
1331 /* mode already set on user, dont allow multiple */
1334 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
1335 log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
1343 int give_voice(userrec *user,char *dest,chanrec *chan,int status)
1348 if ((!user) || (!dest) || (!chan))
1352 if (status < STATUS_HOP)
1354 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1362 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1367 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1372 for (i = 0; i != MAXCHANS; i++)
1374 if ((d->chans[i].channel == chan) && (chan != NULL))
1376 if (d->chans[i].uc_modes & UCMODE_VOICE)
1378 /* mode already set on user, dont allow multiple */
1381 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
1382 log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
1390 int take_ops(userrec *user,char *dest,chanrec *chan,int status)
1395 if ((!user) || (!dest) || (!chan))
1399 if (status != STATUS_OP)
1401 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1409 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1414 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1419 for (i = 0; i != MAXCHANS; i++)
1421 if ((d->chans[i].channel == chan) && (chan != NULL))
1423 if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
1425 /* mode already set on user, dont allow multiple */
1428 d->chans[i].uc_modes ^= UCMODE_OP;
1429 log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
1437 int take_hops(userrec *user,char *dest,chanrec *chan,int status)
1442 if ((!user) || (!dest) || (!chan))
1446 if (status != STATUS_OP)
1448 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1456 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1461 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1466 for (i = 0; i != MAXCHANS; i++)
1468 if ((d->chans[i].channel == chan) && (chan != NULL))
1470 if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
1472 /* mode already set on user, dont allow multiple */
1475 d->chans[i].uc_modes ^= UCMODE_HOP;
1476 log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
1484 int take_voice(userrec *user,char *dest,chanrec *chan,int status)
1489 if ((!user) || (!dest) || (!chan))
1493 if (status < STATUS_HOP)
1495 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1503 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1508 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1513 for (i = 0; i != MAXCHANS; i++)
1515 if ((d->chans[i].channel == chan) && (chan != NULL))
1517 if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
1519 /* mode already set on user, dont allow multiple */
1522 d->chans[i].uc_modes ^= UCMODE_VOICE;
1523 log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
1531 void TidyBan(char *ban)
1533 char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
1537 char* pos_of_pling = strchr(temp,'!');
1538 char* pos_of_at = strchr(temp,'@');
1540 pos_of_pling[0] = '\0';
1541 pos_of_at[0] = '\0';
1545 strncpy(NICK,temp,NICKMAX);
1546 strncpy(IDENT,pos_of_pling,IDENTMAX+1);
1547 strncpy(HOST,pos_of_at,160);
1549 sprintf(ban,"%s!%s@%s",NICK,IDENT,HOST);
1552 int add_ban(userrec *user,char *dest,chanrec *chan,int status)
1555 if ((!user) || (!dest) || (!chan))
1557 if (strchr(dest,'!')==0)
1559 if (strchr(dest,'@')==0)
1561 for (int i = 0; i < strlen(dest); i++)
1564 for (int i = 0; i < strlen(dest); i++)
1568 for (int i = 0; i < strlen(dest); i++)
1574 for (int i = 0; i < strlen(dest); i++)
1579 log(DEBUG,"add_ban: %s %s",chan->name,user->nick);
1582 for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1584 if (!strcasecmp(i->data,dest))
1586 // dont allow a user to set the same ban twice
1591 b.set_time = time(NULL);
1592 strncpy(b.data,dest,MAXBUF);
1593 strncpy(b.set_by,user->nick,NICKMAX);
1594 chan->bans.push_back(b);
1598 int take_ban(userrec *user,char *dest,chanrec *chan,int status)
1600 if ((!user) || (!dest) || (!chan))
1605 log(DEBUG,"del_ban: %s %s",chan->name,user->nick);
1606 for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1608 if (!strcasecmp(i->data,dest))
1610 chan->bans.erase(i);
1617 void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt)
1619 char modelist[MAXBUF];
1620 char outlist[MAXBUF];
1621 char outstr[MAXBUF];
1622 char outpars[32][MAXBUF];
1628 bool k_set = false, l_set = false;
1635 log(DEBUG,"process_modes: start");
1637 strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
1638 /* parameters[2] onwards are parameters for
1639 * modes that require them :) */
1640 strcpy(outlist,"+");
1643 log(DEBUG,"process_modes: modelist: %s",modelist);
1645 for (ptr = 0; ptr < strlen(modelist); ptr++)
1650 log(DEBUG,"process_modes: modechar: %c",modelist[ptr]);
1651 switch (modelist[ptr])
1656 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1658 outlist[strlen(outlist)-1] = '-';
1662 strcat(outlist,"-");
1672 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1674 outlist[strlen(outlist)-1] = '+';
1678 strcat(outlist,"+");
1685 if ((param >= pcnt)) break;
1688 r = give_ops(user,parameters[param++],chan,status);
1692 r = take_ops(user,parameters[param++],chan,status);
1696 strcat(outlist,"o");
1697 strcpy(outpars[pc++],parameters[param-1]);
1702 if ((param >= pcnt)) break;
1705 r = give_hops(user,parameters[param++],chan,status);
1709 r = take_hops(user,parameters[param++],chan,status);
1713 strcat(outlist,"h");
1714 strcpy(outpars[pc++],parameters[param-1]);
1720 if ((param >= pcnt)) break;
1723 r = give_voice(user,parameters[param++],chan,status);
1727 r = take_voice(user,parameters[param++],chan,status);
1731 strcat(outlist,"v");
1732 strcpy(outpars[pc++],parameters[param-1]);
1737 if ((param >= pcnt)) break;
1740 r = add_ban(user,parameters[param++],chan,status);
1744 r = take_ban(user,parameters[param++],chan,status);
1748 strcat(outlist,"b");
1749 strcpy(outpars[pc++],parameters[param-1]);
1754 if ((param >= pcnt))
1762 if (!strcmp(chan->key,""))
1764 strcat(outlist,"k");
1765 strcpy(outpars[pc++],parameters[param++]);
1766 strcpy(chan->key,parameters[param-1]);
1772 /* only allow -k if correct key given */
1773 if (strcmp(chan->key,""))
1775 strcat(outlist,"k");
1776 strcpy(chan->key,"");
1786 strcat(outlist,"l");
1791 if ((param >= pcnt)) break;
1797 bool invalid = false;
1798 for (int i = 0; i < strlen(parameters[param]); i++)
1800 if ((parameters[param][i] < '0') || (parameters[param][i] > '9'))
1805 if (atoi(parameters[param]) < 1)
1813 chan->limit = atoi(parameters[param]);
1816 strcat(outlist,"l");
1817 strcpy(outpars[pc++],parameters[param++]);
1824 if (chan->inviteonly != mdir)
1826 strcat(outlist,"i");
1828 chan->inviteonly = mdir;
1832 if (chan->topiclock != mdir)
1834 strcat(outlist,"t");
1836 chan->topiclock = mdir;
1840 if (chan->noexternal != mdir)
1842 strcat(outlist,"n");
1844 chan->noexternal = mdir;
1848 if (chan->moderated != mdir)
1850 strcat(outlist,"m");
1852 chan->moderated = mdir;
1856 if (chan->secret != mdir)
1858 strcat(outlist,"s");
1859 if (chan->c_private)
1861 chan->c_private = 0;
1864 strcat(outlist,"-p+");
1868 strcat(outlist,"+p-");
1872 chan->secret = mdir;
1876 if (chan->c_private != mdir)
1878 strcat(outlist,"p");
1884 strcat(outlist,"-s+");
1888 strcat(outlist,"+s-");
1892 chan->c_private = mdir;
1899 /* this ensures only the *valid* modes are sent out onto the network */
1900 while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
1902 outlist[strlen(outlist)-1] = '\0';
1904 if (strcmp(outlist,""))
1906 strcpy(outstr,outlist);
1907 for (ptr = 0; ptr < pc; ptr++)
1910 strcat(outstr,outpars[ptr]);
1912 WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
1916 void handle_mode(char **parameters, int pcnt, userrec *user)
1922 char outpars[MAXBUF];
1924 dest = Find(parameters[0]);
1926 if ((dest) && (pcnt == 1))
1928 WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes);
1931 if ((dest) && (pcnt > 1))
1936 if (strchr(user->modes,'o'))
1947 WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
1951 strcpy(outpars,"+");
1954 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1957 for (i = 0; i < strlen(parameters[1]); i++)
1959 if (parameters[1][i] == '+')
1963 if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1965 outpars[strlen(outpars)-1] = '+';
1969 strcat(outpars,"+");
1975 if (parameters[1][i] == '-')
1979 if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1981 outpars[strlen(outpars)-1] = '-';
1985 strcat(outpars,"-");
1993 if (strchr(user->modes,'o'))
1999 if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's'))
2008 if (!strchr(dest->modes,parameters[1][i]))
2010 dest->modes[strlen(dest->modes)+1]='\0';
2011 dest->modes[strlen(dest->modes)] = parameters[1][i];
2012 outpars[strlen(outpars)+1]='\0';
2013 outpars[strlen(outpars)] = parameters[1][i];
2022 outpars[strlen(outpars)+1]='\0';
2023 outpars[strlen(outpars)] = parameters[1][i];
2026 for (q = 0; q < strlen(user->modes); q++)
2028 if (user->modes[q] != parameters[1][i])
2030 moo[0] = user->modes[q];
2035 strcpy(user->modes,temp);
2040 if (strlen(outpars))
2046 while (i < strlen (outpars))
2048 b[z++] = outpars[i++];
2050 if (i<strlen(outpars)-1)
2052 if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
2054 // someones playing silly buggers and trying
2055 // to put a +- or -+ into the line...
2059 if (i == strlen(outpars)-1)
2061 if ((outpars[i] == '-') || (outpars[i] == '+'))
2069 if ((b[z] == '-') || (b[z] == '+'))
2072 if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
2075 WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
2080 Ptr = FindChan(parameters[0]);
2085 /* just /modes #channel */
2086 WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
2087 WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
2093 if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b")))
2096 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
2098 WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
2100 WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
2104 if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
2106 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, Ptr->name);
2110 process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt);
2114 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2118 /* This function pokes and hacks at a parameter list like the following:
2120 * PART #winbot, #darkgalaxy :m00!
2122 * to turn it into a series of individual calls like this:
2124 * PART #winbot :m00!
2125 * PART #darkgalaxy :m00!
2127 * The seperate calls are sent to a callback function provided by the caller
2128 * (the caller will usually call itself recursively). The callback function
2129 * must be a command handler. Calling this function on a line with no list causes
2130 * no action to be taken. You must provide a starting and ending parameter number
2131 * where the range of the list can be found, useful if you have a terminating
2132 * parameter as above which is actually not part of the list, or parameters
2133 * before the actual list as well. This code is used by many functions which
2134 * can function as "one to list" (see the RFC) */
2136 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
2141 char blog[32][MAXBUF];
2142 char blog2[32][MAXBUF];
2143 int i = 0, j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
2144 char keystr[MAXBUF];
2147 for (i = 0; i <32; i++)
2150 for (i = 0; i <32; i++)
2151 strcpy(blog2[i],"");
2154 for (i = 0; i <10; i++)
2158 parameters[i] = moo;
2163 if (pcnt > 1) /* we have a key to copy */
2165 strcpy(keystr,parameters[1]);
2169 if (!parameters[start])
2173 if (!strchr(parameters[start],','))
2178 for (i = start; i <= end; i++)
2182 strcat(plist,parameters[i]);
2190 for (i = 0; i < t; i++)
2192 if (plist[i] == ',')
2195 strcpy(blog[j++],param);
2199 strcpy(blog[j++],param);
2202 if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
2207 if ((joins) && (keystr))
2209 if (strchr(keystr,','))
2213 t2 = strlen(keystr);
2214 for (i = 0; i < t2; i++)
2216 if (keystr[i] == ',')
2219 strcpy(blog2[j++],param);
2223 strcpy(blog2[j++],param);
2228 for (j = 0; j < total; j++)
2234 for (q = end; q < pcnt-1; q++)
2236 if (parameters[q+1])
2238 pars[q-end+1] = parameters[q+1];
2241 if ((joins) && (parameters[1]))
2252 /* repeatedly call the function with the hacked parameter list */
2253 if ((joins) && (pcnt > 1))
2257 // pars[1] already set up and containing key from blog2[j]
2262 pars[1] = parameters[1];
2268 fn(pars,pcnt-(end-start),u);
2275 void handle_join(char **parameters, int pcnt, userrec *user)
2280 if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
2282 if (parameters[0][0] == '#')
2284 Ptr = add_channel(user,parameters[0],parameters[1]);
2289 void handle_part(char **parameters, int pcnt, userrec *user)
2295 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
2297 del_channel(user,parameters[0],parameters[1]);
2301 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
2303 del_channel(user,parameters[0],NULL);
2307 void handle_kick(char **parameters, int pcnt, userrec *user)
2309 chanrec* Ptr = FindChan(parameters[0]);
2310 userrec* u = Find(parameters[1]);
2314 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2318 if (!has_channel(u,Ptr))
2320 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
2326 kick_channel(user,u,Ptr,parameters[2]);
2330 kick_channel(user,u,Ptr,user->nick);
2335 void handle_die(char **parameters, int pcnt, userrec *user)
2337 log(DEBUG,"die: %s",user->nick);
2338 if (!strcmp(parameters[0],diepass))
2340 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
2346 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
2350 void handle_restart(char **parameters, int pcnt, userrec *user)
2352 log(DEBUG,"restart: %s",user->nick);
2353 if (!strcmp(parameters[0],restartpass))
2355 WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host);
2358 /* Will finish this later when i can be arsed :) */
2362 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
2367 void kill_link(userrec *user,char* reason)
2369 user_hash::iterator iter = clientlist.find(user->nick);
2371 log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
2372 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
2373 fdatasync(user->fd);
2374 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
2375 FOREACH_MOD OnUserQuit(user);
2376 log(DEBUG,"closing fd %d",user->fd);
2377 /* bugfix, cant close() a nonblocking socket (sux!) */
2378 WriteCommonExcept(user,"QUIT :%s",reason);
2381 NonBlocking(user->fd);
2384 if (iter != clientlist.end())
2386 log(DEBUG,"deleting user hash value %p",iter->second);
2387 delete iter->second;
2388 clientlist.erase(iter);
2391 purge_empty_chans();
2395 void handle_kill(char **parameters, int pcnt, userrec *user)
2397 userrec *u = Find(parameters[0]);
2398 char killreason[MAXBUF];
2400 log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
2403 WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
2404 sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]);
2405 kill_link(u,killreason);
2409 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2413 void handle_summon(char **parameters, int pcnt, userrec *user)
2415 WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
2418 void handle_users(char **parameters, int pcnt, userrec *user)
2420 WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
2424 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
2426 char* Passwd(userrec *user)
2428 for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2430 if (match(user->host,i->host) && (i->type == CC_ALLOW))
2438 bool IsDenied(userrec *user)
2440 for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2442 if (match(user->host,i->host) && (i->type == CC_DENY))
2451 void handle_pass(char **parameters, int pcnt, userrec *user)
2453 if (!strcasecmp(parameters[0],Passwd(user)))
2455 user->haspassed = true;
2459 void handle_invite(char **parameters, int pcnt, userrec *user)
2461 userrec* u = Find(parameters[0]);
2462 chanrec* c = FindChan(parameters[1]);
2468 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[1]);
2474 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
2483 if (cstatus(user,c) < STATUS_HOP)
2485 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, c->name);
2489 u->InviteTo(c->name);
2490 WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
2491 WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
2495 void handle_topic(char **parameters, int pcnt, userrec *user)
2501 if (strlen(parameters[0]) <= CHANMAX)
2503 Ptr = FindChan(parameters[0]);
2508 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
2509 WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
2513 WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2518 WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2524 if (loop_call(handle_topic,parameters,pcnt,user,0,pcnt-2,0))
2526 if (strlen(parameters[0]) <= CHANMAX)
2528 Ptr = FindChan(parameters[0]);
2531 if ((Ptr->topiclock) && (cstatus(user,Ptr)<STATUS_HOP))
2533 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator", user->nick, Ptr->name);
2536 strcpy(Ptr->topic,parameters[1]);
2537 strcpy(Ptr->setby,user->nick);
2538 Ptr->topicset = time(NULL);
2539 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
2543 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2549 /* sends out an error notice to all connected clients (not to be used
2552 void send_error(char *s)
2554 log(DEBUG,"send_error: %s",s);
2555 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
2557 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
2561 void Error(int status)
2563 signal (SIGALRM, SIG_IGN);
2564 signal (SIGPIPE, SIG_IGN);
2565 signal (SIGTERM, SIG_IGN);
2566 signal (SIGABRT, SIG_IGN);
2567 signal (SIGSEGV, SIG_IGN);
2568 signal (SIGURG, SIG_IGN);
2569 signal (SIGKILL, SIG_IGN);
2570 log(DEBUG,"*** fell down a pothole in the road to perfection ***");
2571 send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
2575 int main (int argc, char *argv[])
2578 log(DEBUG,"*** InspIRCd starting up!");
2581 log(DEBUG,"main: no config");
2582 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
2585 if (InspIRCd() == ERROR)
2587 log(DEBUG,"main: daemon function bailed");
2588 printf("ERROR: could not initialise. Shutting down.\n");
2595 template<typename T> inline string ConvToStr(const T &in)
2598 if (!(tmp << in)) return string();
2602 /* re-allocates a nick in the user_hash after they change nicknames,
2603 * returns a pointer to the new user as it may have moved */
2605 userrec* ReHashNick(char* Old, char* New)
2607 user_hash::iterator newnick;
2608 user_hash::iterator oldnick = clientlist.find(Old);
2610 log(DEBUG,"ReHashNick: %s %s",Old,New);
2612 if (!strcasecmp(Old,New))
2614 log(DEBUG,"old nick is new nick, skipping");
2615 return oldnick->second;
2618 if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
2620 log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
2622 clientlist[New] = new userrec();
2623 clientlist[New] = oldnick->second;
2624 /*delete oldnick->second; */
2625 clientlist.erase(oldnick);
2627 log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
2629 return clientlist[New];
2632 /* adds or updates an entry in the whowas list */
2633 void AddWhoWas(userrec* u)
2635 user_hash::iterator iter = whowas.find(u->nick);
2636 userrec *a = new userrec();
2637 strcpy(a->nick,u->nick);
2638 strcpy(a->ident,u->ident);
2639 strcpy(a->dhost,u->dhost);
2640 strcpy(a->host,u->host);
2641 strcpy(a->fullname,u->fullname);
2642 strcpy(a->server,u->server);
2643 a->signon = u->signon;
2645 /* MAX_WHOWAS: max number of /WHOWAS items
2646 * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
2647 * can be replaced by a newer one
2650 if (iter == whowas.end())
2652 if (whowas.size() == WHOWAS_MAX)
2654 for (user_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
2656 // 3600 seconds in an hour ;)
2657 if ((i->second->signon)<(time(NULL)-(WHOWAS_STALE*3600)))
2661 log(DEBUG,"added WHOWAS entry, purged an old record");
2668 log(DEBUG,"added fresh WHOWAS entry");
2669 whowas[a->nick] = a;
2674 log(DEBUG,"updated WHOWAS entry");
2675 delete iter->second;
2681 /* add a client connection to the sockets list */
2682 void AddClient(int socket, char* host, int port, bool iscached)
2686 char resolved[MAXBUF];
2689 user_hash::iterator iter;
2691 tempnick = ConvToStr(socket) + "-unknown";
2692 sprintf(tn2,"%d-unknown",socket);
2694 iter = clientlist.find(tempnick);
2696 if (iter != clientlist.end()) return;
2699 * It is OK to access the value here this way since we know
2700 * it exists, we just created it above.
2702 * At NO other time should you access a value in a map or a
2703 * hash_map this way.
2705 clientlist[tempnick] = new userrec();
2707 NonBlocking(socket);
2708 log(DEBUG,"AddClient: %d %s %d",socket,host,port);
2711 clientlist[tempnick]->fd = socket;
2712 strncpy(clientlist[tempnick]->nick, tn2,NICKMAX);
2713 strncpy(clientlist[tempnick]->host, host,160);
2714 strncpy(clientlist[tempnick]->dhost, host,160);
2715 strncpy(clientlist[tempnick]->server, ServerName,256);
2716 clientlist[tempnick]->registered = 0;
2717 clientlist[tempnick]->signon = time(NULL);
2718 clientlist[tempnick]->nping = time(NULL)+240;
2719 clientlist[tempnick]->lastping = 1;
2720 clientlist[tempnick]->port = port;
2724 WriteServ(socket,"NOTICE Auth :Found your hostname (cached)...");
2728 WriteServ(socket,"NOTICE Auth :Looking up your hostname...");
2731 if (clientlist.size() == MAXCLIENTS)
2732 kill_link(clientlist[tempnick],"No more connections allowed in this class");
2735 void handle_names(char **parameters, int pcnt, userrec *user)
2739 if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
2741 c = FindChan(parameters[0]);
2744 /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
2746 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
2750 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2755 void handle_privmsg(char **parameters, int pcnt, userrec *user)
2760 if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
2762 if (parameters[0][0] == '#')
2764 chan = FindChan(parameters[0]);
2767 if ((chan->noexternal) && (!has_channel(user,chan)))
2769 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2772 if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2774 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2777 ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
2781 /* no such nick/channel */
2782 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2787 dest = Find(parameters[0]);
2790 if (strcmp(dest->awaymsg,""))
2792 /* auto respond with aweh msg */
2793 WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
2795 WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
2799 /* no such nick/channel */
2800 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2804 void handle_notice(char **parameters, int pcnt, userrec *user)
2809 if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
2811 if (parameters[0][0] == '#')
2813 chan = FindChan(parameters[0]);
2816 if ((chan->noexternal) && (!has_channel(user,chan)))
2818 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2821 if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2823 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2826 WriteChannel(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
2830 /* no such nick/channel */
2831 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2836 dest = Find(parameters[0]);
2839 WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
2843 /* no such nick/channel */
2844 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2850 char* chlist(userrec *user)
2855 log(DEBUG,"chlist: %s",user->nick);
2861 for (i = 0; i != MAXCHANS; i++)
2863 if (user->chans[i].channel != NULL)
2865 if (user->chans[i].channel->name)
2867 strcpy(cmp,user->chans[i].channel->name);
2869 if (!strstr(lst,cmp))
2871 if ((!user->chans[i].channel->c_private) && (!user->chans[i].channel->secret))
2873 strcat(lst,cmode(user,user->chans[i].channel));
2874 strcat(lst,user->chans[i].channel->name);
2884 void handle_info(char **parameters, int pcnt, userrec *user)
2886 WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick);
2887 WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick);
2888 WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick);
2889 WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
2892 void handle_time(char **parameters, int pcnt, userrec *user)
2895 struct tm * timeinfo;
2898 timeinfo = localtime ( &rawtime );
2899 WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
2903 void handle_whois(char **parameters, int pcnt, userrec *user)
2908 if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
2910 dest = Find(parameters[0]);
2913 WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
2914 if ((user == dest) || (strchr(user->modes,'o')))
2916 WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host);
2918 if (strcmp(chlist(dest),""))
2920 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest));
2922 WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, ServerDesc);
2923 if (strcmp(dest->awaymsg,""))
2925 WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
2927 if (strchr(dest->modes,'o'))
2929 WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick);
2931 //WriteServ(user->fd,"310 %s %s :is available for help.",user->nick, dest->nick);
2932 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon);
2934 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
2938 /* no such nick/channel */
2939 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2943 void handle_quit(char **parameters, int pcnt, userrec *user)
2945 user_hash::iterator iter = clientlist.find(user->nick);
2947 /* theres more to do here, but for now just close the socket */
2950 if (parameters[0][0] == ':')
2954 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]);
2955 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]);
2956 WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
2960 Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
2961 WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
2962 WriteCommonExcept(user,"QUIT :Client exited");
2965 FOREACH_MOD OnUserQuit(user);
2967 /* confucious say, he who close nonblocking socket, get nothing! */
2970 NonBlocking(user->fd);
2973 if (iter != clientlist.end())
2975 log(DEBUG,"deleting user hash value");
2976 delete iter->second;
2977 clientlist.erase(iter);
2980 purge_empty_chans();
2983 void handle_who(char **parameters, int pcnt, userrec *user)
2987 /* theres more to do here, but for now just close the socket */
2990 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
2992 Ptr = user->chans[0].channel;
2993 printf(user->chans[0].channel->name);
2994 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
2996 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
2998 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);
3001 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3004 if (parameters[0][0] = '#')
3006 Ptr = FindChan(parameters[0]);
3009 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3011 if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
3013 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);
3016 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3020 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
3026 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
3028 Ptr = user->chans[0].channel;
3029 printf(user->chans[0].channel->name);
3030 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3032 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
3034 if (strchr(i->second->modes,'o'))
3036 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);
3040 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3046 void handle_wallops(char **parameters, int pcnt, userrec *user)
3048 WriteWallOps(user,"%s",parameters[0]);
3051 void handle_list(char **parameters, int pcnt, userrec *user)
3055 WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
3056 for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
3058 if ((!i->second->c_private) && (!i->second->secret))
3060 WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
3063 WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
3067 void handle_rehash(char **parameters, int pcnt, userrec *user)
3069 WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CONFIG_FILE);
3071 FOREACH_MOD OnRehash();
3072 WriteOpers("%s is rehashing config file %s",user->nick,CONFIG_FILE);
3078 return clientlist.size();
3081 int usercount_invisible(void)
3085 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3087 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
3092 int usercount_opers(void)
3096 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3098 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
3103 int usercount_unknown(void)
3107 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3109 if ((i->second->fd) && (i->second->registered != 7))
3117 return chanlist.size();
3120 int servercount(void)
3125 void handle_lusers(char **parameters, int pcnt, userrec *user)
3127 WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
3128 WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
3129 WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
3130 WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
3131 WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,usercnt());
3134 void handle_admin(char **parameters, int pcnt, userrec *user)
3136 WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
3137 WriteServ(user->fd,"257 %s :Name - %s",user->nick,AdminName);
3138 WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
3139 WriteServ(user->fd,"258 %s :E-Mail - %s",user->nick,AdminEmail);
3142 void ShowMOTD(userrec *user)
3146 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
3149 WriteServ(user->fd,"375 %s :- %s message of the day",user->nick,ServerName);
3150 for (int i = 0; i != MOTD.size(); i++)
3152 WriteServ(user->fd,"372 %s :- %s",user->nick,MOTD[i].c_str());
3154 WriteServ(user->fd,"376 %s :End of %s message of the day.",user->nick,ServerName);
3157 void ShowRULES(userrec *user)
3161 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
3164 WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
3165 for (int i = 0; i != RULES.size(); i++)
3167 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
3169 WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
3172 /* shows the message of the day, and any other on-logon stuff */
3173 void ConnectUser(userrec *user)
3175 user->registered = 7;
3176 user->idle_lastmsg = time(NULL);
3177 log(DEBUG,"ConnectUser: %s",user->nick);
3179 if (strcmp(Passwd(user),"") && (!user->haspassed))
3181 Write(user->fd,"ERROR :Closing link: Invalid password");
3182 fdatasync(user->fd);
3183 kill_link(user,"Invalid password");
3188 Write(user->fd,"ERROR :Closing link: Unauthorized connection");
3189 fdatasync(user->fd);
3190 kill_link(user,"Unauthorised connection");
3193 WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
3194 WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
3195 WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
3196 WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
3197 WriteServ(user->fd,"004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
3198 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);
3199 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);
3201 FOREACH_MOD OnUserConnect(user);
3202 WriteOpers("*** Client connecting on port %d: %s!%s@%s",user->port,user->nick,user->ident,user->host);
3205 void handle_version(char **parameters, int pcnt, userrec *user)
3207 WriteServ(user->fd,"351 %s :%s %s :%s",user->nick,VERSION,ServerName,SYSTEM);
3210 void handle_ping(char **parameters, int pcnt, userrec *user)
3212 WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
3215 void handle_pong(char **parameters, int pcnt, userrec *user)
3217 // set the user as alive so they survive to next ping
3221 void handle_motd(char **parameters, int pcnt, userrec *user)
3226 void handle_rules(char **parameters, int pcnt, userrec *user)
3231 void handle_user(char **parameters, int pcnt, userrec *user)
3233 if (user->registered < 3)
3235 WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~");
3236 strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */
3237 strncat(user->ident,parameters[0],IDENTMAX);
3238 strncpy(user->fullname,parameters[3],128);
3239 user->registered = (user->registered | 1);
3243 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
3246 /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
3247 if (user->registered == 3)
3249 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3254 void handle_userhost(char **parameters, int pcnt, userrec *user)
3256 char Return[MAXBUF],junk[MAXBUF];
3257 sprintf(Return,"302 %s :",user->nick);
3258 for (int i = 0; i < pcnt; i++)
3260 userrec *u = Find(parameters[i]);
3263 if (strchr(u->modes,'o'))
3265 sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host);
3266 strcat(Return,junk);
3270 sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host);
3271 strcat(Return,junk);
3275 WriteServ(user->fd,Return);
3279 void handle_ison(char **parameters, int pcnt, userrec *user)
3281 char Return[MAXBUF];
3282 sprintf(Return,"303 %s :",user->nick);
3283 for (int i = 0; i < pcnt; i++)
3285 userrec *u = Find(parameters[i]);
3288 strcat(Return,u->nick);
3292 WriteServ(user->fd,Return);
3296 void handle_away(char **parameters, int pcnt, userrec *user)
3300 strcpy(user->awaymsg,parameters[0]);
3301 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
3305 strcpy(user->awaymsg,"");
3306 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
3310 void handle_whowas(char **parameters, int pcnt, userrec* user)
3312 user_hash::iterator i = whowas.find(parameters[0]);
3314 if (i == whowas.end())
3316 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
3317 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3321 time_t rawtime = i->second->signon;
3325 timeinfo = localtime(&rawtime);
3326 strcpy(b,asctime(timeinfo));
3327 b[strlen(b)-1] = '\0';
3329 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
3330 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
3331 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3336 void handle_trace(char **parameters, int pcnt, userrec *user)
3338 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3342 if (isnick(i->second->nick))
3344 if (strchr(i->second->modes,'o'))
3346 WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
3350 WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
3355 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
3361 void handle_stats(char **parameters, int pcnt, userrec *user)
3367 if (strlen(parameters[0])>1)
3369 /* make the stats query 1 character long */
3370 parameters[0][1] = '\0';
3373 /* stats m (list number of times each command has been used, plus bytecount) */
3374 if (!strcasecmp(parameters[0],"m"))
3376 for (int i = 0; i < cmdlist.size(); i++)
3378 if (cmdlist[i].handler_function)
3380 if (cmdlist[i].use_count)
3382 /* RPL_STATSCOMMANDS */
3383 WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
3390 /* stats z (debug and memory info) */
3391 if (!strcasecmp(parameters[0],"z"))
3393 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
3394 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
3395 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
3396 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
3397 WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
3398 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
3399 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
3400 WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount);
3404 if (!strcasecmp(parameters[0],"o"))
3406 for (int i = 0; i < ConfValueEnum("oper"); i++)
3408 char LoginName[MAXBUF];
3409 char HostName[MAXBUF];
3410 char OperType[MAXBUF];
3411 ConfValue("oper","name",i,LoginName);
3412 ConfValue("oper","host",i,HostName);
3413 ConfValue("oper","type",i,OperType);
3414 WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
3418 /* stats l (show user I/O stats) */
3419 if (!strcasecmp(parameters[0],"l"))
3421 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
3422 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3424 if (isnick(i->second->nick))
3426 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);
3430 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);
3436 /* stats u (show server uptime) */
3437 if (!strcasecmp(parameters[0],"u"))
3439 time_t current_time = 0;
3440 current_time = time(NULL);
3441 time_t server_uptime = current_time - startup_time;
3443 stime = gmtime(&server_uptime);
3444 /* i dont know who the hell would have an ircd running for over a year nonstop, but
3445 * Craig suggested this, and it seemed a good idea so in it went */
3446 if (stime->tm_year > 70)
3448 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);
3452 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);
3456 WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
3457 WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
3461 void handle_connect(char **parameters, int pcnt, userrec *user)
3463 WriteServ(user->fd,"NOTICE %s :*** Connecting to %s port %s...",user->nick,parameters[0],parameters[1]);
3464 if (!me[defaultRoute]->BeginLink(parameters[0],atoi(parameters[1]),"password"))
3466 WriteServ(user->fd,"NOTICE %s :*** Failed to send auth packet to %s!",user->nick,parameters[0]);
3470 void handle_squit(char **parameters, int pcnt, userrec *user)
3474 void handle_oper(char **parameters, int pcnt, userrec *user)
3476 char LoginName[MAXBUF];
3477 char Password[MAXBUF];
3478 char OperType[MAXBUF];
3479 char TypeName[MAXBUF];
3480 char Hostname[MAXBUF];
3483 for (i = 0; i < ConfValueEnum("oper"); i++)
3485 ConfValue("oper","name",i,LoginName);
3486 ConfValue("oper","password",i,Password);
3487 if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1])))
3489 /* correct oper credentials */
3490 ConfValue("oper","type",i,OperType);
3491 WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
3492 WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
3493 WriteServ(user->fd,"MODE %s :+o",user->nick);
3494 for (j =0; j < ConfValueEnum("type"); j++)
3496 ConfValue("type","name",j,TypeName);
3497 if (!strcmp(TypeName,OperType))
3499 /* found this oper's opertype */
3500 ConfValue("type","host",j,Hostname);
3501 strncpy(user->dhost,Hostname,256);
3504 if (!strchr(user->modes,'o'))
3506 strcat(user->modes,"o");
3512 WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
3513 WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
3516 void handle_nick(char **parameters, int pcnt, userrec *user)
3520 log(DEBUG,"not enough params for handle_nick");
3525 log(DEBUG,"invalid parameter passed to handle_nick");
3528 if (!strlen(parameters[0]))
3530 log(DEBUG,"zero length new nick passed to handle_nick");
3535 log(DEBUG,"invalid user passed to handle_nick");
3540 log(DEBUG,"invalid old nick passed to handle_nick");
3543 if (!strcasecmp(user->nick,parameters[0]))
3545 log(DEBUG,"old nick is new nick, skipping");
3550 if (strlen(parameters[0]) > 1)
3552 if (parameters[0][0] == ':')
3557 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
3559 WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
3563 if (isnick(parameters[0]) == 0)
3565 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
3569 if (user->registered == 7)
3571 WriteCommon(user,"NICK %s",parameters[0]);
3574 /* change the nick of the user in the users_hash */
3575 user = ReHashNick(user->nick, parameters[0]);
3576 /* actually change the nick within the record */
3578 if (!user->nick) return;
3580 strncpy(user->nick, parameters[0],NICKMAX);
3582 log(DEBUG,"new nick set: %s",user->nick);
3584 if (user->registered < 3)
3585 user->registered = (user->registered | 2);
3586 if (user->registered == 3)
3588 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3591 log(DEBUG,"exit nickchange: %s",user->nick);
3594 int process_parameters(char **command_p,char *parameters)
3599 q = strlen(parameters);
3602 /* no parameters, command_p invalid! */
3605 if (parameters[0] == ':')
3607 command_p[0] = parameters+1;
3612 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
3614 /* only one parameter */
3615 command_p[0] = parameters;
3616 if (parameters[0] == ':')
3618 if (strchr(parameters,' ') != NULL)
3626 command_p[j++] = parameters;
3627 for (i = 0; i <= q; i++)
3629 if (parameters[i] == ' ')
3631 command_p[j++] = parameters+i+1;
3632 parameters[i] = '\0';
3633 if (command_p[j-1][0] == ':')
3635 *command_p[j-1]++; /* remove dodgy ":" */
3637 /* parameter like this marks end of the sequence */
3641 return j; /* returns total number of items in the list */
3644 void process_command(userrec *user, char* cmd)
3648 char *command_p[127];
3649 char p[MAXBUF], temp[MAXBUF];
3650 int i, j, items, cmd_found;
3652 for (int i = 0; i < 127; i++)
3653 command_p[i] = NULL;
3663 if (!strcmp(cmd,""))
3670 FOREACH_MOD OnServerRaw(temp,true);
3671 const char* cmd2 = temp.c_str();
3672 sprintf(cmd,"%s",cmd2);
3674 if (!strchr(cmd,' '))
3676 /* no parameters, lets skip the formalities and not chop up
3679 command_p[0] = NULL;
3681 for (int i = 0; i <= strlen(cmd); i++)
3683 cmd[i] = toupper(cmd[i]);
3690 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
3691 for (i = 0; i < strlen(temp); i++)
3693 if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
3699 /* split the full string into a command plus parameters */
3703 if (strchr(cmd,' '))
3705 for (i = 0; i <= strlen(cmd); i++)
3707 /* capitalise the command ONLY, leave params intact */
3708 cmd[i] = toupper(cmd[i]);
3709 /* are we nearly there yet?! :P */
3713 parameters = cmd+i+1;
3721 for (i = 0; i <= strlen(cmd); i++)
3723 cmd[i] = toupper(cmd[i]);
3731 for (i = 0; i != cmdlist.size(); i++)
3733 if (strcmp(cmdlist[i].command,""))
3735 if (!strcmp(command, cmdlist[i].command))
3739 if (strcmp(parameters,""))
3741 items = process_parameters(command_p,parameters);
3746 command_p[0] = NULL;
3752 command_p[0] = NULL;
3757 user->idle_lastmsg = time(NULL);
3758 /* activity resets the ping pending timer */
3759 user->nping = time(NULL) + 120;
3760 if ((items) < cmdlist[i].min_params)
3762 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
3763 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
3766 if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
3768 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
3769 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
3773 /* if the command isnt USER, PASS, or NICK, and nick is empty,
3775 if ((strcmp(command,"USER")) && (strcmp(command,"NICK")) && (strcmp(command,"PASS")))
3777 if ((!isnick(user->nick)) || (user->registered != 7))
3779 log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3780 WriteServ(user->fd,"451 %s :You have not registered",command);
3784 if ((user->registered == 7) || (!strcmp(command,"USER")) || (!strcmp(command,"NICK")) || (!strcmp(command,"PASS")))
3786 log(DEBUG,"process_command: handler: %s %s %d",user->nick,command,items);
3787 if (cmdlist[i].handler_function)
3789 /* ikky /stats counters */
3794 user->bytes_in += strlen(temp);
3797 cmdlist[i].use_count++;
3798 cmdlist[i].total_bytes+=strlen(temp);
3801 /* WARNING: nothing may come after the
3802 * command handler call, as the handler
3803 * may free the user structure! */
3805 cmdlist[i].handler_function(command_p,items,user);
3811 log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3812 WriteServ(user->fd,"451 %s :You have not registered",command);
3820 if ((!cmd_found) && (user))
3822 log(DEBUG,"process_command: not in table: %s %s",user->nick,command);
3823 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
3828 void createcommand(char* cmd, handlerfunc f, char flags, int minparams)
3831 /* create the command and push it onto the table */
3832 strcpy(comm.command,cmd);
3833 comm.handler_function = f;
3834 comm.flags_needed = flags;
3835 comm.min_params = minparams;
3837 comm.total_bytes = 0;
3838 cmdlist.push_back(comm);
3841 void SetupCommandTable(void)
3843 createcommand("USER",handle_user,0,4);
3844 createcommand("NICK",handle_nick,0,1);
3845 createcommand("QUIT",handle_quit,0,1);
3846 createcommand("VERSION",handle_version,0,0);
3847 createcommand("PING",handle_ping,0,1);
3848 createcommand("PONG",handle_pong,0,1);
3849 createcommand("ADMIN",handle_admin,0,0);
3850 createcommand("PRIVMSG",handle_privmsg,0,2);
3851 createcommand("INFO",handle_info,0,0);
3852 createcommand("TIME",handle_time,0,0);
3853 createcommand("WHOIS",handle_whois,0,1);
3854 createcommand("WALLOPS",handle_wallops,'o',1);
3855 createcommand("NOTICE",handle_notice,0,2);
3856 createcommand("JOIN",handle_join,0,1);
3857 createcommand("NAMES",handle_names,0,1);
3858 createcommand("PART",handle_part,0,1);
3859 createcommand("KICK",handle_kick,0,2);
3860 createcommand("MODE",handle_mode,0,1);
3861 createcommand("TOPIC",handle_topic,0,1);
3862 createcommand("WHO",handle_who,0,1);
3863 createcommand("MOTD",handle_motd,0,0);
3864 createcommand("RULES",handle_join,0,0);
3865 createcommand("OPER",handle_oper,0,2);
3866 createcommand("LIST",handle_list,0,0);
3867 createcommand("DIE",handle_die,'o',1);
3868 createcommand("RESTART",handle_restart,'o',1);
3869 createcommand("KILL",handle_kill,'o',2);
3870 createcommand("REHASH",handle_rehash,'o',0);
3871 createcommand("LUSERS",handle_lusers,0,0);
3872 createcommand("STATS",handle_stats,0,1);
3873 createcommand("USERHOST",handle_userhost,0,1);
3874 createcommand("AWAY",handle_away,0,0);
3875 createcommand("ISON",handle_ison,0,0);
3876 createcommand("SUMMON",handle_summon,0,0);
3877 createcommand("USERS",handle_users,0,0);
3878 createcommand("INVITE",handle_invite,0,2);
3879 createcommand("PASS",handle_pass,0,1);
3880 createcommand("TRACE",handle_trace,'o',0);
3881 createcommand("WHOWAS",handle_whowas,0,1);
3882 createcommand("CONNECT",handle_connect,'o',2);
3883 createcommand("SQUIT",handle_squit,'o',1);
3886 void process_buffer(userrec *user)
3894 if (!strcmp(user->inbuf,""))
3898 strncpy(cmd,user->inbuf,MAXBUF);
3899 if (!strcmp(cmd,""))
3903 if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
3905 cmd[strlen(cmd)-1] = '\0';
3907 if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
3909 cmd[strlen(cmd)-1] = '\0';
3911 strcpy(user->inbuf,"");
3912 if (!strcmp(cmd,""))
3916 log(DEBUG,"InspIRCd: processing: %s %s",user->nick,cmd);
3917 process_command(user,cmd);
3920 void handle_link_packet(char* udp_msg, char* udp_host, int udp_port, serverrec *serv)
3926 struct sockaddr_in client, server;
3927 char addrs[MAXBUF][255];
3928 int openSockfd[MAXSOCKS], incomingSockfd, result = TRUE;
3930 int count = 0, scanDetectTrigger = TRUE, showBanner = FALSE;
3931 int selectResult = 0;
3932 char *temp, configToken[MAXBUF], stuff[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
3933 char resolvedHost[MAXBUF];
3937 log(DEBUG,"InspIRCd: startup: begin");
3941 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
3943 log(DEBUG,"InspIRCd: startup: not starting with UID 0!");
3945 SetupCommandTable();
3946 log(DEBUG,"InspIRCd: startup: default command table set up");
3949 if (strcmp(DieValue,""))
3951 printf("WARNING: %s\n\n",DieValue);
3954 log(DEBUG,"InspIRCd: startup: read config");
3956 int count2 = 0, count3 = 0;
3957 for (count = 0; count < ConfValueEnum("bind"); count++)
3959 ConfValue("bind","port",count,configToken);
3960 ConfValue("bind","address",count,Addr);
3961 ConfValue("bind","type",count,Type);
3962 if (!strcmp(Type,"clients"))
3964 ports[count2] = atoi(configToken);
3965 strcpy(addrs[count2],Addr);
3970 char Default[MAXBUF];
3971 strcpy(Default,"no");
3972 ConfValue("bind","default",count,Default);
3973 if (strchr(Default,'y'))
3975 defaultRoute = count3;
3976 log(DEBUG,"InspIRCd: startup: binding '%s:%s' is default server route",Addr,configToken);
3978 me[count3] = new serverrec(ServerName,100L,false);
3979 me[count3]->CreateListener(Addr,atoi(configToken));
3982 log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
3985 UDPportCount = count3;
3987 log(DEBUG,"InspIRCd: startup: read %d total client ports and %d total server ports",portCount,UDPportCount);
3989 log(DEBUG,"InspIRCd: startup: InspIRCd is now running!");
3992 for (count = 0; count < ConfValueEnum("module"); count++)
3994 char modfile[MAXBUF];
3995 ConfValue("module","name",count,configToken);
3996 sprintf(modfile,"%s/%s",MOD_PATH,configToken);
3997 printf("Loading module... \033[1;37m%s\033[0;37m\n",modfile);
3998 log(DEBUG,"InspIRCd: startup: Loading module: %s",modfile);
4000 factory[count] = new ircd_module(modfile);
4001 if (factory[count]->LastError())
4003 log(DEBUG,"Unable to load %s: %s",modfile,factory[count]->LastError());
4004 sprintf("Unable to load %s: %s\nExiting...\n",modfile,factory[count]->LastError());
4007 if (factory[count]->factory)
4009 modules[count] = factory[count]->factory->CreateModule();
4010 /* save the module and the module's classfactory, if
4011 * this isnt done, random crashes can occur :/ */
4015 log(DEBUG,"Unable to load %s",modfile);
4016 sprintf("Unable to load %s\nExiting...\n",modfile);
4020 MODCOUNT = count - 1;
4021 log(DEBUG,"Total loaded modules: %d",MODCOUNT+1);
4023 servers = new server_list;
4026 printf("\nInspIRCd is now running!\n");
4028 startup_time = time(NULL);
4030 if (DaemonSeed() == ERROR)
4032 log(DEBUG,"InspIRCd: startup: can't daemonise");
4033 printf("ERROR: could not go into daemon mode. Shutting down.\n");
4038 /* setup select call */
4039 FD_ZERO(&selectFds);
4040 log(DEBUG,"InspIRCd: startup: zero selects");
4042 for (count = 0; count < portCount; count++)
4044 if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
4046 log(DEBUG,"InspIRCd: startup: bad fd %d",openSockfd[boundPortCount]);
4049 if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR)
4051 log(DEBUG,"InspIRCd: startup: failed to bind port %d",ports[count]);
4053 else /* well we at least bound to one socket so we'll continue */
4059 log(DEBUG,"InspIRCd: startup: total bound ports %d",boundPortCount);
4061 /* if we didn't bind to anything then abort */
4062 if (boundPortCount == 0)
4064 log(DEBUG,"InspIRCd: startup: no ports bound, bailing!");
4068 length = sizeof (client);
4069 int flip_flop = 0, udp_port = 0;
4070 char udp_msg[MAXBUF], udp_host[MAXBUF];
4072 /* main loop for multiplexing/resetting */
4075 /* set up select call */
4076 for (count = 0; count < boundPortCount; count++)
4078 FD_SET (openSockfd[count], &selectFds);
4081 /* added timeout! select was waiting forever... wank... :/ */
4092 selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv);
4094 for (int x = 0; x != UDPportCount; x++)
4096 if (me[x]->RecvPacket(udp_msg, udp_host, udp_port))
4098 FOREACH_MOD OnPacketReceive(udp_msg);
4099 WriteOpers("UDP Link Packet: '%s' from %s:%d:%d [route%d]",udp_msg,udp_host,udp_port,me[x]->port,x);
4100 // Packets must go back via the route they arrived on :)
4101 handle_link_packet(udp_msg, udp_host, udp_port, me[x]);
4105 for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++)
4109 if (!count2->second) break;
4112 if (count2->second->fd)
4114 if (((time(NULL)) > count2->second->nping) && (isnick(count2->second->nick)) && (count2->second->registered == 7))
4116 if (!count2->second->lastping)
4118 log(DEBUG,"InspIRCd: ping timeout: %s",count2->second->nick);
4119 kill_link(count2->second,"Ping timeout");
4122 Write(count2->second->fd,"PING :%s",ServerName);
4123 log(DEBUG,"InspIRCd: pinging: %s",count2->second->nick);
4124 count2->second->lastping = 0;
4125 count2->second->nping = time(NULL)+120;
4128 result = read(count2->second->fd, data, 1);
4129 // result EAGAIN means nothing read
4130 if (result == EAGAIN)
4136 log(DEBUG,"InspIRCd: Exited: %s",count2->second->nick);
4137 kill_link(count2->second,"Client exited");
4139 else if (result > 0)
4141 strncat(count2->second->inbuf, data, result);
4142 if (strchr(count2->second->inbuf, '\n') || strchr(count2->second->inbuf, '\r'))
4144 /* at least one complete line is waiting to be processed */
4145 if (!count2->second->fd)
4149 process_buffer(count2->second);
4157 /* select is reporting a waiting socket. Poll them all to find out which */
4158 if (selectResult > 0)
4160 char target[MAXBUF], resolved[MAXBUF];
4161 for (count = 0; count < boundPortCount; count++)
4163 if (FD_ISSET (openSockfd[count], &selectFds))
4165 incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
4167 address_cache::iterator iter = IP.find(client.sin_addr);
4168 bool iscached = false;
4169 if (iter == IP.end())
4171 /* ip isn't in cache, add it */
4172 strncpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF);
4173 if(CleanAndResolve(resolved, target) != TRUE)
4175 strncpy(resolved,target,MAXBUF);
4177 /* hostname now in 'target' */
4178 IP[client.sin_addr] = new string(resolved);
4179 /* hostname in cache */
4183 /* found ip (cached) */
4184 strncpy(resolved, iter->second->c_str(), MAXBUF);
4188 if (incomingSockfd < 0)
4190 WriteOpers("*** WARNING: Accept failed on port %d (%s)", ports[count],target);
4191 log(DEBUG,"InspIRCd: accept failed: %d",ports[count]);
4195 AddClient(incomingSockfd, resolved, ports[count], iscached);
4196 log(DEBUG,"InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd);
4205 close (incomingSockfd);