2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5 * Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net>
6 * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
7 * Copyright (C) 2006-2008 Craig Edwards <craigedwards@brainbox.cc>
8 * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
9 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10 * Copyright (C) 2006 Jamie ??? <???@???>
12 * This file is part of InspIRCd. InspIRCd is free software: you can
13 * redistribute it and/or modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation, version 2.
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 static const char* const helptext[] =
30 "DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP]",
31 "You may allow DCCs from specific users by specifying a",
32 "DCC allow for the user you want to receive DCCs from.",
33 "For example, to allow the user Brain to send you inspircd.exe",
36 "Brain would then be able to send you files. They would have to",
37 "resend the file again if the server gave them an error message",
38 "before you added them to your DCCALLOW list.",
39 "DCCALLOW entries will be temporary by default, if you want to add",
40 "them to your DCCALLOW list until you leave IRC, type:",
42 "To remove the user from your DCCALLOW list, type:",
44 "To see the users in your DCCALLOW list, type:",
46 "NOTE: If the user leaves IRC or changes their nickname",
47 " they will be removed from your DCCALLOW list.",
48 " your DCCALLOW list will be deleted when you leave IRC."
68 DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }
71 typedef std::vector<User *> userlist;
73 typedef std::vector<DCCAllow> dccallowlist;
75 typedef std::vector<BannedFileList> bannedfilelist;
77 typedef SimpleExtItem<dccallowlist> DCCAllowExt;
79 class CommandDccallow : public Command
84 unsigned int maxentries;
85 CommandDccallow(Module* parent, DCCAllowExt& Ext)
86 : Command(parent, "DCCALLOW", 0)
89 syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]";
90 /* XXX we need to fix this so it can work with translation stuff (i.e. move +- into a seperate param */
93 CmdResult Handle(const std::vector<std::string> ¶meters, User *user)
95 /* syntax: DCCALLOW [+|-]<nick> (<time>) */
96 if (!parameters.size())
98 // display current DCCALLOW list
99 DisplayDCCAllowList(user);
102 else if (parameters.size() > 0)
104 char action = *parameters[0].c_str();
106 // if they didn't specify an action, this is probably a command
107 if (action != '+' && action != '-')
109 if (!strcasecmp(parameters[0].c_str(), "LIST"))
111 // list current DCCALLOW list
112 DisplayDCCAllowList(user);
115 else if (!strcasecmp(parameters[0].c_str(), "HELP"))
123 user->WriteNumeric(998, "DCCALLOW command not understood. For help on DCCALLOW, type /DCCALLOW HELP");
128 std::string nick(parameters[0], 1);
129 User *target = ServerInstance->FindNickOnly(nick);
131 if ((target) && (!target->quitting) && (target->registered == REG_ALL))
136 // check if it contains any entries
140 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
142 // search through list
143 if (i->nickname == target->nick)
146 user->WriteNumeric(995, user->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", target->nick.c_str()));
152 else if (action == '+')
156 user->WriteNumeric(996, user->nick, "You cannot add yourself to your own DCCALLOW list!");
163 dl = new dccallowlist;
165 // add this user to the userlist
169 if (dl->size() >= maxentries)
171 user->WriteNumeric(996, user->nick, "Too many nicks on DCCALLOW list");
175 for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
177 if (k->nickname == target->nick)
179 user->WriteNumeric(996, user->nick, InspIRCd::Format("%s is already on your DCCALLOW list", target->nick.c_str()));
184 std::string mask = target->nick+"!"+target->ident+"@"+target->dhost;
185 std::string default_length = ServerInstance->Config->ConfValue("dccallow")->getString("length");
187 unsigned long length;
188 if (parameters.size() < 2)
190 length = InspIRCd::Duration(default_length);
192 else if (!atoi(parameters[1].c_str()))
198 length = InspIRCd::Duration(parameters[1]);
201 if (!InspIRCd::IsValidMask(mask))
206 dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
210 user->WriteNumeric(993, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %ld seconds", target->nick.c_str(), length));
214 user->WriteNumeric(994, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for this session", target->nick.c_str()));
223 // nick doesn't exist
224 user->WriteNumeric(Numerics::NoSuchNick(nick));
231 RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
233 return ROUTE_BROADCAST;
236 void DisplayHelp(User* user)
238 for (size_t i = 0; i < sizeof(helptext)/sizeof(helptext[0]); i++)
239 user->WriteNumeric(998, helptext[i]);
240 user->WriteNumeric(999, "End of DCCALLOW HELP");
242 LocalUser* localuser = IS_LOCAL(user);
244 localuser->CommandFloodPenalty += 4000;
247 void DisplayDCCAllowList(User* user)
249 // display current DCCALLOW list
250 user->WriteNumeric(990, "Users on your DCCALLOW list:");
255 for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
257 user->WriteNumeric(991, user->nick, InspIRCd::Format("%s (%s)", c->nickname.c_str(), c->hostmask.c_str()));
261 user->WriteNumeric(992, "End of DCCALLOW list");
266 class ModuleDCCAllow : public Module
273 : ext("dccallow", ExtensionItem::EXT_USER, this)
278 void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE
280 dccallowlist* udl = ext.get(user);
282 // remove their DCCALLOW list if they have one
284 stdalgo::erase(ul, user);
286 // remove them from any DCCALLOW lists
287 // they are currently on
291 void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
296 ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
299 return MOD_RES_PASSTHRU;
301 if (target_type == TYPE_USER)
303 User* u = (User*)dest;
305 /* Always allow a user to dcc themselves (although... why?) */
307 return MOD_RES_PASSTHRU;
309 if ((text.length()) && (text[0] == '\1'))
313 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
314 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
316 if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
319 if (dl && dl->size())
321 for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
322 if (InspIRCd::Match(user->GetFullHost(), iter->hostmask))
323 return MOD_RES_PASSTHRU;
326 std::string buf = text.substr(5);
327 size_t s = buf.find(' ');
328 if (s == std::string::npos)
329 return MOD_RES_PASSTHRU;
331 const std::string type = buf.substr(0, s);
333 ConfigTag* conftag = ServerInstance->Config->ConfValue("dccallow");
334 bool blockchat = conftag->getBool("blockchat");
336 if (stdalgo::string::equalsci(type, "SEND"))
340 buf = buf.substr(s + 1);
342 if (!buf.empty() && buf[0] == '"')
344 s = buf.find('"', 1);
346 if (s == std::string::npos || s <= 1)
347 return MOD_RES_PASSTHRU;
358 if (s == std::string::npos)
359 return MOD_RES_PASSTHRU;
361 std::string defaultaction = conftag->getString("action");
362 std::string filename = buf.substr(first, s);
365 for (unsigned int i = 0; i < bfl.size(); i++)
367 if (InspIRCd::Match(filename, bfl[i].filemask, ascii_case_insensitive_map))
369 /* We have a matching badfile entry, override whatever the default action is */
370 if (bfl[i].action == "allow")
371 return MOD_RES_PASSTHRU;
380 /* only follow the default action if no badfile matches were found above */
381 if ((!found) && (defaultaction == "allow"))
382 return MOD_RES_PASSTHRU;
384 user->WriteNotice("The user " + u->nick + " is not accepting DCC SENDs from you. Your file " + filename + " was not sent.");
385 u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to send you a file named " + filename + ", which was blocked.");
386 u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
389 else if ((blockchat) && (stdalgo::string::equalsci(type, "CHAT")))
391 user->WriteNotice("The user " + u->nick + " is not accepting DCC CHAT requests from you.");
392 u->WriteNotice(user->nick + " (" + user->ident + "@" + user->dhost + ") attempted to initiate a DCC CHAT session, which was blocked.");
393 u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
399 return MOD_RES_PASSTHRU;
404 for (userlist::iterator iter = ul.begin(); iter != ul.end();)
406 User* u = (User*)(*iter);
412 dccallowlist::iterator iter2 = dl->begin();
413 while (iter2 != dl->end())
415 if (iter2->length != 0 && (iter2->set_on + iter2->length) <= ServerInstance->Time())
417 u->WriteNumeric(997, u->nick, InspIRCd::Format("DCCALLOW entry for %s has expired", iter2->nickname.c_str()));
418 iter2 = dl->erase(iter2);
430 iter = ul.erase(iter);
435 void RemoveNick(User* user)
437 /* Iterate through all DCCALLOW lists and remove user */
438 for (userlist::iterator iter = ul.begin(); iter != ul.end();)
440 User *u = (User*)(*iter);
446 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
448 if (i->nickname == user->nick)
451 u->WriteNotice(i->nickname + " left the network or changed their nickname and has been removed from your DCCALLOW list");
452 u->WriteNumeric(995, u->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", i->nickname.c_str()));
462 iter = ul.erase(iter);
467 void RemoveFromUserlist(User *user)
469 // remove user from userlist
470 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
472 User* u = (User*)(*j);
481 void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
483 ConfigTag* tag = ServerInstance->Config->ConfValue("dccallow");
484 cmd.maxentries = tag->getInt("maxentries", 20);
487 ConfigTagList tags = ServerInstance->Config->ConfTags("banfile");
488 for (ConfigIter i = tags.first; i != tags.second; ++i)
491 bf.filemask = i->second->getString("pattern");
492 bf.action = i->second->getString("action");
497 Version GetVersion() CXX11_OVERRIDE
499 return Version("Provides support for the /DCCALLOW command", VF_COMMON | VF_VENDOR);
503 MODULE_INIT(ModuleDCCAllow)