00001
00002
00003
00004
00005
00006
00007
00008
00009
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> ¶ms) 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)