00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "module.h"
00019 #include "memoserv.h"
00020
00021 static ServiceReference<MemoServService> MemoServService("MemoServService", "MemoServ");
00022
00023 static bool HSRequestMemoUser = false;
00024 static bool HSRequestMemoOper = false;
00025
00026 void req_send_memos(CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost);
00027
00028 struct HostRequest : ExtensibleItem, Serializable
00029 {
00030 Anope::string nick;
00031 Anope::string ident;
00032 Anope::string host;
00033 time_t time;
00034
00035 HostRequest() : Serializable("HostRequest") { }
00036
00037 void Serialize(Serialize::Data &data) const anope_override
00038 {
00039 data["nick"] << this->nick;
00040 data["ident"] << this->ident;
00041 data["host"] << this->host;
00042 data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time;
00043 }
00044
00045 static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
00046 {
00047 Anope::string snick;
00048 data["nick"] >> snick;
00049
00050 NickAlias *na = NickAlias::Find(snick);
00051 if (na == NULL)
00052 return NULL;
00053
00054 HostRequest *req;
00055 if (obj)
00056 req = anope_dynamic_static_cast<HostRequest *>(obj);
00057 else
00058 req = new HostRequest;
00059 req->nick = na->nick;
00060 data["ident"] >> req->ident;
00061 data["host"] >> req->host;
00062 data["time"] >> req->time;
00063
00064 if (!obj)
00065 na->Extend("hs_request", req);
00066 return req;
00067 }
00068 };
00069
00070 class CommandHSRequest : public Command
00071 {
00072 bool isvalidchar(char c)
00073 {
00074 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
00075 return true;
00076 return false;
00077 }
00078
00079 public:
00080 CommandHSRequest(Module *creator) : Command(creator, "hostserv/request", 1, 1)
00081 {
00082 this->SetDesc(_("Request a vHost for your nick"));
00083 this->SetSyntax(_("vhost"));
00084 }
00085
00086 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00087 {
00088 User *u = source.GetUser();
00089 NickAlias *na = NickAlias::Find(source.GetNick());
00090 if (!na || na->nc != source.GetAccount())
00091 {
00092 source.Reply(ACCESS_DENIED);
00093 return;
00094 }
00095
00096 Anope::string rawhostmask = params[0];
00097
00098 Anope::string user, host;
00099 size_t a = rawhostmask.find('@');
00100
00101 if (a == Anope::string::npos)
00102 host = rawhostmask;
00103 else
00104 {
00105 user = rawhostmask.substr(0, a);
00106 host = rawhostmask.substr(a + 1);
00107 }
00108
00109 if (host.empty())
00110 {
00111 this->OnSyntaxError(source, "");
00112 return;
00113 }
00114
00115 if (!user.empty())
00116 {
00117 if (user.length() > Config->UserLen)
00118 {
00119 source.Reply(HOST_SET_IDENTTOOLONG, Config->UserLen);
00120 return;
00121 }
00122 else if (!IRCD->CanSetVIdent)
00123 {
00124 source.Reply(HOST_NO_VIDENT);
00125 return;
00126 }
00127 for (Anope::string::iterator s = user.begin(), s_end = user.end(); s != s_end; ++s)
00128 if (!isvalidchar(*s))
00129 {
00130 source.Reply(HOST_SET_IDENT_ERROR);
00131 return;
00132 }
00133 }
00134
00135 if (host.length() > Config->HostLen)
00136 {
00137 source.Reply(HOST_SET_TOOLONG, Config->HostLen);
00138 return;
00139 }
00140
00141 if (!IRCD->IsHostValid(host))
00142 {
00143 source.Reply(HOST_SET_ERROR);
00144 return;
00145 }
00146
00147 if (HSRequestMemoOper && Config->MSSendDelay > 0 && u && u->lastmemosend + Config->MSSendDelay > Anope::CurTime)
00148 {
00149 source.Reply(_("Please wait %d seconds before requesting a new vHost."), Config->MSSendDelay);
00150 u->lastmemosend = Anope::CurTime;
00151 return;
00152 }
00153
00154
00155 HostRequest *req = new HostRequest;
00156 req->nick = source.GetNick();
00157 req->ident = user;
00158 req->host = host;
00159 req->time = Anope::CurTime;
00160 na->Extend("hs_request", req);
00161
00162 source.Reply(_("Your vHost has been requested."));
00163 req_send_memos(source, user, host);
00164 Log(LOG_COMMAND, source, this) << "to request new vhost " << (!user.empty() ? user + "@" : "") << host;
00165
00166 return;
00167 }
00168
00169 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00170 {
00171 this->SendSyntax(source);
00172 source.Reply(" ");
00173 source.Reply(_("Request the given vHost to be actived for your nick by the\n"
00174 "network administrators. Please be patient while your request\n"
00175 "is being considered."));
00176 return true;
00177 }
00178 };
00179
00180 class CommandHSActivate : public Command
00181 {
00182 public:
00183 CommandHSActivate(Module *creator) : Command(creator, "hostserv/activate", 1, 1)
00184 {
00185 this->SetDesc(_("Approve the requested vHost of a user"));
00186 this->SetSyntax(_("\037nick\037"));
00187 }
00188
00189 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00190 {
00191
00192 const Anope::string &nick = params[0];
00193
00194 NickAlias *na = NickAlias::Find(nick);
00195 HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
00196 if (req)
00197 {
00198 na->SetVhost(req->ident, req->host, source.GetNick(), req->time);
00199 FOREACH_MOD(I_OnSetVhost, OnSetVhost(na));
00200
00201 if (HSRequestMemoUser && MemoServService)
00202 MemoServService->Send(Config->HostServ, na->nick, _("[auto memo] Your requested vHost has been approved."), true);
00203
00204 source.Reply(_("vHost for %s has been activated."), na->nick.c_str());
00205 Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
00206 na->Shrink("hs_request");
00207 }
00208 else
00209 source.Reply(_("No request for nick %s found."), nick.c_str());
00210 }
00211
00212 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00213 {
00214 this->SendSyntax(source);
00215 source.Reply(" ");
00216 source.Reply(_("Activate the requested vHost for the given nick."));
00217 if (HSRequestMemoUser)
00218 source.Reply(_("A memo informing the user will also be sent."));
00219
00220 return true;
00221 }
00222 };
00223
00224 class CommandHSReject : public Command
00225 {
00226 public:
00227 CommandHSReject(Module *creator) : Command(creator, "hostserv/reject", 1, 2)
00228 {
00229 this->SetDesc(_("Reject the requested vHost of a user"));
00230 }
00231
00232 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00233 {
00234
00235 const Anope::string &nick = params[0];
00236 const Anope::string &reason = params.size() > 1 ? params[1] : "";
00237
00238 NickAlias *na = NickAlias::Find(nick);
00239 HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
00240 if (req)
00241 {
00242 na->Shrink("hs_request");
00243
00244 if (HSRequestMemoUser && MemoServService)
00245 {
00246 Anope::string message;
00247 if (!reason.empty())
00248 message = Anope::printf(_("[auto memo] Your requested vHost has been rejected. Reason: %s"), reason.c_str());
00249 else
00250 message = _("[auto memo] Your requested vHost has been rejected.");
00251
00252 MemoServService->Send(Config->HostServ, nick, message, true);
00253 }
00254
00255 source.Reply(_("vHost for %s has been rejected."), nick.c_str());
00256 Log(LOG_COMMAND, source, this, NULL) << "to reject vhost for " << nick << " (" << (!reason.empty() ? reason : "") << ")";
00257 }
00258 else
00259 source.Reply(_("No request for nick %s found."), nick.c_str());
00260
00261 return;
00262 }
00263
00264 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00265 {
00266 this->SendSyntax(source);
00267 source.Reply(" ");
00268 source.Reply(_("Reject the requested vHost for the given nick."));
00269 if (HSRequestMemoUser)
00270 source.Reply(_("A memo informing the user will also be sent."));
00271
00272 return true;
00273 }
00274 };
00275
00276 class CommandHSWaiting : public Command
00277 {
00278 void DoList(CommandSource &source)
00279 {
00280 int counter = 1;
00281 int from = 0, to = 0;
00282 unsigned display_counter = 0;
00283 ListFormatter list;
00284
00285 list.AddColumn("Number").AddColumn("Nick").AddColumn("Vhost").AddColumn("Created");
00286
00287 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
00288 {
00289 const NickAlias *na = it->second;
00290 HostRequest *hr = na->GetExt<HostRequest *>("hs_request");
00291 if (!hr)
00292 continue;
00293
00294 if (((counter >= from && counter <= to) || (!from && !to)) && display_counter < Config->NSListMax)
00295 {
00296 ++display_counter;
00297
00298 ListFormatter::ListEntry entry;
00299 entry["Number"] = stringify(counter);
00300 entry["Nick"] = it->first;
00301 if (!hr->ident.empty())
00302 entry["Vhost"] = hr->ident + "@" + hr->host;
00303 else
00304 entry["Vhost"] = hr->host;
00305 entry["Created"] = Anope::strftime(hr->time);
00306 list.AddEntry(entry);
00307 }
00308 ++counter;
00309 }
00310 source.Reply(_("Displayed all records (count: \002%d\002)."), display_counter);
00311
00312 std::vector<Anope::string> replies;
00313 list.Process(replies);
00314
00315 for (unsigned i = 0; i < replies.size(); ++i)
00316 source.Reply(replies[i]);
00317 }
00318
00319 public:
00320 CommandHSWaiting(Module *creator) : Command(creator, "hostserv/waiting", 0, 0)
00321 {
00322 this->SetDesc(_("Retrieves the vhost requests"));
00323 this->SetSyntax("");
00324 }
00325
00326 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00327 {
00328 return this->DoList(source);
00329 }
00330
00331 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00332 {
00333 this->SendSyntax(source);
00334 source.Reply(" ");
00335 source.Reply(_("This command retrieves the vhost requests."));
00336
00337 return true;
00338 }
00339 };
00340
00341 class HSRequest : public Module
00342 {
00343 Serialize::Type request_type;
00344 CommandHSRequest commandhsrequest;
00345 CommandHSActivate commandhsactive;
00346 CommandHSReject commandhsreject;
00347 CommandHSWaiting commandhswaiting;
00348
00349 public:
00350 HSRequest(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00351 request_type("HostRequest", HostRequest::Unserialize), commandhsrequest(this), commandhsactive(this), commandhsreject(this), commandhswaiting(this)
00352 {
00353 this->SetAuthor("Anope");
00354
00355 if (!IRCD || !IRCD->CanSetVHost)
00356 throw ModuleException("Your IRCd does not support vhosts");
00357
00358 Implementation i[] = { I_OnReload };
00359 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00360
00361 this->OnReload();
00362 }
00363
00364 ~HSRequest()
00365 {
00366 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
00367 {
00368 NickAlias *na = it->second;
00369 na->Shrink("hs_request");
00370 }
00371 }
00372
00373 void OnReload() anope_override
00374 {
00375 ConfigReader config;
00376 HSRequestMemoUser = config.ReadFlag("hs_request", "memouser", "no", 0);
00377 HSRequestMemoOper = config.ReadFlag("hs_request", "memooper", "no", 0);
00378
00379 Log(LOG_DEBUG) << "[hs_request] Set config vars: MemoUser=" << HSRequestMemoUser << " MemoOper=" << HSRequestMemoOper;
00380 }
00381 };
00382
00383 void req_send_memos(CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost)
00384 {
00385 Anope::string host;
00386 std::list<std::pair<Anope::string, Anope::string> >::iterator it, it_end;
00387
00388 if (!vIdent.empty())
00389 host = vIdent + "@" + vHost;
00390 else
00391 host = vHost;
00392
00393 if (HSRequestMemoOper == 1 && MemoServService)
00394 for (unsigned i = 0; i < Config->Opers.size(); ++i)
00395 {
00396 Oper *o = Config->Opers[i];
00397
00398 const NickAlias *na = NickAlias::Find(o->name);
00399 if (!na)
00400 continue;
00401
00402 Anope::string message = Anope::printf(_("[auto memo] vHost \002%s\002 has been requested by %s."), host.c_str(), source.GetNick().c_str());
00403
00404 MemoServService->Send(Config->HostServ, na->nick, message, true);
00405 }
00406 }
00407
00408 MODULE_INIT(HSRequest)