anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
hs_request.cpp (11285B)
1 /* hs_request.c - Add request and activate functionality to HostServ 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Based on the original module by Rob <rob@anope.org> 7 * Included in the Anope module pack since Anope 1.7.11 8 * Anope Coder: GeniusDex <geniusdex@anope.org> 9 * 10 * Please read COPYING and README for further details. 11 * 12 * Send bug reports to the Anope Coder instead of the module 13 * author, because any changes since the inclusion into anope 14 * are not supported by the original author. 15 */ 16 17 #include "module.h" 18 19 static ServiceReference<MemoServService> memoserv("MemoServService", "MemoServ"); 20 21 static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost); 22 23 struct HostRequest : Serializable 24 { 25 Anope::string nick; 26 Anope::string ident; 27 Anope::string host; 28 time_t time; 29 30 HostRequest(Extensible *) : Serializable("HostRequest") { } 31 32 void Serialize(Serialize::Data &data) const anope_override 33 { 34 data["nick"] << this->nick; 35 data["ident"] << this->ident; 36 data["host"] << this->host; 37 data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time; 38 } 39 40 static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) 41 { 42 Anope::string snick; 43 data["nick"] >> snick; 44 45 NickAlias *na = NickAlias::Find(snick); 46 if (na == NULL) 47 return NULL; 48 49 HostRequest *req; 50 if (obj) 51 req = anope_dynamic_static_cast<HostRequest *>(obj); 52 else 53 req = na->Extend<HostRequest>("hostrequest"); 54 if (req) 55 { 56 req->nick = na->nick; 57 data["ident"] >> req->ident; 58 data["host"] >> req->host; 59 data["time"] >> req->time; 60 } 61 62 return req; 63 } 64 }; 65 66 class CommandHSRequest : public Command 67 { 68 bool isvalidchar(char c) 69 { 70 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-') 71 return true; 72 return false; 73 } 74 75 public: 76 CommandHSRequest(Module *creator) : Command(creator, "hostserv/request", 1, 1) 77 { 78 this->SetDesc(_("Request a vHost for your nick")); 79 this->SetSyntax(_("vhost")); 80 } 81 82 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 83 { 84 if (Anope::ReadOnly) 85 { 86 source.Reply(READ_ONLY_MODE); 87 return; 88 } 89 90 User *u = source.GetUser(); 91 NickAlias *na = NickAlias::Find(source.GetNick()); 92 if (!na || na->nc != source.GetAccount()) 93 { 94 source.Reply(ACCESS_DENIED); 95 return; 96 } 97 98 if (source.GetAccount()->HasExt("UNCONFIRMED")) 99 { 100 source.Reply(_("You must confirm your account before you may request a vhost.")); 101 return; 102 } 103 104 Anope::string rawhostmask = params[0]; 105 106 Anope::string user, host; 107 size_t a = rawhostmask.find('@'); 108 109 if (a == Anope::string::npos) 110 host = rawhostmask; 111 else 112 { 113 user = rawhostmask.substr(0, a); 114 host = rawhostmask.substr(a + 1); 115 } 116 117 if (host.empty()) 118 { 119 this->OnSyntaxError(source, ""); 120 return; 121 } 122 123 if (!user.empty()) 124 { 125 if (user.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) 126 { 127 source.Reply(HOST_SET_IDENTTOOLONG, Config->GetBlock("networkinfo")->Get<unsigned>("userlen")); 128 return; 129 } 130 else if (!IRCD->CanSetVIdent) 131 { 132 source.Reply(HOST_NO_VIDENT); 133 return; 134 } 135 for (Anope::string::iterator s = user.begin(), s_end = user.end(); s != s_end; ++s) 136 if (!isvalidchar(*s)) 137 { 138 source.Reply(HOST_SET_IDENT_ERROR); 139 return; 140 } 141 } 142 143 if (host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")) 144 { 145 source.Reply(HOST_SET_TOOLONG, Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")); 146 return; 147 } 148 149 if (!IRCD->IsHostValid(host)) 150 { 151 source.Reply(HOST_SET_ERROR); 152 return; 153 } 154 155 time_t send_delay = Config->GetModule("memoserv")->Get<time_t>("senddelay"); 156 if (Config->GetModule(this->owner)->Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime) 157 { 158 source.Reply(_("Please wait %d seconds before requesting a new vHost."), send_delay); 159 u->lastmemosend = Anope::CurTime; 160 return; 161 } 162 163 HostRequest req(na); 164 req.nick = source.GetNick(); 165 req.ident = user; 166 req.host = host; 167 req.time = Anope::CurTime; 168 na->Extend<HostRequest>("hostrequest", req); 169 170 source.Reply(_("Your vHost has been requested.")); 171 req_send_memos(owner, source, user, host); 172 Log(LOG_COMMAND, source, this) << "to request new vhost " << (!user.empty() ? user + "@" : "") << host; 173 } 174 175 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 176 { 177 this->SendSyntax(source); 178 source.Reply(" "); 179 source.Reply(_("Request the given vHost to be activated for your nick by the\n" 180 "network administrators. Please be patient while your request\n" 181 "is being considered.")); 182 return true; 183 } 184 }; 185 186 class CommandHSActivate : public Command 187 { 188 public: 189 CommandHSActivate(Module *creator) : Command(creator, "hostserv/activate", 1, 1) 190 { 191 this->SetDesc(_("Approve the requested vHost of a user")); 192 this->SetSyntax(_("\037nick\037")); 193 } 194 195 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 196 { 197 if (Anope::ReadOnly) 198 { 199 source.Reply(READ_ONLY_MODE); 200 return; 201 } 202 203 const Anope::string &nick = params[0]; 204 205 NickAlias *na = NickAlias::Find(nick); 206 HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL; 207 if (req) 208 { 209 na->SetVhost(req->ident, req->host, source.GetNick(), req->time); 210 FOREACH_MOD(OnSetVhost, (na)); 211 212 if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv) 213 memoserv->Send(source.service->nick, na->nick, _("[auto memo] Your requested vHost has been approved."), true); 214 215 source.Reply(_("vHost for %s has been activated."), na->nick.c_str()); 216 Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host; 217 na->Shrink<HostRequest>("hostrequest"); 218 } 219 else 220 source.Reply(_("No request for nick %s found."), nick.c_str()); 221 } 222 223 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 224 { 225 this->SendSyntax(source); 226 source.Reply(" "); 227 source.Reply(_("Activate the requested vHost for the given nick.")); 228 if (Config->GetModule(this->owner)->Get<bool>("memouser")) 229 source.Reply(_("A memo informing the user will also be sent.")); 230 231 return true; 232 } 233 }; 234 235 class CommandHSReject : public Command 236 { 237 public: 238 CommandHSReject(Module *creator) : Command(creator, "hostserv/reject", 1, 2) 239 { 240 this->SetDesc(_("Reject the requested vHost of a user")); 241 this->SetSyntax(_("\037nick\037 [\037reason\037]")); 242 } 243 244 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 245 { 246 if (Anope::ReadOnly) 247 { 248 source.Reply(READ_ONLY_MODE); 249 return; 250 } 251 252 const Anope::string &nick = params[0]; 253 const Anope::string &reason = params.size() > 1 ? params[1] : ""; 254 255 NickAlias *na = NickAlias::Find(nick); 256 HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL; 257 if (req) 258 { 259 na->Shrink<HostRequest>("hostrequest"); 260 261 if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv) 262 { 263 Anope::string message; 264 if (!reason.empty()) 265 message = Anope::printf(_("[auto memo] Your requested vHost has been rejected. Reason: %s"), reason.c_str()); 266 else 267 message = _("[auto memo] Your requested vHost has been rejected."); 268 269 memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true); 270 } 271 272 source.Reply(_("vHost for %s has been rejected."), nick.c_str()); 273 Log(LOG_COMMAND, source, this) << "to reject vhost for " << nick << " (" << (!reason.empty() ? reason : "no reason") << ")"; 274 } 275 else 276 source.Reply(_("No request for nick %s found."), nick.c_str()); 277 } 278 279 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 280 { 281 this->SendSyntax(source); 282 source.Reply(" "); 283 source.Reply(_("Reject the requested vHost for the given nick.")); 284 if (Config->GetModule(this->owner)->Get<bool>("memouser")) 285 source.Reply(_("A memo informing the user will also be sent, which includes the reason for the rejection if supplied.")); 286 287 return true; 288 } 289 }; 290 291 class CommandHSWaiting : public Command 292 { 293 public: 294 CommandHSWaiting(Module *creator) : Command(creator, "hostserv/waiting", 0, 0) 295 { 296 this->SetDesc(_("Retrieves the vhost requests")); 297 } 298 299 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 300 { 301 unsigned counter = 0; 302 unsigned display_counter = 0, listmax = Config->GetModule(this->owner)->Get<unsigned>("listmax"); 303 ListFormatter list(source.GetAccount()); 304 305 list.AddColumn(_("Number")).AddColumn(_("Nick")).AddColumn(_("Vhost")).AddColumn(_("Created")); 306 307 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it) 308 { 309 const NickAlias *na = it->second; 310 HostRequest *hr = na->GetExt<HostRequest>("hostrequest"); 311 if (!hr) 312 continue; 313 314 if (!listmax || display_counter < listmax) 315 { 316 ++display_counter; 317 318 ListFormatter::ListEntry entry; 319 entry["Number"] = stringify(display_counter); 320 entry["Nick"] = it->first; 321 if (!hr->ident.empty()) 322 entry["Vhost"] = hr->ident + "@" + hr->host; 323 else 324 entry["Vhost"] = hr->host; 325 entry["Created"] = Anope::strftime(hr->time, NULL, true); 326 list.AddEntry(entry); 327 } 328 ++counter; 329 } 330 331 std::vector<Anope::string> replies; 332 list.Process(replies); 333 334 for (unsigned i = 0; i < replies.size(); ++i) 335 source.Reply(replies[i]); 336 337 source.Reply(_("Displayed \002%d\002 records (\002%d\002 total)."), display_counter, counter); 338 } 339 340 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 341 { 342 this->SendSyntax(source); 343 source.Reply(" "); 344 source.Reply(_("This command retrieves the vhost requests.")); 345 346 return true; 347 } 348 }; 349 350 class HSRequest : public Module 351 { 352 CommandHSRequest commandhsrequest; 353 CommandHSActivate commandhsactive; 354 CommandHSReject commandhsreject; 355 CommandHSWaiting commandhswaiting; 356 ExtensibleItem<HostRequest> hostrequest; 357 Serialize::Type request_type; 358 359 public: 360 HSRequest(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 361 commandhsrequest(this), commandhsactive(this), 362 commandhsreject(this), commandhswaiting(this), hostrequest(this, "hostrequest"), request_type("HostRequest", HostRequest::Unserialize) 363 { 364 if (!IRCD || !IRCD->CanSetVHost) 365 throw ModuleException("Your IRCd does not support vhosts"); 366 } 367 }; 368 369 static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost) 370 { 371 Anope::string host; 372 std::list<std::pair<Anope::string, Anope::string> >::iterator it, it_end; 373 374 if (!vIdent.empty()) 375 host = vIdent + "@" + vHost; 376 else 377 host = vHost; 378 379 if (Config->GetModule(me)->Get<bool>("memooper") && memoserv) 380 for (unsigned i = 0; i < Oper::opers.size(); ++i) 381 { 382 Oper *o = Oper::opers[i]; 383 384 const NickAlias *na = NickAlias::Find(o->name); 385 if (!na) 386 continue; 387 388 Anope::string message = Anope::printf(_("[auto memo] vHost \002%s\002 has been requested by %s."), host.c_str(), source.GetNick().c_str()); 389 390 memoserv->Send(source.service->nick, na->nick, message, true); 391 } 392 } 393 394 MODULE_INIT(HSRequest)