X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_spanningtree.cpp;h=fa22f80a1555bd523e0328078845a33f21e23990;hb=8b126657e79754e1d843da6c48d770937b589dab;hp=6acef2d6290c59748637d669029844c8dad14dd9;hpb=4bbf61304fa7605c9fbba6c24f91f31449280104;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp index 6acef2d62..fa22f80a1 100644 --- a/src/modules/m_spanningtree.cpp +++ b/src/modules/m_spanningtree.cpp @@ -45,7 +45,10 @@ using namespace std; enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED }; typedef nspace::hash_map, irc::StrHashComp> user_hash; +typedef nspace::hash_map, irc::StrHashComp> chan_hash; + extern user_hash clientlist; +extern chan_hash chanlist; class TreeServer; class TreeSocket; @@ -219,6 +222,11 @@ TreeServer* RouteEnumerate(TreeServer* Current, std::string ServerName) TreeServer* BestRouteTo(std::string ServerName) { log(DEBUG,"Finding best route to %s",ServerName.c_str()); + if (ServerName.c_str() == TreeRoot->GetName()) + { + log(DEBUG,"Cant route to myself!!!"); + return NULL; + } // first, find the server by recursively walking the tree TreeServer* Found = RouteEnumerate(TreeRoot,ServerName); // did we find it? If not, they did something wrong, abort. @@ -429,6 +437,53 @@ class TreeSocket : public InspSocket } } + bool ForceMode(std::string source, std::deque params) + { + userrec* who = new userrec; + who->fd = FD_MAGIC_NUMBER; + if (params.size() < 2) + return true; + char* modelist[255]; + for (unsigned int q = 0; q < params.size(); q++) + { + modelist[q] = (char*)params[q].c_str(); + } + Srv->SendMode(modelist,params.size(),who); + DoOneToAllButSender(source,"FMODE",params,source); + delete who; + return true; + } + + bool ForceTopic(std::string source, std::deque params) + { + // FTOPIC %s %lu %s :%s + if (params.size() != 4) + return true; + std::string channel = params[0]; + time_t ts = atoi(params[1].c_str()); + std::string setby = params[2]; + std::string topic = params[3]; + + chanrec* c = Srv->FindChannel(channel); + if (c) + { + if ((ts >= c->topicset) || (!*c->topic)) + { + strlcpy(c->topic,topic.c_str(),MAXTOPIC); + strlcpy(c->setby,setby.c_str(),NICKMAX); + c->topicset = ts; + WriteChannelWithServ((char*)source.c_str(), c, "TOPIC %s :%s", c->name, c->topic); + } + + } + + // all done, send it on its way + params[3] = ":" + params[3]; + DoOneToAllButSender(source,"FTOPIC",params,source); + + return true; + } + bool ForceJoin(std::string source, std::deque params) { if (params.size() < 1) @@ -490,6 +545,12 @@ class TreeSocket : public InspSocket std::string ident = params[4]; time_t age = atoi(params[0].c_str()); std::string modes = params[5]; + if (*(modes.c_str()) == '+') + { + char* m = (char*)modes.c_str(); + m++; + modes = m; + } std::string ip = params[6]; std::string gecos = params[7]; char* tempnick = (char*)nick.c_str(); @@ -500,10 +561,11 @@ class TreeSocket : public InspSocket if (iter != clientlist.end()) { // nick collision - log(DEBUG,"Nick collision on %s!%s@%s",tempnick,ident.c_str(),host.c_str()); + log(DEBUG,"Nick collision on %s!%s@%s: %lu %lu",tempnick,ident.c_str(),host.c_str(),(unsigned long)age,(unsigned long)iter->second->age); + this->WriteLine(":"+Srv->GetServerName()+" KILL "+tempnick+" :Nickname collision"); return true; } - + clientlist[tempnick] = new userrec(); clientlist[tempnick]->fd = FD_MAGIC_NUMBER; strlcpy(clientlist[tempnick]->nick, tempnick,NICKMAX); @@ -520,10 +582,31 @@ class TreeSocket : public InspSocket clientlist[tempnick]->chans[i].channel = NULL; clientlist[tempnick]->chans[i].uc_modes = 0; } + params[7] = ":" + params[7]; DoOneToAllButSender(source,"NICK",params,source); return true; } + void SendChannelModes(TreeServer* Current) + { + char data[MAXBUF]; + for (chan_hash::iterator c = chanlist.begin(); c != chanlist.end(); c++) + { + snprintf(data,MAXBUF,":%s FMODE %s +%s",Srv->GetServerName().c_str(),c->second->name,chanmodes(c->second)); + this->WriteLine(data); + if (*c->second->topic) + { + snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",Srv->GetServerName().c_str(),c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic); + this->WriteLine(data); + } + for (BanList::iterator b = c->second->bans.begin(); b != c->second->bans.end(); b++) + { + snprintf(data,MAXBUF,":%s FMODE %s +b %s",Srv->GetServerName().c_str(),c->second->name,b->data); + this->WriteLine(data); + } + } + } + // send all users and their channels void SendUsers(TreeServer* Current) { @@ -554,6 +637,7 @@ class TreeSocket : public InspSocket // Send users and their channels this->SendUsers(s); // TODO: Send everything else (channel modes etc) + this->SendChannelModes(s); this->WriteLine("ENDBURST"); } @@ -604,6 +688,59 @@ class TreeSocket : public InspSocket return false; } + bool OperType(std::string prefix, std::deque params) + { + if (params.size() != 1) + return true; + std::string opertype = params[0]; + userrec* u = Srv->FindNick(prefix); + if (u) + { + strlcpy(u->oper,opertype.c_str(),NICKMAX); + if (!strchr(u->modes,'o')) + { + strcat(u->modes,"o"); + } + DoOneToAllButSender(u->server,"OPERTYPE",params,u->server); + } + return true; + } + + bool RemoteRehash(std::string prefix, std::deque params) + { + if (params.size() < 1) + return true; + std::string servermask = params[0]; + if (Srv->MatchText(Srv->GetServerName(),servermask)) + { + Srv->RehashServer(); + } + DoOneToAllButSender(prefix,"REHASH",params,prefix); + return; + } + + bool RemoteKill(std::string prefix, std::deque params) + { + if (params.size() != 2) + return true; + std::string nick = params[0]; + std::string reason = params[1]; + userrec* u = Srv->FindNick(prefix); + userrec* who = Srv->FindNick(nick); + if (who) + { + std::string sourceserv = prefix; + if (u) + { + sourceserv = u->server; + } + params[1] = ":" + params[1]; + DoOneToAllButSender(prefix,"KILL",params,sourceserv); + Srv->QuitUser(who,reason); + } + return true; + } + bool RemoteServer(std::string prefix, std::deque params) { if (params.size() < 4) @@ -625,6 +762,7 @@ class TreeSocket : public InspSocket } TreeServer* Node = new TreeServer(servername,description,ParentOfThis,NULL); ParentOfThis->AddChild(Node); + params[3] = ":" + params[3]; DoOneToAllButSender(prefix,"SERVER",params,prefix); Srv->SendOpers("*** Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")"); return true; @@ -657,6 +795,7 @@ class TreeSocket : public InspSocket // node. TreeServer* Node = new TreeServer(servername,description,TreeRoot,this); TreeRoot->AddChild(Node); + params[3] = ":" + params[3]; DoOneToAllButSender(TreeRoot->GetName(),"SERVER",params,servername); this->DoBurst(Node); return true; @@ -708,30 +847,39 @@ class TreeSocket : public InspSocket while (!s.eof()) { s >> param; - if ((param.c_str()[0] == ':') && (item)) + if ((param != "") && (param != "\n")) { - char* str = (char*)param.c_str(); - str++; - param = str; - std::string append; - while (!s.eof()) + if ((param.c_str()[0] == ':') && (item)) { - append = ""; - s >> append; - if (append != "") + char* str = (char*)param.c_str(); + str++; + param = str; + std::string append; + while (!s.eof()) { - param = param + " " + append; + append = ""; + s >> append; + if (append != "") + { + param = param + " " + append; + } } } + item++; + n.push_back(param); } - item++; - n.push_back(param); } return n; } bool ProcessLine(std::string line) { + char* l = (char*)line.c_str(); + while ((strlen(l)) && (l[strlen(l)-1] == '\r') || (l[strlen(l)-1] == '\n')) + l[strlen(l)-1] = '\0'; + line = l; + if (line == "") + return true; Srv->Log(DEBUG,"inbound-line: '"+line+"'"); std::deque params = this->Split(line,true); std::string command = ""; @@ -831,6 +979,26 @@ class TreeSocket : public InspSocket { return this->RemoteServer(prefix,params); } + else if (command == "OPERTYPE") + { + return this->OperType(prefix,params); + } + else if (command == "FMODE") + { + return this->ForceMode(prefix,params); + } + else if (command == "KILL") + { + return this->RemoteKill(prefix,params); + } + else if (command == "FTOPIC") + { + return this->ForceTopic(prefix,params); + } + else if (command == "REHASH") + { + return this->RemoteRehash(prefix,params); + } else if (command == "SQUIT") { if (params.size() == 2) @@ -905,10 +1073,6 @@ class TreeSocket : public InspSocket TreeServer* s = FindServer(quitserver); if (s) { - std::deque params; - params.push_back(quitserver); - params.push_back(":Remote host closed the connection"); - DoOneToAllButSender(Srv->GetServerName(),"SQUIT",params,quitserver); Squit(s,"Remote host closed the connection"); } } @@ -933,6 +1097,7 @@ bool DoOneToAllButSenderRaw(std::string data,std::string omit) Sock->WriteLine(data); } } + return true; } bool DoOneToAllButSender(std::string prefix, std::string command, std::deque params, std::string omit) @@ -1223,6 +1388,61 @@ class ModuleSpanningTree : public Module return 0; } + virtual void OnGetServerDescription(std::string servername,std::string &description) + { + TreeServer* s = FindServer(servername); + if (s) + { + description = s->GetDesc(); + } + } + + virtual void OnUserInvite(userrec* source,userrec* dest,chanrec* channel) + { + if (std::string(source->server) == Srv->GetServerName()) + { + std::deque params; + params.push_back(dest->nick); + params.push_back(channel->name); + DoOneToMany(source->nick,"INVITE",params); + } + } + + virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, std::string topic) + { + std::deque params; + params.push_back(chan->name); + params.push_back(":"+topic); + DoOneToMany(user->nick,"TOPIC",params); + } + + virtual void OnUserNotice(userrec* user, void* dest, int target_type, std::string text) + { + if (target_type == TYPE_USER) + { + userrec* d = (userrec*)dest; + if ((std::string(d->server) != Srv->GetServerName()) && (std::string(user->server) == Srv->GetServerName())) + { + std::deque params; + params.clear(); + params.push_back(d->nick); + params.push_back(":"+text); + DoOneToOne(user->nick,"NOTICE",params,d->server); + } + } + else + { + if (std::string(user->server) == Srv->GetServerName()) + { + chanrec *c = (chanrec*)dest; + std::deque params; + params.push_back(c->name); + params.push_back(":"+text); + DoOneToMany(user->nick,"NOTICE",params); + } + } + } + virtual void OnUserMessage(userrec* user, void* dest, int target_type, std::string text) { if (target_type == TYPE_USER) @@ -1283,6 +1503,123 @@ class ModuleSpanningTree : public Module } } + virtual void OnUserConnect(userrec* user) + { + char agestr[MAXBUF]; + if (std::string(user->server) == Srv->GetServerName()) + { + log(DEBUG,"**** User on %s CONNECTS: %s",user->server,user->nick); + std::deque params; + snprintf(agestr,MAXBUF,"%lu",(unsigned long)user->age); + params.clear(); + params.push_back(agestr); + params.push_back(user->nick); + params.push_back(user->host); + params.push_back(user->dhost); + params.push_back(user->ident); + params.push_back("+"+std::string(user->modes)); + params.push_back(user->ip); + params.push_back(":"+std::string(user->fullname)); + DoOneToMany(Srv->GetServerName(),"NICK",params); + } + } + + virtual void OnUserQuit(userrec* user, std::string reason) + { + if (std::string(user->server) == Srv->GetServerName()) + { + log(DEBUG,"**** User on %s QUITS: %s",user->server,user->nick); + std::deque params; + params.push_back(":"+reason); + DoOneToMany(user->nick,"QUIT",params); + } + } + + virtual void OnUserPostNick(userrec* user, std::string oldnick) + { + if (std::string(user->server) == Srv->GetServerName()) + { + log(DEBUG,"**** User on %s changes NICK: %s",user->server,user->nick); + std::deque params; + params.push_back(user->nick); + DoOneToMany(oldnick,"NICK",params); + } + } + + virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, std::string reason) + { + if (std::string(source->server) == Srv->GetServerName()) + { + log(DEBUG,"**** User on %s KICKs: %s %s",source->server,source->nick,user->nick); + std::deque params; + params.push_back(chan->name); + params.push_back(user->nick); + params.push_back(":"+reason); + DoOneToMany(source->nick,"KICK",params); + } + } + + virtual void OnRemoteKill(userrec* source, userrec* dest, std::string reason) + { + std::deque params; + params.push_back(dest->nick); + params.push_back(":"+reason); + DoOneToMany(source->nick,"KILL",params); + } + + virtual void OnRehash(std::string parameter) + { + if (parameter != "") + { + std::deque params; + params.push_back(parameter); + DoOneToMany(Srv->GetServerName(),"REHASH",params); + // check for self + if (Srv->MatchText(Srv->GetServerName(),parameter)) + { + Srv->RehashServer(); + } + } + } + + // note: the protocol does not allow direct umode +o except + // via NICK with 8 params. sending OPERTYPE infers +o modechange + // locally. + virtual void OnOper(userrec* user, std::string opertype) + { + if (std::string(user->server) == Srv->GetServerName()) + { + std::deque params; + params.push_back(opertype); + DoOneToMany(user->nick,"OPERTYPE",params); + } + } + + virtual void OnMode(userrec* user, void* dest, int target_type, std::string text) + { + log(DEBUG,"*** ONMODE TRIGGER"); + if (std::string(user->server) == Srv->GetServerName()) + { + log(DEBUG,"*** LOCAL"); + if (target_type == TYPE_USER) + { + userrec* u = (userrec*)dest; + std::deque params; + params.push_back(u->nick); + params.push_back(text); + DoOneToMany(user->nick,"MODE",params); + } + else + { + chanrec* c = (chanrec*)dest; + std::deque params; + params.push_back(c->name); + params.push_back(text); + DoOneToMany(user->nick,"MODE",params); + } + } + } + virtual ~ModuleSpanningTree() { delete Srv;