channels.cpp

Go to the documentation of this file.
00001 /* Channel-handling routines.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  */
00012 
00013 #include "services.h"
00014 #include "channels.h"
00015 #include "regchannel.h"
00016 #include "logger.h"
00017 #include "modules.h"
00018 #include "users.h"
00019 #include "bots.h"
00020 #include "servers.h"
00021 #include "protocol.h"
00022 #include "users.h"
00023 #include "config.h"
00024 #include "access.h"
00025 #include "sockets.h"
00026 
00027 channel_map ChannelList;
00028 
00029 Channel::Channel(const Anope::string &nname, time_t ts)
00030 {
00031         if (nname.empty())
00032                 throw CoreException("A channel without a name ?");
00033 
00034         this->name = nname;
00035 
00036         size_t old = ChannelList.size();
00037         ChannelList[this->name] = this;
00038         if (old == ChannelList.size())
00039                 Log(LOG_DEBUG) << "Duplicate channel " << this->name << " in table?";
00040 
00041         this->creation_time = ts;
00042         this->server_modetime = this->chanserv_modetime = 0;
00043         this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_ts = this->topic_time = 0;
00044 
00045         this->ci = ChannelInfo::Find(this->name);
00046         if (this->ci)
00047                 this->ci->c = this;
00048 
00049         Log(NULL, this, "create");
00050 
00051         FOREACH_MOD(I_OnChannelCreate, OnChannelCreate(this));
00052 }
00053 
00054 Channel::~Channel()
00055 {
00056         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
00057 
00058         ModeManager::StackerDel(this);
00059 
00060         Log(NULL, this, "destroy");
00061 
00062         if (this->ci)
00063                 this->ci->c = NULL;
00064 
00065         ChannelList.erase(this->name);
00066 }
00067 
00068 void Channel::Reset()
00069 {
00070         this->modes.clear();
00071 
00072         for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
00073         {
00074                 ChanUserContainer *uc = *it;
00075 
00076                 ChannelStatus f = uc->status;
00077                 uc->status.modes.clear();
00078 
00079                 if (BotInfo::Find(uc->user->nick))
00080                 {
00081                         for (unsigned i = 0; i < ModeManager::ChannelModes.size(); ++i)
00082                         {
00083                                 ChannelMode *cm = ModeManager::ChannelModes[i];
00084 
00085                                 if (f.modes.count(cm->name))
00086                                          this->SetMode(NULL, cm, uc->user->GetUID(), false);
00087                         }
00088                 }
00089         }
00090 
00091         this->CheckModes();
00092 
00093         for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
00094                 this->SetCorrectModes((*it)->user, true, false);
00095         
00096         if (this->ci && Me && Me->IsSynced())
00097                 this->ci->RestoreTopic();
00098 }
00099 
00100 void Channel::Sync()
00101 {
00102         if (!this->HasMode("PERM") && (this->users.empty() || (this->users.size() == 1 && this->ci && this->ci->bi && *this->ci->bi == this->users.front()->user)))
00103         {
00104                 this->Hold();
00105         }
00106         if (this->ci)
00107         {
00108                 this->CheckModes();
00109 
00110                 if (Me && Me->IsSynced())
00111                         this->ci->RestoreTopic();
00112         }
00113 }
00114 
00115 void Channel::CheckModes()
00116 {
00117         if (this->bouncy_modes)
00118                 return;
00119 
00120         /* Check for mode bouncing */
00121         if (this->server_modecount >= 3 && this->chanserv_modecount >= 3)
00122         {
00123                 Log() << "Warning: unable to set modes on channel " << this->name << ". Are your servers' U:lines configured correctly?";
00124                 this->bouncy_modes = 1;
00125                 return;
00126         }
00127 
00128         EventReturn MOD_RESULT;
00129         FOREACH_RESULT(I_OnCheckModes, OnCheckModes(this));
00130         if (MOD_RESULT == EVENT_STOP)
00131                 return;
00132 
00133         if (this->ci)
00134                 for (ChannelInfo::ModeList::const_iterator it = this->ci->GetMLock().begin(), it_end = this->ci->GetMLock().end(); it != it_end; ++it)
00135                 {
00136                         const ModeLock *ml = it->second;
00137                         ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
00138                         if (!cm)
00139                                 continue;
00140 
00141                         if (cm->type == MODE_REGULAR)
00142                         {
00143                                 if (!this->HasMode(cm->name) && ml->set)
00144                                         this->SetMode(NULL, cm);
00145                                 else if (this->HasMode(cm->name) && !ml->set)
00146                                         this->RemoveMode(NULL, cm);
00147                         }
00148                         else if (cm->type == MODE_PARAM)
00149                         {
00150                                 /* If the channel doesnt have the mode, or it does and it isn't set correctly */
00151                                 if (ml->set)
00152                                 {
00153                                         Anope::string param;
00154                                         this->GetParam(cm->name, param);
00155 
00156                                         if (!this->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param)))
00157                                                 this->SetMode(NULL, cm, ml->param);
00158                                 }
00159                                 else
00160                                 {
00161                                         if (this->HasMode(cm->name))
00162                                                 this->RemoveMode(NULL, cm);
00163                                 }
00164         
00165                         }
00166                         else if (cm->type == MODE_LIST)
00167                         {
00168                                 if (ml->set)
00169                                         this->SetMode(NULL, cm, ml->param);
00170                                 else
00171                                         this->RemoveMode(NULL, cm, ml->param);
00172                         }
00173                 }
00174 }
00175 
00176 ChanUserContainer* Channel::JoinUser(User *user)
00177 {
00178         Log(user, this, "join");
00179 
00180         ChanUserContainer *cuc = new ChanUserContainer(user, this);
00181         user->chans.push_back(cuc);
00182         this->users.push_back(cuc);
00183 
00184         if (this->ci && this->ci->HasExt("PERSIST") && this->creation_time > this->ci->time_registered)
00185         {
00186                 Log(LOG_DEBUG) << "Changing TS of " << this->name << " from " << this->creation_time << " to " << this->ci->time_registered;
00187                 this->creation_time = this->ci->time_registered;
00188                 IRCD->SendChannel(this);
00189                 this->Reset();
00190         }
00191 
00192         return cuc;
00193 }
00194 
00195 void Channel::DeleteUser(User *user)
00196 {
00197         Log(user, this, "leave");
00198         FOREACH_MOD(I_OnLeaveChannel, OnLeaveChannel(user, this));
00199 
00200         ChanUserContainer *cul;
00201         ChanUserList::iterator cit, cit_end;
00202         for (cit = this->users.begin(), cit_end = this->users.end(); cit != cit_end && (*cit)->user != user; ++cit);
00203         if (cit == cit_end)
00204         {
00205                 Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete nonexistant user " << user->nick << " from channel " << this->name;
00206                 return;
00207         }
00208         cul = *cit;
00209         this->users.erase(cit);
00210 
00211         ChanUserList::iterator uit, uit_end;
00212         for (uit = user->chans.begin(), uit_end = user->chans.end(); uit != uit_end && (*uit)->chan != this; ++uit);
00213         if (uit == uit_end)
00214                 Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete nonexistant channel " << this->name << " from " << user->nick << "'s channel list";
00215         else
00216         {
00217                 if (cul != *uit)
00218                         Log(LOG_DEBUG) << "Channel::DeleteUser() mismatch between user and channel usre container objects";
00219                 user->chans.erase(uit);
00220         }
00221         delete cul;
00222 
00223         /* Channel is persistent, it shouldn't be deleted and the service bot should stay */
00224         if (this->HasExt("PERSIST") || (this->ci && this->ci->HasExt("PERSIST")))
00225                 return;
00226 
00227         /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly
00228          * We also don't part the bot here either, if necessary we will part it after the sync
00229          */
00230         if (this->HasExt("SYNCING"))
00231                 return;
00232 
00233         /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */
00234         if (this->HasExt("INHABIT"))
00235                 return;
00236 
00237         if (this->users.empty())
00238                 delete this;
00239 }
00240 
00241 ChanUserContainer *Channel::FindUser(const User *u) const
00242 {
00243         for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
00244                 if ((*it)->user == u)
00245                         return *it;
00246         return NULL;
00247 }
00248 
00249 bool Channel::HasUserStatus(const User *u, ChannelModeStatus *cms) const
00250 {
00251         /* Usually its more efficient to search the users channels than the channels users */
00252         ChanUserContainer *cc = u->FindChannel(this);
00253         if (cc)
00254         {
00255                 if (cms)
00256                         return cc->status.modes.count(cms->name);
00257                 else
00258                         return cc->status.modes.empty();
00259         }
00260 
00261         return false;
00262 }
00263 
00264 bool Channel::HasUserStatus(const User *u, const Anope::string &mname) const
00265 {
00266         return HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(ModeManager::FindChannelModeByName(mname)));
00267 }
00268 
00269 size_t Channel::HasMode(const Anope::string &mname, const Anope::string &param)
00270 {
00271         if (param.empty())
00272                 return modes.count(mname);
00273         std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = this->GetModeList(mname);
00274         for (; its.first != its.second; ++its.first)
00275                 if (its.first->second == param)
00276                         return 1;
00277         return 0;
00278 }
00279 
00280 Anope::string Channel::GetModes(bool complete, bool plus)
00281 {
00282         Anope::string res, params;
00283 
00284         for (std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it)
00285         {
00286                 ChannelMode *cm = ModeManager::FindChannelModeByName(it->first);
00287                 if (!cm || cm->type == MODE_LIST)
00288                         continue;
00289 
00290                 res += cm->mchar;
00291 
00292                 if (complete && !it->second.empty())
00293                 {
00294                         ChannelModeParam *cmp = NULL;
00295                         if (cm->type == MODE_PARAM)
00296                                 cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00297 
00298                         if (plus || !cmp || !cmp->minus_no_arg)
00299                                 params += " " + it->second;
00300                 }
00301         }
00302 
00303         return res + params;
00304 }
00305 
00306 const Channel::ModeList &Channel::GetModes() const
00307 {
00308         return this->modes;
00309 }
00310 
00311 std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> Channel::GetModeList(const Anope::string &mname)
00312 {
00313         Channel::ModeList::iterator it = this->modes.find(mname), it_end = it;
00314         if (it != this->modes.end())
00315                 it_end = this->modes.upper_bound(mname);
00316         return std::make_pair(it, it_end);
00317 }
00318 
00319 void Channel::SetModeInternal(MessageSource &setter, ChannelMode *cm, const Anope::string &param, bool enforce_mlock)
00320 {
00321         if (!cm)
00322                 return;
00323 
00324         EventReturn MOD_RESULT;
00325 
00326         /* Setting v/h/o/a/q etc */
00327         if (cm->type == MODE_STATUS)
00328         {
00329                 if (param.empty())
00330                 {
00331                         Log() << "Channel::SetModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name;
00332                         return;
00333                 }
00334 
00335                 User *u = User::Find(param);
00336 
00337                 if (!u)
00338                 {
00339                         Log() << "MODE " << this->name << " +" << cm->mchar << " for nonexistant user " << param;
00340                         return;
00341                 }
00342 
00343                 Log(LOG_DEBUG) << "Setting +" << cm->mchar << " on " << this->name << " for " << u->nick;
00344 
00345                 /* Set the status on the user */
00346                 ChanUserContainer *cc = u->FindChannel(this);
00347                 if (cc)
00348                         cc->status.modes.insert(cm->name);
00349 
00350                 FOREACH_RESULT(I_OnChannelModeSet, OnChannelModeSet(this, setter, cm->name, param));
00351 
00352                 /* Enforce secureops, etc */
00353                 if (enforce_mlock && MOD_RESULT != EVENT_STOP)
00354                         this->SetCorrectModes(u, false, false);
00355                 return;
00356         }
00357 
00358         if (cm->type != MODE_LIST)
00359                 this->modes.erase(cm->name);
00360         this->modes.insert(std::make_pair(cm->name, param));
00361 
00362         if (param.empty() && cm->type != MODE_REGULAR)
00363         {
00364                 Log() << "Channel::SetModeInternal() mode " << cm->mchar << " for " << this->name << " with no paramater, but is a param mode";
00365                 return;
00366         }
00367 
00368         if (cm->type == MODE_LIST)
00369         {
00370                 ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
00371                 cml->OnAdd(this, param);
00372         }
00373 
00374         /* Channel mode +P or so was set, mark this channel as persistent */
00375         if (cm->name == "PERM")
00376         {
00377                 this->Extend("PERSIST");
00378                 if (this->ci)
00379                         this->ci->ExtendMetadata("PERSIST");
00380         }
00381 
00382         FOREACH_RESULT(I_OnChannelModeSet, OnChannelModeSet(this, setter, cm->name, param));
00383 
00384         /* Check if we should enforce mlock */
00385         if (!enforce_mlock || MOD_RESULT == EVENT_STOP)
00386                 return;
00387 
00388         this->CheckModes();
00389 }
00390 
00391 void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *cm, const Anope::string &param, bool enforce_mlock)
00392 {
00393         if (!cm)
00394                 return;
00395 
00396         EventReturn MOD_RESULT;
00397 
00398         /* Setting v/h/o/a/q etc */
00399         if (cm->type == MODE_STATUS)
00400         {
00401                 if (param.empty())
00402                 {
00403                         Log() << "Channel::RemoveModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name;
00404                         return;
00405                 }
00406 
00407                 BotInfo *bi = BotInfo::Find(param);
00408                 User *u = bi ? bi : User::Find(param);
00409 
00410                 if (!u)
00411                 {
00412                         Log() << "Channel::RemoveModeInternal() MODE " << this->name << "-" << cm->mchar << " for nonexistant user " << param;
00413                         return;
00414                 }
00415 
00416                 Log(LOG_DEBUG) << "Setting -" << cm->mchar << " on " << this->name << " for " << u->nick;
00417 
00418                 /* Remove the status on the user */
00419                 ChanUserContainer *cc = u->FindChannel(this);
00420                 if (cc)
00421                         cc->status.modes.erase(cm->name);
00422 
00423                 FOREACH_RESULT(I_OnChannelModeUnset, OnChannelModeUnset(this, setter, cm->name, param));
00424 
00425                 if (enforce_mlock)
00426                 {
00427                         /* Reset modes on bots if we're supposed to */
00428                         if (this->ci && this->ci->bi && this->ci->bi == bi)
00429                         {
00430                                 if (ModeManager::DefaultBotModes.modes.count(cm->name))
00431                                         this->SetMode(bi, cm, bi->GetUID());
00432                         }
00433 
00434                         this->SetCorrectModes(u, false, false);
00435                 }
00436                 return;
00437         }
00438 
00439         if (cm->type == MODE_LIST && !param.empty())
00440         {
00441                 std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = this->GetModeList(cm->name);
00442                 for (; its.first != its.second; ++its.first)
00443                         if (Anope::Match(param, its.first->second))
00444                         {
00445                                 this->modes.erase(its.first);
00446                                 break;
00447                         }
00448         }
00449         else
00450                 this->modes.erase(cm->name);
00451         
00452         if (cm->type == MODE_LIST)
00453         {
00454                 ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
00455                 cml->OnDel(this, param);
00456         }
00457 
00458         if (cm->name == "PERM")
00459         {
00460                 this->Shrink("PERSIST");
00461 
00462                 if (this->ci)
00463                         this->ci->Shrink("PERSIST");
00464 
00465                 if (this->users.empty() && !this->HasExt("SYNCING") && !this->HasExt("INHABIT"))
00466                 {
00467                         delete this;
00468                         return;
00469                 }
00470         }
00471 
00472         FOREACH_RESULT(I_OnChannelModeUnset, OnChannelModeUnset(this, setter, cm->name, param));
00473 
00474         /* Check for mlock */
00475         if (!enforce_mlock || MOD_RESULT == EVENT_STOP)
00476                 return;
00477 
00478         this->CheckModes();
00479 }
00480 
00481 void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param, bool enforce_mlock)
00482 {
00483         if (!cm)
00484                 return;
00485         /* Don't set modes already set */
00486         if (cm->type == MODE_REGULAR && HasMode(cm->name))
00487                 return;
00488         else if (cm->type == MODE_PARAM)
00489         {
00490                 ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00491                 if (!cmp->IsValid(param))
00492                         return;
00493 
00494                 Anope::string cparam;
00495                 if (GetParam(cm->name, cparam) && cparam.equals_cs(param))
00496                         return;
00497         }
00498         else if (cm->type == MODE_STATUS)
00499         {
00500                 User *u = User::Find(param);
00501                 if (!u || HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(cm)))
00502                         return;
00503         }
00504         else if (cm->type == MODE_LIST)
00505         {
00506                 ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
00507                 if (this->HasMode(cm->name, param) || !cml->IsValid(param))
00508                         return;
00509         }
00510 
00511         if (Me->IsSynced())
00512         {
00513                 if (this->chanserv_modetime != Anope::CurTime)
00514                 {
00515                         this->chanserv_modecount = 0;
00516                         this->chanserv_modetime = Anope::CurTime;
00517                 }
00518 
00519                 this->chanserv_modecount++;
00520         }
00521 
00522         ModeManager::StackerAdd(bi, this, cm, true, param);
00523         MessageSource ms(bi);
00524         SetModeInternal(ms, cm, param, enforce_mlock);
00525 }
00526 
00527 void Channel::SetMode(BotInfo *bi, const Anope::string &mname, const Anope::string &param, bool enforce_mlock)
00528 {
00529         SetMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock);
00530 }
00531 
00532 void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param, bool enforce_mlock)
00533 {
00534         if (!cm)
00535                 return;
00536         /* Don't unset modes that arent set */
00537         if ((cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && !HasMode(cm->name))
00538                 return;
00539         /* Don't unset status that aren't set */
00540         else if (cm->type == MODE_STATUS)
00541         {
00542                 User *u = User::Find(param);
00543                 if (!u || !HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(cm)))
00544                         return;
00545         }
00546         else if (cm->type == MODE_LIST)
00547         {
00548                 if (!this->HasMode(cm->name, param))
00549                         return;
00550         }
00551 
00552         /* Get the param to send, if we need it */
00553         Anope::string realparam = param;
00554         if (cm->type == MODE_PARAM)
00555         {
00556                 realparam.clear();
00557                 ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00558                 if (!cmp->minus_no_arg)
00559                         this->GetParam(cmp->name, realparam);
00560         }
00561 
00562         if (Me->IsSynced())
00563         {
00564                 if (this->chanserv_modetime != Anope::CurTime)
00565                 {
00566                         this->chanserv_modecount = 0;
00567                         this->chanserv_modetime = Anope::CurTime;
00568                 }
00569 
00570                 this->chanserv_modecount++;
00571         }
00572 
00573         ModeManager::StackerAdd(bi, this, cm, false, realparam);
00574         MessageSource ms(bi);
00575         RemoveModeInternal(ms, cm, realparam, enforce_mlock);
00576 }
00577 
00578 void Channel::RemoveMode(BotInfo *bi, const Anope::string &mname, const Anope::string &param, bool enforce_mlock)
00579 {
00580         RemoveMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock);
00581 }
00582 
00583 bool Channel::GetParam(const Anope::string &mname, Anope::string &target) const
00584 {
00585         std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.find(mname);
00586 
00587         target.clear();
00588 
00589         if (it != this->modes.end())
00590         {
00591                 target = it->second;
00592                 return true;
00593         }
00594 
00595         return false;
00596 }
00597 
00598 void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const char *cmodes, ...)
00599 {
00600         char buf[BUFSIZE] = "";
00601         va_list args;
00602         Anope::string modebuf, sbuf;
00603         int add = -1;
00604         va_start(args, cmodes);
00605         vsnprintf(buf, BUFSIZE - 1, cmodes, args);
00606         va_end(args);
00607 
00608         spacesepstream sep(buf);
00609         sep.GetToken(modebuf);
00610         for (unsigned i = 0, end = modebuf.length(); i < end; ++i)
00611         {
00612                 ChannelMode *cm;
00613 
00614                 switch (modebuf[i])
00615                 {
00616                         case '+':
00617                                 add = 1;
00618                                 continue;
00619                         case '-':
00620                                 add = 0;
00621                                 continue;
00622                         default:
00623                                 if (add == -1)
00624                                         continue;
00625                                 cm = ModeManager::FindChannelModeByChar(modebuf[i]);
00626                                 if (!cm)
00627                                         continue;
00628                 }
00629 
00630                 if (add)
00631                 {
00632                         if (cm->type != MODE_REGULAR && sep.GetToken(sbuf))
00633                         {
00634                                 if (cm->type == MODE_STATUS)
00635                                 {
00636                                         User *targ = User::Find(sbuf);
00637                                         if (targ != NULL)
00638                                                 sbuf = targ->GetUID();
00639                                 }
00640                                 this->SetMode(bi, cm, sbuf, enforce_mlock);
00641                         }
00642                         else
00643                                 this->SetMode(bi, cm, "", enforce_mlock);
00644                 }
00645                 else if (!add)
00646                 {
00647                         if (cm->type != MODE_REGULAR && sep.GetToken(sbuf))
00648                         {
00649                                 if (cm->type == MODE_STATUS)
00650                                 {
00651                                         User *targ = User::Find(sbuf);
00652                                         if (targ != NULL)
00653                                                 sbuf = targ->GetUID();
00654                                 }
00655                                 this->RemoveMode(bi, cm, sbuf, enforce_mlock);
00656                         }
00657                         else
00658                                 this->RemoveMode(bi, cm, "", enforce_mlock);
00659                 }
00660         }
00661 }
00662 
00663 void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, time_t ts, bool enforce_mlock)
00664 {
00665         if (source.GetServer() && source.GetServer()->IsSynced())
00666         {
00667                 if (Anope::CurTime != this->server_modetime)
00668                 {
00669                         this->server_modecount = 0;
00670                         this->server_modetime = Anope::CurTime;
00671                 }
00672 
00673                 ++this->server_modecount;
00674         }
00675 
00676         if (!ts)
00677                 ;
00678         else if (ts > this->creation_time)
00679         {
00680                 Log(LOG_DEBUG) << "Dropping mode " << mode << " on " << this->name << ", " << ts << " > " << this->creation_time;
00681                 return;
00682         }
00683         else if (ts < this->creation_time)
00684         {
00685                 Log(LOG_DEBUG) << "Changing TS of " << this->name << " from " << this->creation_time << " to " << ts;
00686                 this->creation_time = ts;
00687                 this->Reset();
00688         }
00689 
00690         User *setter = source.GetUser();
00691         /* Removing channel modes *may* delete this channel */
00692         Reference<Channel> this_reference(this);
00693 
00694         spacesepstream sep_modes(mode);
00695         Anope::string m;
00696 
00697         sep_modes.GetToken(m);
00698 
00699         Anope::string modestring;
00700         Anope::string paramstring;
00701         int add = -1;
00702         for (unsigned int i = 0, end = m.length(); i < end && this_reference; ++i)
00703         {
00704                 ChannelMode *cm;
00705 
00706                 switch (m[i])
00707                 {
00708                         case '+':
00709                                 modestring += '+';
00710                                 add = 1;
00711                                 continue;
00712                         case '-':
00713                                 modestring += '-';
00714                                 add = 0;
00715                                 continue;
00716                         default:
00717                                 if (add == -1)
00718                                         continue;
00719                                 cm = ModeManager::FindChannelModeByChar(m[i]);
00720                                 if (!cm)
00721                                 {
00722                                         Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << m[i];
00723                                         continue;
00724                                 }
00725                                 modestring += cm->mchar;
00726                 }
00727 
00728                 if (cm->type == MODE_REGULAR)
00729                 {
00730                         if (add)
00731                                 this->SetModeInternal(source, cm, "", false);
00732                         else
00733                                 this->RemoveModeInternal(source, cm, "", false);
00734                         continue;
00735                 }
00736                 else if (cm->type == MODE_PARAM)
00737                 {
00738                         ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00739 
00740                         if (!add && cmp->minus_no_arg)
00741                         {
00742                                 this->RemoveModeInternal(source, cm, "", false);
00743                                 continue;
00744                         }
00745                 }
00746                 Anope::string token;
00747                 if (sep_modes.GetToken(token))
00748                 {
00749                         User *u = NULL;
00750                         if (cm->type == MODE_STATUS && (u = User::Find(token)))
00751                                 paramstring += " " + u->nick;
00752                         else
00753                                 paramstring += " " + token;
00754 
00755                         if (add)
00756                                 this->SetModeInternal(source, cm, token, false);
00757                         else
00758                                 this->RemoveModeInternal(source, cm, token, false);
00759                 }
00760                 else
00761                         Log() << "warning: Channel::SetModesInternal() recieved more modes requiring params than params, modes: " << mode;
00762         }
00763 
00764         if (!this_reference)
00765                 return;
00766 
00767         if (setter)
00768                 Log(setter, this, "mode") << modestring << paramstring;
00769         else
00770                 Log(LOG_DEBUG) << source.GetName() << " is setting " << this->name << " to " << modestring << paramstring;
00771         
00772         if (enforce_mlock)
00773                 this->CheckModes();
00774 }
00775 
00776 bool Channel::MatchesList(User *u, const Anope::string &mode)
00777 {
00778         if (!this->HasMode(mode))
00779                 return false;
00780 
00781 
00782         std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> m = this->GetModeList(mode);
00783         for (; m.first != m.second; ++m.first)
00784         {
00785                 Entry e(mode, m.first->second);
00786                 if (e.Matches(u))
00787                         return true;
00788         }
00789 
00790         return false;
00791 }
00792 
00793 void Channel::KickInternal(MessageSource &source, const Anope::string &nick, const Anope::string &reason)
00794 {
00795         User *sender = source.GetUser();
00796         User *target = User::Find(nick);
00797         if (!target)
00798         {
00799                 Log() << "Channel::KickInternal got a nonexistent user " << nick << " on " << this->name << ": " << reason;
00800                 return;
00801         }
00802 
00803         BotInfo *bi = NULL;
00804         if (target->server == Me)
00805                 bi = BotInfo::Find(nick);
00806 
00807         if (sender)
00808                 Log(sender, this, "kick") << "kicked " << target->nick << " (" << reason << ")";
00809         else
00810                 Log(target, this, "kick") << "was kicked by " << source.GetSource() << " (" << reason << ")";
00811 
00812         Anope::string chname = this->name;
00813 
00814         if (target->FindChannel(this))
00815         {
00816                 FOREACH_MOD(I_OnUserKicked, OnUserKicked(this, target, source, reason));
00817                 if (bi)
00818                         this->Extend("INHABIT");
00819                 this->DeleteUser(target);
00820         }
00821         else
00822                 Log() << "Channel::KickInternal got kick for user " << target->nick << " from " << source.GetSource() << " who isn't on channel " << this->name;
00823 
00824         /* Bots get rejoined */
00825         if (bi)
00826         {
00827                 bi->Join(this, &ModeManager::DefaultBotModes);
00828                 this->Shrink("INHABIT");
00829         }
00830 }
00831 
00832 bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
00833 {
00834         va_list args;
00835         char buf[BUFSIZE] = "";
00836         va_start(args, reason);
00837         vsnprintf(buf, BUFSIZE - 1, reason, args);
00838         va_end(args);
00839 
00840         /* May not kick ulines */
00841         if (u->server->IsULined())
00842                 return false;
00843 
00844         /* Do not kick protected clients */
00845         if (u->IsProtected())
00846                 return false;
00847         
00848         if (bi == NULL)
00849                 bi = this->ci->WhoSends();
00850 
00851         EventReturn MOD_RESULT;
00852         FOREACH_RESULT(I_OnBotKick, OnBotKick(bi, this, u, buf));
00853         if (MOD_RESULT == EVENT_STOP)
00854                 return false;
00855         IRCD->SendKick(bi, this, u, "%s", buf);
00856         MessageSource ms(bi);
00857         this->KickInternal(ms, u->nick, buf);
00858         return true;
00859 }
00860 
00861 void Channel::ChangeTopicInternal(const Anope::string &user, const Anope::string &newtopic, time_t ts)
00862 {
00863         User *u = User::Find(user);
00864 
00865         this->topic = newtopic;
00866         this->topic_setter = u ? u->nick : user;
00867         this->topic_ts = ts;
00868         this->topic_time = Anope::CurTime;
00869 
00870         Log(LOG_DEBUG) << "Topic of " << this->name << " changed by " << (u ? u->nick : user) << " to " << newtopic;
00871 
00872         FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(this, user, this->topic));
00873 
00874         if (this->ci)
00875                 this->ci->CheckTopic();
00876 }
00877 
00878 void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtopic, time_t ts)
00879 {
00880         User *u = User::Find(user);
00881 
00882         this->topic = newtopic;
00883         this->topic_setter = u ? u->nick : user;
00884         this->topic_ts = ts;
00885 
00886         IRCD->SendTopic(this->ci->WhoSends(), this);
00887 
00888         /* Now that the topic is set update the time set. This is *after* we set it so the protocol modules are able to tell the old last set time */
00889         this->topic_time = Anope::CurTime;
00890 
00891         FOREACH_MOD(I_OnTopicUpdated, OnTopicUpdated(this, user, this->topic));
00892 
00893         if (this->ci)
00894                 this->ci->CheckTopic();
00895 }
00896 
00897 void Channel::Hold()
00898 {
00902         class ChanServTimer : public Timer
00903         {
00904          private:
00905                 Reference<Channel> c;
00906 
00907          public:
00911                 ChanServTimer(Channel *chan) : Timer(Config->CSInhabit), c(chan)
00912                 {
00913                         if (!ChanServ || !c)
00914                                 return;
00915                         c->Extend("INHABIT");
00916                         if (!c->ci || !c->ci->bi)
00917                                 ChanServ->Join(c);
00918                         else if (!c->FindUser(c->ci->bi))
00919                                 c->ci->bi->Join(c);
00920                 }
00921 
00925                 void Tick(time_t) anope_override
00926                 {
00927                         if (!c)
00928                                 return;
00929 
00930                         c->Shrink("INHABIT");
00931 
00932                         if (!c->ci || !c->ci->bi)
00933                         {
00934                                 if (ChanServ)
00935                                         ChanServ->Part(c);
00936                         }
00937                         else if (c->users.size() == 1 || c->users.size() < Config->BSMinUsers)
00938                                 c->ci->bi->Part(c);
00939                 }
00940         };
00941 
00942         new ChanServTimer(this);
00943 }
00944 
00945 void Channel::SetCorrectModes(User *user, bool give_modes, bool check_noop)
00946 {
00947         ChannelMode *owner = ModeManager::FindChannelModeByName("OWNER"),
00948                 *admin = ModeManager::FindChannelModeByName("PROTECT"),
00949                 *op = ModeManager::FindChannelModeByName("OP"),
00950                 *halfop = ModeManager::FindChannelModeByName("HALFOP"),
00951                 *voice = ModeManager::FindChannelModeByName("VOICE"),
00952                 *registered = ModeManager::FindChannelModeByName("REGISTERED");
00953 
00954         if (user == NULL)
00955                 return;
00956         
00957         if (!this->ci)
00958                 return;
00959 
00960         Log(LOG_DEBUG) << "Setting correct user modes for " << user->nick << " on " << this->name << " (" << (give_modes ? "" : "not ") << "giving modes)";
00961 
00962         AccessGroup u_access = ci->AccessFor(user);
00963 
00964         if (give_modes && (!user->Account() || user->Account()->HasExt("AUTOOP")) && (!check_noop || !ci->HasExt("NOAUTOOP")))
00965         {
00966                 if (owner && u_access.HasPriv("AUTOOWNER"))
00967                         this->SetMode(NULL, "OWNER", user->GetUID());
00968                 else if (admin && u_access.HasPriv("AUTOPROTECT"))
00969                         this->SetMode(NULL, "PROTECT", user->GetUID());
00970 
00971                 if (op && u_access.HasPriv("AUTOOP"))
00972                         this->SetMode(NULL, "OP", user->GetUID());
00973                 else if (halfop && u_access.HasPriv("AUTOHALFOP"))
00974                         this->SetMode(NULL, "HALFOP", user->GetUID());
00975                 else if (voice && u_access.HasPriv("AUTOVOICE"))
00976                         this->SetMode(NULL, "VOICE", user->GetUID());
00977         }
00978         /* If this channel has secureops, or the registered channel mode exists and the channel does not have +r set (aka the channel
00979          * was created just now or while we were off), or the registered channel mode does not exist and channel is syncing (aka just
00980          * created *to us*) and the user's server is synced (aka this isn't us doing our initial uplink - without this we would be deopping all
00981          * users with no access on a non-secureops channel on startup), and the user's server isn't ulined, then set negative modes.
00982          */
00983         if ((ci->HasExt("SECUREOPS") || (registered && !this->HasMode("REGISTERED")) || (!registered && this->HasExt("SYNCING") && user->server->IsSynced())) && !user->server->IsULined())
00984         {
00985                 if (owner && !u_access.HasPriv("AUTOOWNER") && !u_access.HasPriv("OWNERME"))
00986                         this->RemoveMode(NULL, "OWNER", user->GetUID());
00987 
00988                 if (admin && !u_access.HasPriv("AUTOPROTECT") && !u_access.HasPriv("PROTECTME"))
00989                         this->RemoveMode(NULL, "PROTECT", user->GetUID());
00990 
00991                 if (op && this->HasUserStatus(user, "OP") && !u_access.HasPriv("AUTOOP") && !u_access.HasPriv("OPDEOPME"))
00992                         this->RemoveMode(NULL, "OP", user->GetUID());
00993 
00994                 if (halfop && !u_access.HasPriv("AUTOHALFOP") && !u_access.HasPriv("HALFOPME"))
00995                         this->RemoveMode(NULL, "HALFOP", user->GetUID());
00996         }
00997 
00998         // Check mlock
00999         for (ChannelInfo::ModeList::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it)
01000         {
01001                 const ModeLock *ml = it->second;
01002                 ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
01003                 if (!cm || cm->type != MODE_STATUS)
01004                         continue;
01005 
01006                 if (Anope::Match(user->nick, ml->param) || Anope::Match(user->GetDisplayedMask(), ml->param))
01007                 {
01008                         if (ml->set != this->HasUserStatus(user, ml->name))
01009                         {
01010                                 if (ml->set)
01011                                         this->SetMode(NULL, cm, user->GetUID(), false);
01012                                 else if (!ml->set)
01013                                         this->RemoveMode(NULL, cm, user->GetUID(), false);
01014                         }
01015                 }
01016         }
01017 }
01018 
01019 bool Channel::Unban(const User *u, bool full)
01020 {
01021         if (!this->HasMode("BAN"))
01022                 return false;
01023 
01024         bool ret = false;
01025 
01026         std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> bans = this->GetModeList("BAN");
01027         for (; bans.first != bans.second;)
01028         {
01029                 Entry ban("BAN", bans.first->second);
01030                 ++bans.first;
01031                 if (ban.Matches(u, full))
01032                 {
01033                         this->RemoveMode(NULL, "BAN", ban.GetMask());
01034                         ret = true;
01035                 }
01036         }
01037 
01038         return ret;
01039 }
01040 
01041 Channel* Channel::Find(const Anope::string &name)
01042 {
01043         channel_map::const_iterator it = ChannelList.find(name);
01044 
01045         if (it != ChannelList.end())
01046                 return it->second;
01047         return NULL;
01048 }
01049