TreeSocket* Socket; /* For directly connected servers this points at the socket object */
time_t NextPing; /* After this time, the server should be PINGed*/
bool LastPingWasGood; /* True if the server responded to the last PING with a PONG */
+ std::map<userrec*,userrec*> Users; /* Users on this server */
public:
this->AddHashEntry();
}
+ void AddUser(userrec* user)
+ {
+ log(DEBUG,"Add user %s to server %s",user->nick,this->ServerName.c_str());
+ std::map<userrec*,userrec*>::iterator iter;
+ iter = Users.find(user);
+ if (iter == Users.end())
+ Users[user] = user;
+ }
+
+ void DelUser(userrec* user)
+ {
+ log(DEBUG,"Remove user %s from server %s",user->nick,this->ServerName.c_str());
+ std::map<userrec*,userrec*>::iterator iter;
+ iter = Users.find(user);
+ if (iter != Users.end())
+ Users.erase(iter);
+ }
+
+ int QuitUsers(const std::string &reason)
+ {
+ int x = Users.size();
+ log(DEBUG,"Removing all users from server %s",this->ServerName.c_str());
+ const char* reason_s = reason.c_str();
+ for (std::map<userrec*,userrec*>::iterator n = Users.begin(); n != Users.end(); n++)
+ {
+ log(DEBUG,"Kill %s",n->second->nick);
+ kill_link(n->second,reason_s);
+ }
+ Users.clear();
+ return x;
+ }
+
/* This method is used to add the structure to the
* hash_map for linear searches. It is only called
* by the constructors.
* is having a REAL bad hair day, this function shouldnt be called
* too many times a month ;-)
*/
- void SquitServer(std::string &from, TreeServer* Current, CullList* Goners)
+ void SquitServer(std::string &from, TreeServer* Current)
{
/* recursively squit the servers attached to 'Current'.
* We're going backwards so we don't remove users
for (unsigned int q = 0; q < Current->ChildCount(); q++)
{
TreeServer* recursive_server = Current->GetChild(q);
- this->SquitServer(from,recursive_server,Goners);
+ this->SquitServer(from,recursive_server);
}
/* Now we've whacked the kids, whack self */
num_lost_servers++;
- for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
+ num_lost_users += Current->QuitUsers(from);
+ /*for (user_hash::iterator u = clientlist.begin(); u != clientlist.end(); u++)
{
if (!strcasecmp(u->second->server,Current->GetName().c_str()))
{
Goners->AddItem(u->second,from);
num_lost_users++;
}
- }
+ }*/
}
/* This is a wrapper function for SquitServer above, which
}
num_lost_servers = 0;
num_lost_users = 0;
- CullList* Goners = new CullList();
std::string from = Current->GetParent()->GetName()+" "+Current->GetName();
- SquitServer(from, Current, Goners);
- Goners->Apply();
+ SquitServer(from, Current);
Current->Tidy();
Current->GetParent()->DelChild(Current);
delete Current;
- delete Goners;
WriteOpers("Netsplit complete, lost \002%d\002 users on \002%d\002 servers.", num_lost_users, num_lost_servers);
}
else
clientlist[tempnick]->registered = 7;
clientlist[tempnick]->signon = age;
strlcpy(clientlist[tempnick]->modes, modes.c_str(),53);
+ for (char *v = clientlist[tempnick]->modes; *v; v++)
+ {
+ switch (*v)
+ {
+ case 'i':
+ clientlist[tempnick]->modebits |= UM_INVISIBLE;
+ break;
+ case 'w':
+ clientlist[tempnick]->modebits |= UM_WALLOPS;
+ break;
+ case 's':
+ clientlist[tempnick]->modebits |= UM_SERVERNOTICE;
+ break;
+ default:
+ break;
+ }
+ }
inet_aton(params[6].c_str(),&clientlist[tempnick]->ip4);
- ucrec a;
- a.channel = NULL;
- a.uc_modes = 0;
- clientlist[tempnick]->chans.resize(MAXCHANS);
-
WriteOpers("*** Client connecting at %s: %s!%s@%s [%s]",clientlist[tempnick]->server,clientlist[tempnick]->nick,clientlist[tempnick]->ident,clientlist[tempnick]->host,(char*)inet_ntoa(clientlist[tempnick]->ip4));
params[7] = ":" + params[7];
TreeServer* SourceServer = FindServer(source);
if (SourceServer)
{
+ SourceServer->AddUser(clientlist[tempnick]);
SourceServer->AddUserCount();
}
log(DEBUG,"Sending FJOINs to other server for %s",c->name);
char list[MAXBUF];
std::string individual_halfops = ":"+Srv->GetServerName()+" FMODE "+c->name;
- size_t counter = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age);
- size_t initial = counter;
+
+ size_t dlen, curlen;
+ dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age);
+ int numusers = 0;
+ char* ptr = list + dlen;
- std::map<char*,char*> *ulist = c->GetUsers();
+ CUList *ulist = c->GetUsers();
std::vector<userrec*> specific_halfop;
std::vector<userrec*> specific_voice;
- for (std::map<char*,char*>::iterator i = ulist->begin(); i != ulist->end(); i++)
+ for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
- char* o = i->second;
- userrec* otheruser = (userrec*)o;
- charlcat(list,' ',MAXBUF);
- counter++;
- int x = cflags(otheruser,c);
+ int x = cflags(i->second,c);
if ((x & UCMODE_HOP) && (x & UCMODE_OP))
{
- specific_halfop.push_back(otheruser);
+ specific_halfop.push_back(i->second);
}
if (((x & UCMODE_HOP) || (x & UCMODE_OP)) && (x & UCMODE_VOICE))
{
- specific_voice.push_back(otheruser);
+ specific_voice.push_back(i->second);
}
- char n = 0;
+ const char* n = "";
if (x & UCMODE_OP)
{
- n = '@';
+ n = "@";
}
else if (x & UCMODE_HOP)
{
- n = '%';
+ n = "%";
}
else if (x & UCMODE_VOICE)
{
- n = '+';
+ n = "+";
}
- if (n)
- {
- charlcat(list,n,MAXBUF);
- counter++;
- }
+ size_t ptrlen = snprintf(ptr, MAXBUF, " %s%s", n, i->second->nick);
+
+ curlen += ptrlen;
+ ptr += ptrlen;
- counter += strlcat(list,otheruser->nick,MAXBUF);
+ numusers++;
- if (counter > (480-NICKMAX))
+ if (curlen > (480-NICKMAX))
{
- log(DEBUG,"FJOIN line wrapped");
this->WriteLine(list);
- counter = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age);
+ dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age);
+ ptr = list + dlen;
+ ptrlen = 0;
+ numusers = 0;
for (unsigned int y = 0; y < specific_voice.size(); y++)
{
this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" +v "+specific_voice[y]->nick);
}
}
}
- if (counter != initial)
+ if (numusers)
{
- log(DEBUG,"Final FJOIN line");
this->WriteLine(list);
for (unsigned int y = 0; y < specific_voice.size(); y++)
{
* back to the core so that a large burst is split into at least 6 sections
* (possibly more)
*/
- std::string burst = "BURST "+ConvToStr(TIME);
+ std::string burst = "BURST "+ConvToStr(time(NULL));
std::string endburst = "ENDBURST";
Srv->SendOpers("*** Bursting to \2"+s->GetName()+"\2.");
this->WriteLine(burst);
}
else if (command == "BURST")
{
- time_t THEM = atoi(params[0].c_str());
- long delta = THEM-TIME;
- if ((delta < -600) || (delta > 600))
+ if (params.size())
{
- WriteOpers("*** \2ERROR\2: Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2");
- this->WriteLine("ERROR :Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
- return false;
+ /* If a time stamp is provided, try and check syncronization */
+ time_t THEM = atoi(params[0].c_str());
+ long delta = THEM-time(NULL);
+ if ((delta < -600) || (delta > 600))
+ {
+ WriteOpers("*** \2ERROR\2: Your clocks are out by %d seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
+ this->WriteLine("ERROR :Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
+ return false;
+ }
+ else if ((delta < -60) || (delta > 60))
+ {
+ WriteOpers("*** \2WARNING\2: Your clocks are out by %d seconds, please consider synching your clocks.",abs(delta));
+ }
}
this->LinkState = CONNECTED;
Node = new TreeServer(InboundServerName,InboundDescription,TreeRoot,this);
}
if (who)
{
- if ((command == "NICK") && (params.size() > 0))
+ if (command == "QUIT")
+ {
+ TreeServer* s = FindServer(who->server);
+ if (s)
+ {
+ s->DelUser(who);
+ }
+ }
+ else if ((command == "NICK") && (params.size() > 0))
{
/* On nick messages, check that the nick doesnt
* already exist here. If it does, kill their copy,
// returns a list of DIRECT servernames for a specific channel
void GetListOfServersForChannel(chanrec* c, std::deque<TreeServer*> &list)
{
- std::map<char*,char*> *ulist = c->GetUsers();
- for (std::map<char*,char*>::iterator i = ulist->begin(); i != ulist->end(); i++)
+ CUList *ulist = c->GetUsers();
+ for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
{
- char* o = i->second;
- userrec* otheruser = (userrec*)o;
- if (otheruser->fd < 0)
+ if (i->second->fd < 0)
{
- TreeServer* best = BestRouteTo(otheruser->server);
+ TreeServer* best = BestRouteTo(i->second->server);
if (best)
AddThisServer(best,list);
}
void HandleLusers(char** parameters, int pcnt, userrec* user)
{
+ unsigned int n_users = usercnt();
+
/* Only update these when someone wants to see them, more efficient */
if ((unsigned int)local_count() > max_local)
max_local = local_count();
- if (clientlist.size() > max_global)
- max_global = clientlist.size();
+ if (n_users > max_global)
+ max_global = n_users;
- WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),this->CountServs());
+ WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,n_users-usercount_invisible(),usercount_invisible(),this->CountServs());
WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
WriteServ(user->fd,"254 %s :I have %d clients and %d servers",user->nick,local_count(),this->CountLocalServs());
WriteServ(user->fd,"265 %s :Current Local Users: %d Max: %d",user->nick,local_count(),max_local);
- WriteServ(user->fd,"266 %s :Current Global Users: %d Max: %d",user->nick,clientlist.size(),max_global);
+ WriteServ(user->fd,"266 %s :Current Global Users: %d Max: %d",user->nick,n_users,max_global);
return;
}
return 0;
}
- virtual int OnPreCommand(std::string command, char **parameters, int pcnt, userrec *user, bool validated)
+ virtual int OnPreCommand(const std::string &command, char **parameters, int pcnt, userrec *user, bool validated)
{
/* If the command doesnt appear to be valid, we dont want to mess with it. */
if (!validated)
return 0;
}
- virtual void OnGetServerDescription(std::string servername,std::string &description)
+ virtual void OnGetServerDescription(const std::string &servername,std::string &description)
{
TreeServer* s = FindServer(servername);
if (s)
}
}
- virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, std::string topic)
+ virtual void OnPostLocalTopicChange(userrec* user, chanrec* chan, const std::string &topic)
{
std::deque<std::string> params;
params.push_back(chan->name);
DoOneToMany(user->nick,"TOPIC",params);
}
- virtual void OnWallops(userrec* user, std::string text)
+ virtual void OnWallops(userrec* user, const std::string &text)
{
if (user->fd > -1)
{
}
}
- virtual void OnUserNotice(userrec* user, void* dest, int target_type, std::string text, char status)
+ virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status)
{
if (target_type == TYPE_USER)
{
}
}
- virtual void OnUserMessage(userrec* user, void* dest, int target_type, std::string text, char status)
+ virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status)
{
if (target_type == TYPE_USER)
{
}
}
- virtual void OnChangeHost(userrec* user, std::string newhost)
+ virtual void OnChangeHost(userrec* user, const std::string &newhost)
{
// only occurs for local clients
if (user->registered != 7)
DoOneToMany(user->nick,"FHOST",params);
}
- virtual void OnChangeName(userrec* user, std::string gecos)
+ virtual void OnChangeName(userrec* user, const std::string &gecos)
{
// only occurs for local clients
if (user->registered != 7)
DoOneToMany(user->nick,"FNAME",params);
}
- virtual void OnUserPart(userrec* user, chanrec* channel, std::string partmessage)
+ virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage)
{
if (user->fd > -1)
{
}
}
- virtual void OnUserQuit(userrec* user, std::string reason)
+ virtual void OnUserQuit(userrec* user, const std::string &reason)
{
if ((user->fd > -1) && (user->registered == 7))
{
}
- virtual void OnUserPostNick(userrec* user, std::string oldnick)
+ virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
{
if (user->fd > -1)
{
}
}
- virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, std::string reason)
+ virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason)
{
if ((source) && (source->fd > -1))
{
}
}
- virtual void OnRemoteKill(userrec* source, userrec* dest, std::string reason)
+ virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason)
{
std::deque<std::string> params;
params.push_back(dest->nick);
DoOneToMany(source->nick,"KILL",params);
}
- virtual void OnRehash(std::string parameter)
+ virtual void OnRehash(const std::string ¶meter)
{
if (parameter != "")
{
// 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)
+ virtual void OnOper(userrec* user, const std::string &opertype)
{
if (user->fd > -1)
{
}
}
- void OnLine(userrec* source, std::string host, bool adding, char linetype, long duration, std::string reason)
+ void OnLine(userrec* source, const std::string &host, bool adding, char linetype, long duration, const std::string &reason)
{
if (source->fd > -1)
{
}
}
- virtual void OnAddGLine(long duration, userrec* source, std::string reason, std::string hostmask)
+ virtual void OnAddGLine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
{
OnLine(source,hostmask,true,'G',duration,reason);
}
- virtual void OnAddZLine(long duration, userrec* source, std::string reason, std::string ipmask)
+ virtual void OnAddZLine(long duration, userrec* source, const std::string &reason, const std::string &ipmask)
{
OnLine(source,ipmask,true,'Z',duration,reason);
}
- virtual void OnAddQLine(long duration, userrec* source, std::string reason, std::string nickmask)
+ virtual void OnAddQLine(long duration, userrec* source, const std::string &reason, const std::string &nickmask)
{
OnLine(source,nickmask,true,'Q',duration,reason);
}
- virtual void OnAddELine(long duration, userrec* source, std::string reason, std::string hostmask)
+ virtual void OnAddELine(long duration, userrec* source, const std::string &reason, const std::string &hostmask)
{
OnLine(source,hostmask,true,'E',duration,reason);
}
- virtual void OnDelGLine(userrec* source, std::string hostmask)
+ virtual void OnDelGLine(userrec* source, const std::string &hostmask)
{
OnLine(source,hostmask,false,'G',0,"");
}
- virtual void OnDelZLine(userrec* source, std::string ipmask)
+ virtual void OnDelZLine(userrec* source, const std::string &ipmask)
{
OnLine(source,ipmask,false,'Z',0,"");
}
- virtual void OnDelQLine(userrec* source, std::string nickmask)
+ virtual void OnDelQLine(userrec* source, const std::string &nickmask)
{
OnLine(source,nickmask,false,'Q',0,"");
}
- virtual void OnDelELine(userrec* source, std::string hostmask)
+ virtual void OnDelELine(userrec* source, const std::string &hostmask)
{
OnLine(source,hostmask,false,'E',0,"");
}
- virtual void OnMode(userrec* user, void* dest, int target_type, std::string text)
+ virtual void OnMode(userrec* user, void* dest, int target_type, const std::string &text)
{
if ((user->fd > -1) && (user->registered == 7))
{
}
}
- virtual void ProtoSendMode(void* opaque, int target_type, void* target, std::string modeline)
+ virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline)
{
TreeSocket* s = (TreeSocket*)opaque;
if (target)
}
}
- virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, std::string extname, std::string extdata)
+ virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata)
{
TreeSocket* s = (TreeSocket*)opaque;
if (target)