anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
ns_list.cpp (9718B)
1 /* NickServ core functions 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "module.h" 13 14 class CommandNSList : public Command 15 { 16 public: 17 CommandNSList(Module *creator) : Command(creator, "nickserv/list", 1, 2) 18 { 19 this->SetDesc(_("List all registered nicknames that match a given pattern")); 20 this->SetSyntax(_("\037pattern\037 [SUSPENDED] [NOEXPIRE] [UNCONFIRMED]")); 21 } 22 23 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 24 { 25 26 Anope::string pattern = params[0]; 27 const NickCore *mync; 28 unsigned nnicks; 29 bool is_servadmin = source.HasCommand("nickserv/list"); 30 int count = 0, from = 0, to = 0; 31 bool suspended, nsnoexpire, unconfirmed; 32 unsigned listmax = Config->GetModule(this->owner)->Get<unsigned>("listmax", "50"); 33 34 suspended = nsnoexpire = unconfirmed = false; 35 36 if (pattern[0] == '#') 37 { 38 Anope::string n1, n2; 39 sepstream(pattern.substr(1), '-').GetToken(n1, 0); 40 sepstream(pattern, '-').GetToken(n2, 1); 41 try 42 { 43 from = convertTo<int>(n1); 44 to = convertTo<int>(n2); 45 } 46 catch (const ConvertException &) 47 { 48 source.Reply(LIST_INCORRECT_RANGE); 49 return; 50 } 51 52 pattern = "*"; 53 } 54 55 nnicks = 0; 56 57 if (is_servadmin && params.size() > 1) 58 { 59 Anope::string keyword; 60 spacesepstream keywords(params[1]); 61 while (keywords.GetToken(keyword)) 62 { 63 if (keyword.equals_ci("NOEXPIRE")) 64 nsnoexpire = true; 65 if (keyword.equals_ci("SUSPENDED")) 66 suspended = true; 67 if (keyword.equals_ci("UNCONFIRMED")) 68 unconfirmed = true; 69 } 70 } 71 72 mync = source.nc; 73 ListFormatter list(source.GetAccount()); 74 75 list.AddColumn(_("Nick")).AddColumn(_("Last usermask")); 76 77 Anope::map<NickAlias *> ordered_map; 78 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it) 79 ordered_map[it->first] = it->second; 80 81 for (Anope::map<NickAlias *>::const_iterator it = ordered_map.begin(), it_end = ordered_map.end(); it != it_end; ++it) 82 { 83 const NickAlias *na = it->second; 84 85 /* Don't show private nicks to non-services admins. */ 86 if (na->nc->HasExt("NS_PRIVATE") && !is_servadmin && na->nc != mync) 87 continue; 88 else if (nsnoexpire && !na->HasExt("NS_NO_EXPIRE")) 89 continue; 90 else if (suspended && !na->nc->HasExt("NS_SUSPENDED")) 91 continue; 92 else if (unconfirmed && !na->nc->HasExt("UNCONFIRMED")) 93 continue; 94 95 /* We no longer compare the pattern against the output buffer. 96 * Instead we build a nice nick!user@host buffer to compare. 97 * The output is then generated separately. -TheShadow */ 98 Anope::string buf = Anope::printf("%s!%s", na->nick.c_str(), !na->last_usermask.empty() ? na->last_usermask.c_str() : "*@*"); 99 if (na->nick.equals_ci(pattern) || Anope::Match(buf, pattern, false, true)) 100 { 101 if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nnicks <= listmax) 102 { 103 bool isnoexpire = false; 104 if (is_servadmin && na->HasExt("NS_NO_EXPIRE")) 105 isnoexpire = true; 106 107 ListFormatter::ListEntry entry; 108 entry["Nick"] = (isnoexpire ? "!" : "") + na->nick; 109 if (na->nc->HasExt("HIDE_MASK") && !is_servadmin && na->nc != mync) 110 entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Hostname hidden]")); 111 else if (na->nc->HasExt("NS_SUSPENDED")) 112 entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Suspended]")); 113 else if (na->nc->HasExt("UNCONFIRMED")) 114 entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Unconfirmed]")); 115 else 116 entry["Last usermask"] = na->last_usermask; 117 list.AddEntry(entry); 118 } 119 ++count; 120 } 121 } 122 123 source.Reply(_("List of entries matching \002%s\002:"), pattern.c_str()); 124 125 std::vector<Anope::string> replies; 126 list.Process(replies); 127 128 for (unsigned i = 0; i < replies.size(); ++i) 129 source.Reply(replies[i]); 130 131 source.Reply(_("End of list - %d/%d matches shown."), nnicks > listmax ? listmax : nnicks, nnicks); 132 return; 133 } 134 135 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 136 { 137 this->SendSyntax(source); 138 source.Reply(" "); 139 source.Reply(_("Lists all registered nicknames which match the given\n" 140 "pattern, in \037nick!user@host\037 format. Nicks with the \002PRIVATE\002\n" 141 "option set will only be displayed to Services Operators with the\n" 142 "proper access. Nicks with the \002NOEXPIRE\002 option set will have\n" 143 "a \002!\002 prefixed to the nickname for Services Operators to see.\n" 144 " \n" 145 "Note that a preceding '#' specifies a range.\n" 146 " \n" 147 "If the SUSPENDED, UNCONFIRMED or NOEXPIRE options are given, only\n" 148 "nicks which, respectively, are SUSPENDED, UNCONFIRMED or have the\n" 149 "NOEXPIRE flag set will be displayed. If multiple options are\n" 150 "given, all nicks matching at least one option will be displayed.\n" 151 "Note that these options are limited to \037Services Operators\037.\n" 152 " \n" 153 "Examples:\n" 154 " \n" 155 " \002LIST *!joeuser@foo.com\002\n" 156 " Lists all registered nicks owned by joeuser@foo.com.\n" 157 " \n" 158 " \002LIST *Bot*!*@*\002\n" 159 " Lists all registered nicks with \002Bot\002 in their\n" 160 " names (case insensitive).\n" 161 " \n" 162 " \002LIST * NOEXPIRE\002\n" 163 " Lists all registered nicks which have been set to not expire.\n" 164 " \n" 165 " \002LIST #51-100\002\n" 166 " Lists all registered nicks within the given range (51-100).")); 167 168 const Anope::string ®exengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine"); 169 if (!regexengine.empty()) 170 { 171 source.Reply(" "); 172 source.Reply(_("Regex matches are also supported using the %s engine.\n" 173 "Enclose your pattern in // if this is desired."), regexengine.c_str()); 174 } 175 176 return true; 177 } 178 }; 179 180 181 class CommandNSSetPrivate : public Command 182 { 183 public: 184 CommandNSSetPrivate(Module *creator, const Anope::string &sname = "nickserv/set/private", size_t min = 1) : Command(creator, sname, min, min + 1) 185 { 186 this->SetDesc(_("Prevent the nickname from appearing in the LIST command")); 187 this->SetSyntax("{ON | OFF}"); 188 } 189 190 void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) 191 { 192 if (Anope::ReadOnly) 193 { 194 source.Reply(READ_ONLY_MODE); 195 return; 196 } 197 198 const NickAlias *na = NickAlias::Find(user); 199 if (!na) 200 { 201 source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); 202 return; 203 } 204 NickCore *nc = na->nc; 205 206 EventReturn MOD_RESULT; 207 FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); 208 if (MOD_RESULT == EVENT_STOP) 209 return; 210 211 if (param.equals_ci("ON")) 212 { 213 Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable private for " << nc->display; 214 nc->Extend<bool>("NS_PRIVATE"); 215 source.Reply(_("Private option is now \002on\002 for \002%s\002."), nc->display.c_str()); 216 } 217 else if (param.equals_ci("OFF")) 218 { 219 Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable private for " << nc->display; 220 nc->Shrink<bool>("NS_PRIVATE"); 221 source.Reply(_("Private option is now \002off\002 for \002%s\002."), nc->display.c_str()); 222 } 223 else 224 this->OnSyntaxError(source, "PRIVATE"); 225 } 226 227 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 228 { 229 this->Run(source, source.nc->display, params[0]); 230 } 231 232 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 233 { 234 this->SendSyntax(source); 235 source.Reply(" "); 236 source.Reply(_("Turns %s's privacy option on or off for your nick.\n" 237 "With \002PRIVATE\002 set, your nickname will not appear in\n" 238 "nickname lists generated with %s's \002LIST\002 command.\n" 239 "(However, anyone who knows your nickname can still get\n" 240 "information on it using the \002INFO\002 command.)"), 241 source.service->nick.c_str(), source.service->nick.c_str()); 242 return true; 243 } 244 }; 245 246 class CommandNSSASetPrivate : public CommandNSSetPrivate 247 { 248 public: 249 CommandNSSASetPrivate(Module *creator) : CommandNSSetPrivate(creator, "nickserv/saset/private", 2) 250 { 251 this->ClearSyntax(); 252 this->SetSyntax(_("\037nickname\037 {ON | OFF}")); 253 } 254 255 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 256 { 257 this->Run(source, params[0], params[1]); 258 } 259 260 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 261 { 262 this->SendSyntax(source); 263 source.Reply(" "); 264 source.Reply(_("Turns %s's privacy option on or off for the nick.\n" 265 "With \002PRIVATE\002 set, the nickname will not appear in\n" 266 "nickname lists generated with %s's \002LIST\002 command.\n" 267 "(However, anyone who knows the nickname can still get\n" 268 "information on it using the \002INFO\002 command.)"), 269 source.service->nick.c_str(), source.service->nick.c_str()); 270 return true; 271 } 272 }; 273 274 275 class NSList : public Module 276 { 277 CommandNSList commandnslist; 278 279 CommandNSSetPrivate commandnssetprivate; 280 CommandNSSASetPrivate commandnssasetprivate; 281 282 SerializableExtensibleItem<bool> priv; 283 284 public: 285 NSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 286 commandnslist(this), commandnssetprivate(this), commandnssasetprivate(this), 287 priv(this, "NS_PRIVATE") 288 { 289 } 290 291 void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_all) anope_override 292 { 293 if (!show_all) 294 return; 295 296 if (priv.HasExt(na->nc)) 297 info.AddOption(_("Private")); 298 } 299 }; 300 301 MODULE_INIT(NSList)