ns_ajoin.cpp

Go to the documentation of this file.
00001 /* NickServ core functions
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 
00014 #include "module.h"
00015 
00016 struct AJoinEntry;
00017 
00018 struct AJoinList : Serialize::Checker<std::vector<AJoinEntry *> >, ExtensibleItem
00019 {
00020         AJoinList() : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { }
00021 };
00022 
00023 struct AJoinEntry : Serializable
00024 {
00025         Serialize::Reference<NickCore> owner;
00026         Anope::string channel;
00027         Anope::string key;
00028 
00029         AJoinEntry() : Serializable("AJoinEntry") { }
00030 
00031         void Serialize(Serialize::Data &sd) const anope_override
00032         {
00033                 if (!this->owner)
00034                         return;
00035 
00036                 sd["owner"] << this->owner->display;
00037                 sd["channel"] << this->channel;
00038                 sd["key"] << this->key;
00039         }
00040 
00041         static Serializable* Unserialize(Serializable *obj, Serialize::Data &sd)
00042         {
00043                 Anope::string sowner;
00044 
00045                 sd["owner"] >> sowner;
00046 
00047                 NickCore *nc = NickCore::Find(sowner);
00048                 if (nc == NULL)
00049                         return NULL;
00050 
00051                 AJoinEntry *aj;
00052                 if (obj)
00053                         aj = anope_dynamic_static_cast<AJoinEntry *>(obj);
00054                 else
00055                 {
00056                         aj = new AJoinEntry();
00057                         aj->owner = nc;
00058                 }
00059 
00060                 sd["channel"] >> aj->channel;
00061                 sd["key"] >> aj->key;
00062 
00063                 if (!obj)
00064                 {
00065                         AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
00066                         if (channels == NULL)
00067                         {
00068                                 channels = new AJoinList();
00069                                 nc->Extend("ns_ajoin_channels", channels);
00070                         }
00071                         (*channels)->push_back(aj);
00072                 }
00073 
00074                 return aj;
00075         }
00076 };
00077 
00078 class CommandNSAJoin : public Command
00079 {
00080         void DoList(CommandSource &source, NickCore *nc)
00081         {
00082                 AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
00083                 if (channels == NULL)
00084                 {
00085                         channels = new AJoinList();
00086                         nc->Extend("ns_ajoin_channels", channels);
00087                 }
00088 
00089                 if ((*channels)->empty())
00090                         source.Reply(_("%s's auto join list is empty."), nc->display.c_str());
00091                 else
00092                 {
00093                         ListFormatter list;
00094                         list.AddColumn("Number").AddColumn("Channel").AddColumn("Key");
00095                         for (unsigned i = 0; i < (*channels)->size(); ++i)
00096                         {
00097                                 AJoinEntry *aj = (*channels)->at(i);
00098                                 ListFormatter::ListEntry entry;
00099                                 entry["Number"] = stringify(i + 1);
00100                                 entry["Channel"] = aj->channel;
00101                                 entry["Key"] = aj->key;
00102                                 list.AddEntry(entry);
00103                         }
00104 
00105                         source.Reply(_("%s's auto join list:"), nc->display.c_str());
00106 
00107                         std::vector<Anope::string> replies;
00108                         list.Process(replies);
00109 
00110                         for (unsigned i = 0; i < replies.size(); ++i)
00111                                 source.Reply(replies[i]);
00112                 }
00113         }
00114 
00115         void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &chan, const Anope::string &key)
00116         {
00117                 AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
00118                 if (channels == NULL)
00119                 {
00120                         channels = new AJoinList();
00121                         nc->Extend("ns_ajoin_channels", channels);
00122                 }
00123 
00124                 unsigned i = 0;
00125                 for (; i < (*channels)->size(); ++i)
00126                         if ((*channels)->at(i)->channel.equals_ci(chan))
00127                                 break;
00128 
00129                 if (*source.nc == nc && (*channels)->size() >= Config->AJoinMax)
00130                         source.Reply(_("Your auto join list is full."));
00131                 else if (i != (*channels)->size())
00132                         source.Reply(_("%s is already on %s's auto join list."), chan.c_str(), nc->display.c_str());
00133                 else if (IRCD->IsChannelValid(chan) == false)
00134                         source.Reply(CHAN_X_INVALID, chan.c_str());
00135                 else
00136                 {
00137                         AJoinEntry *entry = new AJoinEntry();
00138                         entry->owner = nc;
00139                         entry->channel = chan;
00140                         entry->key = key;
00141                         (*channels)->push_back(entry);
00142                         source.Reply(_("Added %s to %s's auto join list."), chan.c_str(), nc->display.c_str());
00143                 }
00144         }
00145 
00146         void DoDel(CommandSource &source, NickCore *nc, const Anope::string &chan)
00147         {
00148                 AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
00149                 if (channels == NULL)
00150                 {
00151                         channels = new AJoinList();
00152                         nc->Extend("ns_ajoin_channels", channels);
00153                 }
00154 
00155                 unsigned i = 0;
00156                 for (; i < (*channels)->size(); ++i)
00157                         if ((*channels)->at(i)->channel.equals_ci(chan))
00158                                 break;
00159                 
00160                 if (i == (*channels)->size())
00161                         source.Reply(_("%s was not found on %s's auto join list."), chan.c_str(), nc->display.c_str());
00162                 else
00163                 {
00164                         delete (*channels)->at(i);
00165                         (*channels)->erase((*channels)->begin() + i);
00166                         source.Reply(_("%s was removed from %s's auto join list."), chan.c_str(), nc->display.c_str());
00167                 }
00168         }
00169 
00170  public:
00171         CommandNSAJoin(Module *creator) : Command(creator, "nickserv/ajoin", 1, 3)
00172         {
00173                 this->SetDesc(_("Manage your auto join list"));
00174                 this->SetSyntax(_("ADD [\037user\037] \037channel\037 [\037key\037]"));
00175                 this->SetSyntax(_("DEL [\037user\037] \037channel\037"));
00176                 this->SetSyntax(_("LIST [\037user\037]"));
00177         }
00178 
00179         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00180         {
00181                 NickCore *nc = source.GetAccount();
00182                 Anope::string param, param2;
00183 
00184                 if (params.size() > 1 && source.IsServicesOper() && IRCD->IsNickValid(params[1]))
00185                 {
00186                         NickAlias *na = NickAlias::Find(params[1]);
00187                         if (!na)
00188                         {
00189                                 source.Reply(NICK_X_NOT_REGISTERED, params[1].c_str());
00190                                 return;
00191                         }
00192 
00193                         nc = na->nc;
00194                         param = params.size() > 2 ? params[2] : "";
00195                         param2 = params.size() > 3 ? params[3] : "";
00196                 }
00197                 else
00198                 {
00199                         param = params.size() > 1 ? params[1] : "";
00200                         param2 = params.size() > 2 ? params[2] : "";
00201                 }
00202 
00203                 if (params[0].equals_ci("LIST"))
00204                         this->DoList(source, nc);
00205                 else if (param.empty())
00206                         this->OnSyntaxError(source, "");
00207                 else if (params[0].equals_ci("ADD"))
00208                         this->DoAdd(source, nc, param, param2);
00209                 else if (params[0].equals_ci("DEL"))
00210                         this->DoDel(source, nc, param);
00211                 else
00212                         this->OnSyntaxError(source, "");
00213         }
00214 
00215         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00216         {
00217                 this->SendSyntax(source);
00218                 source.Reply(" ");
00219                 source.Reply(_("This command manages your auto join list. When you identify\n"
00220                                 "you will automatically join the channels on your auto join list.\n"
00221                                 "Services Operators may provide a nick to modify other users'\n"
00222                                 "auto join lists."));
00223                 return true;
00224         }
00225 };
00226 
00227 class NSAJoin : public Module
00228 {
00229         Serialize::Type ajoinentry_type;
00230         CommandNSAJoin commandnsajoin;
00231 
00232  public:
00233         NSAJoin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00234                 ajoinentry_type("AJoinEntry", AJoinEntry::Unserialize), commandnsajoin(this)
00235         {
00236                 this->SetAuthor("Anope");
00237 
00238                 if (!IRCD->CanSVSJoin)
00239                         throw ModuleException("Your IRCd does not support SVSJOIN");
00240 
00241                 Implementation i[] = { I_OnNickIdentify };
00242                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00243         }
00244 
00245         void OnNickIdentify(User *u) anope_override
00246         {
00247                 if (!NickServ)
00248                         return;
00249 
00250                 AJoinList *channels = u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
00251                 if (channels == NULL)
00252                 {
00253                         channels = new AJoinList();
00254                         u->Account()->Extend("ns_ajoin_channels", channels);
00255                 }
00256 
00257                 for (unsigned i = 0; i < (*channels)->size(); ++i)
00258                 {
00259                         AJoinEntry *entry = (*channels)->at(i);
00260                         Channel *c = Channel::Find(entry->channel);
00261                         ChannelInfo *ci;
00262 
00263                         if (c)
00264                                 ci = c->ci;
00265                         else
00266                                 ci = ChannelInfo::Find(entry->channel);
00267 
00268                         bool need_invite = false;
00269                         Anope::string key = entry->key;
00270                         
00271                         if (ci != NULL)
00272                         {
00273                                 if (ci->HasExt("SUSPENDED"))
00274                                         continue;
00275                         }
00276                         if (c != NULL)
00277                         {
00278                                 if (c->FindUser(u) != NULL)
00279                                         continue;
00280                                 else if (c->HasMode("OPERONLY") && !u->HasMode("OPER"))
00281                                         continue;
00282                                 else if (c->HasMode("ADMINONLY") && !u->HasMode("ADMIN"))
00283                                         continue;
00284                                 else if (c->HasMode("SSL") && !u->HasMode("SSL"))
00285                                         continue;
00286                                 else if (c->MatchesList(u, "BAN") == true && c->MatchesList(u, "EXCEPT") == false)
00287                                         need_invite = true;
00288                                 else if (c->HasMode("INVITE") && c->MatchesList(u, "INVITEOVERRIDE") == false)
00289                                         need_invite = true;
00290                                         
00291                                 if (c->HasMode("KEY"))
00292                                 {
00293                                         Anope::string k;
00294                                         if (c->GetParam("KEY", k))
00295                                         {
00296                                                 if (ci->AccessFor(u).HasPriv("GETKEY"))
00297                                                         key = k;
00298                                                 else if (key != k)
00299                                                         need_invite = true;
00300                                         }
00301                                 }
00302                                 if (c->HasMode("LIMIT"))
00303                                 {
00304                                         Anope::string l;
00305                                         if (c->GetParam("LIMIT", l))
00306                                         {
00307                                                 try
00308                                                 {
00309                                                         unsigned limit = convertTo<unsigned>(l);
00310                                                         if (c->users.size() >= limit)
00311                                                                 need_invite = true;
00312                                                 }
00313                                                 catch (const ConvertException &) { }
00314                                         }
00315                                 }
00316                         }
00317 
00318                         if (need_invite && c != NULL)
00319                         {
00320                                 if (!ci->AccessFor(u).HasPriv("INVITE"))
00321                                         continue;
00322                                 IRCD->SendInvite(NickServ, c, u);
00323                         }
00324 
00325                         IRCD->SendSVSJoin(NickServ, u, entry->channel, key);
00326                 }
00327         }
00328 };
00329 
00330 MODULE_INIT(NSAJoin)