diff options
60 files changed, 822 insertions, 953 deletions
@@ -848,6 +848,11 @@ sub writefiles { chomp(my $incos = `uname -n -s -r`); chomp(my $version = `sh src/version.sh`); chomp(my $revision2 = getrevision()); + my $branch = "InspIRCd-0.0"; + if ($version =~ /^(InspIRCd-[0-9]+\.[0-9]+)\.[0-9]+/) + { + $branch = $1; + } if ($writeheader == 1) { print "Writing \e[1;32minspircd_config.h\e[0m\n"; @@ -861,6 +866,7 @@ sub writefiles { #define CoreExport /**/ #define DllExport /**/ +#define CONFIG_PATH "$config{CONFIG_DIR}" #define MOD_PATH "$config{MODULE_DIR}" #define SOMAXCONN_S "$config{_SOMAXCONN}" #define ENTRYPOINT int main(int argc, char** argv) @@ -932,6 +938,7 @@ print FILEHANDLE "#define MAXBUF " . ($config{MAXBUF}+2) . "\n"; open(FILEHANDLE, ">include/inspircd_version.h.tmp"); print FILEHANDLE <<EOF; +#define BRANCH "$branch" #define VERSION "$version" #define REVISION "$revision2" #define SYSTEM "$incos" diff --git a/docs/conf/inspircd.helpop-full.example b/docs/conf/inspircd.helpop-full.example index c4936eea6..27b689f51 100644 --- a/docs/conf/inspircd.helpop-full.example +++ b/docs/conf/inspircd.helpop-full.example @@ -954,6 +954,7 @@ Y Show connection classes O Show opertypes and the allowed user and channel modes it can set E Show socket engine events S Show currently held registered nicknames +G Show how many local users are connected from each country according to GeoIP Note that all /STATS use is broadcast to online IRC operators."> diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 9d9b61b93..76563fbeb 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -305,7 +305,7 @@ #<module name="m_cban.so"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# Censor module: Adds the channel mode +G +# Censor module: Adds channel and user mode +G #<module name="m_censor.so"> # #-#-#-#-#-#-#-#-#-#-#- CENSOR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-# @@ -378,8 +378,13 @@ # joining a channel with +H 'X:T' set; 'T' is the maximum time to keep # lines in the history buffer. Designed so that the new user knows what # the current topic of conversation is when joining the channel. -# NOTE: Currently hard-limited to a maximum of 50 lines. #<module name="m_chanhistory.so"> +# +# Set the maximum number of lines allowed to be stored per channel below. +# This is the hard limit for 'X'. +# If notice is set to yes, joining users will get a NOTICE before playback +# telling them about the following lines being the pre-join history. +#<chanhistory maxlines="20" notice="yes"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Channel logging module: used to send snotice output to channels, to diff --git a/include/configparser.h b/include/configparser.h index 478899ed9..4b83d26d7 100644 --- a/include/configparser.h +++ b/include/configparser.h @@ -61,13 +61,19 @@ struct ParseStack struct FileWrapper { FILE* const f; - FileWrapper(FILE* file) : f(file) {} + bool close_with_pclose; + FileWrapper(FILE* file, bool use_pclose = false) : f(file), close_with_pclose(use_pclose) {} operator bool() { return f; } operator FILE*() { return f; } ~FileWrapper() { if (f) - fclose(f); + { + if (close_with_pclose) + pclose(f); + else + fclose(f); + } } }; diff --git a/include/hashcomp.h b/include/hashcomp.h index 0340cb634..59986e66f 100644 --- a/include/hashcomp.h +++ b/include/hashcomp.h @@ -441,7 +441,7 @@ namespace irc /** Used to split on commas */ - commasepstream* sep; + commasepstream sep; /** Current position in a range of ports */ @@ -462,7 +462,7 @@ namespace irc /** Used to determine overlapping of ports * without O(n) algorithm being used */ - std::map<long, bool> overlap_set; + std::set<long> overlap_set; /** Returns true if val overlaps an existing range */ @@ -475,10 +475,6 @@ namespace irc */ portparser(const std::string &source, bool allow_overlapped = true); - /** Frees the internal commasepstream object - */ - ~portparser(); - /** Fetch the next token from the stream * @return The next port number is returned, or 0 if none remain */ diff --git a/include/inspircd.h b/include/inspircd.h index 78e0c1b3e..c06a28043 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -790,10 +790,6 @@ class CoreExport InspIRCd */ void SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...) CUSTOM_PRINTF(5, 6); - /** Handle /STATS - */ - void DoStats(char statschar, User* user, string_list &results); - /** Handle /WHOIS */ void DoWhois(User* user, User* dest,unsigned long signon, unsigned long idle, const char* nick); diff --git a/make/gnutlscert.pm b/make/gnutlscert.pm index 1621c2c27..ab8aae427 100644 --- a/make/gnutlscert.pm +++ b/make/gnutlscert.pm @@ -36,7 +36,7 @@ sub make_gnutls_cert() my $timestr = time(); my $org = promptstring_s("Please enter the organization name", "My IRC Network"); my $unit = promptstring_s("Please enter the unit Name", "Server Admins"); - my $state = promptstring_s("Pleae enter your state (two letter code)", "CA"); + my $state = promptstring_s("Please enter your state (two letter code)", "CA"); my $country = promptstring_s("Please enter your country", "Oompa Loompa Land"); my $commonname = promptstring_s("Please enter the certificate common name (hostname)", "irc.mynetwork.com"); my $email = promptstring_s("Please enter a contact email address", "oompa\@loompa.com"); diff --git a/src/channels.cpp b/src/channels.cpp index f1dba5315..c265171b5 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -1013,7 +1013,7 @@ Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired) if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time())) { /* Expired invite, remove it. */ - ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p timed out at %lu", (void*) inv, inv->expiry); + ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, ServerInstance->TimeString(inv->expiry).c_str()); i = locallist.erase(i); inv->cull(); delete inv; diff --git a/src/commands/cmd_commands.cpp b/src/commands/cmd_commands.cpp index 13bd3fab8..36408b363 100644 --- a/src/commands/cmd_commands.cpp +++ b/src/commands/cmd_commands.cpp @@ -48,6 +48,10 @@ CmdResult CommandCommands::Handle (const std::vector<std::string>&, User *user) list.reserve(ServerInstance->Parser->cmdlist.size()); for (Commandtable::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++) { + // Don't show S2S commands to users + if (i->second->flags_needed == FLAG_SERVERONLY) + continue; + Module* src = i->second->creator; char buffer[MAXBUF]; snprintf(buffer, MAXBUF, ":%s %03d %s :%s %s %d %d", diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp index 244bb44c3..3b0507175 100644 --- a/src/commands/cmd_stats.cpp +++ b/src/commands/cmd_stats.cpp @@ -20,6 +20,12 @@ #include "inspircd.h" +#include "xline.h" +#include "commands/cmd_whowas.h" + +#ifdef WINDOWS +# pragma comment(lib, "psapi.lib") // For GetProcessMemoryInfo() +#endif /** Handle /STATS. These command handlers can be reloaded by the core, * and handle basic RFC1459 commands. Commands within modules work @@ -28,6 +34,7 @@ */ class CommandStats : public Command { + void DoStats(char statschar, User* user, string_list &results); public: /** Constructor for stats. */ @@ -47,13 +54,349 @@ class CommandStats : public Command } }; +void CommandStats::DoStats(char statschar, User* user, string_list &results) +{ + std::string sn(ServerInstance->Config->ServerName); + + bool isPublic = ServerInstance->Config->UserStats.find(statschar) != std::string::npos; + bool isRemoteOper = IS_REMOTE(user) && IS_OPER(user); + bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"); + + if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs) + { + ServerInstance->SNO->WriteToSnoMask('t', + "%s '%c' denied for %s (%s@%s)", + (IS_LOCAL(user) ? "Stats" : "Remote stats"), + statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + results.push_back(sn + " 481 " + user->nick + " :Permission denied - STATS " + statschar + " requires the servers/auspex priv."); + return; + } + + ModResult MOD_RESULT; + FIRST_MOD_RESULT(OnStats, MOD_RESULT, (statschar, user, results)); + if (MOD_RESULT == MOD_RES_DENY) + { + results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); + ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", + (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + return; + } + + switch (statschar) + { + /* stats p (show listening ports) */ + case 'p': + { + for (std::vector<ListenSocket*>::const_iterator i = ServerInstance->ports.begin(); i != ServerInstance->ports.end(); ++i) + { + ListenSocket* ls = *i; + std::string ip = ls->bind_addr; + if (ip.empty()) + ip.assign("*"); + std::string type = ls->bind_tag->getString("type", "clients"); + std::string hook = ls->bind_tag->getString("ssl", "plaintext"); + + results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ls->bind_port)+ + " (" + type + ", " + hook + ")"); + } + } + break; + + /* These stats symbols must be handled by a linking module */ + case 'n': + case 'c': + break; + + case 'i': + { + for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) + { + ConnectClass* c = *i; + std::stringstream res; + res << sn << " 215 " << user->nick << " I " << c->name << ' '; + if (c->type == CC_ALLOW) + res << '+'; + if (c->type == CC_DENY) + res << '-'; + + if (c->type == CC_NAMED) + res << '*'; + else + res << c->host; + + res << ' ' << c->config->getString("port", "*") << ' '; + + res << c->GetRecvqMax() << ' ' << c->GetSendqSoftMax() << ' ' << c->GetSendqHardMax() + << ' ' << c->GetCommandRate() << ' ' << c->GetPenaltyThreshold(); + if (c->fakelag) + res << '*'; + results.push_back(res.str()); + } + } + break; + + case 'Y': + { + int idx = 0; + for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++) + { + ConnectClass* c = *i; + results.push_back(sn+" 215 "+user->nick+" i NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : ServerInstance->SE->GetMaxFds())+" "+ConvToStr(idx)+" "+ServerInstance->Config->ServerName+" *"); + results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqHardMax())+" :"+ + ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout())); + idx++; + } + } + break; + + case 'U': + { + for(std::map<irc::string, bool>::iterator i = ServerInstance->Config->ulines.begin(); i != ServerInstance->Config->ulines.end(); ++i) + { + results.push_back(sn+" 248 "+user->nick+" U "+std::string(i->first.c_str())); + } + } + break; + + case 'P': + { + int idx = 0; + for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) + { + if (IS_OPER(i->second) && !ServerInstance->ULine(i->second->server)) + { + results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+ + (IS_LOCAL(i->second) ? ConvToStr(ServerInstance->Time() - i->second->idle_lastmsg) + " secs" : "unavailable")); + idx++; + } + } + results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)"); + } + break; + + case 'k': + ServerInstance->XLines->InvokeStats("K",216,user,results); + break; + case 'g': + ServerInstance->XLines->InvokeStats("G",223,user,results); + break; + case 'q': + ServerInstance->XLines->InvokeStats("Q",217,user,results); + break; + case 'Z': + ServerInstance->XLines->InvokeStats("Z",223,user,results); + break; + case 'e': + ServerInstance->XLines->InvokeStats("E",223,user,results); + break; + case 'E': + results.push_back(sn+" 249 "+user->nick+" :Total events: "+ConvToStr(ServerInstance->SE->TotalEvents)); + results.push_back(sn+" 249 "+user->nick+" :Read events: "+ConvToStr(ServerInstance->SE->ReadEvents)); + results.push_back(sn+" 249 "+user->nick+" :Write events: "+ConvToStr(ServerInstance->SE->WriteEvents)); + results.push_back(sn+" 249 "+user->nick+" :Error events: "+ConvToStr(ServerInstance->SE->ErrorEvents)); + break; + + /* stats m (list number of times each command has been used, plus bytecount) */ + case 'm': + for (Commandtable::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++) + { + if (i->second->use_count) + { + /* RPL_STATSCOMMANDS */ + results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes)); + } + } + break; + + /* stats z (debug and memory info) */ + case 'z': + { + results.push_back(sn+" 249 "+user->nick+" :Users: "+ConvToStr(ServerInstance->Users->clientlist->size())); + results.push_back(sn+" 249 "+user->nick+" :Channels: "+ConvToStr(ServerInstance->chanlist->size())); + results.push_back(sn+" 249 "+user->nick+" :Commands: "+ConvToStr(ServerInstance->Parser->cmdlist.size())); + + if (!ServerInstance->Config->WhoWasGroupSize == 0 && !ServerInstance->Config->WhoWasMaxGroups == 0) + { + Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); + if (whowas) + { + WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_STATS); + req.user = user; + req.Send(); + results.push_back(sn+" 249 "+user->nick+" :"+req.value); + } + } + + float kbitpersec_in, kbitpersec_out, kbitpersec_total; + char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30]; + + ServerInstance->SE->GetStats(kbitpersec_in, kbitpersec_out, kbitpersec_total); + + snprintf(kbitpersec_total_s, 30, "%03.5f", kbitpersec_total); + snprintf(kbitpersec_out_s, 30, "%03.5f", kbitpersec_out); + snprintf(kbitpersec_in_s, 30, "%03.5f", kbitpersec_in); + + results.push_back(sn+" 249 "+user->nick+" :Bandwidth total: "+ConvToStr(kbitpersec_total_s)+" kilobits/sec"); + results.push_back(sn+" 249 "+user->nick+" :Bandwidth out: "+ConvToStr(kbitpersec_out_s)+" kilobits/sec"); + results.push_back(sn+" 249 "+user->nick+" :Bandwidth in: "+ConvToStr(kbitpersec_in_s)+" kilobits/sec"); + +#ifndef WIN32 + /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef. + * Also cuts out some identical code in both branches of the ifndef. -- Om + */ + rusage R; + + /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */ + if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */ + { + results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K"); + results.push_back(sn+" 249 "+user->nick+" :Signals: "+ConvToStr(R.ru_nsignals)); + results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(R.ru_majflt)); + results.push_back(sn+" 249 "+user->nick+" :Swaps: "+ConvToStr(R.ru_nswap)); + results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw)); + + char percent[30]; + + float n_elapsed = (ServerInstance->Time() - ServerInstance->stats->LastSampled.tv_sec) * 1000000 + + (ServerInstance->Time_ns() - ServerInstance->stats->LastSampled.tv_nsec) / 1000; + float n_eaten = ((R.ru_utime.tv_sec - ServerInstance->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - ServerInstance->stats->LastCPU.tv_usec); + float per = (n_eaten / n_elapsed) * 100; + + snprintf(percent, 30, "%03.5f%%", per); + results.push_back(sn+" 249 "+user->nick+" :CPU Use (now): "+percent); + + n_elapsed = ServerInstance->Time() - ServerInstance->startup_time; + n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0; + per = (n_eaten / n_elapsed) * 100; + snprintf(percent, 30, "%03.5f%%", per); + results.push_back(sn+" 249 "+user->nick+" :CPU Use (total): "+percent); + } +#else + PROCESS_MEMORY_COUNTERS MemCounters; + if (GetProcessMemoryInfo(GetCurrentProcess(), &MemCounters, sizeof(MemCounters))) + { + results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K"); + results.push_back(sn+" 249 "+user->nick+" :Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K"); + results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(MemCounters.PageFaultCount)); + results.push_back(sn+" 249 "+user->nick+" :CPU Usage: " + ConvToStr(getcpu()) + "%"); + } +#endif + } + break; + + case 'T': + { + char buffer[MAXBUF]; + results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(ServerInstance->stats->statsAccept)+" refused "+ConvToStr(ServerInstance->stats->statsRefused)); + results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(ServerInstance->stats->statsUnknown)); + results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(ServerInstance->stats->statsCollisions)); + results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(ServerInstance->stats->statsDnsGood+ServerInstance->stats->statsDnsBad)+" succeeded "+ConvToStr(ServerInstance->stats->statsDnsGood)+" failed "+ConvToStr(ServerInstance->stats->statsDnsBad)); + results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(ServerInstance->stats->statsConnects)); + snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK", + user->nick.c_str(),ServerInstance->stats->statsSent / 1024.0,ServerInstance->stats->statsRecv / 1024.0); + results.push_back(sn+buffer); + } + break; + + /* stats o */ + case 'o': + { + ConfigTagList tags = ServerInstance->Config->ConfTags("oper"); + for(ConfigIter i = tags.first; i != tags.second; ++i) + { + ConfigTag* tag = i->second; + results.push_back(sn+" 243 "+user->nick+" O "+tag->getString("host")+" * "+ + tag->getString("name") + " " + tag->getString("type")+" 0"); + } + } + break; + case 'O': + { + for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++) + { + // just the types, not the actual oper blocks... + if (i->first[0] != ' ') + continue; + OperInfo* tag = i->second; + tag->init(); + std::string umodes; + std::string cmodes; + for(char c='A'; c < 'z'; c++) + { + ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER); + if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A']) + umodes.push_back(c); + mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL); + if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A']) + cmodes.push_back(c); + } + results.push_back(sn+" 243 "+user->nick+" O "+tag->NameStr() + " " + umodes + " " + cmodes); + } + } + break; + + /* stats l (show user I/O stats) */ + case 'l': + results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open"); + for (std::vector<LocalUser*>::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) + { + LocalUser* i = *n; + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); + } + break; + + /* stats L (show user I/O stats with IP addresses) */ + case 'L': + results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open"); + for (std::vector<LocalUser*>::iterator n = ServerInstance->Users->local_users.begin(); n != ServerInstance->Users->local_users.end(); n++) + { + LocalUser* i = *n; + results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(ServerInstance->Time() - i->age)); + } + break; + + /* stats u (show server uptime) */ + case 'u': + { + time_t current_time = 0; + current_time = ServerInstance->Time(); + time_t server_uptime = current_time - ServerInstance->startup_time; + struct tm* stime; + stime = gmtime(&server_uptime); + /* i dont know who the hell would have an ircd running for over a year nonstop, but + * Craig suggested this, and it seemed a good idea so in it went */ + if (stime->tm_year > 70) + { + char buffer[MAXBUF]; + snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick.c_str(),(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); + results.push_back(sn+buffer); + } + else + { + char buffer[MAXBUF]; + snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick.c_str(),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); + results.push_back(sn+buffer); + } + } + break; + + default: + break; + } + + results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); + ServerInstance->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", + (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + return; +} + CmdResult CommandStats::Handle (const std::vector<std::string>& parameters, User *user) { if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName) return CMD_SUCCESS; string_list values; char search = parameters[0][0]; - ServerInstance->DoStats(search, user, values); + DoStats(search, user, values); for (size_t i = 0; i < values.size(); i++) user->SendText(":%s", values[i].c_str()); diff --git a/src/configparser.cpp b/src/configparser.cpp index a8e36f6e0..b6e3f7187 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -307,7 +307,7 @@ void ParseStack::DoReadFile(const std::string& key, const std::string& name, int if (exec && (flags & FLAG_NO_EXEC)) throw CoreException("Invalid <execfiles> tag in file included with noexec=\"yes\""); - FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(name.c_str(), "r")); + FileWrapper file(exec ? popen(name.c_str(), "r") : fopen(name.c_str(), "r"), exec); if (!file) throw CoreException("Could not read \"" + name + "\" for \"" + key + "\" file"); @@ -364,7 +364,7 @@ bool ParseStack::ParseExec(const std::string& name, int flags) /* It's not already included, add it to the list of files we've loaded */ - FileWrapper file(popen(name.c_str(), "r")); + FileWrapper file(popen(name.c_str(), "r"), true); if (!file) throw CoreException("Could not open executable \"" + name + "\" for include"); diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp index 92de37e61..2cb6fb972 100644 --- a/src/hashcomp.cpp +++ b/src/hashcomp.cpp @@ -483,29 +483,17 @@ std::string& irc::stringjoiner::GetJoined() return joined; } -irc::portparser::portparser(const std::string &source, bool allow_overlapped) : in_range(0), range_begin(0), range_end(0), overlapped(allow_overlapped) +irc::portparser::portparser(const std::string &source, bool allow_overlapped) + : sep(source), in_range(0), range_begin(0), range_end(0), overlapped(allow_overlapped) { - sep = new irc::commasepstream(source); - overlap_set.clear(); -} - -irc::portparser::~portparser() -{ - delete sep; } bool irc::portparser::Overlaps(long val) { - if (!overlapped) + if (overlapped) return false; - if (overlap_set.find(val) == overlap_set.end()) - { - overlap_set[val] = true; - return false; - } - else - return true; + return (!overlap_set.insert(val).second); } long irc::portparser::GetToken() @@ -533,14 +521,14 @@ long irc::portparser::GetToken() } std::string x; - sep->GetToken(x); + sep.GetToken(x); if (x.empty()) return 0; while (Overlaps(atoi(x.c_str()))) { - if (!sep->GetToken(x)) + if (!sep.GetToken(x)) return 0; } diff --git a/src/inspircd.cpp b/src/inspircd.cpp index cf8c22633..4abfb496a 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -195,24 +195,21 @@ void InspIRCd::ResetMaxBans() void InspIRCd::RehashUsersAndChans() { user_hash* old_users = Users->clientlist; - user_hash* old_uuid = Users->uuidlist; - chan_hash* old_chans = chanlist; - - Users->clientlist = new user_hash(); - Users->uuidlist = new user_hash(); - chanlist = new chan_hash(); - + Users->clientlist = new user_hash; for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++) Users->clientlist->insert(*n); + delete old_users; + user_hash* old_uuid = Users->uuidlist; + Users->uuidlist = new user_hash; for (user_hash::const_iterator n = old_uuid->begin(); n != old_uuid->end(); n++) Users->uuidlist->insert(*n); + delete old_uuid; + chan_hash* old_chans = chanlist; + chanlist = new chan_hash; for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++) chanlist->insert(*n); - - delete old_users; - delete old_uuid; delete old_chans; // Reset the already_sent IDs so we don't wrap it around and drop a message @@ -306,7 +303,7 @@ void InspIRCd::WritePID(const std::string &filename) } InspIRCd::InspIRCd(int argc, char** argv) : - ConfigFileName("conf/inspircd.conf"), + ConfigFileName(CONFIG_PATH "/inspircd.conf"), /* Functor pointer initialisation. * diff --git a/src/mode.cpp b/src/mode.cpp index 5efc98250..845b23fb0 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -1,6 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2012 Shawn Smith <shawn@inspircd.org> * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org> * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net> @@ -132,47 +133,39 @@ bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ou ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { - if (adding) - { - if (!dest->IsModeSet(this->GetModeChar())) - { - dest->SetMode(this->GetModeChar(),true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet(this->GetModeChar())) - { - dest->SetMode(this->GetModeChar(),false); - return MODEACTION_ALLOW; - } - } + /* We're either trying to add a mode we already have or + remove a mode we don't have, deny. */ + if (dest->IsModeSet(this->GetModeChar()) == adding) + return MODEACTION_DENY; - return MODEACTION_DENY; + /* adding will be either true or false, depending on if we + are adding or removing the mode, since we already checked + to make sure we aren't adding a mode we have or that we + aren't removing a mode we don't have, we don't have to do any + other checks here to see if it's true or false, just add or + remove the mode */ + dest->SetMode(this->GetModeChar(), adding); + + return MODEACTION_ALLOW; } ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { - if (adding) - { - if (!channel->IsModeSet(this->GetModeChar())) - { - channel->SetMode(this->GetModeChar(),true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet(this->GetModeChar())) - { - channel->SetMode(this->GetModeChar(),false); - return MODEACTION_ALLOW; - } - } + /* We're either trying to add a mode we already have or + remove a mode we don't have, deny. */ + if (channel->IsModeSet(this->GetModeChar()) == adding) + return MODEACTION_DENY; - return MODEACTION_DENY; + /* adding will be either true or false, depending on if we + are adding or removing the mode, since we already checked + to make sure we aren't adding a mode we have or that we + aren't removing a mode we don't have, we don't have to do any + other checks here to see if it's true or false, just add or + remove the mode */ + channel->SetMode(this->GetModeChar(), adding); + + return MODEACTION_ALLOW; } ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) @@ -906,9 +899,6 @@ bool ModeParser::DelModeWatcher(ModeWatcher* mw) */ void ModeHandler::RemoveMode(User* user, irc::modestacker* stack) { - char moderemove[MAXBUF]; - std::vector<std::string> parameters; - if (user->IsModeSet(this->GetModeChar())) { if (stack) @@ -917,9 +907,10 @@ void ModeHandler::RemoveMode(User* user, irc::modestacker* stack) } else { - sprintf(moderemove,"-%c",this->GetModeChar()); + std::vector<std::string> parameters; parameters.push_back(user->nick); - parameters.push_back(moderemove); + parameters.push_back("-"); + parameters[1].push_back(this->GetModeChar()); ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient); } } @@ -930,9 +921,6 @@ void ModeHandler::RemoveMode(User* user, irc::modestacker* stack) */ void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack) { - char moderemove[MAXBUF]; - std::vector<std::string> parameters; - if (channel->IsModeSet(this->GetModeChar())) { if (stack) @@ -941,9 +929,10 @@ void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack) } else { - sprintf(moderemove,"-%c",this->GetModeChar()); + std::vector<std::string> parameters; parameters.push_back(channel->name); - parameters.push_back(moderemove); + parameters.push_back("-"); + parameters[1].push_back(this->GetModeChar()); ServerInstance->SendMode(parameters, ServerInstance->FakeClient); } } diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 6ca876d4c..7d8e9581e 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -28,8 +28,19 @@ #include "ssl.h" #include "m_cap.h" +#ifdef WINDOWS +# pragma comment(lib, "libgnutls.lib") +# pragma comment(lib, "libgcrypt.lib") +# pragma comment(lib, "libgpg-error.lib") +# pragma comment(lib, "user32.lib") +# pragma comment(lib, "advapi32.lib") +# pragma comment(lib, "libgcc.lib") +# pragma comment(lib, "libmingwex.lib") +# pragma comment(lib, "gdi32.lib") +#endif + /* $ModDesc: Provides SSL support for clients */ -/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") */ +/* $CompileFlags: pkgconfincludes("gnutls","/gnutls/gnutls.h","") -Wno-deprecated-declarations */ /* $LinkerFlags: rpath("pkg-config --libs gnutls") pkgconflibs("gnutls","/libgnutls.so","-lgnutls") -lgcrypt */ enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED }; @@ -151,6 +162,7 @@ class ModuleSSLGnuTLS : public Module gnutls_certificate_credentials x509_cred; gnutls_dh_params dh_params; gnutls_digest_algorithm_t hash; + gnutls_priority_t priority; std::string sslports; int dh_bits; @@ -172,6 +184,8 @@ class ModuleSSLGnuTLS : public Module gnutls_global_init(); // This must be called once in the program gnutls_x509_privkey_init(&x509_key); + // Init this here so it's always initialized, avoids an extra boolean + gnutls_priority_init(&priority, "NORMAL", NULL); cred_alloc = false; dh_alloc = false; @@ -203,6 +217,10 @@ class ModuleSSLGnuTLS : public Module if (Conf->getBool("showports", true)) { + sslports = Conf->getString("advertisedports"); + if (!sslports.empty()) + return; + for (size_t i = 0; i < ServerInstance->ports.size(); i++) { ListenSocket* port = ServerInstance->ports[i]; @@ -213,11 +231,20 @@ class ModuleSSLGnuTLS : public Module ServerInstance->Logs->Log("m_ssl_gnutls", DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %s", portid.c_str()); if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") - sslports.append(portid).append(";"); + { + /* + * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display + * the IP:port in ISUPPORT. + * + * We used to advertise all ports seperated by a ';' char that matched the above criteria, + * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. + * To solve this by default we now only display the first IP:port found and let the user + * configure the exact value for the 005 token, if necessary. + */ + sslports = portid; + break; + } } - - if (!sslports.empty()) - sslports.erase(sslports.end() - 1); } } @@ -241,6 +268,13 @@ class ModuleSSLGnuTLS : public Module dh_bits = Conf->getInt("dhbits"); std::string hashname = Conf->getString("hash", "md5"); + // The GnuTLS manual states that the gnutls_set_default_priority() + // call we used previously when initializing the session is the same + // as setting the "NORMAL" priority string. + // Thus if the setting below is not in the config we will behave exactly + // the same as before, when the priority setting wasn't available. + std::string priorities = Conf->getString("priority", "NORMAL"); + if((dh_bits != 768) && (dh_bits != 1024) && (dh_bits != 2048) && (dh_bits != 3072) && (dh_bits != 4096)) dh_bits = 1024; @@ -305,6 +339,21 @@ class ModuleSSLGnuTLS : public Module if((ret = gnutls_certificate_set_x509_key(x509_cred, &x509_certs[0], certcount, x509_key)) < 0) throw ModuleException("Unable to set GnuTLS cert/key pair: " + std::string(gnutls_strerror(ret))); + // It's safe to call this every time as we cannot have this uninitialized, see constructor and below. + gnutls_priority_deinit(priority); + + // Try to set the priorities for ciphers, kex methods etc. to the user supplied string + // If the user did not supply anything then the string is already set to "NORMAL" + const char* priocstr = priorities.c_str(); + const char* prioerror; + + if ((ret = gnutls_priority_init(&priority, priocstr, &prioerror)) < 0) + { + // gnutls did not understand the user supplied string, log and fall back to the default priorities + ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to set priorities to \"%s\": %s Syntax error at position %d, falling back to default (NORMAL)", priorities.c_str(), gnutls_strerror(ret), (prioerror - priocstr)); + gnutls_priority_init(&priority, "NORMAL", NULL); + } + gnutls_certificate_client_set_retrieve_function (x509_cred, cert_callback); ret = gnutls_dh_params_init(&dh_params); @@ -338,6 +387,7 @@ class ModuleSSLGnuTLS : public Module gnutls_x509_crt_deinit(x509_certs[i]); gnutls_x509_privkey_deinit(x509_key); + gnutls_priority_deinit(priority); if (dh_alloc) gnutls_dh_params_deinit(dh_params); @@ -399,44 +449,39 @@ class ModuleSSLGnuTLS : public Module } } - void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + void InitSession(StreamSocket* user, bool me_server) { - int fd = user->GetFd(); - issl_session* session = &sessions[fd]; - - /* For STARTTLS: Don't try and init a session on a socket that already has a session */ - if (session->sess) - return; + issl_session* session = &sessions[user->GetFd()]; - gnutls_init(&session->sess, GNUTLS_SERVER); + gnutls_init(&session->sess, me_server ? GNUTLS_SERVER : GNUTLS_CLIENT); - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. + gnutls_priority_set(session->sess, priority); gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(user)); gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); - gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. + if (me_server) + gnutls_certificate_server_set_request(session->sess, GNUTLS_CERT_REQUEST); // Request client certificate if any. Handshake(session, user); } - void OnStreamSocketConnect(StreamSocket* user) + void OnStreamSocketAccept(StreamSocket* user, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) { issl_session* session = &sessions[user->GetFd()]; - gnutls_init(&session->sess, GNUTLS_CLIENT); + /* For STARTTLS: Don't try and init a session on a socket that already has a session */ + if (session->sess) + return; - gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate. - gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred); - gnutls_dh_set_prime_bits(session->sess, dh_bits); - gnutls_transport_set_ptr(session->sess, reinterpret_cast<gnutls_transport_ptr_t>(user)); - gnutls_transport_set_push_function(session->sess, gnutls_push_wrapper); - gnutls_transport_set_pull_function(session->sess, gnutls_pull_wrapper); + InitSession(user, true); + } - Handshake(session, user); + void OnStreamSocketConnect(StreamSocket* user) + { + InitSession(user, false); } void OnStreamSocketClose(StreamSocket* user) diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index 0a5a76792..a8020bba1 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -159,20 +159,34 @@ class ModuleSSLOpenSSL : public Module if (Conf->getBool("showports", true)) { + sslports = Conf->getString("advertisedports"); + if (!sslports.empty()) + return; + for (size_t i = 0; i < ServerInstance->ports.size(); i++) { ListenSocket* port = ServerInstance->ports[i]; if (port->bind_tag->getString("ssl") != "openssl") continue; - std::string portid = port->bind_desc; + const std::string& portid = port->bind_desc; ServerInstance->Logs->Log("m_ssl_openssl", DEFAULT, "m_ssl_openssl.so: Enabling SSL for port %s", portid.c_str()); + if (port->bind_tag->getString("type", "clients") == "clients" && port->bind_addr != "127.0.0.1") - sslports.append(portid).append(";"); + { + /* + * Found an SSL port for clients that is not bound to 127.0.0.1 and handled by us, display + * the IP:port in ISUPPORT. + * + * We used to advertise all ports seperated by a ';' char that matched the above criteria, + * but this resulted in too long ISUPPORT lines if there were lots of ports to be displayed. + * To solve this by default we now only display the first IP:port found and let the user + * configure the exact value for the 005 token, if necessary. + */ + sslports = portid; + break; + } } - - if (!sslports.empty()) - sslports.erase(sslports.end() - 1); } } @@ -198,6 +212,16 @@ class ModuleSSLOpenSSL : public Module throw ModuleException("Unknown hash type " + hash); use_sha = (hash == "sha1"); + std::string ciphers = conf->getString("ciphers", ""); + + if (!ciphers.empty()) + { + if ((!SSL_CTX_set_cipher_list(ctx, ciphers.c_str())) || (!SSL_CTX_set_cipher_list(clictx, ciphers.c_str()))) + { + ServerInstance->Logs->Log("m_ssl_openssl",DEFAULT, "m_ssl_openssl.so: Can't set cipher list to %s.", ciphers.c_str()); + ERR_print_errors_cb(error_callback, this); + } + } /* Load our keys and certificates * NOTE: OpenSSL's error logging API sucks, don't blame us for this clusterfuck. @@ -262,8 +286,10 @@ class ModuleSSLOpenSSL : public Module if (sessions[user->eh.GetFd()].sess) { if (!sessions[user->eh.GetFd()].cert->fingerprint.empty()) - user->WriteServ("NOTICE %s :*** You are connected using SSL fingerprint %s", - user->nick.c_str(), sessions[user->eh.GetFd()].cert->fingerprint.c_str()); + user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"" + " and your SSL fingerprint is %s", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess), sessions[user->eh.GetFd()].cert->fingerprint.c_str()); + else + user->WriteServ("NOTICE %s :*** You are connected using SSL cipher \"%s\"", user->nick.c_str(), SSL_get_cipher(sessions[user->eh.GetFd()].sess)); } } } diff --git a/src/modules/m_blockamsg.cpp b/src/modules/m_blockamsg.cpp index 1d26b7639..8160fcf54 100644 --- a/src/modules/m_blockamsg.cpp +++ b/src/modules/m_blockamsg.cpp @@ -98,8 +98,8 @@ class ModuleBlockAmsg : public Module virtual ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - // Don't do anything with unregistered users, or remote ones. - if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user)) + // Don't do anything with unregistered users + if (user->registered != REG_ALL) return MOD_RES_PASSTHRU; // We want case insensitive command comparison. diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index 482d526eb..16eba953f 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -129,12 +129,7 @@ class ModuleChanHistory : public Module { ConfigTag* tag = ServerInstance->Config->ConfValue("chanhistory"); m.maxlines = tag->getInt("maxlines", 50); - sendnotice = tag->getInt("notice", true); - } - - ~ModuleChanHistory() - { - ServerInstance->Modes->DelMode(&m); + sendnotice = tag->getBool("notice", true); } void OnUserMessage(User* user,void* dest,int target_type, const std::string &text, char status, const CUList&) diff --git a/src/modules/m_chanlog.cpp b/src/modules/m_chanlog.cpp index ed5063fad..29385b8e2 100644 --- a/src/modules/m_chanlog.cpp +++ b/src/modules/m_chanlog.cpp @@ -28,7 +28,8 @@ class ModuleChanLog : public Module /* * Multimap so people can redirect a snomask to multiple channels. */ - std::multimap<char, std::string> logstreams; + typedef std::multimap<char, std::string> ChanLogTargets; + ChanLogTargets logstreams; public: ModuleChanLog() { @@ -72,30 +73,21 @@ class ModuleChanLog : public Module virtual ModResult OnSendSnotice(char &sno, std::string &desc, const std::string &msg) { - std::multimap<char, std::string>::const_iterator it = logstreams.find(sno); - char buf[MAXBUF]; - - if (it == logstreams.end()) + std::pair<ChanLogTargets::const_iterator, ChanLogTargets::const_iterator> itpair = logstreams.equal_range(sno); + if (itpair.first == itpair.second) return MOD_RES_PASSTHRU; + char buf[MAXBUF]; snprintf(buf, MAXBUF, "\2%s\2: %s", desc.c_str(), msg.c_str()); - while (it != logstreams.end()) + for (ChanLogTargets::const_iterator it = itpair.first; it != itpair.second; ++it) { - if (it->first != sno) - { - it++; - continue; - } - Channel *c = ServerInstance->FindChan(it->second); if (c) { c->WriteChannelWithServ(ServerInstance->Config->ServerName.c_str(), "PRIVMSG %s :%s", c->name.c_str(), buf); ServerInstance->PI->SendChannelPrivmsg(c, 0, buf); } - - it++; } return MOD_RES_PASSTHRU; diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp index 667ddd928..2ac24c5d5 100644 --- a/src/modules/m_chgname.cpp +++ b/src/modules/m_chgname.cpp @@ -52,14 +52,14 @@ class CommandChgname : public Command if (parameters[1].length() > ServerInstance->Config->Limits.MaxGecos) { - user->WriteServ("NOTICE %s :*** GECOS too long", user->nick.c_str()); + user->WriteServ("NOTICE %s :*** CHGNAME: GECOS too long", user->nick.c_str()); return CMD_FAILURE; } if (IS_LOCAL(dest)) { dest->ChangeName(parameters[1].c_str()); - ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's real name to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str()); + ServerInstance->SNO->WriteGlobalSno('a', "%s used CHGNAME to change %s's GECOS to '%s'", user->nick.c_str(), dest->nick.c_str(), dest->fullname.c_str()); } return CMD_SUCCESS; diff --git a/src/modules/m_commonchans.cpp b/src/modules/m_commonchans.cpp index ac8a7ba29..877ba87d7 100644 --- a/src/modules/m_commonchans.cpp +++ b/src/modules/m_commonchans.cpp @@ -23,32 +23,10 @@ /** Handles user mode +c */ -class PrivacyMode : public ModeHandler +class PrivacyMode : public SimpleUserModeHandler { public: - PrivacyMode(Module* Creator) : ModeHandler(Creator, "deaf_commonchan", 'c', PARAM_NONE, MODETYPE_USER) { } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('c')) - { - dest->SetMode('c',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('c')) - { - dest->SetMode('c',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } + PrivacyMode(Module* Creator) : SimpleUserModeHandler(Creator, "deaf_commonchan", 'c') { } }; class ModulePrivacyMode : public Module diff --git a/src/modules/m_connflood.cpp b/src/modules/m_connflood.cpp index d0e925716..9d7c9cb2c 100644 --- a/src/modules/m_connflood.cpp +++ b/src/modules/m_connflood.cpp @@ -23,27 +23,25 @@ /* $ModDesc: Connection throttle */ -int conns = 0, throttled = 0; - class ModuleConnFlood : public Module { private: - int seconds, maxconns, timeout, boot_wait; + int seconds, timeout, boot_wait; + unsigned int conns; + unsigned int maxconns; + bool throttled; time_t first; std::string quitmsg; public: - ModuleConnFlood() { - + ModuleConnFlood() + : conns(0), throttled(false) + { InitConf(); Implementation eventlist[] = { I_OnRehash, I_OnUserRegister }; ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleConnFlood() - { - } - virtual Version GetVersion() { return Version("Connection throttle", VF_VENDOR); @@ -78,12 +76,12 @@ public: /* increase connection count */ conns++; - if (throttled == 1) + if (throttled) { if (tdiff > seconds + timeout) { /* expire throttle */ - throttled = 0; + throttled = false; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle deactivated"); return MOD_RES_PASSTHRU; } @@ -96,7 +94,7 @@ public: { if (conns >= maxconns) { - throttled = 1; + throttled = true; ServerInstance->SNO->WriteGlobalSno('a', "Connection throttle activated"); ServerInstance->Users->QuitUser(user, quitmsg); return MOD_RES_DENY; diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index b28edde83..1eb3c1899 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -20,7 +20,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style CYCLE command. */ +/* $ModDesc: Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel. */ /** Handle /CYCLE */ @@ -97,7 +97,7 @@ class ModuleCycle : public Module virtual Version GetVersion() { - return Version("Provides support for unreal-style CYCLE command.", VF_VENDOR); + return Version("Provides command CYCLE, acts as a server-side HOP command to part and rejoin a channel.", VF_VENDOR); } }; diff --git a/src/modules/m_halfop.cpp b/src/modules/m_halfop.cpp index f0eda3e56..7a43f0241 100644 --- a/src/modules/m_halfop.cpp +++ b/src/modules/m_halfop.cpp @@ -92,11 +92,6 @@ class ModuleHalfop : public Module throw ModuleException("Could not add new modes!"); } - ~ModuleHalfop() - { - ServerInstance->Modes->DelMode(&mh); - } - Version GetVersion() { return Version("Channel half-operator mode provider", VF_VENDOR); diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index bbc7ae3ac..60c23f45b 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -29,35 +29,13 @@ static std::map<irc::string, std::string> helpop_map; /** Handles user mode +h */ -class Helpop : public ModeHandler +class Helpop : public SimpleUserModeHandler { public: - Helpop(Module* Creator) : ModeHandler(Creator, "helpop", 'h', PARAM_NONE, MODETYPE_USER) + Helpop(Module* Creator) : SimpleUserModeHandler(Creator, "helpop", 'h') { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('h')) - { - dest->SetMode('h',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('h')) - { - dest->SetMode('h',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; /** Handles /HELPOP diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp index 17e2e8605..9c582551b 100644 --- a/src/modules/m_hidechans.cpp +++ b/src/modules/m_hidechans.cpp @@ -24,32 +24,10 @@ /** Handles user mode +I */ -class HideChans : public ModeHandler +class HideChans : public SimpleUserModeHandler { public: - HideChans(Module* Creator) : ModeHandler(Creator, "hidechans", 'I', PARAM_NONE, MODETYPE_USER) { } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('I')) - { - dest->SetMode('I',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('I')) - { - dest->SetMode('I',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } + HideChans(Module* Creator) : SimpleUserModeHandler(Creator, "hidechans", 'I') { } }; class ModuleHideChans : public Module diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index cde50b1a9..998a57bb3 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -25,35 +25,13 @@ /** Handles user mode +H */ -class HideOper : public ModeHandler +class HideOper : public SimpleUserModeHandler { public: - HideOper(Module* Creator) : ModeHandler(Creator, "hideoper", 'H', PARAM_NONE, MODETYPE_USER) + HideOper(Module* Creator) : SimpleUserModeHandler(Creator, "hideoper", 'H') { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('H')) - { - dest->SetMode('H',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('H')) - { - dest->SetMode('H',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; class ModuleHideOper : public Module diff --git a/src/modules/m_hostchange.cpp b/src/modules/m_hostchange.cpp index 2635015c7..e63c61631 100644 --- a/src/modules/m_hostchange.cpp +++ b/src/modules/m_hostchange.cpp @@ -28,12 +28,22 @@ class Host { public: - std::string action; + enum HostChangeAction + { + HCA_SET, + HCA_SUFFIX, + HCA_ADDNICK + }; + + HostChangeAction action; std::string newhost; std::string ports; + + Host(HostChangeAction Action, const std::string& Newhost, const std::string& Ports) : + action(Action), newhost(Newhost), ports(Ports) {} }; -typedef std::map<std::string,Host*> hostchanges_t; +typedef std::vector<std::pair<std::string, Host> > hostchanges_t; class ModuleHostChange : public Module { @@ -51,44 +61,39 @@ class ModuleHostChange : public Module ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleHostChange() - { - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - delete i->second; - } - hostchanges.clear(); - } - - void Prioritize() - { - Module* cloak = ServerInstance->Modules->Find("m_cloaking.so"); - ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_AFTER, &cloak); - } - - virtual void OnRehash(User* user) { ConfigReader Conf; MySuffix = Conf.ReadValue("host","suffix",0); MyPrefix = Conf.ReadValue("host","prefix","",0); MySeparator = Conf.ReadValue("host","separator",".",0); - for (hostchanges_t::iterator i = hostchanges.begin(); i != hostchanges.end(); i++) - { - delete i->second; - } hostchanges.clear(); - for (int index = 0; index < Conf.Enumerate("hostchange"); index++) + + std::set<std::string> dupecheck; + ConfigTagList tags = ServerInstance->Config->ConfTags("hostchange"); + for (ConfigIter i = tags.first; i != tags.second; ++i) { - std::string mask = Conf.ReadValue("hostchange", "mask", index); - std::string ports = Conf.ReadValue("hostchange", "ports", index); - std::string action = Conf.ReadValue("hostchange", "action", index); - std::string newhost = Conf.ReadValue("hostchange", "value", index); - Host* x = new Host; - x->action = action; - x->ports = ports; - x->newhost = newhost; - hostchanges[mask] = x; + ConfigTag* tag = i->second; + std::string mask = tag->getString("mask"); + if (!dupecheck.insert(mask).second) + throw ModuleException("Duplicate hostchange entry: " + mask); + + Host::HostChangeAction act; + std::string newhost; + std::string action = tag->getString("action"); + if (!strcasecmp(action.c_str(), "set")) + { + act = Host::HCA_SET; + newhost = tag->getString("newhost"); + } + else if (!strcasecmp(action.c_str(), "suffix")) + act = Host::HCA_SUFFIX; + else if (!strcasecmp(action.c_str(), "addnick")) + act = Host::HCA_ADDNICK; + else + throw ModuleException("Invalid hostchange action: " + action); + + hostchanges.push_back(std::make_pair(mask, Host(act, tag->getString("ports"), newhost))); } } @@ -105,11 +110,11 @@ class ModuleHostChange : public Module { if (((InspIRCd::MatchCIDR(user->MakeHost(), i->first)) || (InspIRCd::MatchCIDR(user->MakeHostIP(), i->first)))) { - Host* h = i->second; + const Host& h = i->second; - if (!h->ports.empty()) + if (!h.ports.empty()) { - irc::portparser portrange(h->ports, false); + irc::portparser portrange(h.ports, false); long portno = -1; bool foundany = false; @@ -123,27 +128,26 @@ class ModuleHostChange : public Module // host of new user matches a hostchange tag's mask std::string newhost; - if (h->action == "set") + if (h.action == Host::HCA_SET) { - newhost = h->newhost; + newhost = h.newhost; } - else if (h->action == "suffix") + else if (h.action == Host::HCA_SUFFIX) { newhost = MySuffix; } - else if (h->action == "addnick") + else if (h.action == Host::HCA_ADDNICK) { // first take their nick and strip out non-dns, leaving just [A-Z0-9\-] std::string complete; - std::string old = user->nick; - for (unsigned int j = 0; j < old.length(); j++) + for (std::string::const_iterator j = user->nick.begin(); j != user->nick.end(); ++j) { - if (((old[j] >= 'A') && (old[j] <= 'Z')) || - ((old[j] >= 'a') && (old[j] <= 'z')) || - ((old[j] >= '0') && (old[j] <= '9')) || - (old[j] == '-')) + if (((*j >= 'A') && (*j <= 'Z')) || + ((*j >= 'a') && (*j <= 'z')) || + ((*j >= '0') && (*j <= '9')) || + (*j == '-')) { - complete = complete + old[j]; + complete = complete + *j; } } if (complete.empty()) diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index b7c9c1cfd..c30e4d200 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -216,15 +216,17 @@ class IdentRequestSocket : public EventHandler char ibuf[MAXBUF]; int recvresult = ServerInstance->SE->Recv(this, ibuf, MAXBUF-1, 0); + /* Close (but don't delete from memory) our socket + * and flag as done since the ident lookup has finished + */ + Close(); + done = true; + /* Cant possibly be a valid response shorter than 3 chars, * because the shortest possible response would look like: '1,1' */ if (recvresult < 3) - { - Close(); - done = true; return; - } ServerInstance->Logs->Log("m_ident",DEBUG,"ReadResponse()"); @@ -263,13 +265,6 @@ class IdentRequestSocket : public EventHandler break; } - - /* Close (but dont delete from memory) our socket - * and flag as done - */ - Close(); - done = true; - return; } }; @@ -388,7 +383,11 @@ class ModuleIdent : public Module { /* Module unloading, tidy up users */ if (target_type == TYPE_USER) - OnUserDisconnect((LocalUser*)item); + { + LocalUser* user = IS_LOCAL((User*) item); + if (user) + OnUserDisconnect(user); + } } virtual void OnUserDisconnect(LocalUser *user) diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index f3045cf52..ff92fcaa3 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -33,47 +33,30 @@ class floodsettings { public: bool ban; - int secs; - int lines; + unsigned int secs; + unsigned int lines; time_t reset; - std::map<User*,int> counters; + std::map<User*, unsigned int> counters; floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c) { reset = ServerInstance->Time() + secs; - }; + } - void addmessage(User* who) + bool addmessage(User* who) { - std::map<User*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - iter->second++; - } - else - { - counters[who] = 1; - } if (ServerInstance->Time() > reset) { counters.clear(); reset = ServerInstance->Time() + secs; } - } - bool shouldkick(User* who) - { - std::map<User*,int>::iterator iter = counters.find(who); - if (iter != counters.end()) - { - return (iter->second >= this->lines); - } - else return false; + return (++counters[who] >= this->lines); } void clear(User* who) { - std::map<User*,int>::iterator iter = counters.find(who); + std::map<User*, unsigned int>::iterator iter = counters.find(who); if (iter != counters.end()) { counters.erase(iter); @@ -92,101 +75,45 @@ class MsgFlood : public ModeHandler ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { - floodsettings *f = ext.get(channel); - if (adding) { - char ndata[MAXBUF]; - char* data = ndata; - strlcpy(ndata,parameter.c_str(),MAXBUF); - char* lines = data; - char* secs = NULL; - bool ban = false; - if (*data == '*') - { - ban = true; - lines++; - } - else + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - ban = false; - } - while (*data) - { - if (*data == ':') - { - *data = 0; - data++; - secs = data; - break; - } - else data++; - } - if (secs) - { - /* Set up the flood parameters for this channel */ - int nlines = atoi(lines); - int nsecs = atoi(secs); - if ((nlines<2) || (nsecs<1)) - { - source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - if (!f) - { - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - f = new floodsettings(ban,nsecs,nlines); - ext.set(channel, f); - channel->SetModeParam('f', parameter); - return MODEACTION_ALLOW; - } - else - { - std::string cur_param = channel->GetModeParameter('f'); - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" +ConvToStr(nsecs); - if (cur_param == parameter) - { - // mode params match - return MODEACTION_DENY; - } - else - { - if ((((nlines != f->lines) || (nsecs != f->secs) || (ban != f->ban))) && (((nsecs > 0) && (nlines > 0)))) - { - floodsettings *fs = new floodsettings(ban,nsecs,nlines); - ext.set(channel, fs); - channel->SetModeParam('f', parameter); - return MODEACTION_ALLOW; - } - else - { - return MODEACTION_DENY; - } - } - } - } + source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); + return MODEACTION_DENY; } - else + + /* Set up the flood parameters for this channel */ + bool ban = (parameter[0] == '*'); + unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); + + if ((nlines<2) || (nsecs<1)) { source->WriteNumeric(608, "%s %s :Invalid flood parameter",source->nick.c_str(),channel->name.c_str()); - parameter.clear(); return MODEACTION_DENY; } + + floodsettings* f = ext.get(channel); + if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban)) + // mode params match + return MODEACTION_DENY; + + ext.set(channel, new floodsettings(ban, nsecs, nlines)); + parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs); + channel->SetModeParam('f', parameter); + return MODEACTION_ALLOW; } else { - if (f) - { - ext.unset(channel); - channel->SetModeParam('f', ""); - return MODEACTION_ALLOW; - } - } + if (!channel->IsModeSet('f')) + return MODEACTION_DENY; - return MODEACTION_DENY; + ext.unset(channel); + channel->SetModeParam('f', ""); + return MODEACTION_ALLOW; + } } }; @@ -208,15 +135,16 @@ class ModuleMsgFlood : public Module ModResult ProcessMessages(User* user,Channel* dest, const std::string &text) { - ModResult res = ServerInstance->OnCheckExemption(user,dest,"flood"); - if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) + if ((!IS_LOCAL(user)) || !dest->IsModeSet('f')) + return MOD_RES_PASSTHRU; + + if (ServerInstance->OnCheckExemption(user,dest,"flood") == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; floodsettings *f = mf.ext.get(dest); if (f) { - f->addmessage(user); - if (f->shouldkick(user)) + if (f->addmessage(user)) { /* Youre outttta here! */ f->clear(user); @@ -230,7 +158,7 @@ class ModuleMsgFlood : public Module } char kickmessage[MAXBUF]; - snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %d lines in %d secs)", f->lines, f->secs); + snprintf(kickmessage, MAXBUF, "Channel flood triggered (limit is %u lines in %u secs)", f->lines, f->secs); dest->KickUser(ServerInstance->FakeClient, user, kickmessage); diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index 2603b0ce5..535f6ec10 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -52,13 +52,12 @@ class ModuleNamesX : public Module ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - irc::string c = command.c_str(); /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ - if (c == "PROTOCTL") + if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"NAMESX"))) { @@ -83,13 +82,16 @@ class ModuleNamesX : public Module void OnSendWhoLine(User* source, const std::vector<std::string>& params, User* user, std::string& line) { - if (!cap.ext.get(source) || line.empty()) + if (!cap.ext.get(source)) return; - std::string::size_type pos = line.find(':'); - if (pos == std::string::npos || pos < 2) + // Channel names can contain ":", and ":" as a 'start-of-token' delimiter is + // only ever valid after whitespace, so... find the actual delimiter first! + // Thanks to FxChiP for pointing this out. + std::string::size_type pos = line.find(" :"); + if (pos == std::string::npos || pos == 0) return; - pos -= 2; + pos--; // Don't do anything if the user has no prefixes if ((line[pos] == 'H') || (line[pos] == 'G') || (line[pos] == '*')) return; diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index 8c8e1c473..d6db7a7f7 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -67,7 +67,7 @@ class ModuleNoCTCP : public Module if (!c->IsModeSet('C')) return MOD_RES_PASSTHRU; - if ((text.empty()) || (text[0] != '\001') || (strncmp(text.c_str(),"\1ACTION ",8))) + if ((text.empty()) || (text[0] != '\001') || (!strncmp(text.c_str(),"\1ACTION ",8))) return MOD_RES_PASSTHRU; ModResult res = ServerInstance->OnCheckExemption(user,c,"noctcp"); diff --git a/src/modules/m_nokicks.cpp b/src/modules/m_nokicks.cpp index 2e598dafe..58e6fbea1 100644 --- a/src/modules/m_nokicks.cpp +++ b/src/modules/m_nokicks.cpp @@ -22,7 +22,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style channel mode +Q */ +/* $ModDesc: Provides channel mode +Q to prevent kicks on the channel. */ class NoKicks : public SimpleChannelModeHandler { @@ -74,7 +74,7 @@ class ModuleNoKicks : public Module Version GetVersion() { - return Version("Provides support for unreal-style channel mode +Q", VF_VENDOR); + return Version("Provides channel mode +Q to prevent kicks on the channel.", VF_VENDOR); } }; diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp index 074c644e1..2e6fad79f 100644 --- a/src/modules/m_operchans.cpp +++ b/src/modules/m_operchans.cpp @@ -24,32 +24,13 @@ /* $ModDesc: Provides support for oper-only chans via the +O channel mode */ -class OperChans : public ModeHandler +class OperChans : public SimpleChannelModeHandler { public: /* This is an oper-only mode */ - OperChans(Module* Creator) : ModeHandler(Creator, "operonly", 'O', PARAM_NONE, MODETYPE_CHANNEL) { oper = true; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + OperChans(Module* Creator) : SimpleChannelModeHandler(Creator, "operonly", 'O') { - if (adding) - { - if (!channel->IsModeSet('O')) - { - channel->SetMode('O',true); - return MODEACTION_ALLOW; - } - } - else - { - if (channel->IsModeSet('O')) - { - channel->SetMode('O',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; + oper = true; } }; diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 3a05fbd56..5c107b6b1 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -24,42 +24,47 @@ /* $ModDesc: Shows a message to opers after oper-up, adds /opermotd */ -static FileReader* opermotd; - -CmdResult ShowOperMOTD(User* user) -{ - if(!opermotd->FileSize()) - { - user->WriteServ(std::string("425 ") + user->nick + std::string(" :OPERMOTD file is missing")); - return CMD_FAILURE; - } - - user->WriteServ(std::string("375 ") + user->nick + std::string(" :- IRC Operators Message of the Day")); - - for(int i=0; i != opermotd->FileSize(); i++) - { - user->WriteServ(std::string("372 ") + user->nick + std::string(" :- ") + opermotd->GetLine(i)); - } - - user->WriteServ(std::string("376 ") + user->nick + std::string(" :- End of OPERMOTD")); - - /* don't route me */ - return CMD_SUCCESS; -} - /** Handle /OPERMOTD */ class CommandOpermotd : public Command { public: - CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0) + FileReader opermotd; + + CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0, 1) { flags_needed = 'o'; syntax = "[<servername>]"; } CmdResult Handle (const std::vector<std::string>& parameters, User* user) { - return ShowOperMOTD(user); + if ((parameters.empty()) || (parameters[0] == ServerInstance->Config->ServerName)) + ShowOperMOTD(user); + return CMD_SUCCESS; + } + + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) + { + if (!parameters.empty()) + return ROUTE_OPT_UCAST(parameters[0]); + return ROUTE_LOCALONLY; + } + + void ShowOperMOTD(User* user) + { + const std::string& servername = ServerInstance->Config->ServerName; + if (!opermotd.FileSize()) + { + user->SendText(":%s 455 %s :OPERMOTD file is missing", servername.c_str(), user->nick.c_str()); + return; + } + + user->SendText(":%s 375 %s :- IRC Operators Message of the Day", servername.c_str(), user->nick.c_str()); + + for (int i=0; i != opermotd.FileSize(); i++) + user->SendText(":%s 372 %s :- %s", servername.c_str(), user->nick.c_str(), opermotd.GetLine(i).c_str()); + + user->SendText(":%s 376 %s :- End of OPERMOTD", servername.c_str(), user->nick.c_str()); } }; @@ -73,36 +78,28 @@ class ModuleOpermotd : public Module void LoadOperMOTD() { ConfigTag* conf = ServerInstance->Config->ConfValue("opermotd"); - opermotd->LoadFile(conf->getString("file","opermotd")); + cmd.opermotd.LoadFile(conf->getString("file","opermotd")); onoper = conf->getBool("onoper", true); } ModuleOpermotd() : cmd(this) { - opermotd = NULL; ServerInstance->AddCommand(&cmd); - opermotd = new FileReader; LoadOperMOTD(); Implementation eventlist[] = { I_OnRehash, I_OnOper }; ServerInstance->Modules->Attach(eventlist, this, 2); } - virtual ~ModuleOpermotd() - { - delete opermotd; - opermotd = NULL; - } - virtual Version GetVersion() { - return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR); + return Version("Shows a message to opers after oper-up, adds /opermotd", VF_VENDOR | VF_OPTCOMMON); } virtual void OnOper(User* user, const std::string &opertype) { - if (onoper) - ShowOperMOTD(user); + if (onoper && IS_LOCAL(user)) + cmd.ShowOperMOTD(user); } virtual void OnRehash(User* user) diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 1a19c6645..c1e6f6c08 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -21,7 +21,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for unreal-style SAPART command */ +/* $ModDesc: Provides command SAPART to force-part users from a channel. */ /** Handle /SAPART */ @@ -116,7 +116,7 @@ class ModuleSapart : public Module virtual Version GetVersion() { - return Version("Provides support for unreal-style SAPART command", VF_OPTCOMMON | VF_VENDOR); + return Version("Provides command SAPART to force-part users from a channel.", VF_OPTCOMMON | VF_VENDOR); } }; diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp index bf65cc5d5..a0e3319af 100644 --- a/src/modules/m_satopic.cpp +++ b/src/modules/m_satopic.cpp @@ -44,8 +44,7 @@ class CommandSATopic : public Command // 3rd parameter overrides access checks target->SetTopic(user, newTopic, true); - ServerInstance->SNO->WriteToSnoMask('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); - ServerInstance->PI->SendSNONotice("A", user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); + ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SATOPIC on " + target->name + ", new topic: " + newTopic); return CMD_SUCCESS; } diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index 57a08ada4..08986d53c 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -40,19 +40,17 @@ class Channel_r : public ModeHandler if (!IS_LOCAL(source) || ServerInstance->ULine(source->nick.c_str()) || ServerInstance->ULine(source->server)) { // Only change the mode if it's not redundant - if ((adding && !channel->IsModeSet('r')) || (!adding && channel->IsModeSet('r'))) + if ((adding != channel->IsModeSet('r'))) { channel->SetMode('r',adding); return MODEACTION_ALLOW; } - - return MODEACTION_DENY; } else { source->WriteNumeric(500, "%s :Only a server may modify the +r channel mode", source->nick.c_str()); - return MODEACTION_DENY; } + return MODEACTION_DENY; } }; @@ -68,18 +66,17 @@ class User_r : public ModeHandler { if (!IS_LOCAL(source) || ServerInstance->ULine(source->nick.c_str()) || ServerInstance->ULine(source->server)) { - if ((adding && !dest->IsModeSet('r')) || (!adding && dest->IsModeSet('r'))) + if ((adding != dest->IsModeSet('r'))) { dest->SetMode('r',adding); return MODEACTION_ALLOW; } - return MODEACTION_DENY; } else { source->WriteNumeric(500, "%s :Only a server may modify the +r user mode", source->nick.c_str()); - return MODEACTION_DENY; } + return MODEACTION_DENY; } }; diff --git a/src/modules/m_servprotect.cpp b/src/modules/m_servprotect.cpp index 7df9effcc..c98eebec3 100644 --- a/src/modules/m_servprotect.cpp +++ b/src/modules/m_servprotect.cpp @@ -21,7 +21,7 @@ #include "inspircd.h" -/* $ModDesc: Provides support for Austhex style +k / UnrealIRCD +S services mode */ +/* $ModDesc: Provides usermode +k to protect services from kicks, kills and mode changes. */ /** Handles user mode +k */ @@ -64,7 +64,7 @@ class ModuleServProtectMode : public Module Version GetVersion() { - return Version("Provides support for Austhex style +k / UnrealIRCD +S services mode", VF_VENDOR); + return Version("Provides usermode +k to protect services from kicks, kills, and mode changes.", VF_VENDOR); } void OnWhois(User* src, User* dst) diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 3b8d4d149..32c1d5dc3 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -50,7 +50,7 @@ class CommandSetname : public Command if (user->ChangeName(parameters[0].c_str())) { - ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to %s", user->nick.c_str(), parameters[0].c_str()); + ServerInstance->SNO->WriteGlobalSno('a', "%s used SETNAME to change their GECOS to '%s'", user->nick.c_str(), parameters[0].c_str()); } return CMD_SUCCESS; diff --git a/src/modules/m_showwhois.cpp b/src/modules/m_showwhois.cpp index 6eec64bd5..d81dd553d 100644 --- a/src/modules/m_showwhois.cpp +++ b/src/modules/m_showwhois.cpp @@ -27,35 +27,13 @@ /** Handle user mode +W */ -class SeeWhois : public ModeHandler +class SeeWhois : public SimpleUserModeHandler { public: - SeeWhois(Module* Creator, bool IsOpersOnly) : ModeHandler(Creator, "showwhois", 'W', PARAM_NONE, MODETYPE_USER) + SeeWhois(Module* Creator, bool IsOpersOnly) : SimpleUserModeHandler(Creator, "showwhois", 'W') { oper = IsOpersOnly; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (adding) - { - if (!dest->IsModeSet('W')) - { - dest->SetMode('W',true); - return MODEACTION_ALLOW; - } - } - else - { - if (dest->IsModeSet('W')) - { - dest->SetMode('W',false); - return MODEACTION_ALLOW; - } - } - - return MODEACTION_DENY; - } }; class WhoisNoticeCmd : public Command diff --git a/src/modules/m_spanningtree/encap.cpp b/src/modules/m_spanningtree/encap.cpp index 51194e6d7..0cc293fa5 100644 --- a/src/modules/m_spanningtree/encap.cpp +++ b/src/modules/m_spanningtree/encap.cpp @@ -38,7 +38,7 @@ void TreeSocket::Encap(User* who, parameterlist ¶ms) params[params.size() - 1] = ":" + params[params.size() - 1]; - if (params[0].find('*') != std::string::npos) + if (params[0].find_first_of("*?") != std::string::npos) { Utils->DoOneToAllButSender(who->uuid, "ENCAP", params, who->server); } diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index efc00334d..3ab5dae9d 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -48,7 +48,7 @@ void SpanningTreeProtocolInterface::GetServerList(ProtoServerList &sl) bool SpanningTreeProtocolInterface::SendEncapsulatedData(const parameterlist &encap) { - if (encap[0].find('*') != std::string::npos) + if (encap[0].find_first_of("*?") != std::string::npos) { Utils->DoOneToMany(ServerInstance->Config->GetSID(), "ENCAP", encap); return true; @@ -164,26 +164,16 @@ void SpanningTreeProtocolInterface::SendChannelNotice(Channel* target, char stat void SpanningTreeProtocolInterface::SendUserPrivmsg(User* target, const std::string &text) { - TreeServer* serv = Utils->FindServer(target->server); - if (serv) - { - TreeSocket* sock = serv->GetSocket(); - if (sock) - { - sock->WriteLine(":" + ServerInstance->Config->GetSID() + " PRIVMSG " + target->nick + " :"+text); - } - } + parameterlist p; + p.push_back(target->uuid); + p.push_back(":" + text); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "PRIVMSG", p, target->server); } void SpanningTreeProtocolInterface::SendUserNotice(User* target, const std::string &text) { - TreeServer* serv = Utils->FindServer(target->server); - if (serv) - { - TreeSocket* sock = serv->GetSocket(); - if (sock) - { - sock->WriteLine(":" + ServerInstance->Config->GetSID() + " NOTICE " + target->nick + " :"+text); - } - } + parameterlist p; + p.push_back(target->uuid); + p.push_back(":" + text); + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "NOTICE", p, target->server); } diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index be5455bce..aebc7e03b 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -94,6 +94,7 @@ class TreeSocket : public BufferedSocket time_t NextPing; /* Time when we are due to ping this server */ bool LastPingWasGood; /* Responded to last ping we sent? */ int proto_version; /* Remote protocol version */ + bool ConnectionFailureShown; /* Set to true if a connection failure message was shown */ public: time_t age; @@ -315,6 +316,10 @@ class TreeSocket : public BufferedSocket /** Handle server quit on close */ virtual void Close(); + + /** Returns true if this server was introduced to the rest of the network + */ + bool Introduced(); }; #endif diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index dcb35af31..3e916544b 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -49,6 +49,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, Link* link, Autoconnect* mya capab->capab_phase = 0; MyRoot = NULL; proto_version = 0; + ConnectionFailureShown = false; LinkState = CONNECTING; if (!link->Hook.empty()) { @@ -78,6 +79,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via age = ServerInstance->Time(); LinkState = WAIT_AUTH_1; proto_version = 0; + ConnectionFailureShown = false; linkID = "inbound from " + client->addr(); FOREACH_MOD(I_OnHookIO, OnHookIO(this, via)); @@ -134,7 +136,7 @@ void TreeSocket::OnConnected() void TreeSocket::OnError(BufferedSocketError e) { - ServerInstance->SNO->WriteGlobalSno('l', "Connection to \002%s\002 failed with error: %s", + ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\002%s\002' failed with error: %s", linkID.c_str(), getError().c_str()); LinkState = DYING; } @@ -183,7 +185,7 @@ void TreeSocket::Squit(TreeServer* Current, const std::string &reason) { DelServerEvent(Utils->Creator, Current->GetName()); - if (!Current->GetSocket() || Current->GetSocket()->GetLinkState() == CONNECTED) + if (!Current->GetSocket() || Current->GetSocket()->Introduced()) { parameterlist params; params.push_back(Current->GetName()); @@ -245,3 +247,8 @@ void TreeSocket::OnDataReady() SendError("RecvQ overrun (line too long)"); Utils->Creator->loopCall = false; } + +bool TreeSocket::Introduced() +{ + return (capab == NULL); +} diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index e6fbad4c6..0a0c22e39 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -484,13 +484,13 @@ void TreeSocket::Close() if (MyRoot) Squit(MyRoot,getError()); - if (!linkID.empty()) + if (!ConnectionFailureShown) { + ConnectionFailureShown = true; ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' failed.",linkID.c_str()); time_t server_uptime = ServerInstance->Time() - this->age; if (server_uptime) ServerInstance->SNO->WriteGlobalSno('l', "Connection to '\2%s\2' was established for %s", linkID.c_str(), Utils->Creator->TimeToStr(server_uptime).c_str()); - linkID.clear(); } } diff --git a/src/modules/m_uhnames.cpp b/src/modules/m_uhnames.cpp index 37bd67440..5693eb807 100644 --- a/src/modules/m_uhnames.cpp +++ b/src/modules/m_uhnames.cpp @@ -51,13 +51,12 @@ class ModuleUHNames : public Module ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { - irc::string c = command.c_str(); /* We don't actually create a proper command handler class for PROTOCTL, * because other modules might want to have PROTOCTL hooks too. * Therefore, we just hook its as an unvalidated command therefore we * can capture it even if it doesnt exist! :-) */ - if (c == "PROTOCTL") + if (command == "PROTOCTL") { if ((parameters.size()) && (!strcasecmp(parameters[0].c_str(),"UHNAMES"))) { diff --git a/src/modules/m_uninvite.cpp b/src/modules/m_uninvite.cpp index 6c392fe49..9287589bb 100644 --- a/src/modules/m_uninvite.cpp +++ b/src/modules/m_uninvite.cpp @@ -63,22 +63,27 @@ class CommandUninvite : public Command } } - irc::string xname(c->name.c_str()); - - if (IS_LOCAL(u)) + /* Servers remember invites only for their local users, so act + * only if the target is local. Otherwise the command will be + * passed to the target users server. + */ + LocalUser* lu = IS_LOCAL(u); + if (lu) { - // TODO send messages & such out to remote servers - LocalUser* lu = IS_LOCAL(u); + irc::string xname(c->name.c_str()); if (!lu->IsInvited(xname)) { - user->WriteNumeric(505, "%s %s %s :Is not invited to channel %s", user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); + user->SendText(":%s 505 %s %s %s :Is not invited to channel %s", user->server.c_str(), user->nick.c_str(), u->nick.c_str(), c->name.c_str(), c->name.c_str()); return CMD_FAILURE; } - user->WriteNumeric(494, "%s %s %s :Uninvited", user->nick.c_str(), c->name.c_str(), u->nick.c_str()); + + user->SendText(":%s 494 %s %s %s :Uninvited", user->server.c_str(), user->nick.c_str(), c->name.c_str(), u->nick.c_str()); lu->RemoveInvite(xname); lu->WriteNumeric(493, "%s :You were uninvited from %s by %s", u->nick.c_str(), c->name.c_str(), user->nick.c_str()); - c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s uninvited %s.", - c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + + std::string msg = "*** " + user->nick + " uninvited " + u->nick + "."; + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE " + c->name + " :" + msg); + ServerInstance->PI->SendChannelNotice(c, 0, msg); } return CMD_SUCCESS; diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp index 1918f3fc5..683c14afa 100644 --- a/src/modules/m_xline_db.cpp +++ b/src/modules/m_xline_db.cpp @@ -25,6 +25,7 @@ class ModuleXLineDB : public Module { + std::vector<XLine *> xlines; bool reading_db; // If this is true, addlines are as a result of db reading, so don't bother flushing the db to disk. // DO REMEMBER TO SET IT, otherwise it's annoying :P public: @@ -49,6 +50,7 @@ class ModuleXLineDB : public Module void OnAddLine(User* source, XLine* line) { ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Adding a line"); + xlines.push_back(line); if (!reading_db) { @@ -74,6 +76,15 @@ class ModuleXLineDB : public Module void RemoveLine(XLine *line) { ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Removing a line"); + for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) + { + if ((*i) == line) + { + xlines.erase(i); + break; + } + } + WriteDatabase(); } @@ -108,19 +119,12 @@ class ModuleXLineDB : public Module fprintf(f, "VERSION 1\n"); // Now, let's write. - std::vector<std::string> types = ServerInstance->XLines->GetAllTypes(); - for (std::vector<std::string>::const_iterator it = types.begin(); it != types.end(); ++it) + XLine *line; + for (std::vector<XLine *>::iterator i = xlines.begin(); i != xlines.end(); i++) { - XLineLookup* lookup = ServerInstance->XLines->GetAll(*it); - if (!lookup) - continue; - - for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) - { - XLine *line = i->second; - fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), - ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); - } + line = (*i); + fprintf(f, "LINE %s %s %s %lu %lu :%s\n", line->type.c_str(), line->Displayable(), + ServerInstance->Config->ServerName.c_str(), (unsigned long)line->set_time, (unsigned long)line->duration, line->reason.c_str()); } ServerInstance->Logs->Log("m_xline_db",DEBUG, "xlinedb: Finished writing XLines. Checking for error.."); diff --git a/src/server.cpp b/src/server.cpp index 4bd81a6d1..b7e58c56b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -72,7 +72,7 @@ std::string InspIRCd::GetVersionString(bool operstring) if (operstring) snprintf(versiondata,MAXBUF,"%s %s :%s [%s,%s,%s]",VERSION,Config->ServerName.c_str(),SYSTEM,REVISION,SE->GetName().c_str(),Config->sid.c_str()); else - snprintf(versiondata,MAXBUF,"InspIRCd-2.0 %s :%s",Config->ServerName.c_str(),Config->CustomVersion.c_str()); + snprintf(versiondata,MAXBUF,"%s %s :%s",BRANCH,Config->ServerName.c_str(),Config->CustomVersion.c_str()); return versiondata; } diff --git a/src/stats.cpp b/src/stats.cpp deleted file mode 100644 index e5ea94b9c..000000000 --- a/src/stats.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org> - * - * This file is part of InspIRCd. InspIRCd is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include "xline.h" -#include "commands/cmd_whowas.h" - -void InspIRCd::DoStats(char statschar, User* user, string_list &results) -{ - std::string sn(this->Config->ServerName); - - bool isPublic = Config->UserStats.find(statschar) != std::string::npos; - bool isRemoteOper = IS_REMOTE(user) && IS_OPER(user); - bool isLocalOperWithPrivs = IS_LOCAL(user) && user->HasPrivPermission("servers/auspex"); - - if (!isPublic && !isRemoteOper && !isLocalOperWithPrivs) - { - this->SNO->WriteToSnoMask('t', - "%s '%c' denied for %s (%s@%s)", - (IS_LOCAL(user) ? "Stats" : "Remote stats"), - statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - results.push_back(sn + " 481 " + user->nick + " :Permission denied - STATS " + statschar + " requires the servers/auspex priv."); - return; - } - - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnStats, MOD_RESULT, (statschar, user, results)); - if (MOD_RESULT == MOD_RES_DENY) - { - results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - this->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", - (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - return; - } - - switch (statschar) - { - /* stats p (show listening ports) */ - case 'p': - { - for (size_t i = 0; i < this->ports.size(); i++) - { - std::string ip = this->ports[i]->bind_addr; - if (ip.empty()) - ip.assign("*"); - std::string type = ports[i]->bind_tag->getString("type", "clients"); - std::string hook = ports[i]->bind_tag->getString("ssl", "plaintext"); - - results.push_back(sn+" 249 "+user->nick+" :"+ ip + ":"+ConvToStr(ports[i]->bind_port)+ - " (" + type + ", " + hook + ")"); - } - } - break; - - /* These stats symbols must be handled by a linking module */ - case 'n': - case 'c': - break; - - case 'i': - { - for (ClassVector::iterator i = this->Config->Classes.begin(); i != this->Config->Classes.end(); i++) - { - ConnectClass* c = *i; - std::stringstream res; - res << sn << " 215 " << user->nick << " I " << c->name << ' '; - if (c->type == CC_ALLOW) - res << '+'; - if (c->type == CC_DENY) - res << '-'; - - if (c->type == CC_NAMED) - res << '*'; - else - res << c->host; - - res << ' ' << c->config->getString("port", "*") << ' '; - - res << c->GetRecvqMax() << ' ' << c->GetSendqSoftMax() << ' ' << c->GetSendqHardMax() - << ' ' << c->GetCommandRate() << ' ' << c->GetPenaltyThreshold(); - if (c->fakelag) - res << '*'; - results.push_back(res.str()); - } - } - break; - - case 'Y': - { - int idx = 0; - for (ClassVector::iterator i = this->Config->Classes.begin(); i != this->Config->Classes.end(); i++) - { - ConnectClass* c = *i; - results.push_back(sn+" 215 "+user->nick+" i NOMATCH * "+c->GetHost()+" "+ConvToStr(c->limit ? c->limit : this->SE->GetMaxFds())+" "+ConvToStr(idx)+" "+this->Config->ServerName+" *"); - results.push_back(sn+" 218 "+user->nick+" Y "+ConvToStr(idx)+" "+ConvToStr(c->GetPingTime())+" 0 "+ConvToStr(c->GetSendqHardMax())+" :"+ - ConvToStr(c->GetRecvqMax())+" "+ConvToStr(c->GetRegTimeout())); - idx++; - } - } - break; - - case 'U': - { - for(std::map<irc::string, bool>::iterator i = Config->ulines.begin(); i != Config->ulines.end(); ++i) - { - results.push_back(sn+" 248 "+user->nick+" U "+std::string(i->first.c_str())); - } - } - break; - - case 'P': - { - int idx = 0; - for (user_hash::iterator i = this->Users->clientlist->begin(); i != this->Users->clientlist->end(); i++) - { - if (IS_OPER(i->second) && !this->ULine(i->second->server)) - { - results.push_back(sn+" 249 "+user->nick+" :"+i->second->nick+" ("+i->second->ident+"@"+i->second->dhost+") Idle: "+ - (IS_LOCAL(i->second) ? ConvToStr(this->Time() - i->second->idle_lastmsg) + " secs" : "unavailable")); - idx++; - } - } - results.push_back(sn+" 249 "+user->nick+" :"+ConvToStr(idx)+" OPER(s)"); - } - break; - - case 'k': - this->XLines->InvokeStats("K",216,user,results); - break; - case 'g': - this->XLines->InvokeStats("G",223,user,results); - break; - case 'q': - this->XLines->InvokeStats("Q",217,user,results); - break; - case 'Z': - this->XLines->InvokeStats("Z",223,user,results); - break; - case 'e': - this->XLines->InvokeStats("E",223,user,results); - break; - case 'E': - results.push_back(sn+" 249 "+user->nick+" :Total events: "+ConvToStr(this->SE->TotalEvents)); - results.push_back(sn+" 249 "+user->nick+" :Read events: "+ConvToStr(this->SE->ReadEvents)); - results.push_back(sn+" 249 "+user->nick+" :Write events: "+ConvToStr(this->SE->WriteEvents)); - results.push_back(sn+" 249 "+user->nick+" :Error events: "+ConvToStr(this->SE->ErrorEvents)); - break; - - /* stats m (list number of times each command has been used, plus bytecount) */ - case 'm': - for (Commandtable::iterator i = this->Parser->cmdlist.begin(); i != this->Parser->cmdlist.end(); i++) - { - if (i->second->use_count) - { - /* RPL_STATSCOMMANDS */ - results.push_back(sn+" 212 "+user->nick+" "+i->second->name+" "+ConvToStr(i->second->use_count)+" "+ConvToStr(i->second->total_bytes)); - } - } - break; - - /* stats z (debug and memory info) */ - case 'z': - { - results.push_back(sn+" 249 "+user->nick+" :Users: "+ConvToStr(this->Users->clientlist->size())); - results.push_back(sn+" 249 "+user->nick+" :Channels: "+ConvToStr(this->chanlist->size())); - results.push_back(sn+" 249 "+user->nick+" :Commands: "+ConvToStr(this->Parser->cmdlist.size())); - - if (!this->Config->WhoWasGroupSize == 0 && !this->Config->WhoWasMaxGroups == 0) - { - Module* whowas = Modules->Find("cmd_whowas.so"); - if (whowas) - { - WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_STATS); - req.user = user; - req.Send(); - results.push_back(sn+" 249 "+user->nick+" :"+req.value); - } - } - - float kbitpersec_in, kbitpersec_out, kbitpersec_total; - char kbitpersec_in_s[30], kbitpersec_out_s[30], kbitpersec_total_s[30]; - - this->SE->GetStats(kbitpersec_in, kbitpersec_out, kbitpersec_total); - - snprintf(kbitpersec_total_s, 30, "%03.5f", kbitpersec_total); - snprintf(kbitpersec_out_s, 30, "%03.5f", kbitpersec_out); - snprintf(kbitpersec_in_s, 30, "%03.5f", kbitpersec_in); - - results.push_back(sn+" 249 "+user->nick+" :Bandwidth total: "+ConvToStr(kbitpersec_total_s)+" kilobits/sec"); - results.push_back(sn+" 249 "+user->nick+" :Bandwidth out: "+ConvToStr(kbitpersec_out_s)+" kilobits/sec"); - results.push_back(sn+" 249 "+user->nick+" :Bandwidth in: "+ConvToStr(kbitpersec_in_s)+" kilobits/sec"); - -#ifndef WIN32 - /* Moved this down here so all the not-windows stuff (look w00tie, I didn't say win32!) is in one ifndef. - * Also cuts out some identical code in both branches of the ifndef. -- Om - */ - rusage R; - - /* Not sure why we were doing '0' with a RUSAGE_SELF comment rather than just using RUSAGE_SELF -- Om */ - if (!getrusage(RUSAGE_SELF,&R)) /* RUSAGE_SELF */ - { - results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr(R.ru_maxrss)+"K"); - results.push_back(sn+" 249 "+user->nick+" :Signals: "+ConvToStr(R.ru_nsignals)); - results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(R.ru_majflt)); - results.push_back(sn+" 249 "+user->nick+" :Swaps: "+ConvToStr(R.ru_nswap)); - results.push_back(sn+" 249 "+user->nick+" :Context Switches: Voluntary; "+ConvToStr(R.ru_nvcsw)+" Involuntary; "+ConvToStr(R.ru_nivcsw)); - - char percent[30]; - - float n_elapsed = (ServerInstance->Time() - this->stats->LastSampled.tv_sec) * 1000000 - + (ServerInstance->Time_ns() - this->stats->LastSampled.tv_nsec) / 1000; - float n_eaten = ((R.ru_utime.tv_sec - this->stats->LastCPU.tv_sec) * 1000000 + R.ru_utime.tv_usec - this->stats->LastCPU.tv_usec); - float per = (n_eaten / n_elapsed) * 100; - - snprintf(percent, 30, "%03.5f%%", per); - results.push_back(sn+" 249 "+user->nick+" :CPU Use (now): "+percent); - - n_elapsed = ServerInstance->Time() - ServerInstance->startup_time; - n_eaten = (float)R.ru_utime.tv_sec + R.ru_utime.tv_usec / 100000.0; - per = (n_eaten / n_elapsed) * 100; - snprintf(percent, 30, "%03.5f%%", per); - results.push_back(sn+" 249 "+user->nick+" :CPU Use (total): "+percent); - } -#else - PROCESS_MEMORY_COUNTERS MemCounters; - if (GetProcessMemoryInfo(GetCurrentProcess(), &MemCounters, sizeof(MemCounters))) - { - results.push_back(sn+" 249 "+user->nick+" :Total allocation: "+ConvToStr((MemCounters.WorkingSetSize + MemCounters.PagefileUsage) / 1024)+"K"); - results.push_back(sn+" 249 "+user->nick+" :Pagefile usage: "+ConvToStr(MemCounters.PagefileUsage / 1024)+"K"); - results.push_back(sn+" 249 "+user->nick+" :Page faults: "+ConvToStr(MemCounters.PageFaultCount)); - results.push_back(sn+" 249 "+user->nick+" :CPU Usage: " + ConvToStr(getcpu()) + "%"); - } -#endif - } - break; - - case 'T': - { - char buffer[MAXBUF]; - results.push_back(sn+" 249 "+user->nick+" :accepts "+ConvToStr(this->stats->statsAccept)+" refused "+ConvToStr(this->stats->statsRefused)); - results.push_back(sn+" 249 "+user->nick+" :unknown commands "+ConvToStr(this->stats->statsUnknown)); - results.push_back(sn+" 249 "+user->nick+" :nick collisions "+ConvToStr(this->stats->statsCollisions)); - results.push_back(sn+" 249 "+user->nick+" :dns requests "+ConvToStr(this->stats->statsDnsGood+this->stats->statsDnsBad)+" succeeded "+ConvToStr(this->stats->statsDnsGood)+" failed "+ConvToStr(this->stats->statsDnsBad)); - results.push_back(sn+" 249 "+user->nick+" :connection count "+ConvToStr(this->stats->statsConnects)); - snprintf(buffer,MAXBUF," 249 %s :bytes sent %5.2fK recv %5.2fK", - user->nick.c_str(),this->stats->statsSent / 1024.0,this->stats->statsRecv / 1024.0); - results.push_back(sn+buffer); - } - break; - - /* stats o */ - case 'o': - { - ConfigTagList tags = ServerInstance->Config->ConfTags("oper"); - for(ConfigIter i = tags.first; i != tags.second; ++i) - { - ConfigTag* tag = i->second; - results.push_back(sn+" 243 "+user->nick+" O "+tag->getString("host")+" * "+ - tag->getString("name") + " " + tag->getString("type")+" 0"); - } - } - break; - case 'O': - { - for(OperIndex::iterator i = ServerInstance->Config->oper_blocks.begin(); i != ServerInstance->Config->oper_blocks.end(); i++) - { - // just the types, not the actual oper blocks... - if (i->first[0] != ' ') - continue; - OperInfo* tag = i->second; - tag->init(); - std::string umodes; - std::string cmodes; - for(char c='A'; c < 'z'; c++) - { - ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER); - if (mh && mh->NeedsOper() && tag->AllowedUserModes[c - 'A']) - umodes.push_back(c); - mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL); - if (mh && mh->NeedsOper() && tag->AllowedChanModes[c - 'A']) - cmodes.push_back(c); - } - results.push_back(sn+" 243 "+user->nick+" O "+tag->NameStr() + " " + umodes + " " + cmodes); - } - } - break; - - /* stats l (show user I/O stats) */ - case 'l': - results.push_back(sn+" 211 "+user->nick+" :nick[ident@host] sendq cmds_out bytes_out cmds_in bytes_in time_open"); - for (std::vector<LocalUser*>::iterator n = this->Users->local_users.begin(); n != this->Users->local_users.end(); n++) - { - LocalUser* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->dhost+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); - } - break; - - /* stats L (show user I/O stats with IP addresses) */ - case 'L': - results.push_back(sn+" 211 "+user->nick+" :nick[ident@ip] sendq cmds_out bytes_out cmds_in bytes_in time_open"); - for (std::vector<LocalUser*>::iterator n = this->Users->local_users.begin(); n != this->Users->local_users.end(); n++) - { - LocalUser* i = *n; - results.push_back(sn+" 211 "+user->nick+" "+i->nick+"["+i->ident+"@"+i->GetIPString()+"] "+ConvToStr(i->eh.getSendQSize())+" "+ConvToStr(i->cmds_out)+" "+ConvToStr(i->bytes_out)+" "+ConvToStr(i->cmds_in)+" "+ConvToStr(i->bytes_in)+" "+ConvToStr(this->Time() - i->age)); - } - break; - - /* stats u (show server uptime) */ - case 'u': - { - time_t current_time = 0; - current_time = this->Time(); - time_t server_uptime = current_time - this->startup_time; - struct tm* stime; - stime = gmtime(&server_uptime); - /* i dont know who the hell would have an ircd running for over a year nonstop, but - * Craig suggested this, and it seemed a good idea so in it went */ - if (stime->tm_year > 70) - { - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF," 242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick.c_str(),(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); - results.push_back(sn+buffer); - } - else - { - char buffer[MAXBUF]; - snprintf(buffer,MAXBUF," 242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick.c_str(),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); - results.push_back(sn+buffer); - } - } - break; - - default: - break; - } - - results.push_back(sn+" 219 "+user->nick+" "+statschar+" :End of /STATS report"); - this->SNO->WriteToSnoMask('t',"%s '%c' requested by %s (%s@%s)", - (IS_LOCAL(user) ? "Stats" : "Remote stats"), statschar, user->nick.c_str(), user->ident.c_str(), user->host.c_str()); - return; -} diff --git a/src/users.cpp b/src/users.cpp index 9c3d645f7..459b9e3ce 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -772,9 +772,9 @@ void LocalUser::FullConnect() this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str()); this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), this->nick.c_str(), this->ident.c_str(), this->host.c_str()); - this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version InspIRCd-2.0",this->nick.c_str(),ServerInstance->Config->ServerName.c_str()); + this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH); this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__); - this->WriteNumeric(RPL_SERVERVERSION, "%s %s InspIRCd-2.0 %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str()); + this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str()); ServerInstance->Config->Send005(this); this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str()); diff --git a/src/version.sh b/src/version.sh index 008c807dd..08ee17904 100755 --- a/src/version.sh +++ b/src/version.sh @@ -1,2 +1,2 @@ #!/bin/sh -echo "InspIRCd-2.0.7" +echo "InspIRCd-2.0.8" diff --git a/src/xline.cpp b/src/xline.cpp index ed3ed6364..397b937ec 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -252,8 +252,6 @@ IdentHostPair XLineManager::IdentSplit(const std::string &ident_and_host) bool XLineManager::AddLine(XLine* line, User* user) { - ServerInstance->BanCache->RemoveEntries(line->type, false); // XXX perhaps remove ELines here? - if (line->duration && ServerInstance->Time() > line->expiry) return false; // Don't apply expired XLines. @@ -273,6 +271,8 @@ bool XLineManager::AddLine(XLine* line, User* user) if (!xlf) return false; + ServerInstance->BanCache->RemoveEntries(line->type, false); // XXX perhaps remove ELines here? + if (xlf->AutoApplyToUserList(line)) pending_lines.push_back(line); diff --git a/win/configure.cpp b/win/configure.cpp index ee03b3659..768b68cc5 100644 --- a/win/configure.cpp +++ b/win/configure.cpp @@ -275,7 +275,11 @@ void Run() fclose(fI); } else - strcpy(version, "InspIRCD-Unknown"); + strcpy(version, "InspIRCd-0.0.0"); + + string branch(version); + branch.erase(branch.find_last_of('.')); + #ifdef WIN64 printf_c("Your operating system is: \033[1;32mwindows_x64 \033[0m\n"); #else @@ -351,6 +355,7 @@ void Run() sc(TGREEN); printf(" done\n"); sc(TNORMAL); printf("Writing inspircd_version.h..."); f = fopen("inspircd_version.h", "w"); + fprintf(f, "#define BRANCH \"%s\"\n", branch.c_str()); fprintf(f, "#define VERSION \"%s\"\n", version); fprintf(f, "#define REVISION \"%s\"\n", revision.c_str()); fprintf(f, "#define SYSTEM \"%s\"\n", machine_text); diff --git a/win/inspircd.nsi b/win/inspircd.nsi index e263f4561..1fa21c6f9 100644 --- a/win/inspircd.nsi +++ b/win/inspircd.nsi @@ -153,6 +153,10 @@ SectionEnd Section "Config Files" SEC02 SetOutPath "$INSTDIR\conf" File "..\docs\conf\*.example" + SetOutPath "$INSTDIR\conf\aliases" + File "..\docs\conf\aliases\*.example" + SetOutPath "$INSTDIR\conf\modules" + File "..\docs\conf\modules\modules.*" SectionEnd Section "Command Handlers" SEC03 @@ -163,6 +167,10 @@ SectionEnd Section "Modules" SEC04 SetOutPath "$INSTDIR\modules" File "..\bin\${BUILD}\modules\m_*.so" + ; Copy DLLs required for modules + SetOutPath "$INSTDIR" + File /nonfatal "*.dll" + File "make_gnutls_cert.bat" SectionEnd Section -AdditionalIcons @@ -216,9 +224,13 @@ Section Uninstall Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\modules\*.so" Delete "$INSTDIR\conf\*.example" + Delete "$INSTDIR\conf\aliases\*.example" + Delete "$INSTDIR\conf\modules\*.example" Delete "$INSTDIR\*.log" Delete "$INSTDIR\logs\*" Delete "$INSTDIR\data\*" + Delete "$INSTDIR\*.dll" + Delete "$INSTDIR\make_gnutls_cert.bat" Delete "$INSTDIR\inspircd.exe" Delete "$SMPROGRAMS\InspIRCd\Uninstall.lnk" Delete "$SMPROGRAMS\InspIRCd\InspIRCd Website.lnk" diff --git a/win/inspircd.vcxproj b/win/inspircd.vcxproj index 03bacaad3..d6da89562 100644 --- a/win/inspircd.vcxproj +++ b/win/inspircd.vcxproj @@ -308,7 +308,6 @@ nmake -f modules.mak <ClCompile Include="..\src\socket.cpp" /> <ClCompile Include="..\src\socketengine.cpp" /> <ClCompile Include="..\src\socketengines\socketengine_select.cpp" /> - <ClCompile Include="..\src\stats.cpp" /> <ClCompile Include="..\src\testsuite.cpp" /> <ClCompile Include="..\src\threadengine.cpp" /> <ClCompile Include="..\src\threadengines\threadengine_win32.cpp" /> @@ -390,4 +389,4 @@ nmake -f modules.mak <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/win/inspircd_win32wrapper.cpp b/win/inspircd_win32wrapper.cpp index 43ca87240..ec4e7833b 100644 --- a/win/inspircd_win32wrapper.cpp +++ b/win/inspircd_win32wrapper.cpp @@ -738,6 +738,7 @@ static void unused_function() reference<Link> unused_Link; reference<Autoconnect> unused_Autoconnect; reference<ssl_cert> unused_Cert; + reference<OperInfo> unused_OperInfo; if (unused_Link) unused_Link->Port = -1; @@ -745,20 +746,26 @@ static void unused_function() unused_Autoconnect->NextConnectTime = -1; if (unused_Cert) unused_Cert->dn = ""; + if (unused_OperInfo) + unused_OperInfo->name = ""; Autoconnect *a = unused_Autoconnect; Link *l = unused_Link; ssl_cert *s = unused_Cert; + OperInfo *o = unused_OperInfo; unused_Link = reference<Link>(unused_Link); unused_Autoconnect = reference<Autoconnect>(unused_Autoconnect); unused_Cert = reference<ssl_cert>(unused_Cert); + unused_OperInfo = reference<OperInfo>(unused_OperInfo); unused_Link = reference<Link>(l); unused_Autoconnect = reference<Autoconnect>(a); unused_Cert = reference<ssl_cert>(s); + unused_OperInfo = reference<OperInfo>(o); delete unused_Link; delete unused_Autoconnect; delete unused_Cert; + delete unused_OperInfo; } diff --git a/win/inspircd_win32wrapper.h b/win/inspircd_win32wrapper.h index 85572fd64..bc7165262 100644 --- a/win/inspircd_win32wrapper.h +++ b/win/inspircd_win32wrapper.h @@ -231,7 +231,6 @@ CoreExport int clock_gettime(int clock, struct timespec * tv); typedef unsigned char uint8_t; typedef unsigned long long uint64_t; typedef signed char int8_t; -typedef signed long int32_t; typedef signed long long int64_t; typedef signed long ssize_t; diff --git a/win/make_gnutls_cert.bat b/win/make_gnutls_cert.bat new file mode 100644 index 000000000..97792cc29 --- /dev/null +++ b/win/make_gnutls_cert.bat @@ -0,0 +1,14 @@ +@echo off
+
+echo This program will generate SSL certificates for m_ssl_gnutls.so
+echo Ensure certtool.exe is in your system path. It can be downloaded
+echo at ftp://ftp.gnu.org/gnu/gnutls/w32/. If you do not know the answer
+echo to one of the questions just press enter.
+echo.
+
+pause
+
+certtool --generate-privkey --outfile conf/key.pem
+certtool --generate-self-signed --load-privkey conf/key.pem --outfile conf/cert.pem
+
+pause
\ No newline at end of file |