00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015
00016
00017
00018 static ConfigReader *Conf;
00019
00020 class BannedFileList : public classbase
00021 {
00022 public:
00023 std::string filemask;
00024 std::string action;
00025 };
00026
00027 class DCCAllow : public classbase
00028 {
00029 public:
00030 std::string nickname;
00031 std::string hostmask;
00032 time_t set_on;
00033 long length;
00034
00035 DCCAllow() { }
00036
00037 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) { }
00038 };
00039
00040 typedef std::vector<User *> userlist;
00041 userlist ul;
00042 typedef std::vector<DCCAllow> dccallowlist;
00043 dccallowlist* dl;
00044 typedef std::vector<BannedFileList> bannedfilelist;
00045 bannedfilelist bfl;
00046
00047 class CommandDccallow : public Command
00048 {
00049 public:
00050 CommandDccallow(InspIRCd* Me) : Command(Me, "DCCALLOW", 0, 0)
00051 {
00052 this->source = "m_dccallow.so";
00053 syntax = "{[+|-]<nick> <time>|HELP|LIST}";
00054
00055 }
00056
00057 CmdResult Handle(const std::vector<std::string> ¶meters, User *user)
00058 {
00059
00060 if (!parameters.size())
00061 {
00062
00063 DisplayDCCAllowList(user);
00064 return CMD_FAILURE;
00065 }
00066 else if (parameters.size() > 0)
00067 {
00068 char action = *parameters[0].c_str();
00069
00070
00071 if (action != '+' && action != '-')
00072 {
00073 if (!strcasecmp(parameters[0].c_str(), "LIST"))
00074 {
00075
00076 DisplayDCCAllowList(user);
00077 return CMD_FAILURE;
00078 }
00079 else if (!strcasecmp(parameters[0].c_str(), "HELP"))
00080 {
00081
00082 DisplayHelp(user);
00083 return CMD_FAILURE;
00084 }
00085 }
00086
00087 std::string nick = parameters[0].substr(1);
00088 User *target = ServerInstance->FindNick(nick);
00089
00090 if (target)
00091 {
00092
00093 if (action == '-')
00094 {
00095
00096 if (user->GetExt("dccallow_list", dl))
00097 {
00098 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
00099 {
00100
00101 if (i->nickname == target->nick)
00102 {
00103 dl->erase(i);
00104 user->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00105 break;
00106 }
00107 }
00108 }
00109 else
00110 {
00111 delete dl;
00112 user->Shrink("dccallow_list");
00113
00114
00115 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
00116 {
00117 User* u = (User*)(*j);
00118 if (u == user)
00119 {
00120 ul.erase(j);
00121 break;
00122 }
00123 }
00124 }
00125 }
00126 else if (action == '+')
00127 {
00128 if (!user->GetExt("dccallow_list", dl))
00129 {
00130 dl = new dccallowlist;
00131 user->Extend("dccallow_list", dl);
00132
00133 ul.push_back(user);
00134 }
00135 for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
00136 {
00137 if (k->nickname == target->nick)
00138 {
00139 user->WriteNumeric(996, "%s %s :%s is already on your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00140 return CMD_FAILURE;
00141 }
00142 else if (InspIRCd::Match(user->GetFullHost(), k->hostmask))
00143 {
00144 user->WriteNumeric(996, "%s %s :You cannot add yourself to your own DCCALLOW list!", user->nick.c_str(), user->nick.c_str());
00145 return CMD_FAILURE;
00146 }
00147 }
00148
00149 std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);
00150 std::string default_length = Conf->ReadValue("dccallow", "length", 0);
00151
00152 long length;
00153 if (parameters.size() < 2)
00154 {
00155 length = ServerInstance->Duration(default_length);
00156 }
00157 else if (!atoi(parameters[1].c_str()))
00158 {
00159 length = 0;
00160 }
00161 else
00162 {
00163 length = ServerInstance->Duration(parameters[1]);
00164 }
00165
00166 if (!ServerInstance->IsValidMask(mask.c_str()))
00167 {
00168 return CMD_FAILURE;
00169 }
00170
00171 dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
00172
00173 if (length > 0)
00174 {
00175 user->WriteNumeric(993, "%s %s :Added %s to DCCALLOW list for %ld seconds", user->nick.c_str(), user->nick.c_str(), target->nick.c_str(), length);
00176 }
00177 else
00178 {
00179 user->WriteNumeric(994, "%s %s :Added %s to DCCALLOW list for this session", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00180 }
00181
00182
00183 return CMD_SUCCESS;
00184 }
00185 }
00186 else
00187 {
00188
00189 user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), nick.c_str());
00190 return CMD_FAILURE;
00191 }
00192 }
00193 return CMD_FAILURE;
00194 }
00195
00196 void DisplayHelp(User* user)
00197 {
00198 user->WriteNumeric(998, "%s :DCCALLOW [<+|->nick.c_str() [time]] [list] [help]", user->nick.c_str());
00199 user->WriteNumeric(998, "%s :You may allow DCCs from specific users by specifying a", user->nick.c_str());
00200 user->WriteNumeric(998, "%s :DCC allow for the user you want to receive DCCs from.", user->nick.c_str());
00201 user->WriteNumeric(998, "%s :For example, to allow the user Brain to send you inspircd.exe", user->nick.c_str());
00202 user->WriteNumeric(998, "%s :you would type:", user->nick.c_str());
00203 user->WriteNumeric(998, "%s :/DCCALLOW +Brain", user->nick.c_str());
00204 user->WriteNumeric(998, "%s :Brain would then be able to send you files. They would have to", user->nick.c_str());
00205 user->WriteNumeric(998, "%s :resend the file again if the server gave them an error message", user->nick.c_str());
00206 user->WriteNumeric(998, "%s :before you added them to your DCCALLOW list.", user->nick.c_str());
00207 user->WriteNumeric(998, "%s :DCCALLOW entries will be temporary by default, if you want to add", user->nick.c_str());
00208 user->WriteNumeric(998, "%s :them to your DCCALLOW list until you leave IRC, type:", user->nick.c_str());
00209 user->WriteNumeric(998, "%s :/DCCALLOW +Brain 0", user->nick.c_str());
00210 user->WriteNumeric(998, "%s :To remove the user from your DCCALLOW list, type:", user->nick.c_str());
00211 user->WriteNumeric(998, "%s :/DCCALLOW -Brain", user->nick.c_str());
00212 user->WriteNumeric(998, "%s :To see the users in your DCCALLOW list, type:", user->nick.c_str());
00213 user->WriteNumeric(998, "%s :/DCCALLOW LIST", user->nick.c_str());
00214 user->WriteNumeric(998, "%s :NOTE: If the user leaves IRC or changes their nickname", user->nick.c_str());
00215 user->WriteNumeric(998, "%s : they will be removed from your DCCALLOW list.", user->nick.c_str());
00216 user->WriteNumeric(998, "%s : your DCCALLOW list will be deleted when you leave IRC.", user->nick.c_str());
00217 user->WriteNumeric(999, "%s :End of DCCALLOW HELP", user->nick.c_str());
00218 }
00219
00220 void DisplayDCCAllowList(User* user)
00221 {
00222
00223 user->WriteNumeric(990, "%s :Users on your DCCALLOW list:", user->nick.c_str());
00224
00225 if (user->GetExt("dccallow_list", dl))
00226 {
00227 for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
00228 {
00229 user->WriteNumeric(991, "%s %s :%s (%s)", user->nick.c_str(), user->nick.c_str(), c->nickname.c_str(), c->hostmask.c_str());
00230 }
00231 }
00232
00233 user->WriteNumeric(992, "%s :End of DCCALLOW list", user->nick.c_str());
00234 }
00235
00236 };
00237
00238 class ModuleDCCAllow : public Module
00239 {
00240 CommandDccallow* mycommand;
00241 public:
00242
00243 ModuleDCCAllow(InspIRCd* Me)
00244 : Module(Me)
00245 {
00246 Conf = new ConfigReader(ServerInstance);
00247 mycommand = new CommandDccallow(ServerInstance);
00248 ServerInstance->AddCommand(mycommand);
00249 ReadFileConf();
00250 Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserQuit, I_OnUserPreNick, I_OnRehash };
00251 ServerInstance->Modules->Attach(eventlist, this, 5);
00252 }
00253
00254
00255 virtual void OnRehash(User* user, const std::string ¶meter)
00256 {
00257 delete Conf;
00258 Conf = new ConfigReader(ServerInstance);
00259 }
00260
00261 virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
00262 {
00263 dccallowlist* udl;
00264
00265
00266 if (user->GetExt("dccallow_list", udl))
00267 {
00268 delete udl;
00269 user->Shrink("dccallow_list");
00270 RemoveFromUserlist(user);
00271 }
00272
00273
00274
00275 RemoveNick(user);
00276 }
00277
00278
00279 virtual int OnUserPreNick(User* user, const std::string &newnick)
00280 {
00281 RemoveNick(user);
00282 return 0;
00283 }
00284
00285 virtual int OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
00286 {
00287 return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
00288 }
00289
00290 virtual int OnUserPreNotice(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
00291 {
00292 if (!IS_LOCAL(user))
00293 return 0;
00294
00295 if (target_type == TYPE_USER)
00296 {
00297 User* u = (User*)dest;
00298
00299
00300 if (user == u)
00301 return 0;
00302
00303 if ((text.length()) && (text[0] == '\1'))
00304 {
00305 Expire();
00306
00307
00308
00309
00310 if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
00311 {
00312 if (u->GetExt("dccallow_list", dl) && dl->size())
00313 {
00314 for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
00315 if (InspIRCd::Match(user->GetFullHost(), iter->hostmask))
00316 return 0;
00317 }
00318
00319
00320 std::stringstream ss(text);
00321 std::string buf;
00322 std::vector<std::string> tokens;
00323
00324 while (ss >> buf)
00325 tokens.push_back(buf);
00326
00327 irc::string type = tokens[1].c_str();
00328
00329 bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0);
00330
00331 if (type == "SEND")
00332 {
00333 std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
00334 std::string filename = tokens[2];
00335
00336 if (defaultaction == "allow")
00337 return 0;
00338
00339 for (unsigned int i = 0; i < bfl.size(); i++)
00340 {
00341 if (InspIRCd::Match(filename, bfl[i].filemask))
00342 {
00343 if (bfl[i].action == "allow")
00344 return 0;
00345 }
00346 else
00347 {
00348 if (defaultaction == "allow")
00349 return 0;
00350 }
00351 user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick.c_str(), u->nick.c_str(), filename.c_str());
00352 u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), filename.c_str());
00353 u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
00354 return 1;
00355 }
00356 }
00357 else if ((type == "CHAT") && (blockchat))
00358 {
00359 user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick.c_str(), u->nick.c_str());
00360 u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str());
00361 u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
00362 return 1;
00363 }
00364 }
00365 }
00366 }
00367 return 0;
00368 }
00369
00370 void Expire()
00371 {
00372 for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
00373 {
00374 User* u = (User*)(*iter);
00375 if (u->GetExt("dccallow_list", dl))
00376 {
00377 if (dl->size())
00378 {
00379 dccallowlist::iterator iter2 = dl->begin();
00380 while (iter2 != dl->end())
00381 {
00382 if (iter2->length != 0 && (iter2->set_on + iter2->length) <= ServerInstance->Time())
00383 {
00384 u->WriteNumeric(997, "%s %s :DCCALLOW entry for %s has expired", u->nick.c_str(), u->nick.c_str(), iter2->nickname.c_str());
00385 iter2 = dl->erase(iter2);
00386 }
00387 else
00388 {
00389 ++iter2;
00390 }
00391 }
00392 }
00393 }
00394 else
00395 {
00396 RemoveFromUserlist(u);
00397 }
00398 }
00399 }
00400
00401 void RemoveNick(User* user)
00402 {
00403
00404 for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
00405 {
00406 User *u = (User*)(*iter);
00407 if (u->GetExt("dccallow_list", dl))
00408 {
00409 if (dl->size())
00410 {
00411 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
00412 {
00413 if (i->nickname == user->nick)
00414 {
00415
00416 u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick.c_str(), i->nickname.c_str());
00417 u->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", u->nick.c_str(), u->nick.c_str(), i->nickname.c_str());
00418 dl->erase(i);
00419 break;
00420 }
00421 }
00422 }
00423 }
00424 else
00425 {
00426 RemoveFromUserlist(u);
00427 }
00428 }
00429 }
00430
00431 void RemoveFromUserlist(User *user)
00432 {
00433
00434 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
00435 {
00436 User* u = (User*)(*j);
00437 if (u == user)
00438 {
00439 ul.erase(j);
00440 break;
00441 }
00442 }
00443 }
00444
00445 void ReadFileConf()
00446 {
00447 bfl.clear();
00448 for (int i = 0; i < Conf->Enumerate("banfile"); i++)
00449 {
00450 BannedFileList bf;
00451 std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
00452 std::string action = Conf->ReadValue("banfile", "action", i);
00453 bf.filemask = fileglob;
00454 bf.action = action;
00455 bfl.push_back(bf);
00456 }
00457
00458 }
00459
00460 virtual ~ModuleDCCAllow()
00461 {
00462 }
00463
00464 virtual Version GetVersion()
00465 {
00466 return Version("$Id: m_dccallow.cpp 10291 2008-08-25 20:35:51Z w00t $", VF_COMMON | VF_VENDOR, API_VERSION);
00467 }
00468 };
00469
00470 MODULE_INIT(ModuleDCCAllow)
00471