*/
typedef nspace::hash_map<std::string, TreeServer*, nspace::hash<string>, irc::StrHashComp> server_hash;
+typedef std::map<TreeServer*,TreeServer*> TreeServerList;
/** The Link class might as well be a struct,
* but this is C++ and we don't believe in structs (!).
void ReadConfiguration(bool rebind);
/** Add a server to the server list for GetListOfServersForChannel
*/
- void AddThisServer(TreeServer* server, std::deque<TreeServer*> &list);
+ void AddThisServer(TreeServer* server, TreeServerList &list);
/** Compile a list of servers which contain members of channel c
*/
- void GetListOfServersForChannel(chanrec* c, std::deque<TreeServer*> &list);
+ void GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list);
/** Find a server by name
*/
TreeServer* FindServer(const std::string &ServerName);
userrec* who = NULL; /* User we are currently checking */
std::string channel = params[0]; /* Channel name, as a string */
time_t TS = atoi(params[1].c_str()); /* Timestamp given to us for remote side */
+ bool created = false;
/* Try and find the channel */
chanrec* chan = this->Instance->FindChan(channel);
/* Does this channel exist? if it does, get its REAL timestamp */
if (chan)
ourTS = chan->age;
+ else
+ created = true; /* don't perform deops, and set TS to correct time after processing. */
/* In 1.1, if they have the newer channel, we immediately clear
* all status modes from our users. We then accept their modes.
{
std::deque<std::string> param_list;
- if (chan)
- chan->age = TS;
-
/* Lower the TS here */
if (Utils->AnnounceTSChange && chan)
chan->WriteChannelWithServ(Instance->Config->ServerName,
"NOTICE %s :TS for %s changed from %lu to %lu", chan->name, chan->name, ourTS, TS);
ourTS = TS;
-
param_list.push_back(channel);
- /* Zap all the privilage modes on our side */
- this->RemoveStatus(Instance->Config->ServerName, param_list);
+
+ /* Zap all the privilage modes on our side, if the channel exists here */
+ if (!created)
+ {
+ this->RemoveStatus(Instance->Config->ServerName, param_list);
+ chan->age = TS;
+ }
}
/* Put the final parameter of the FJOIN into a tokenstream ready to split it */
free(mode_users[f]);
}
+ /* if we newly created the channel, set it's TS properly. */
+ if (created)
+ {
+ /* find created channel .. */
+ chan = this->Instance->FindChan(channel);
+ if (chan)
+ /* w00t said this shouldnt be needed but it is.
+ * This isnt strictly true, as chan can be NULL
+ * if a nick collision has occured and therefore
+ * the channel was never created.
+ */
+ chan->age = TS;
+ }
+
/* All done. That wasnt so bad was it, you can wipe
* the sweat from your forehead now. :-)
*/
delete TreeRoot;
}
-void SpanningTreeUtilities::AddThisServer(TreeServer* server, std::deque<TreeServer*> &list)
+void SpanningTreeUtilities::AddThisServer(TreeServer* server, TreeServerList &list)
{
- for (unsigned int c = 0; c < list.size(); c++)
- {
- if (list[c] == server)
- {
- return;
- }
- }
- list.push_back(server);
+ if (list.find(server) == list.end())
+ list[server] = server;
}
/** returns a list of DIRECT servernames for a specific channel */
-void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, std::deque<TreeServer*> &list)
+void SpanningTreeUtilities::GetListOfServersForChannel(chanrec* c, TreeServerList &list, char status, const CUList &exempt_list)
{
- CUList *ulist = c->GetUsers();
+ CUList *ulist;
+ switch (status)
+ {
+ case '@':
+ ulist = c->GetOppedUsers();
+ break;
+ case '%':
+ ulist = c->GetHalfoppedUsers();
+ break;
+ case '+':
+ ulist = c->GetVoicedUsers();
+ break;
+ default:
+ ulist = c->GetUsers();
+ break;
+ }
for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
- if (i->second->GetFd() < 0)
+ if ((i->second->GetFd() < 0) && (exempt_list.find(i->second) == exempt_list.end()))
{
TreeServer* best = this->BestRouteTo(i->second->server);
if (best)
bool SpanningTreeUtilities::DoOneToAllButSenderRaw(const std::string &data, const std::string &omit, const std::string &prefix, const irc::string &command, std::deque<std::string> ¶ms)
{
+ char pfx = 0;
TreeServer* omitroute = this->BestRouteTo(omit);
if ((command == "NOTICE") || (command == "PRIVMSG"))
{
/* Prefixes */
if ((*(params[0].c_str()) == '@') || (*(params[0].c_str()) == '%') || (*(params[0].c_str()) == '+'))
{
+ pfx = params[0][0];
params[0] = params[0].substr(1, params[0].length()-1);
}
if ((*(params[0].c_str()) != '#') && (*(params[0].c_str()) != '$'))
else
{
chanrec* c = ServerInstance->FindChan(params[0]);
- if (c)
+ userrec* u = ServerInstance->FindNick(prefix);
+ if (c && u)
{
- std::deque<TreeServer*> list;
- GetListOfServersForChannel(c,list);
- unsigned int lsize = list.size();
- for (unsigned int i = 0; i < lsize; i++)
+ CUList elist;
+ TreeServerList list;
+ FOREACH_MOD(I_OnBuildExemptList, OnBuildExemptList((command == "PRIVMSG" ? MSG_PRIVMSG : MSG_NOTICE), c, u, pfx, elist));
+ GetListOfServersForChannel(c,list,pfx,elist);
+
+ for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
- TreeSocket* Sock = list[i]->GetSocket();
- if ((Sock) && (list[i]->GetName() != omit) && (omitroute != list[i]))
+ TreeSocket* Sock = i->second->GetSocket();
+ if ((Sock) && (i->second->GetName() != omit) && (omitroute != i->second))
{
Sock->WriteLine(data);
}
if (n_users > max_global)
max_global = n_users;
- user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),this->CountServs());
+ unsigned int ulined_count = 0;
+ unsigned int ulined_local_count = 0;
+
+ /* If ulined are hidden and we're not an oper, count the number of ulined servers hidden,
+ * locally and globally (locally means directly connected to us)
+ */
+ if ((Utils->HideULines) && (!*user->oper))
+ {
+ for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++)
+ {
+ if (ServerInstance->ULine(q->second->GetName().c_str()))
+ {
+ ulined_count++;
+ if (q->second->GetParent() == Utils->TreeRoot)
+ ulined_local_count++;
+ }
+ }
+ }
+
+ user->WriteServ("251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-ServerInstance->InvisibleUserCount(),ServerInstance->InvisibleUserCount(),ulined_count ? this->CountServs() - ulined_count : this->CountServs());
if (ServerInstance->OperCount())
user->WriteServ("252 %s %d :operator(s) online",user->nick,ServerInstance->OperCount());
if (ServerInstance->UnregisteredUserCount())
user->WriteServ("253 %s %d :unknown connections",user->nick,ServerInstance->UnregisteredUserCount());
if (ServerInstance->ChannelCount())
user->WriteServ("254 %s %d :channels formed",user->nick,ServerInstance->ChannelCount());
- user->WriteServ("254 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),this->CountLocalServs());
+ user->WriteServ("254 %s :I have %d clients and %d servers",user->nick,ServerInstance->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs());
user->WriteServ("265 %s :Current Local Users: %d Max: %d",user->nick,ServerInstance->LocalUserCount(),max_local);
user->WriteServ("266 %s :Current Global Users: %d Max: %d",user->nick,n_users,max_global);
return;
virtual int OnStats(char statschar, userrec* user, string_list &results)
{
- if (statschar == 'c')
+ if ((statschar == 'c') || (statschar == 'n'))
{
for (unsigned int i = 0; i < Utils->LinkBlocks.size(); i++)
{
- results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" C *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].EncryptionKey != "" ? 'e' : '-')+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s');
- results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str());
+ results.push_back(std::string(ServerInstance->Config->ServerName)+" 213 "+user->nick+" "+statschar+" *@"+(Utils->LinkBlocks[i].HiddenFromStats ? "<hidden>" : Utils->LinkBlocks[i].IPAddr)+" * "+Utils->LinkBlocks[i].Name.c_str()+" "+ConvToStr(Utils->LinkBlocks[i].Port)+" "+(Utils->LinkBlocks[i].EncryptionKey != "" ? 'e' : '-')+(Utils->LinkBlocks[i].AutoConnect ? 'a' : '-')+'s');
+ if (statschar == 'c')
+ results.push_back(std::string(ServerInstance->Config->ServerName)+" 244 "+user->nick+" H * * "+Utils->LinkBlocks[i].Name.c_str());
}
results.push_back(std::string(ServerInstance->Config->ServerName)+" 219 "+user->nick+" "+statschar+" :End of /STATS report");
ServerInstance->SNO->WriteToSnoMask('t',"Notice: %s '%c' requested by %s (%s@%s)",(!strcmp(user->server,ServerInstance->Config->ServerName) ? "Stats" : "Remote stats"),statschar,user->nick,user->ident,user->host);
}
}
- virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status)
+ virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_USER)
{
std::string cname = c->name;
if (status)
cname = status + cname;
- std::deque<TreeServer*> list;
- Utils->GetListOfServersForChannel(c,list);
- unsigned int ucount = list.size();
- for (unsigned int i = 0; i < ucount; i++)
+ TreeServerList list;
+ Utils->GetListOfServersForChannel(c,list,status,exempt_list);
+
+ for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
- TreeSocket* Sock = list[i]->GetSocket();
+ TreeSocket* Sock = i->second->GetSocket();
if (Sock)
Sock->WriteLine(":"+std::string(user->nick)+" NOTICE "+cname+" :"+text);
}
}
}
- virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status)
+ virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status, const CUList &exempt_list)
{
if (target_type == TYPE_USER)
{
std::string cname = c->name;
if (status)
cname = status + cname;
- std::deque<TreeServer*> list;
- Utils->GetListOfServersForChannel(c,list);
- unsigned int ucount = list.size();
- for (unsigned int i = 0; i < ucount; i++)
+ TreeServerList list;
+ Utils->GetListOfServersForChannel(c,list,status,exempt_list);
+
+ for (TreeServerList::iterator i = list.begin(); i != list.end(); i++)
{
- TreeSocket* Sock = list[i]->GetSocket();
+ TreeSocket* Sock = i->second->GetSocket();
if (Sock)
Sock->WriteLine(":"+std::string(user->nick)+" PRIVMSG "+cname+" :"+text);
}