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, time_t so, unsigned long ln)
77 typedef std::vector<User *> userlist;
79 typedef std::vector<DCCAllow> dccallowlist;
81 typedef std::vector<BannedFileList> bannedfilelist;
83 typedef SimpleExtItem<dccallowlist> DCCAllowExt;
85 class CommandDccallow : public Command
90 unsigned int maxentries;
91 CommandDccallow(Module* parent, DCCAllowExt& Ext)
92 : Command(parent, "DCCALLOW", 0)
95 syntax = "[(+|-)<nick> [<time>]]|[LIST|HELP]";
96 /* XXX we need to fix this so it can work with translation stuff (i.e. move +- into a seperate param */
99 CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE
101 /* syntax: DCCALLOW [+|-]<nick> (<time>) */
102 if (!parameters.size())
104 // display current DCCALLOW list
105 DisplayDCCAllowList(user);
108 else if (parameters.size() > 0)
110 char action = *parameters[0].c_str();
112 // if they didn't specify an action, this is probably a command
113 if (action != '+' && action != '-')
115 if (!strcasecmp(parameters[0].c_str(), "LIST"))
117 // list current DCCALLOW list
118 DisplayDCCAllowList(user);
121 else if (!strcasecmp(parameters[0].c_str(), "HELP"))
129 user->WriteNumeric(998, "DCCALLOW command not understood. For help on DCCALLOW, type /DCCALLOW HELP");
134 std::string nick(parameters[0], 1);
135 User *target = ServerInstance->FindNickOnly(nick);
137 if ((target) && (!target->quitting) && (target->registered == REG_ALL))
142 // check if it contains any entries
146 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
148 // search through list
149 if (i->nickname == target->nick)
152 user->WriteNumeric(995, user->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", target->nick.c_str()));
158 else if (action == '+')
162 user->WriteNumeric(996, user->nick, "You cannot add yourself to your own DCCALLOW list!");
169 dl = new dccallowlist;
171 // add this user to the userlist
175 if (dl->size() >= maxentries)
177 user->WriteNumeric(996, user->nick, "Too many nicks on DCCALLOW list");
181 for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
183 if (k->nickname == target->nick)
185 user->WriteNumeric(996, user->nick, InspIRCd::Format("%s is already on your DCCALLOW list", target->nick.c_str()));
190 std::string mask = target->nick+"!"+target->ident+"@"+target->GetDisplayedHost();
191 std::string default_length = ServerInstance->Config->ConfValue("dccallow")->getString("length");
193 unsigned long length;
194 if (parameters.size() < 2)
196 length = InspIRCd::Duration(default_length);
198 else if (!atoi(parameters[1].c_str()))
204 length = InspIRCd::Duration(parameters[1]);
207 if (!InspIRCd::IsValidMask(mask))
212 dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
216 user->WriteNumeric(993, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %ld seconds", target->nick.c_str(), length));
220 user->WriteNumeric(994, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for this session", target->nick.c_str()));
229 // nick doesn't exist
230 user->WriteNumeric(Numerics::NoSuchNick(nick));
237 RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) CXX11_OVERRIDE
239 return ROUTE_BROADCAST;
242 void DisplayHelp(User* user)
244 for (size_t i = 0; i < sizeof(helptext)/sizeof(helptext[0]); i++)
245 user->WriteNumeric(998, helptext[i]);
246 user->WriteNumeric(999, "End of DCCALLOW HELP");
248 LocalUser* localuser = IS_LOCAL(user);
250 localuser->CommandFloodPenalty += 4000;
253 void DisplayDCCAllowList(User* user)
255 // display current DCCALLOW list
256 user->WriteNumeric(990, "Users on your DCCALLOW list:");
261 for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
263 user->WriteNumeric(991, user->nick, InspIRCd::Format("%s (%s)", c->nickname.c_str(), c->hostmask.c_str()));
267 user->WriteNumeric(992, "End of DCCALLOW list");
272 class ModuleDCCAllow : public Module
279 : ext("dccallow", ExtensionItem::EXT_USER, this)
284 void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) CXX11_OVERRIDE
286 dccallowlist* udl = ext.get(user);
288 // remove their DCCALLOW list if they have one
290 stdalgo::erase(ul, user);
292 // remove them from any DCCALLOW lists
293 // they are currently on
297 void OnUserPostNick(User* user, const std::string &oldnick) CXX11_OVERRIDE
302 ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
305 return MOD_RES_PASSTHRU;
307 if (target_type == TYPE_USER)
309 User* u = (User*)dest;
311 /* Always allow a user to dcc themselves (although... why?) */
313 return MOD_RES_PASSTHRU;
315 if ((text.length()) && (text[0] == '\1'))
319 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
320 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
322 if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
325 if (dl && dl->size())
327 for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
328 if (InspIRCd::Match(user->GetFullHost(), iter->hostmask))
329 return MOD_RES_PASSTHRU;
332 std::string buf = text.substr(5);
333 size_t s = buf.find(' ');
334 if (s == std::string::npos)
335 return MOD_RES_PASSTHRU;
337 const std::string type = buf.substr(0, s);
339 ConfigTag* conftag = ServerInstance->Config->ConfValue("dccallow");
340 bool blockchat = conftag->getBool("blockchat");
342 if (stdalgo::string::equalsci(type, "SEND"))
346 buf = buf.substr(s + 1);
348 if (!buf.empty() && buf[0] == '"')
350 s = buf.find('"', 1);
352 if (s == std::string::npos || s <= 1)
353 return MOD_RES_PASSTHRU;
364 if (s == std::string::npos)
365 return MOD_RES_PASSTHRU;
367 std::string defaultaction = conftag->getString("action");
368 std::string filename = buf.substr(first, s);
371 for (unsigned int i = 0; i < bfl.size(); i++)
373 if (InspIRCd::Match(filename, bfl[i].filemask, ascii_case_insensitive_map))
375 /* We have a matching badfile entry, override whatever the default action is */
376 if (bfl[i].action == "allow")
377 return MOD_RES_PASSTHRU;
386 /* only follow the default action if no badfile matches were found above */
387 if ((!found) && (defaultaction == "allow"))
388 return MOD_RES_PASSTHRU;
390 user->WriteNotice("The user " + u->nick + " is not accepting DCC SENDs from you. Your file " + filename + " was not sent.");
391 u->WriteNotice(user->nick + " (" + user->ident + "@" + user->GetDisplayedHost() + ") attempted to send you a file named " + filename + ", which was blocked.");
392 u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
395 else if ((blockchat) && (stdalgo::string::equalsci(type, "CHAT")))
397 user->WriteNotice("The user " + u->nick + " is not accepting DCC CHAT requests from you.");
398 u->WriteNotice(user->nick + " (" + user->ident + "@" + user->GetDisplayedHost() + ") attempted to initiate a DCC CHAT session, which was blocked.");
399 u->WriteNotice("If you trust " + user->nick + " and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.");
405 return MOD_RES_PASSTHRU;
410 for (userlist::iterator iter = ul.begin(); iter != ul.end();)
412 User* u = (User*)(*iter);
418 dccallowlist::iterator iter2 = dl->begin();
419 while (iter2 != dl->end())
421 time_t expires = iter2->set_on + iter2->length;
422 if (iter2->length != 0 && expires <= ServerInstance->Time())
424 u->WriteNumeric(997, u->nick, InspIRCd::Format("DCCALLOW entry for %s has expired", iter2->nickname.c_str()));
425 iter2 = dl->erase(iter2);
437 iter = ul.erase(iter);
442 void RemoveNick(User* user)
444 /* Iterate through all DCCALLOW lists and remove user */
445 for (userlist::iterator iter = ul.begin(); iter != ul.end();)
447 User *u = (User*)(*iter);
453 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
455 if (i->nickname == user->nick)
458 u->WriteNotice(i->nickname + " left the network or changed their nickname and has been removed from your DCCALLOW list");
459 u->WriteNumeric(995, u->nick, InspIRCd::Format("Removed %s from your DCCALLOW list", i->nickname.c_str()));
469 iter = ul.erase(iter);
474 void RemoveFromUserlist(User *user)
476 // remove user from userlist
477 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
479 User* u = (User*)(*j);
488 void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
490 ConfigTag* tag = ServerInstance->Config->ConfValue("dccallow");
491 cmd.maxentries = tag->getInt("maxentries", 20);
494 ConfigTagList tags = ServerInstance->Config->ConfTags("banfile");
495 for (ConfigIter i = tags.first; i != tags.second; ++i)
498 bf.filemask = i->second->getString("pattern");
499 bf.action = i->second->getString("action");
504 Version GetVersion() CXX11_OVERRIDE
506 return Version("Provides support for the /DCCALLOW command", VF_COMMON | VF_VENDOR);
510 MODULE_INIT(ModuleDCCAllow)