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>
32 #include <ext/hash_map>
41 #include "connection.h"
53 #define nspace __gnu_cxx
58 int LogLevel = DEFAULT;
59 char ServerName[MAXBUF];
61 char ServerDesc[MAXBUF];
62 char AdminName[MAXBUF];
63 char AdminEmail[MAXBUF];
64 char AdminNick[MAXBUF];
66 char restartpass[MAXBUF];
70 char PrefixQuit[MAXBUF];
71 char DieValue[MAXBUF];
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
76 time_t startup_time = time(NULL);
78 extern vector<Module*> modules;
79 extern vector<ircd_module*> factory;
85 template<> struct nspace::hash<in_addr>
87 size_t operator()(const struct in_addr &a) const
90 memcpy(&q,&a,sizeof(size_t));
95 template<> struct nspace::hash<string>
97 size_t operator()(const string &s) const
100 static struct hash<const char *> strhash;
112 bool operator()(const string& s1, const string& s2) const
114 char a[MAXBUF],b[MAXBUF];
115 strcpy(a,s1.c_str());
116 strcpy(b,s2.c_str());
117 return (strcasecmp(a,b) == 0);
122 struct InAddr_HashComp
125 bool operator()(const in_addr &s1, const in_addr &s2) const
130 memcpy(&q,&s1,sizeof(size_t));
131 memcpy(&p,&s2,sizeof(size_t));
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;
145 serverrec* servers[255];
147 user_hash clientlist;
150 command_table cmdlist;
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;
165 long MyKey = C.GenKey();
169 int has_channel(userrec *u, chanrec *c);
170 int usercount(chanrec *c);
171 int usercount_i(chanrec *c);
172 void update_stats_l(int fd,int data_out);
173 char* Passwd(userrec *user);
174 bool IsDenied(userrec *user);
175 void AddWhoWas(userrec* u);
178 void safedelete(userrec *p)
182 log(DEBUG,"deleting %s %s %s %s",p->nick,p->ident,p->dhost,p->fullname);
183 log(DEBUG,"safedelete(userrec*): pointer is safe to delete");
188 log(DEBUG,"safedelete(userrec*): unsafe pointer operation squished");
192 void safedelete(chanrec *p)
197 log(DEBUG,"safedelete(chanrec*): pointer is safe to delete");
201 log(DEBUG,"safedelete(chanrec*): unsafe pointer operation squished");
206 /* chop a string down to 512 characters and preserve linefeed (irc max
213 FOREACH_MOD OnServerRaw(temp,false);
214 const char* str2 = temp.c_str();
215 sprintf(str,"%s",str2);
218 if (strlen(str) > 512)
227 std::string getservername()
232 std::string getserverdesc()
237 std::string getnetworkname()
242 std::string getadminname()
247 std::string getadminemail()
252 std::string getadminnick()
257 void log(int level,char *text, ...)
259 char textbuffer[MAXBUF];
263 struct tm * timeinfo;
264 if (level < LogLevel)
268 timeinfo = localtime (&rawtime);
270 f = fopen("ircd.log","a+");
274 va_start (argsPtr, text);
275 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
277 strcpy(b,asctime(timeinfo));
278 b[strlen(b)-1] = ':';
279 fprintf(f,"%s %s\n",b,textbuffer);
284 printf("Can't write log file, bailing!!!");
289 void readfile(file_cache &F, const char* fname)
292 char linebuf[MAXBUF];
294 log(DEBUG,"readfile: loading %s",fname);
296 file = fopen(fname,"r");
301 fgets(linebuf,sizeof(linebuf),file);
302 linebuf[strlen(linebuf)-1]='\0';
303 if (!strcmp(linebuf,""))
309 F.push_back(linebuf);
316 log(DEBUG,"readfile: failed to load file: %s",fname);
318 log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
321 void ReadConfig(void)
323 char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF];
326 ConfValue("server","name",0,ServerName);
327 ConfValue("server","description",0,ServerDesc);
328 ConfValue("server","network",0,Network);
329 ConfValue("admin","name",0,AdminName);
330 ConfValue("admin","email",0,AdminEmail);
331 ConfValue("admin","nick",0,AdminNick);
332 ConfValue("files","motd",0,motd);
333 ConfValue("files","rules",0,rules);
334 ConfValue("power","diepass",0,diepass);
335 ConfValue("power","pause",0,pauseval);
336 ConfValue("power","restartpass",0,restartpass);
337 ConfValue("options","prefixquit",0,PrefixQuit);
338 ConfValue("die","value",0,DieValue);
339 ConfValue("options","loglevel",0,dbg);
340 if (!strcmp(dbg,"debug"))
342 if (!strcmp(dbg,"verbose"))
344 if (!strcmp(dbg,"default"))
346 if (!strcmp(dbg,"sparse"))
348 if (!strcmp(dbg,"none"))
350 readfile(RULES,rules);
351 log(DEBUG,"Reading connect classes");
353 for (int i = 0; i < ConfValueEnum("connect"); i++)
356 ConfValue("connect","allow",i,Value);
357 if (strcmp(Value,""))
359 strcpy(c.host,Value);
362 ConfValue("connect","password",i,Value);
363 strcpy(c.pass,Value);
364 Classes.push_back(c);
365 log(DEBUG,"Read connect class type ALLOW, host=%s password=%s",c.host,c.pass);
369 ConfValue("connect","deny",i,Value);
370 strcpy(c.host,Value);
372 Classes.push_back(c);
373 log(DEBUG,"Read connect class type DENY, host=%s",c.host);
382 log(DEBUG,"Blocking: %d",s);
383 flags = fcntl(s, F_GETFL, 0);
384 fcntl(s, F_SETFL, flags ^ O_NONBLOCK);
387 void NonBlocking(int s)
390 log(DEBUG,"NonBlocking: %d",s);
391 flags = fcntl(s, F_GETFL, 0);
392 fcntl(s, F_SETFL, flags | O_NONBLOCK);
396 int CleanAndResolve (char *resolvedHost, const char *unresolvedHost)
398 struct hostent *hostPtr = NULL;
401 memset (resolvedHost, '\0',MAXBUF);
402 if(unresolvedHost == NULL)
404 if ((inet_aton(unresolvedHost,&addr)) == 0)
406 hostPtr = gethostbyaddr ((char *)&addr.s_addr,sizeof(addr.s_addr),AF_INET);
408 snprintf(resolvedHost,MAXBUF,"%s",hostPtr->h_name);
410 snprintf(resolvedHost,MAXBUF,"%s",unresolvedHost);
414 /* write formatted text to a socket, in same format as printf */
416 void Write(int sock,char *text, ...)
418 char textbuffer[MAXBUF];
422 va_start (argsPtr, text);
423 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
425 sprintf(tb,"%s\r\n",textbuffer);
427 write(sock,tb,strlen(tb));
428 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
431 /* write a server formatted numeric response to a single socket */
433 void WriteServ(int sock, char* text, ...)
435 char textbuffer[MAXBUF],tb[MAXBUF];
437 va_start (argsPtr, text);
439 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
441 sprintf(tb,":%s %s\r\n",ServerName,textbuffer);
443 write(sock,tb,strlen(tb));
444 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
447 /* write text from an originating user to originating user */
449 void WriteFrom(int sock, userrec *user,char* text, ...)
451 char textbuffer[MAXBUF],tb[MAXBUF];
453 va_start (argsPtr, text);
455 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
457 sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer);
459 write(sock,tb,strlen(tb));
460 update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */
463 /* write text to an destination user from a source user (e.g. user privmsg) */
465 void WriteTo(userrec *source, userrec *dest,char *data, ...)
467 char textbuffer[MAXBUF],tb[MAXBUF];
469 va_start (argsPtr, data);
470 if ((!dest) || (!source))
474 vsnprintf(textbuffer, MAXBUF, data, argsPtr);
477 WriteFrom(dest->fd,source,"%s",textbuffer);
480 /* write formatted text from a source user to all users on a channel
481 * including the sender (NOT for privmsg, notice etc!) */
483 void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...)
485 char textbuffer[MAXBUF];
487 va_start (argsPtr, text);
488 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
490 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
492 if (has_channel(i->second,Ptr))
494 WriteTo(user,i->second,"%s",textbuffer);
499 /* write formatted text from a source user to all users on a channel except
500 * for the sender (for privmsg etc) */
502 void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...)
504 char textbuffer[MAXBUF];
506 va_start (argsPtr, text);
507 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
510 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
512 if (has_channel(i->second,Ptr) && (user != i->second))
514 WriteTo(user,i->second,"%s",textbuffer);
519 int c_count(userrec* u)
522 for (int i =0; i != MAXCHANS; i++)
523 if (u->chans[i].channel)
529 /* return 0 or 1 depending if users u and u2 share one or more common channels
530 * (used by QUIT, NICK etc which arent channel specific notices) */
532 int common_channels(userrec *u, userrec *u2)
541 for (i = 0; i != MAXCHANS; i++)
543 for (z = 0; z != MAXCHANS; z++)
545 if ((u->chans[i].channel == u2->chans[z].channel) && (u->chans[i].channel) && (u2->chans[z].channel) && (u->registered == 7) && (u2->registered == 7))
547 if ((c_count(u)) && (c_count(u2)))
557 /* write a formatted string to all users who share at least one common
558 * channel, including the source user e.g. for use in NICK */
560 void WriteCommon(userrec *u, char* text, ...)
562 char textbuffer[MAXBUF];
564 va_start (argsPtr, text);
565 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
568 WriteFrom(u->fd,u,"%s",textbuffer);
570 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
572 if (common_channels(u,i->second) && (i->second != u))
574 WriteFrom(i->second->fd,u,"%s",textbuffer);
579 /* write a formatted string to all users who share at least one common
580 * channel, NOT including the source user e.g. for use in QUIT */
582 void WriteCommonExcept(userrec *u, char* text, ...)
584 char textbuffer[MAXBUF];
586 va_start (argsPtr, text);
587 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
590 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
592 if ((common_channels(u,i->second)) && (u != i->second))
594 WriteFrom(i->second->fd,u,"%s",textbuffer);
599 void WriteOpers(char* text, ...)
601 char textbuffer[MAXBUF];
603 va_start (argsPtr, text);
604 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
607 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
609 if (strchr(i->second->modes,'o'))
611 if (strchr(i->second->modes,'s'))
613 // send server notices to all with +s
614 // (TODO: needs SNOMASKs)
615 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
621 void WriteWallOps(userrec *source, char* text, ...)
624 char textbuffer[MAXBUF];
626 va_start (argsPtr, text);
627 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
630 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
632 if (strchr(i->second->modes,'w'))
634 WriteTo(source,i->second,"WALLOPS %s",textbuffer);
639 /* convert a string to lowercase. Note following special circumstances
640 * taken from RFC 1459. Many "official" server branches still hold to this
641 * rule so i will too;
643 * Because of IRC's scandanavian origin, the characters {}| are
644 * considered to be the lower case equivalents of the characters []\,
645 * respectively. This is a critical issue when determining the
646 * equivalence of two nicknames.
649 void strlower(char *n)
655 for (int i = 0; i != strlen(n); i++)
657 n[i] = tolower(n[i]);
667 /* verify that a user's ident and nickname is valid */
669 int isident(const char* n)
682 for (i = 0; i != strlen(n); i++)
684 if ((n[i] < 33) || (n[i] > 125))
688 /* can't occur ANYWHERE in an Ident! */
689 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
698 int isnick(const char* n)
710 if (strlen(n) > NICKMAX-1)
714 for (i = 0; i != strlen(n); i++)
716 if ((n[i] < 33) || (n[i] > 125))
720 /* can't occur ANYWHERE in a nickname! */
721 if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i]))
725 /* can't occur as the first char of a nickname... */
726 if ((strchr("0123456789",n[i])) && (!i))
734 /* Find a user record by nickname and return a pointer to it */
736 userrec* Find(string nick)
738 user_hash::iterator iter = clientlist.find(nick);
740 if (iter == clientlist.end())
741 /* Couldn't find it */
747 void update_stats_l(int fd,int data_out) /* add one line-out to stats L for this fd */
749 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
751 if (i->second->fd == fd)
753 i->second->bytes_out+=data_out;
754 i->second->cmds_out++;
760 /* find a channel record by channel name and return a pointer to it */
762 chanrec* FindChan(const char* chan)
764 chan_hash::iterator iter = chanlist.find(chan);
766 if (iter == chanlist.end())
767 /* Couldn't find it */
774 void purge_empty_chans(void)
776 int go_again = 1, purge = 0;
781 for (chan_hash::iterator i = chanlist.begin(); i != chanlist.end(); i++)
784 if (!usercount(i->second))
786 /* kill the record */
787 if (i != chanlist.end())
789 log(DEBUG,"del_channel: destroyed: %s",i->second->name);
800 log(DEBUG,"completed channel purge, killed %d",purge);
803 /* returns the status character for a given user on a channel, e.g. @ for op,
804 * % for halfop etc. If the user has several modes set, the highest mode
805 * the user has must be returned. */
807 char* cmode(userrec *user, chanrec *chan)
810 for (i = 0; i != MAXCHANS; i++)
812 if ((user->chans[i].channel == chan) && (chan != NULL))
814 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
818 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
822 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
831 char scratch[MAXMODES];
833 char* chanmodes(chanrec *chan)
836 if (chan->noexternal)
844 if (strcmp(chan->key,""))
852 if (chan->inviteonly)
868 if (strcmp(chan->key,""))
871 strcat(scratch,chan->key);
876 sprintf(foo," %d",chan->limit);
879 log(DEBUG,"chanmodes: %s %s",chan->name,scratch);
883 /* returns the status value for a given user on a channel, e.g. STATUS_OP for
884 * op, STATUS_VOICE for voice etc. If the user has several modes set, the
885 * highest mode the user has must be returned. */
887 int cstatus(userrec *user, chanrec *chan)
890 for (i = 0; i != MAXCHANS; i++)
892 if ((user->chans[i].channel == chan) && (chan != NULL))
894 if ((user->chans[i].uc_modes & UCMODE_OP) > 0)
898 if ((user->chans[i].uc_modes & UCMODE_HOP) > 0)
902 if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0)
906 return STATUS_NORMAL;
912 /* compile a userlist of a channel into a string, each nick seperated by
913 * spaces and op, voice etc status shown as @ and + */
915 void userlist(userrec *user,chanrec *c)
917 sprintf(list,"353 %s = %s :", user->nick, c->name);
918 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
920 if (has_channel(i->second,c))
922 if (isnick(i->second->nick))
924 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
926 /* user is +i, and source not on the channel, does not show
927 * nick in NAMES list */
930 strcat(list,cmode(i->second,c));
931 strcat(list,i->second->nick);
933 if (strlen(list)>(480-NICKMAX))
935 /* list overflowed into
936 * multiple numerics */
937 WriteServ(user->fd,list);
938 sprintf(list,"353 %s = %s :", user->nick, c->name);
943 /* if whats left in the list isnt empty, send it */
944 if (list[strlen(list)-1] != ':')
946 WriteServ(user->fd,list);
950 /* return a count of the users on a specific channel accounting for
951 * invisible users who won't increase the count. e.g. for /LIST */
953 int usercount_i(chanrec *c)
959 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
961 if (has_channel(i->second,c))
963 if (isnick(i->second->nick))
965 if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
967 /* user is +i, and source not on the channel, does not show
968 * nick in NAMES list */
975 log(DEBUG,"usercount_i: %s %d",c->name,count);
980 int usercount(chanrec *c)
986 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
990 if (has_channel(i->second,c))
992 if ((isnick(i->second->nick)) && (i->second->registered == 7))
999 log(DEBUG,"usercount: %s %d",c->name,count);
1004 /* add a channel to a user, creating the record for it if needed and linking
1005 * it to the user record */
1007 chanrec* add_channel(userrec *user, char* cname, char* key)
1013 if ((!cname) || (!user))
1017 if (strlen(cname) > CHANMAX-1)
1019 cname[CHANMAX-1] = '\0';
1022 log(DEBUG,"add_channel: %s %s",user->nick,cname);
1024 if ((has_channel(user,FindChan(cname))) && (FindChan(cname)))
1026 return NULL; // already on the channel!
1029 if (!FindChan(cname))
1031 /* create a new one */
1032 log(DEBUG,"add_channel: creating: %s",cname);
1034 chanlist[cname] = new chanrec();
1036 strcpy(chanlist[cname]->name, cname);
1037 chanlist[cname]->topiclock = 1;
1038 chanlist[cname]->noexternal = 1;
1039 chanlist[cname]->created = time(NULL);
1040 strcpy(chanlist[cname]->topic, "");
1041 strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
1042 chanlist[cname]->topicset = 0;
1043 Ptr = chanlist[cname];
1044 log(DEBUG,"add_channel: created: %s",cname);
1045 /* set created to 2 to indicate user
1046 * is the first in the channel
1047 * and should be given ops */
1053 /* channel exists, just fish out a pointer to its struct */
1054 Ptr = FindChan(cname);
1057 log(DEBUG,"add_channel: joining to: %s",Ptr->name);
1058 if (strcmp(Ptr->key,""))
1060 log(DEBUG,"add_channel: %s has key %s",Ptr->name,Ptr->key);
1063 log(DEBUG,"add_channel: no key given in JOIN");
1064 WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
1069 log(DEBUG,"key at %p is %s",key,key);
1070 if (strcasecmp(key,Ptr->key))
1072 log(DEBUG,"add_channel: bad key given in JOIN");
1073 WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
1078 log(DEBUG,"add_channel: no key");
1080 if (Ptr->inviteonly)
1082 log(DEBUG,"add_channel: channel is +i");
1083 if (user->IsInvited(Ptr->name))
1085 /* user was invited to channel */
1086 /* there may be an optional channel NOTICE here */
1090 WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
1094 log(DEBUG,"add_channel: channel is not +i");
1098 if (usercount(Ptr) == Ptr->limit)
1100 WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
1105 log(DEBUG,"add_channel: about to walk banlist");
1107 /* check user against the channel banlist */
1108 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1110 if (match(user->GetFullHost(),i->data))
1112 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
1117 log(DEBUG,"add_channel: bans checked");
1119 user->RemoveInvite(Ptr->name);
1121 log(DEBUG,"add_channel: invites removed");
1127 log(DEBUG,"Passed channel checks");
1129 for (i =0; i != MAXCHANS; i++)
1131 if (user->chans[i].channel == NULL)
1133 log(DEBUG,"Adding into their channel list");
1137 /* first user in is given ops */
1138 user->chans[i].uc_modes = UCMODE_OP;
1142 user->chans[i].uc_modes = 0;
1144 user->chans[i].channel = Ptr;
1145 WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
1147 log(DEBUG,"Sent JOIN to client");
1151 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
1152 WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
1155 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
1156 WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr));
1157 WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1158 FOREACH_MOD OnUserJoin(user,Ptr);
1162 log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
1163 WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
1167 /* remove a channel from a users record, and remove the record from memory
1168 * if the channel has become empty */
1170 chanrec* del_channel(userrec *user, char* cname, char* reason)
1176 if ((!cname) || (!user))
1181 Ptr = FindChan(cname);
1188 FOREACH_MOD OnUserPart(user,Ptr);
1189 log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
1191 for (i =0; i != MAXCHANS; i++)
1193 /* zap it from the channel list of the user */
1194 if (user->chans[i].channel == Ptr)
1198 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
1202 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
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 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
1234 if ((!Ptr) || (!user) || (!src))
1239 log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
1241 if (!has_channel(user,Ptr))
1243 WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
1246 if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
1248 if (cstatus(src,Ptr) == STATUS_HOP)
1250 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
1254 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator",src->nick, Ptr->name);
1260 for (i =0; i != MAXCHANS; i++)
1262 /* zap it from the channel list of the user */
1263 if (user->chans[i].channel == Ptr)
1265 WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
1266 user->chans[i].uc_modes = 0;
1267 user->chans[i].channel = NULL;
1268 log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
1273 /* if there are no users left on the channel */
1274 if (!usercount(Ptr))
1276 chan_hash::iterator iter = chanlist.find(Ptr->name);
1278 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
1280 /* kill the record */
1281 if (iter != chanlist.end())
1283 log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
1284 delete iter->second;
1285 chanlist.erase(iter);
1291 /* returns 1 if user u has channel c in their record, 0 if not */
1293 int has_channel(userrec *u, chanrec *c)
1301 for (i =0; i != MAXCHANS; i++)
1303 if (u->chans[i].channel == c)
1311 int give_ops(userrec *user,char *dest,chanrec *chan,int status)
1316 if ((!user) || (!dest) || (!chan))
1320 if (status != STATUS_OP)
1322 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1329 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1335 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1340 for (i = 0; i != MAXCHANS; i++)
1342 if ((d->chans[i].channel == chan) && (chan != NULL))
1344 if (d->chans[i].uc_modes & UCMODE_OP)
1346 /* mode already set on user, dont allow multiple */
1349 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
1350 log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
1358 int give_hops(userrec *user,char *dest,chanrec *chan,int status)
1363 if ((!user) || (!dest) || (!chan))
1367 if (status != STATUS_OP)
1369 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1377 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1382 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1387 for (i = 0; i != MAXCHANS; i++)
1389 if ((d->chans[i].channel == chan) && (chan != NULL))
1391 if (d->chans[i].uc_modes & UCMODE_HOP)
1393 /* mode already set on user, dont allow multiple */
1396 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
1397 log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
1405 int give_voice(userrec *user,char *dest,chanrec *chan,int status)
1410 if ((!user) || (!dest) || (!chan))
1414 if (status < STATUS_HOP)
1416 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1424 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1429 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1434 for (i = 0; i != MAXCHANS; i++)
1436 if ((d->chans[i].channel == chan) && (chan != NULL))
1438 if (d->chans[i].uc_modes & UCMODE_VOICE)
1440 /* mode already set on user, dont allow multiple */
1443 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
1444 log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
1452 int take_ops(userrec *user,char *dest,chanrec *chan,int status)
1457 if ((!user) || (!dest) || (!chan))
1461 if (status != STATUS_OP)
1463 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1471 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1476 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1481 for (i = 0; i != MAXCHANS; i++)
1483 if ((d->chans[i].channel == chan) && (chan != NULL))
1485 if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
1487 /* mode already set on user, dont allow multiple */
1490 d->chans[i].uc_modes ^= UCMODE_OP;
1491 log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
1499 int take_hops(userrec *user,char *dest,chanrec *chan,int status)
1504 if ((!user) || (!dest) || (!chan))
1508 if (status != STATUS_OP)
1510 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
1518 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1523 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1528 for (i = 0; i != MAXCHANS; i++)
1530 if ((d->chans[i].channel == chan) && (chan != NULL))
1532 if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
1534 /* mode already set on user, dont allow multiple */
1537 d->chans[i].uc_modes ^= UCMODE_HOP;
1538 log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
1546 int take_voice(userrec *user,char *dest,chanrec *chan,int status)
1551 if ((!user) || (!dest) || (!chan))
1555 if (status < STATUS_HOP)
1557 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name);
1565 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1570 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
1575 for (i = 0; i != MAXCHANS; i++)
1577 if ((d->chans[i].channel == chan) && (chan != NULL))
1579 if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
1581 /* mode already set on user, dont allow multiple */
1584 d->chans[i].uc_modes ^= UCMODE_VOICE;
1585 log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
1593 void TidyBan(char *ban)
1595 char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF];
1599 char* pos_of_pling = strchr(temp,'!');
1600 char* pos_of_at = strchr(temp,'@');
1602 pos_of_pling[0] = '\0';
1603 pos_of_at[0] = '\0';
1607 strncpy(NICK,temp,NICKMAX);
1608 strncpy(IDENT,pos_of_pling,IDENTMAX+1);
1609 strncpy(HOST,pos_of_at,160);
1611 sprintf(ban,"%s!%s@%s",NICK,IDENT,HOST);
1614 int add_ban(userrec *user,char *dest,chanrec *chan,int status)
1617 if ((!user) || (!dest) || (!chan))
1619 if (strchr(dest,'!')==0)
1621 if (strchr(dest,'@')==0)
1623 for (int i = 0; i < strlen(dest); i++)
1626 for (int i = 0; i < strlen(dest); i++)
1630 for (int i = 0; i < strlen(dest); i++)
1636 for (int i = 0; i < strlen(dest); i++)
1641 log(DEBUG,"add_ban: %s %s",chan->name,user->nick);
1644 for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1646 if (!strcasecmp(i->data,dest))
1648 // dont allow a user to set the same ban twice
1653 b.set_time = time(NULL);
1654 strncpy(b.data,dest,MAXBUF);
1655 strncpy(b.set_by,user->nick,NICKMAX);
1656 chan->bans.push_back(b);
1660 int take_ban(userrec *user,char *dest,chanrec *chan,int status)
1662 if ((!user) || (!dest) || (!chan))
1667 log(DEBUG,"del_ban: %s %s",chan->name,user->nick);
1668 for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
1670 if (!strcasecmp(i->data,dest))
1672 chan->bans.erase(i);
1679 void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt)
1681 char modelist[MAXBUF];
1682 char outlist[MAXBUF];
1683 char outstr[MAXBUF];
1684 char outpars[32][MAXBUF];
1690 bool k_set = false, l_set = false;
1697 log(DEBUG,"process_modes: start");
1699 strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
1700 /* parameters[2] onwards are parameters for
1701 * modes that require them :) */
1702 strcpy(outlist,"+");
1705 log(DEBUG,"process_modes: modelist: %s",modelist);
1707 for (ptr = 0; ptr < strlen(modelist); ptr++)
1712 log(DEBUG,"process_modes: modechar: %c",modelist[ptr]);
1713 char modechar = modelist[ptr];
1714 switch (modelist[ptr])
1719 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1721 outlist[strlen(outlist)-1] = '-';
1725 strcat(outlist,"-");
1735 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
1737 outlist[strlen(outlist)-1] = '+';
1741 strcat(outlist,"+");
1748 if ((param >= pcnt)) break;
1751 r = give_ops(user,parameters[param++],chan,status);
1755 r = take_ops(user,parameters[param++],chan,status);
1759 strcat(outlist,"o");
1760 strcpy(outpars[pc++],parameters[param-1]);
1765 if ((param >= pcnt)) break;
1768 r = give_hops(user,parameters[param++],chan,status);
1772 r = take_hops(user,parameters[param++],chan,status);
1776 strcat(outlist,"h");
1777 strcpy(outpars[pc++],parameters[param-1]);
1783 if ((param >= pcnt)) break;
1786 r = give_voice(user,parameters[param++],chan,status);
1790 r = take_voice(user,parameters[param++],chan,status);
1794 strcat(outlist,"v");
1795 strcpy(outpars[pc++],parameters[param-1]);
1800 if ((param >= pcnt)) break;
1803 r = add_ban(user,parameters[param++],chan,status);
1807 r = take_ban(user,parameters[param++],chan,status);
1811 strcat(outlist,"b");
1812 strcpy(outpars[pc++],parameters[param-1]);
1817 if ((param >= pcnt))
1825 if (!strcmp(chan->key,""))
1827 strcat(outlist,"k");
1828 strcpy(outpars[pc++],parameters[param++]);
1829 strcpy(chan->key,parameters[param-1]);
1835 /* only allow -k if correct key given */
1836 if (strcmp(chan->key,""))
1838 strcat(outlist,"k");
1839 strcpy(chan->key,"");
1849 strcat(outlist,"l");
1854 if ((param >= pcnt)) break;
1860 bool invalid = false;
1861 for (int i = 0; i < strlen(parameters[param]); i++)
1863 if ((parameters[param][i] < '0') || (parameters[param][i] > '9'))
1868 if (atoi(parameters[param]) < 1)
1876 chan->limit = atoi(parameters[param]);
1879 strcat(outlist,"l");
1880 strcpy(outpars[pc++],parameters[param++]);
1887 if (chan->inviteonly != mdir)
1889 strcat(outlist,"i");
1891 chan->inviteonly = mdir;
1895 if (chan->topiclock != mdir)
1897 strcat(outlist,"t");
1899 chan->topiclock = mdir;
1903 if (chan->noexternal != mdir)
1905 strcat(outlist,"n");
1907 chan->noexternal = mdir;
1911 if (chan->moderated != mdir)
1913 strcat(outlist,"m");
1915 chan->moderated = mdir;
1919 if (chan->secret != mdir)
1921 strcat(outlist,"s");
1922 if (chan->c_private)
1924 chan->c_private = 0;
1927 strcat(outlist,"-p+");
1931 strcat(outlist,"+p-");
1935 chan->secret = mdir;
1939 if (chan->c_private != mdir)
1941 strcat(outlist,"p");
1947 strcat(outlist,"-s+");
1951 strcat(outlist,"+s-");
1955 chan->c_private = mdir;
1961 if (ModeDefined(modelist[ptr],MT_CHANNEL))
1963 if ((ModeDefinedOn(modelist[ptr],MT_CHANNEL)>0) && (mdir))
1965 p.push_back(parameters[param]);
1967 if ((ModeDefinedOff(modelist[ptr],MT_CHANNEL)>0) && (!mdir))
1969 p.push_back(parameters[param]);
1971 for (int i = 0; i <= MODCOUNT; i++)
1973 if (modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p))
1975 char app[] = {modechar, 0};
1976 strcat(outlist, app);
1977 chan->SetCustomMode(modelist[ptr],mdir);
1978 // include parameters in output if mode has them
1979 if ((ModeDefinedOn(modelist[ptr],MT_CHANNEL)>0) || (ModeDefinedOff(modelist[ptr],MT_CHANNEL)>0))
1981 chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
1982 strcpy(outpars[pc++],parameters[param++]);
1993 /* this ensures only the *valid* modes are sent out onto the network */
1994 while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
1996 outlist[strlen(outlist)-1] = '\0';
1998 if (strcmp(outlist,""))
2000 strcpy(outstr,outlist);
2001 for (ptr = 0; ptr < pc; ptr++)
2004 strcat(outstr,outpars[ptr]);
2006 WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
2010 void handle_mode(char **parameters, int pcnt, userrec *user)
2016 char outpars[MAXBUF];
2018 dest = Find(parameters[0]);
2020 if ((dest) && (pcnt == 1))
2022 WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes);
2025 if ((dest) && (pcnt > 1))
2030 if (strchr(user->modes,'o'))
2041 WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
2045 strcpy(outpars,"+");
2048 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
2051 for (i = 0; i < strlen(parameters[1]); i++)
2053 if (parameters[1][i] == '+')
2057 if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
2059 outpars[strlen(outpars)-1] = '+';
2063 strcat(outpars,"+");
2069 if (parameters[1][i] == '-')
2073 if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
2075 outpars[strlen(outpars)-1] = '-';
2079 strcat(outpars,"-");
2087 if (strchr(user->modes,'o'))
2093 if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's'))
2102 if (!strchr(dest->modes,parameters[1][i]))
2104 dest->modes[strlen(dest->modes)+1]='\0';
2105 dest->modes[strlen(dest->modes)] = parameters[1][i];
2106 outpars[strlen(outpars)+1]='\0';
2107 outpars[strlen(outpars)] = parameters[1][i];
2116 outpars[strlen(outpars)+1]='\0';
2117 outpars[strlen(outpars)] = parameters[1][i];
2120 for (q = 0; q < strlen(user->modes); q++)
2122 if (user->modes[q] != parameters[1][i])
2124 moo[0] = user->modes[q];
2129 strcpy(user->modes,temp);
2134 if (strlen(outpars))
2140 while (i < strlen (outpars))
2142 b[z++] = outpars[i++];
2144 if (i<strlen(outpars)-1)
2146 if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
2148 // someones playing silly buggers and trying
2149 // to put a +- or -+ into the line...
2153 if (i == strlen(outpars)-1)
2155 if ((outpars[i] == '-') || (outpars[i] == '+'))
2163 if ((b[z] == '-') || (b[z] == '+'))
2166 if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
2169 WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
2174 Ptr = FindChan(parameters[0]);
2179 /* just /modes #channel */
2180 WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
2181 WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
2187 if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b")))
2190 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
2192 WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
2194 WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
2198 if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
2200 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, Ptr->name);
2204 process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt);
2208 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2212 /* This function pokes and hacks at a parameter list like the following:
2214 * PART #winbot, #darkgalaxy :m00!
2216 * to turn it into a series of individual calls like this:
2218 * PART #winbot :m00!
2219 * PART #darkgalaxy :m00!
2221 * The seperate calls are sent to a callback function provided by the caller
2222 * (the caller will usually call itself recursively). The callback function
2223 * must be a command handler. Calling this function on a line with no list causes
2224 * no action to be taken. You must provide a starting and ending parameter number
2225 * where the range of the list can be found, useful if you have a terminating
2226 * parameter as above which is actually not part of the list, or parameters
2227 * before the actual list as well. This code is used by many functions which
2228 * can function as "one to list" (see the RFC) */
2230 int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins)
2235 char blog[32][MAXBUF];
2236 char blog2[32][MAXBUF];
2237 int i = 0, j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0;
2238 char keystr[MAXBUF];
2241 for (i = 0; i <32; i++)
2244 for (i = 0; i <32; i++)
2245 strcpy(blog2[i],"");
2248 for (i = 0; i <10; i++)
2252 parameters[i] = moo;
2257 if (pcnt > 1) /* we have a key to copy */
2259 strcpy(keystr,parameters[1]);
2263 if (!parameters[start])
2267 if (!strchr(parameters[start],','))
2272 for (i = start; i <= end; i++)
2276 strcat(plist,parameters[i]);
2284 for (i = 0; i < t; i++)
2286 if (plist[i] == ',')
2289 strcpy(blog[j++],param);
2293 strcpy(blog[j++],param);
2296 if ((joins) && (keystr) && (total>0)) // more than one channel and is joining
2301 if ((joins) && (keystr))
2303 if (strchr(keystr,','))
2307 t2 = strlen(keystr);
2308 for (i = 0; i < t2; i++)
2310 if (keystr[i] == ',')
2313 strcpy(blog2[j++],param);
2317 strcpy(blog2[j++],param);
2322 for (j = 0; j < total; j++)
2328 for (q = end; q < pcnt-1; q++)
2330 if (parameters[q+1])
2332 pars[q-end+1] = parameters[q+1];
2335 if ((joins) && (parameters[1]))
2346 /* repeatedly call the function with the hacked parameter list */
2347 if ((joins) && (pcnt > 1))
2351 // pars[1] already set up and containing key from blog2[j]
2356 pars[1] = parameters[1];
2362 fn(pars,pcnt-(end-start),u);
2369 void handle_join(char **parameters, int pcnt, userrec *user)
2374 if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
2376 if (parameters[0][0] == '#')
2378 Ptr = add_channel(user,parameters[0],parameters[1]);
2383 void handle_part(char **parameters, int pcnt, userrec *user)
2389 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
2391 del_channel(user,parameters[0],parameters[1]);
2395 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
2397 del_channel(user,parameters[0],NULL);
2401 void handle_kick(char **parameters, int pcnt, userrec *user)
2403 chanrec* Ptr = FindChan(parameters[0]);
2404 userrec* u = Find(parameters[1]);
2408 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2412 if (!has_channel(u,Ptr))
2414 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
2420 kick_channel(user,u,Ptr,parameters[2]);
2424 kick_channel(user,u,Ptr,user->nick);
2429 void handle_die(char **parameters, int pcnt, userrec *user)
2431 log(DEBUG,"die: %s",user->nick);
2432 if (!strcmp(parameters[0],diepass))
2434 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
2440 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
2444 void handle_restart(char **parameters, int pcnt, userrec *user)
2446 log(DEBUG,"restart: %s",user->nick);
2447 if (!strcmp(parameters[0],restartpass))
2449 WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host);
2452 /* Will finish this later when i can be arsed :) */
2456 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
2461 void kill_link(userrec *user,char* reason)
2463 user_hash::iterator iter = clientlist.find(user->nick);
2465 log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
2466 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
2467 fdatasync(user->fd);
2468 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
2469 FOREACH_MOD OnUserQuit(user);
2470 log(DEBUG,"closing fd %d",user->fd);
2471 /* bugfix, cant close() a nonblocking socket (sux!) */
2472 WriteCommonExcept(user,"QUIT :%s",reason);
2475 NonBlocking(user->fd);
2477 bool do_purge = false;
2479 if (user->registered == 7) {
2484 if (iter != clientlist.end())
2486 log(DEBUG,"deleting user hash value %d",iter->second);
2488 delete iter->second;
2490 clientlist.erase(iter);
2494 purge_empty_chans();
2499 void handle_kill(char **parameters, int pcnt, userrec *user)
2501 userrec *u = Find(parameters[0]);
2502 char killreason[MAXBUF];
2504 log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
2507 WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
2508 sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]);
2509 kill_link(u,killreason);
2513 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2517 void handle_summon(char **parameters, int pcnt, userrec *user)
2519 WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
2522 void handle_users(char **parameters, int pcnt, userrec *user)
2524 WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
2528 // looks up a users password for their connection class (<ALLOW>/<DENY> tags)
2530 char* Passwd(userrec *user)
2532 for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2534 if (match(user->host,i->host) && (i->type == CC_ALLOW))
2542 bool IsDenied(userrec *user)
2544 for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++)
2546 if (match(user->host,i->host) && (i->type == CC_DENY))
2555 void handle_pass(char **parameters, int pcnt, userrec *user)
2557 if (!strcasecmp(parameters[0],Passwd(user)))
2559 user->haspassed = true;
2563 void handle_invite(char **parameters, int pcnt, userrec *user)
2565 userrec* u = Find(parameters[0]);
2566 chanrec* c = FindChan(parameters[1]);
2572 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[1]);
2578 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
2587 if (cstatus(user,c) < STATUS_HOP)
2589 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, c->name);
2593 u->InviteTo(c->name);
2594 WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
2595 WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
2599 void handle_topic(char **parameters, int pcnt, userrec *user)
2605 if (strlen(parameters[0]) <= CHANMAX)
2607 Ptr = FindChan(parameters[0]);
2612 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
2613 WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
2617 WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2622 WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
2628 if (loop_call(handle_topic,parameters,pcnt,user,0,pcnt-2,0))
2630 if (strlen(parameters[0]) <= CHANMAX)
2632 Ptr = FindChan(parameters[0]);
2635 if ((Ptr->topiclock) && (cstatus(user,Ptr)<STATUS_HOP))
2637 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator", user->nick, Ptr->name);
2640 strcpy(Ptr->topic,parameters[1]);
2641 strcpy(Ptr->setby,user->nick);
2642 Ptr->topicset = time(NULL);
2643 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
2647 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2653 /* sends out an error notice to all connected clients (not to be used
2656 void send_error(char *s)
2658 log(DEBUG,"send_error: %s",s);
2659 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
2661 WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s);
2665 void Error(int status)
2667 signal (SIGALRM, SIG_IGN);
2668 signal (SIGPIPE, SIG_IGN);
2669 signal (SIGTERM, SIG_IGN);
2670 signal (SIGABRT, SIG_IGN);
2671 signal (SIGSEGV, SIG_IGN);
2672 signal (SIGURG, SIG_IGN);
2673 signal (SIGKILL, SIG_IGN);
2674 log(DEBUG,"*** fell down a pothole in the road to perfection ***");
2675 send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*");
2679 int main (int argc, char *argv[])
2682 log(DEBUG,"*** InspIRCd starting up!");
2683 if (!FileExists(CONFIG_FILE))
2685 printf("ERROR: Cannot open config file: %s\nExiting...\n",CONFIG_FILE);
2686 log(DEBUG,"main: no config");
2687 printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n");
2690 if (InspIRCd() == ERROR)
2692 log(DEBUG,"main: daemon function bailed");
2693 printf("ERROR: could not initialise. Shutting down.\n");
2700 template<typename T> inline string ConvToStr(const T &in)
2703 if (!(tmp << in)) return string();
2707 /* re-allocates a nick in the user_hash after they change nicknames,
2708 * returns a pointer to the new user as it may have moved */
2710 userrec* ReHashNick(char* Old, char* New)
2712 user_hash::iterator newnick;
2713 user_hash::iterator oldnick = clientlist.find(Old);
2715 log(DEBUG,"ReHashNick: %s %s",Old,New);
2717 if (!strcasecmp(Old,New))
2719 log(DEBUG,"old nick is new nick, skipping");
2720 return oldnick->second;
2723 if (oldnick == clientlist.end()) return NULL; /* doesnt exist */
2725 log(DEBUG,"ReHashNick: Found hashed nick %s",Old);
2727 clientlist[New] = new userrec();
2728 clientlist[New] = oldnick->second;
2729 /*delete oldnick->second; */
2730 clientlist.erase(oldnick);
2732 log(DEBUG,"ReHashNick: Nick rehashed as %s",New);
2734 return clientlist[New];
2737 /* adds or updates an entry in the whowas list */
2738 void AddWhoWas(userrec* u)
2740 user_hash::iterator iter = whowas.find(u->nick);
2741 userrec *a = new userrec();
2742 strcpy(a->nick,u->nick);
2743 strcpy(a->ident,u->ident);
2744 strcpy(a->dhost,u->dhost);
2745 strcpy(a->host,u->host);
2746 strcpy(a->fullname,u->fullname);
2747 strcpy(a->server,u->server);
2748 a->signon = u->signon;
2750 /* MAX_WHOWAS: max number of /WHOWAS items
2751 * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
2752 * can be replaced by a newer one
2755 if (iter == whowas.end())
2757 if (whowas.size() == WHOWAS_MAX)
2759 for (user_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
2761 // 3600 seconds in an hour ;)
2762 if ((i->second->signon)<(time(NULL)-(WHOWAS_STALE*3600)))
2766 log(DEBUG,"added WHOWAS entry, purged an old record");
2773 log(DEBUG,"added fresh WHOWAS entry");
2774 whowas[a->nick] = a;
2779 log(DEBUG,"updated WHOWAS entry");
2780 delete iter->second;
2786 /* add a client connection to the sockets list */
2787 void AddClient(int socket, char* host, int port, bool iscached)
2791 char resolved[MAXBUF];
2794 user_hash::iterator iter;
2796 tempnick = ConvToStr(socket) + "-unknown";
2797 sprintf(tn2,"%d-unknown",socket);
2799 iter = clientlist.find(tempnick);
2801 if (iter != clientlist.end()) return;
2804 * It is OK to access the value here this way since we know
2805 * it exists, we just created it above.
2807 * At NO other time should you access a value in a map or a
2808 * hash_map this way.
2810 clientlist[tempnick] = new userrec();
2812 NonBlocking(socket);
2813 log(DEBUG,"AddClient: %d %s %d",socket,host,port);
2816 clientlist[tempnick]->fd = socket;
2817 strncpy(clientlist[tempnick]->nick, tn2,NICKMAX);
2818 strncpy(clientlist[tempnick]->host, host,160);
2819 strncpy(clientlist[tempnick]->dhost, host,160);
2820 strncpy(clientlist[tempnick]->server, ServerName,256);
2821 clientlist[tempnick]->registered = 0;
2822 clientlist[tempnick]->signon = time(NULL);
2823 clientlist[tempnick]->nping = time(NULL)+240;
2824 clientlist[tempnick]->lastping = 1;
2825 clientlist[tempnick]->port = port;
2829 WriteServ(socket,"NOTICE Auth :Found your hostname (cached)...");
2833 WriteServ(socket,"NOTICE Auth :Looking up your hostname...");
2836 if (clientlist.size() == MAXCLIENTS)
2837 kill_link(clientlist[tempnick],"No more connections allowed in this class");
2840 void handle_names(char **parameters, int pcnt, userrec *user)
2844 if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
2846 c = FindChan(parameters[0]);
2849 /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
2851 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
2855 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2860 void handle_privmsg(char **parameters, int pcnt, userrec *user)
2865 if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
2867 if (parameters[0][0] == '#')
2869 chan = FindChan(parameters[0]);
2872 if ((chan->noexternal) && (!has_channel(user,chan)))
2874 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2877 if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2879 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2882 ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
2886 /* no such nick/channel */
2887 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2892 dest = Find(parameters[0]);
2895 if (strcmp(dest->awaymsg,""))
2897 /* auto respond with aweh msg */
2898 WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
2900 WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
2904 /* no such nick/channel */
2905 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2909 void handle_notice(char **parameters, int pcnt, userrec *user)
2914 if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
2916 if (parameters[0][0] == '#')
2918 chan = FindChan(parameters[0]);
2921 if ((chan->noexternal) && (!has_channel(user,chan)))
2923 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
2926 if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
2928 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
2931 WriteChannel(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
2935 /* no such nick/channel */
2936 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2941 dest = Find(parameters[0]);
2944 WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
2948 /* no such nick/channel */
2949 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
2955 char* chlist(userrec *user)
2960 log(DEBUG,"chlist: %s",user->nick);
2966 for (i = 0; i != MAXCHANS; i++)
2968 if (user->chans[i].channel != NULL)
2970 if (user->chans[i].channel->name)
2972 strcpy(cmp,user->chans[i].channel->name);
2974 if (!strstr(lst,cmp))
2976 if ((!user->chans[i].channel->c_private) && (!user->chans[i].channel->secret))
2978 strcat(lst,cmode(user,user->chans[i].channel));
2979 strcat(lst,user->chans[i].channel->name);
2989 void handle_info(char **parameters, int pcnt, userrec *user)
2991 WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick);
2992 WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick);
2993 WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick);
2994 WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
2997 void handle_time(char **parameters, int pcnt, userrec *user)
3000 struct tm * timeinfo;
3003 timeinfo = localtime ( &rawtime );
3004 WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
3008 void handle_whois(char **parameters, int pcnt, userrec *user)
3013 if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
3015 dest = Find(parameters[0]);
3018 WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
3019 if ((user == dest) || (strchr(user->modes,'o')))
3021 WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host);
3023 if (strcmp(chlist(dest),""))
3025 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest));
3027 WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, ServerDesc);
3028 if (strcmp(dest->awaymsg,""))
3030 WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
3032 if (strchr(dest->modes,'o'))
3034 WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick);
3036 //WriteServ(user->fd,"310 %s %s :is available for help.",user->nick, dest->nick);
3037 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon);
3039 WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
3043 /* no such nick/channel */
3044 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
3048 void handle_quit(char **parameters, int pcnt, userrec *user)
3050 user_hash::iterator iter = clientlist.find(user->nick);
3052 /* theres more to do here, but for now just close the socket */
3055 if (parameters[0][0] == ':')
3059 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]);
3060 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]);
3061 WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
3065 Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
3066 WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
3067 WriteCommonExcept(user,"QUIT :Client exited");
3070 FOREACH_MOD OnUserQuit(user);
3072 /* confucious say, he who close nonblocking socket, get nothing! */
3075 NonBlocking(user->fd);
3078 if (iter != clientlist.end())
3080 log(DEBUG,"deleting user hash value");
3081 delete iter->second;
3082 clientlist.erase(iter);
3085 purge_empty_chans();
3088 void handle_who(char **parameters, int pcnt, userrec *user)
3090 chanrec* Ptr = NULL;
3092 /* theres more to do here, but for now just close the socket */
3095 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
3097 if (user->chans[0].channel)
3099 Ptr = user->chans[0].channel;
3100 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3102 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
3104 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);
3110 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3114 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
3118 if (parameters[0][0] = '#')
3120 Ptr = FindChan(parameters[0]);
3123 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3125 if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
3127 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);
3130 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3134 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
3140 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
3142 Ptr = user->chans[0].channel;
3143 printf(user->chans[0].channel->name);
3144 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3146 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
3148 if (strchr(i->second->modes,'o'))
3150 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);
3154 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
3160 void handle_wallops(char **parameters, int pcnt, userrec *user)
3162 WriteWallOps(user,"%s",parameters[0]);
3165 void handle_list(char **parameters, int pcnt, userrec *user)
3169 WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
3170 for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
3172 if ((!i->second->c_private) && (!i->second->secret))
3174 WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
3177 WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
3181 void handle_rehash(char **parameters, int pcnt, userrec *user)
3183 WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CONFIG_FILE);
3185 FOREACH_MOD OnRehash();
3186 WriteOpers("%s is rehashing config file %s",user->nick,CONFIG_FILE);
3192 return clientlist.size();
3195 int usercount_invisible(void)
3199 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3201 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++;
3206 int usercount_opers(void)
3210 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3212 if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++;
3217 int usercount_unknown(void)
3221 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
3223 if ((i->second->fd) && (i->second->registered != 7))
3231 return chanlist.size();
3234 int servercount(void)
3239 void handle_lusers(char **parameters, int pcnt, userrec *user)
3241 WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
3242 WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
3243 WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
3244 WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
3245 WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,usercnt());
3248 void handle_admin(char **parameters, int pcnt, userrec *user)
3250 WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
3251 WriteServ(user->fd,"257 %s :Name - %s",user->nick,AdminName);
3252 WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
3253 WriteServ(user->fd,"258 %s :E-Mail - %s",user->nick,AdminEmail);
3256 void ShowMOTD(userrec *user)
3260 WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick);
3263 WriteServ(user->fd,"375 %s :- %s message of the day",user->nick,ServerName);
3264 for (int i = 0; i != MOTD.size(); i++)
3266 WriteServ(user->fd,"372 %s :- %s",user->nick,MOTD[i].c_str());
3268 WriteServ(user->fd,"376 %s :End of %s message of the day.",user->nick,ServerName);
3271 void ShowRULES(userrec *user)
3275 WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick);
3278 WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName);
3279 for (int i = 0; i != RULES.size(); i++)
3281 WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str());
3283 WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName);
3286 /* shows the message of the day, and any other on-logon stuff */
3287 void ConnectUser(userrec *user)
3289 user->registered = 7;
3290 user->idle_lastmsg = time(NULL);
3291 log(DEBUG,"ConnectUser: %s",user->nick);
3293 if (strcmp(Passwd(user),"") && (!user->haspassed))
3295 Write(user->fd,"ERROR :Closing link: Invalid password");
3296 fdatasync(user->fd);
3297 kill_link(user,"Invalid password");
3302 Write(user->fd,"ERROR :Closing link: Unauthorized connection");
3303 fdatasync(user->fd);
3304 kill_link(user,"Unauthorised connection");
3307 WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network);
3308 WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host);
3309 WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION);
3310 WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
3311 WriteServ(user->fd,"004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION);
3312 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);
3313 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);
3315 FOREACH_MOD OnUserConnect(user);
3316 WriteOpers("*** Client connecting on port %d: %s!%s@%s",user->port,user->nick,user->ident,user->host);
3319 void handle_version(char **parameters, int pcnt, userrec *user)
3321 WriteServ(user->fd,"351 %s :%s %s :%s",user->nick,VERSION,ServerName,SYSTEM);
3324 void handle_ping(char **parameters, int pcnt, userrec *user)
3326 WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
3329 void handle_pong(char **parameters, int pcnt, userrec *user)
3331 // set the user as alive so they survive to next ping
3335 void handle_motd(char **parameters, int pcnt, userrec *user)
3340 void handle_rules(char **parameters, int pcnt, userrec *user)
3345 void handle_user(char **parameters, int pcnt, userrec *user)
3347 if (user->registered < 3)
3349 if (isident(parameters[0]) == 0) {
3350 // This kinda Sucks, According to the RFC thou, its either this,
3351 // or "You have already registered" :p -- Craig
3352 WriteServ(user->fd,"461 %s USER :Not enough parameters",user->nick);
3355 WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~");
3356 strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */
3357 strncat(user->ident,parameters[0],IDENTMAX);
3358 strncpy(user->fullname,parameters[3],128);
3359 user->registered = (user->registered | 1);
3364 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
3367 /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
3368 if (user->registered == 3)
3370 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3375 void handle_userhost(char **parameters, int pcnt, userrec *user)
3377 char Return[MAXBUF],junk[MAXBUF];
3378 sprintf(Return,"302 %s :",user->nick);
3379 for (int i = 0; i < pcnt; i++)
3381 userrec *u = Find(parameters[i]);
3384 if (strchr(u->modes,'o'))
3386 sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host);
3387 strcat(Return,junk);
3391 sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host);
3392 strcat(Return,junk);
3396 WriteServ(user->fd,Return);
3400 void handle_ison(char **parameters, int pcnt, userrec *user)
3402 char Return[MAXBUF];
3403 sprintf(Return,"303 %s :",user->nick);
3404 for (int i = 0; i < pcnt; i++)
3406 userrec *u = Find(parameters[i]);
3409 strcat(Return,u->nick);
3413 WriteServ(user->fd,Return);
3417 void handle_away(char **parameters, int pcnt, userrec *user)
3421 strcpy(user->awaymsg,parameters[0]);
3422 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
3426 strcpy(user->awaymsg,"");
3427 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
3431 void handle_whowas(char **parameters, int pcnt, userrec* user)
3433 user_hash::iterator i = whowas.find(parameters[0]);
3435 if (i == whowas.end())
3437 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
3438 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3442 time_t rawtime = i->second->signon;
3446 timeinfo = localtime(&rawtime);
3447 strcpy(b,asctime(timeinfo));
3448 b[strlen(b)-1] = '\0';
3450 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
3451 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
3452 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
3457 void handle_trace(char **parameters, int pcnt, userrec *user)
3459 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3463 if (isnick(i->second->nick))
3465 if (strchr(i->second->modes,'o'))
3467 WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
3471 WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
3476 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
3482 void handle_stats(char **parameters, int pcnt, userrec *user)
3488 if (strlen(parameters[0])>1)
3490 /* make the stats query 1 character long */
3491 parameters[0][1] = '\0';
3494 /* stats m (list number of times each command has been used, plus bytecount) */
3495 if (!strcasecmp(parameters[0],"m"))
3497 for (int i = 0; i < cmdlist.size(); i++)
3499 if (cmdlist[i].handler_function)
3501 if (cmdlist[i].use_count)
3503 /* RPL_STATSCOMMANDS */
3504 WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
3511 /* stats z (debug and memory info) */
3512 if (!strcasecmp(parameters[0],"z"))
3514 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
3515 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
3516 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
3517 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
3518 WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
3519 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
3520 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
3521 WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount);
3525 if (!strcasecmp(parameters[0],"o"))
3527 for (int i = 0; i < ConfValueEnum("oper"); i++)
3529 char LoginName[MAXBUF];
3530 char HostName[MAXBUF];
3531 char OperType[MAXBUF];
3532 ConfValue("oper","name",i,LoginName);
3533 ConfValue("oper","host",i,HostName);
3534 ConfValue("oper","type",i,OperType);
3535 WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
3539 /* stats l (show user I/O stats) */
3540 if (!strcasecmp(parameters[0],"l"))
3542 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
3543 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
3545 if (isnick(i->second->nick))
3547 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);
3551 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);
3557 /* stats u (show server uptime) */
3558 if (!strcasecmp(parameters[0],"u"))
3560 time_t current_time = 0;
3561 current_time = time(NULL);
3562 time_t server_uptime = current_time - startup_time;
3564 stime = gmtime(&server_uptime);
3565 /* i dont know who the hell would have an ircd running for over a year nonstop, but
3566 * Craig suggested this, and it seemed a good idea so in it went */
3567 if (stime->tm_year > 70)
3569 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);
3573 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);
3577 WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
3578 WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
3582 void handle_connect(char **parameters, int pcnt, userrec *user)
3584 char Link_ServerName[1024];
3585 char Link_IPAddr[1024];
3586 char Link_Port[1024];
3587 char Link_Pass[1024];
3591 for (int i = 0; i < ConfValueEnum("link"); i++)
3593 ConfValue("link","name",i,Link_ServerName);
3594 ConfValue("link","ipaddr",i,Link_IPAddr);
3595 ConfValue("link","port",i,Link_Port);
3596 ConfValue("link","sendpass",i,Link_Pass);
3597 log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
3598 LinkPort = atoi(Link_Port);
3599 if (match(Link_ServerName,parameters[0])) {
3605 WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,parameters[0]);
3609 // TODO: Perform a check here to stop a server being linked twice!
3611 WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port);
3613 if (me[defaultRoute])
3616 // at this point parameters[0] is an ip in a string.
3617 // TODO: Look this up from the <link> blocks instead!
3618 for (int j = 0; j < 255; j++) {
3619 if (servers[j] == NULL) {
3620 servers[j] = new serverrec;
3621 strcpy(servers[j]->internal_addr,Link_IPAddr);
3622 strcpy(servers[j]->name,Link_ServerName);
3623 log(DEBUG,"Allocated new serverrec");
3624 if (!me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass))
3626 WriteServ(user->fd,"NOTICE %s :*** Failed to send auth packet to %s!",user->nick,Link_IPAddr);
3631 WriteServ(user->fd,"NOTICE %s :*** Failed to create server record for address %s!",user->nick,Link_IPAddr);
3635 WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it.",user->nick);
3639 void handle_squit(char **parameters, int pcnt, userrec *user)
3641 // send out an squit across the mesh and then clear the server list (for local squit)
3644 void handle_oper(char **parameters, int pcnt, userrec *user)
3646 char LoginName[MAXBUF];
3647 char Password[MAXBUF];
3648 char OperType[MAXBUF];
3649 char TypeName[MAXBUF];
3650 char Hostname[MAXBUF];
3653 for (i = 0; i < ConfValueEnum("oper"); i++)
3655 ConfValue("oper","name",i,LoginName);
3656 ConfValue("oper","password",i,Password);
3657 if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1])))
3659 /* correct oper credentials */
3660 ConfValue("oper","type",i,OperType);
3661 WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
3662 WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
3663 WriteServ(user->fd,"MODE %s :+o",user->nick);
3664 for (j =0; j < ConfValueEnum("type"); j++)
3666 ConfValue("type","name",j,TypeName);
3667 if (!strcmp(TypeName,OperType))
3669 /* found this oper's opertype */
3670 ConfValue("type","host",j,Hostname);
3671 strncpy(user->dhost,Hostname,256);
3674 if (!strchr(user->modes,'o'))
3676 strcat(user->modes,"o");
3682 WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
3683 WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
3686 void handle_nick(char **parameters, int pcnt, userrec *user)
3690 log(DEBUG,"not enough params for handle_nick");
3695 log(DEBUG,"invalid parameter passed to handle_nick");
3698 if (!strlen(parameters[0]))
3700 log(DEBUG,"zero length new nick passed to handle_nick");
3705 log(DEBUG,"invalid user passed to handle_nick");
3710 log(DEBUG,"invalid old nick passed to handle_nick");
3713 if (!strcasecmp(user->nick,parameters[0]))
3715 log(DEBUG,"old nick is new nick, skipping");
3720 if (strlen(parameters[0]) > 1)
3722 if (parameters[0][0] == ':')
3727 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
3729 WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
3733 if (isnick(parameters[0]) == 0)
3735 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
3739 if (user->registered == 7)
3741 WriteCommon(user,"NICK %s",parameters[0]);
3744 /* change the nick of the user in the users_hash */
3745 user = ReHashNick(user->nick, parameters[0]);
3746 /* actually change the nick within the record */
3748 if (!user->nick) return;
3750 strncpy(user->nick, parameters[0],NICKMAX);
3752 log(DEBUG,"new nick set: %s",user->nick);
3754 if (user->registered < 3)
3755 user->registered = (user->registered | 2);
3756 if (user->registered == 3)
3758 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
3761 log(DEBUG,"exit nickchange: %s",user->nick);
3764 int process_parameters(char **command_p,char *parameters)
3769 q = strlen(parameters);
3772 /* no parameters, command_p invalid! */
3775 if (parameters[0] == ':')
3777 command_p[0] = parameters+1;
3782 if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':'))
3784 /* only one parameter */
3785 command_p[0] = parameters;
3786 if (parameters[0] == ':')
3788 if (strchr(parameters,' ') != NULL)
3796 command_p[j++] = parameters;
3797 for (i = 0; i <= q; i++)
3799 if (parameters[i] == ' ')
3801 command_p[j++] = parameters+i+1;
3802 parameters[i] = '\0';
3803 if (command_p[j-1][0] == ':')
3805 *command_p[j-1]++; /* remove dodgy ":" */
3807 /* parameter like this marks end of the sequence */
3811 return j; /* returns total number of items in the list */
3814 void process_command(userrec *user, char* cmd)
3818 char *command_p[127];
3819 char p[MAXBUF], temp[MAXBUF];
3820 int i, j, items, cmd_found;
3822 for (int i = 0; i < 127; i++)
3823 command_p[i] = NULL;
3833 if (!strcmp(cmd,""))
3840 FOREACH_MOD OnServerRaw(tmp,true);
3841 const char* cmd2 = tmp.c_str();
3842 snprintf(cmd,512,"%s",cmd2);
3844 if (!strchr(cmd,' '))
3846 /* no parameters, lets skip the formalities and not chop up
3849 command_p[0] = NULL;
3851 for (int i = 0; i <= strlen(cmd); i++)
3853 cmd[i] = toupper(cmd[i]);
3860 /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */
3861 for (i = 0; i < strlen(temp); i++)
3863 if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7))
3869 /* split the full string into a command plus parameters */
3873 if (strchr(cmd,' '))
3875 for (i = 0; i <= strlen(cmd); i++)
3877 /* capitalise the command ONLY, leave params intact */
3878 cmd[i] = toupper(cmd[i]);
3879 /* are we nearly there yet?! :P */
3883 parameters = cmd+i+1;
3891 for (i = 0; i <= strlen(cmd); i++)
3893 cmd[i] = toupper(cmd[i]);
3901 for (i = 0; i != cmdlist.size(); i++)
3903 if (strcmp(cmdlist[i].command,""))
3905 if (!strcmp(command, cmdlist[i].command))
3909 if (strcmp(parameters,""))
3911 items = process_parameters(command_p,parameters);
3916 command_p[0] = NULL;
3922 command_p[0] = NULL;
3927 user->idle_lastmsg = time(NULL);
3928 /* activity resets the ping pending timer */
3929 user->nping = time(NULL) + 120;
3930 if ((items) < cmdlist[i].min_params)
3932 log(DEBUG,"process_command: not enough parameters: %s %s",user->nick,command);
3933 WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command);
3936 if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed))
3938 log(DEBUG,"process_command: permission denied: %s %s",user->nick,command);
3939 WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick);
3943 /* if the command isnt USER, PASS, or NICK, and nick is empty,
3945 if ((strcmp(command,"USER")) && (strcmp(command,"NICK")) && (strcmp(command,"PASS")))
3947 if ((!isnick(user->nick)) || (user->registered != 7))
3949 log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3950 WriteServ(user->fd,"451 %s :You have not registered",command);
3954 if ((user->registered == 7) || (!strcmp(command,"USER")) || (!strcmp(command,"NICK")) || (!strcmp(command,"PASS")))
3956 log(DEBUG,"process_command: handler: %s %s %d",user->nick,command,items);
3957 if (cmdlist[i].handler_function)
3959 /* ikky /stats counters */
3964 user->bytes_in += strlen(temp);
3967 cmdlist[i].use_count++;
3968 cmdlist[i].total_bytes+=strlen(temp);
3971 /* WARNING: nothing may come after the
3972 * command handler call, as the handler
3973 * may free the user structure! */
3975 cmdlist[i].handler_function(command_p,items,user);
3981 log(DEBUG,"process_command: not registered: %s %s",user->nick,command);
3982 WriteServ(user->fd,"451 %s :You have not registered",command);
3990 if ((!cmd_found) && (user))
3992 log(DEBUG,"process_command: not in table: %s %s",user->nick,command);
3993 WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command);
3998 void createcommand(char* cmd, handlerfunc f, char flags, int minparams)
4001 /* create the command and push it onto the table */
4002 strcpy(comm.command,cmd);
4003 comm.handler_function = f;
4004 comm.flags_needed = flags;
4005 comm.min_params = minparams;
4007 comm.total_bytes = 0;
4008 cmdlist.push_back(comm);
4011 void SetupCommandTable(void)
4013 createcommand("USER",handle_user,0,4);
4014 createcommand("NICK",handle_nick,0,1);
4015 createcommand("QUIT",handle_quit,0,0);
4016 createcommand("VERSION",handle_version,0,0);
4017 createcommand("PING",handle_ping,0,1);
4018 createcommand("PONG",handle_pong,0,1);
4019 createcommand("ADMIN",handle_admin,0,0);
4020 createcommand("PRIVMSG",handle_privmsg,0,2);
4021 createcommand("INFO",handle_info,0,0);
4022 createcommand("TIME",handle_time,0,0);
4023 createcommand("WHOIS",handle_whois,0,1);
4024 createcommand("WALLOPS",handle_wallops,'o',1);
4025 createcommand("NOTICE",handle_notice,0,2);
4026 createcommand("JOIN",handle_join,0,1);
4027 createcommand("NAMES",handle_names,0,1);
4028 createcommand("PART",handle_part,0,1);
4029 createcommand("KICK",handle_kick,0,2);
4030 createcommand("MODE",handle_mode,0,1);
4031 createcommand("TOPIC",handle_topic,0,1);
4032 createcommand("WHO",handle_who,0,1);
4033 createcommand("MOTD",handle_motd,0,0);
4034 createcommand("RULES",handle_join,0,0);
4035 createcommand("OPER",handle_oper,0,2);
4036 createcommand("LIST",handle_list,0,0);
4037 createcommand("DIE",handle_die,'o',1);
4038 createcommand("RESTART",handle_restart,'o',1);
4039 createcommand("KILL",handle_kill,'o',2);
4040 createcommand("REHASH",handle_rehash,'o',0);
4041 createcommand("LUSERS",handle_lusers,0,0);
4042 createcommand("STATS",handle_stats,0,1);
4043 createcommand("USERHOST",handle_userhost,0,1);
4044 createcommand("AWAY",handle_away,0,0);
4045 createcommand("ISON",handle_ison,0,0);
4046 createcommand("SUMMON",handle_summon,0,0);
4047 createcommand("USERS",handle_users,0,0);
4048 createcommand("INVITE",handle_invite,0,2);
4049 createcommand("PASS",handle_pass,0,1);
4050 createcommand("TRACE",handle_trace,'o',0);
4051 createcommand("WHOWAS",handle_whowas,0,1);
4052 createcommand("CONNECT",handle_connect,'o',1);
4053 createcommand("SQUIT",handle_squit,'o',1);
4056 void process_buffer(userrec *user)
4064 if (!strcmp(user->inbuf,""))
4068 strncpy(cmd,user->inbuf,MAXBUF);
4069 if (!strcmp(cmd,""))
4073 if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
4075 cmd[strlen(cmd)-1] = '\0';
4077 if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10))
4079 cmd[strlen(cmd)-1] = '\0';
4081 strcpy(user->inbuf,"");
4082 if (!strcmp(cmd,""))
4086 log(DEBUG,"InspIRCd: processing: %s %s",user->nick,cmd);
4087 process_command(user,cmd);
4090 void process_restricted_commands(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
4092 WriteOpers("Secure-UDP-Channel: Token='%c', Params='%s'",token,params);
4096 void handle_link_packet(long theirkey, char* udp_msg, char* udp_host, int udp_port, serverrec *serv)
4098 char response[10240];
4099 char token = udp_msg[0];
4100 char* params = udp_msg + 2;
4101 char finalparam[1024];
4102 strcpy(finalparam," :xxxx");
4103 if (strstr(params," :")) {
4104 strncpy(finalparam,strstr(params," :"),1024);
4107 // S test.chatspike.net password :ChatSpike InspIRCd test server
4108 char* servername = strtok(params," ");
4109 char* password = strtok(NULL," ");
4110 char* serverdesc = finalparam+2;
4111 WriteOpers("CONNECT from %s (%s)",servername,udp_host,password,serverdesc);
4114 char Link_ServerName[1024];
4115 char Link_IPAddr[1024];
4116 char Link_Port[1024];
4117 char Link_Pass[1024];
4118 char Link_SendPass[1024];
4121 // search for a corresponding <link> block in the config files
4122 for (int i = 0; i < ConfValueEnum("link"); i++)
4124 ConfValue("link","name",i,Link_ServerName);
4125 ConfValue("link","ipaddr",i,Link_IPAddr);
4126 ConfValue("link","port",i,Link_Port);
4127 ConfValue("link","recvpass",i,Link_Pass);
4128 ConfValue("link","sendpass",i,Link_SendPass);
4129 log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
4130 LinkPort = atoi(Link_Port);
4131 if (!strcasecmp(Link_ServerName,servername)) {
4132 if (!strcasecmp(Link_IPAddr,udp_host)) {
4133 if (LinkPort == udp_port) {
4134 // we have a matching link line -
4135 // send a 'diminutive' server message back...
4136 snprintf(response,10240,"s %s %s :%s",ServerName,Link_SendPass,ServerDesc);
4137 serv->SendPacket(response,udp_host,udp_port,0);
4138 WriteOpers("CONNECT from %s accepted, authenticating",servername);
4139 for (int j = 0; j < 255; j++) {
4140 if (servers[j] == NULL) {
4141 servers[j] = new serverrec;
4142 strcpy(servers[j]->internal_addr,udp_host);
4143 strcpy(servers[j]->name,servername);
4144 // create a server record for this server
4145 snprintf(response,10240,"O %d",MyKey);
4146 serv->SendPacket(response,udp_host,udp_port,0);
4150 WriteOpers("Internal error connecting to %s, failed to create server record!",servername);
4154 log(DEBUG,"Port numbers '%d' and '%d' don't match",LinkPort,udp_port);
4158 log(DEBUG,"IP Addresses '%s' and '%s' don't match",Link_IPAddr,udp_host);
4162 log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername);
4165 serv->SendPacket("E :Access is denied (no matching link block)",udp_host,udp_port,0);
4166 WriteOpers("CONNECT from %s denied, no matching link block",servername);
4171 // if this is received, this means the server-ip that sent it said "OK" to credentials.
4172 // only when a server says this do we exchange keys. The server MUST have an entry in the servers
4173 // array, which is only added by an 'S' packet or BeginLink().
4174 for (int i = 0; i < 255; i++) {
4175 if (servers[i] != NULL) {
4176 if (!strcasecmp(servers[i]->internal_addr,udp_host)) {
4177 servers[i]->key = atoi(params);
4178 log(DEBUG,"Key for this server is now %d",servers[i]->key);
4179 serv->SendPacket("Z blah blah",udp_host,udp_port,MyKey);
4184 WriteOpers("\2WARNING!\2 Server ip %s attempted a key exchange, but is not in the authentication state! Possible intrusion attempt!",udp_host);
4188 // S test.chatspike.net password :ChatSpike InspIRCd test server
4189 char* servername = strtok(params," ");
4190 char* password = strtok(NULL," ");
4191 char* serverdesc = finalparam+2;
4193 // TODO: we should do a check here to ensure that this server is one we recently initiated a
4194 // link with, and didnt hear an 's' or 'E' back from yet (these are the only two valid responses
4195 // to an 'S' command. If we didn't recently send an 'S' to this server, theyre trying to spoof
4196 // a connect, so put out an oper alert!
4201 // for now, just accept all, we'll fix that later.
4202 WriteOpers("%s accepted our link credentials ",servername);
4204 char Link_ServerName[1024];
4205 char Link_IPAddr[1024];
4206 char Link_Port[1024];
4207 char Link_Pass[1024];
4208 char Link_SendPass[1024];
4211 // search for a corresponding <link> block in the config files
4212 for (int i = 0; i < ConfValueEnum("link"); i++)
4214 ConfValue("link","name",i,Link_ServerName);
4215 ConfValue("link","ipaddr",i,Link_IPAddr);
4216 ConfValue("link","port",i,Link_Port);
4217 ConfValue("link","recvpass",i,Link_Pass);
4218 ConfValue("link","sendpass",i,Link_SendPass);
4219 log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
4220 LinkPort = atoi(Link_Port);
4221 if (!strcasecmp(Link_ServerName,servername)) {
4222 if (!strcasecmp(Link_IPAddr,udp_host)) {
4223 if (LinkPort == udp_port) {
4224 // matching link at this end too, we're all done!
4225 // at this point we must begin key exchange and insert this
4226 // server into our 'active' table.
4227 for (int j = 0; j < 255; j++) {
4228 if (servers[j] != NULL) {
4229 if (!strcasecmp(servers[j]->internal_addr,udp_host)) {
4230 WriteOpers("Server %s authenticated, exchanging server keys...",servername);
4231 snprintf(response,10240,"O %d",MyKey);
4232 serv->SendPacket(response,udp_host,udp_port,0);
4237 WriteOpers("\2WARNING!\2 %s sent us an authentication packet but we are not authenticating with this server right noe! Possible intrusion attempt!",udp_host);
4242 log(DEBUG,"Port numbers '%d' and '%d' don't match",LinkPort,udp_port);
4246 log(DEBUG,"IP Addresses '%s' and '%s' don't match",Link_IPAddr,udp_host);
4250 log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername);
4253 serv->SendPacket("E :Access is denied (no matching link block)",udp_host,udp_port,0);
4254 WriteOpers("CONNECT from %s denied, no matching link block",servername);
4259 char* error_message = finalparam+2;
4260 WriteOpers("ERROR from %s: %s",udp_host,error_message);
4261 // remove this server from any lists
4262 for (int j = 0; j < 255; j++) {
4263 if (servers[j] != NULL) {
4264 if (!strcasecmp(servers[j]->internal_addr,udp_host)) {
4274 serverrec* source_server = NULL;
4276 for (int j = 0; j < 255; j++) {
4277 if (servers[j] != NULL) {
4278 if (!strcasecmp(servers[j]->internal_addr,udp_host)) {
4279 if (servers[j]->key == theirkey) {
4280 // found a valid key for this server, can process restricted stuff here
4281 process_restricted_commands(token,params,servers[j],serv,udp_host,udp_port);
4289 log(DEBUG,"Unrecognised token or unauthenticated host in datagram from %s:%d: %c",udp_host,udp_port,token);
4295 struct sockaddr_in client, server;
4296 char addrs[MAXBUF][255];
4297 int openSockfd[MAXSOCKS], incomingSockfd, result = TRUE;
4299 int count = 0, scanDetectTrigger = TRUE, showBanner = FALSE;
4300 int selectResult = 0;
4301 char *temp, configToken[MAXBUF], stuff[MAXBUF], Addr[MAXBUF], Type[MAXBUF];
4302 char resolvedHost[MAXBUF];
4306 log(DEBUG,"InspIRCd: startup: begin");
4310 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
4312 log(DEBUG,"InspIRCd: startup: not starting with UID 0!");
4314 SetupCommandTable();
4315 log(DEBUG,"InspIRCd: startup: default command table set up");
4318 if (strcmp(DieValue,""))
4320 printf("WARNING: %s\n\n",DieValue);
4323 log(DEBUG,"InspIRCd: startup: read config");
4325 int count2 = 0, count3 = 0;
4326 for (count = 0; count < ConfValueEnum("bind"); count++)
4328 ConfValue("bind","port",count,configToken);
4329 ConfValue("bind","address",count,Addr);
4330 ConfValue("bind","type",count,Type);
4331 if (!strcmp(Type,"servers"))
4333 char Default[MAXBUF];
4334 strcpy(Default,"no");
4335 ConfValue("bind","default",count,Default);
4336 if (strchr(Default,'y'))
4338 defaultRoute = count3;
4339 log(DEBUG,"InspIRCd: startup: binding '%s:%s' is default server route",Addr,configToken);
4341 me[count3] = new serverrec(ServerName,100L,false);
4342 me[count3]->CreateListener(Addr,atoi(configToken));
4347 ports[count2] = atoi(configToken);
4348 strcpy(addrs[count2],Addr);
4351 log(DEBUG,"InspIRCd: startup: read binding %s:%s [%s] from config",Addr,configToken, Type);
4354 UDPportCount = count3;
4356 log(DEBUG,"InspIRCd: startup: read %d total client ports and %d total server ports",portCount,UDPportCount);
4358 log(DEBUG,"InspIRCd: startup: InspIRCd is now running!");
4362 /* BugFix By Craig! :p */
4364 for (count = 0; count2 < ConfValueEnum("module"); count2++)
4366 char modfile[MAXBUF];
4367 ConfValue("module","name",count,configToken);
4368 sprintf(modfile,"%s/%s",MOD_PATH,configToken);
4369 printf("Loading module... \033[1;37m%s\033[0;37m\n",modfile);
4370 log(DEBUG,"InspIRCd: startup: Loading module: %s",modfile);
4371 /* If The File Doesnt exist, Trying to load it
4372 * Will Segfault the IRCd.. So, check to see if
4373 * it Exists, Before Proceeding. */
4374 if (FileExists(modfile))
4376 factory[count] = new ircd_module(modfile);
4377 if (factory[count]->LastError())
4379 log(DEBUG,"Unable to load %s: %s",modfile,factory[count]->LastError());
4380 sprintf("Unable to load %s: %s\nExiting...\n",modfile,factory[count]->LastError());
4383 if (factory[count]->factory)
4385 modules[count] = factory[count]->factory->CreateModule();
4386 /* save the module and the module's classfactory, if
4387 * this isnt done, random crashes can occur :/ */
4391 log(DEBUG,"Unable to load %s",modfile);
4392 sprintf("Unable to load %s\nExiting...\n",modfile);
4395 /* Increase the Count */
4400 log(DEBUG,"InspIRCd: startup: Module Not Found %s",modfile);
4401 printf("Module Not Found: \033[1;37m%s\033[0;37m, Skipping\n",modfile);
4404 MODCOUNT = count - 1;
4405 log(DEBUG,"Total loaded modules: %d",MODCOUNT+1);
4407 printf("\nInspIRCd is now running!\n");
4409 startup_time = time(NULL);
4411 if (DaemonSeed() == ERROR)
4413 log(DEBUG,"InspIRCd: startup: can't daemonise");
4414 printf("ERROR: could not go into daemon mode. Shutting down.\n");
4419 /* setup select call */
4420 FD_ZERO(&selectFds);
4421 log(DEBUG,"InspIRCd: startup: zero selects");
4422 log(VERBOSE,"InspIRCd: startup: portCount = %d", portCount);
4424 for (count = 0; count < portCount; count++)
4426 if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR)
4428 log(DEBUG,"InspIRCd: startup: bad fd %d",openSockfd[boundPortCount]);
4431 if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR)
4433 log(DEBUG,"InspIRCd: startup: failed to bind port %d",ports[count]);
4435 else /* well we at least bound to one socket so we'll continue */
4441 log(DEBUG,"InspIRCd: startup: total bound ports %d",boundPortCount);
4443 /* if we didn't bind to anything then abort */
4444 if (boundPortCount == 0)
4446 log(DEBUG,"InspIRCd: startup: no ports bound, bailing!");
4450 length = sizeof (client);
4451 int flip_flop = 0, udp_port = 0;
4452 char udp_msg[MAXBUF], udp_host[MAXBUF];
4454 /* main loop for multiplexing/resetting */
4457 /* set up select call */
4458 for (count = 0; count < boundPortCount; count++)
4460 FD_SET (openSockfd[count], &selectFds);
4463 /* added timeout! select was waiting forever... wank... :/ */
4474 selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv);
4476 for (int x = 0; x != UDPportCount; x++)
4479 if (me[x]->RecvPacket(udp_msg, udp_host, udp_port, theirkey))
4481 if (strlen(udp_msg)<1) {
4482 log(DEBUG,"Invalid datagram from %s:%d:%d [route%d]",udp_host,udp_port,me[x]->port,x);
4485 FOREACH_MOD OnPacketReceive(udp_msg);
4486 // Packets must go back via the route they arrived on :)
4487 handle_link_packet(theirkey, udp_msg, udp_host, udp_port, me[x]);
4492 for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++)
4496 if (!count2->second) break;
4499 if (count2->second->fd)
4501 if (((time(NULL)) > count2->second->nping) && (isnick(count2->second->nick)) && (count2->second->registered == 7))
4503 if (!count2->second->lastping)
4505 log(DEBUG,"InspIRCd: ping timeout: %s",count2->second->nick);
4506 kill_link(count2->second,"Ping timeout");
4509 Write(count2->second->fd,"PING :%s",ServerName);
4510 log(DEBUG,"InspIRCd: pinging: %s",count2->second->nick);
4511 count2->second->lastping = 0;
4512 count2->second->nping = time(NULL)+120;
4515 result = read(count2->second->fd, data, 1);
4516 // result EAGAIN means nothing read
4517 if (result == EAGAIN)
4523 log(DEBUG,"InspIRCd: Exited: %s",count2->second->nick);
4524 kill_link(count2->second,"Client exited");
4526 else if (result > 0)
4528 strncat(count2->second->inbuf, data, result);
4529 if (strchr(count2->second->inbuf, '\n') || strchr(count2->second->inbuf, '\r'))
4531 /* at least one complete line is waiting to be processed */
4532 if (!count2->second->fd)
4536 process_buffer(count2->second);
4544 /* select is reporting a waiting socket. Poll them all to find out which */
4545 if (selectResult > 0)
4547 char target[MAXBUF], resolved[MAXBUF];
4548 for (count = 0; count < boundPortCount; count++)
4550 if (FD_ISSET (openSockfd[count], &selectFds))
4552 incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length);
4554 address_cache::iterator iter = IP.find(client.sin_addr);
4555 bool iscached = false;
4556 if (iter == IP.end())
4558 /* ip isn't in cache, add it */
4559 strncpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF);
4560 if(CleanAndResolve(resolved, target) != TRUE)
4562 strncpy(resolved,target,MAXBUF);
4564 /* hostname now in 'target' */
4565 IP[client.sin_addr] = new string(resolved);
4566 /* hostname in cache */
4570 /* found ip (cached) */
4571 strncpy(resolved, iter->second->c_str(), MAXBUF);
4575 if (incomingSockfd < 0)
4577 WriteOpers("*** WARNING: Accept failed on port %d (%s)", ports[count],target);
4578 log(DEBUG,"InspIRCd: accept failed: %d",ports[count]);
4582 AddClient(incomingSockfd, resolved, ports[count], iscached);
4583 log(DEBUG,"InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd);
4592 close (incomingSockfd);