00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "xline.h"
00015
00016 enum FilterFlags
00017 {
00018 FLAG_PART = 2,
00019 FLAG_QUIT = 4,
00020 FLAG_PRIVMSG = 8,
00021 FLAG_NOTICE = 16
00022 };
00023
00024 class FilterResult : public classbase
00025 {
00026 public:
00027 std::string freeform;
00028 std::string reason;
00029 std::string action;
00030 long gline_time;
00031 std::string flags;
00032
00033 bool flag_no_opers;
00034 bool flag_part_message;
00035 bool flag_quit_message;
00036 bool flag_privmsg;
00037 bool flag_notice;
00038
00039 FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt, const std::string &fla) :
00040 freeform(free), reason(rea), action(act), gline_time(gt), flags(fla)
00041 {
00042 this->FillFlags(fla);
00043 }
00044
00045 int FillFlags(const std::string &fl)
00046 {
00047 flags = fl;
00048 flag_no_opers = flag_part_message = flag_quit_message = flag_privmsg = flag_notice = false;
00049 size_t x = 0;
00050
00051 for (std::string::const_iterator n = flags.begin(); n != flags.end(); ++n, ++x)
00052 {
00053 switch (*n)
00054 {
00055 case 'o':
00056 flag_no_opers = true;
00057 break;
00058 case 'P':
00059 flag_part_message = true;
00060 break;
00061 case 'q':
00062 flag_quit_message = true;
00063 break;
00064 case 'p':
00065 flag_privmsg = true;
00066 break;
00067 case 'n':
00068 flag_notice = true;
00069 break;
00070 case '*':
00071 flag_no_opers = flag_part_message = flag_quit_message =
00072 flag_privmsg = flag_notice = true;
00073 break;
00074 default:
00075 return x;
00076 break;
00077 }
00078 }
00079 return 0;
00080 }
00081
00082 FilterResult()
00083 {
00084 }
00085
00086 virtual ~FilterResult()
00087 {
00088 }
00089 };
00090
00091 class CommandFilter;
00092
00093 class FilterBase : public Module
00094 {
00095 CommandFilter* filtcommand;
00096 int flags;
00097 protected:
00098 std::vector<std::string> exemptfromfilter;
00099 public:
00100 FilterBase(InspIRCd* Me, const std::string &source);
00101 virtual ~FilterBase();
00102 virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
00103 virtual FilterResult* FilterMatch(User* user, const std::string &text, int flags) = 0;
00104 virtual bool DeleteFilter(const std::string &freeform) = 0;
00105 virtual void SyncFilters(Module* proto, void* opaque) = 0;
00106 virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter);
00107 virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration, const std::string &flags) = 0;
00108 virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
00109 virtual void OnRehash(User* user, const std::string ¶meter);
00110 virtual Version GetVersion();
00111 std::string EncodeFilter(FilterResult* filter);
00112 FilterResult DecodeFilter(const std::string &data);
00113 virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);
00114 virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);
00115 virtual int OnStats(char symbol, User* user, string_list &results) = 0;
00116 virtual int OnPreCommand(std::string &command, std::vector<std::string> ¶meters, User *user, bool validated, const std::string &original_line);
00117 bool AppliesToMe(User* user, FilterResult* filter, int flags);
00118 };
00119
00120 class CommandFilter : public Command
00121 {
00122 FilterBase* Base;
00123 public:
00124 CommandFilter(FilterBase* f, InspIRCd* Me, const std::string &ssource) : Command(Me, "FILTER", "o", 1), Base(f)
00125 {
00126 this->source = ssource;
00127 this->syntax = "<filter-definition> <type> <flags> [<gline-duration>] :<reason>";
00128 }
00129
00130 CmdResult Handle(const std::vector<std::string> ¶meters, User *user)
00131 {
00132 if (parameters.size() == 1)
00133 {
00134
00135 if (Base->DeleteFilter(parameters[0]))
00136 {
00137 user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick.c_str(), parameters[0].c_str());
00138 return CMD_SUCCESS;
00139 }
00140 else
00141 {
00142 user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick.c_str(), parameters[0].c_str());
00143 return CMD_FAILURE;
00144 }
00145 }
00146 else
00147 {
00148
00149 if (parameters.size() >= 4)
00150 {
00151 std::string freeform = parameters[0];
00152 std::string type = parameters[1];
00153 std::string flags = parameters[2];
00154 std::string reason;
00155 long duration = 0;
00156
00157
00158 if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill") && (type != "silent"))
00159 {
00160 user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', 'silent' and 'kill'.", user->nick.c_str(), freeform.c_str());
00161 return CMD_FAILURE;
00162 }
00163
00164 if (type == "gline")
00165 {
00166 if (parameters.size() >= 5)
00167 {
00168 duration = ServerInstance->Duration(parameters[3]);
00169 reason = parameters[4];
00170 }
00171 else
00172 {
00173 this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter.");
00174 return CMD_FAILURE;
00175 }
00176 }
00177 else
00178 {
00179 reason = parameters[3];
00180 }
00181 std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration, flags);
00182 if (result.first)
00183 {
00184 user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, flags '%s', reason: '%s'", user->nick.c_str(), freeform.c_str(),
00185 type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[3].c_str() : ""),
00186 flags.c_str(), reason.c_str());
00187 return CMD_SUCCESS;
00188 }
00189 else
00190 {
00191 user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick.c_str(), freeform.c_str(), result.second.c_str());
00192 return CMD_FAILURE;
00193 }
00194 }
00195 else
00196 {
00197 this->TooFewParams(user, ".");
00198 return CMD_FAILURE;
00199 }
00200
00201 }
00202 }
00203
00204 void TooFewParams(User* user, const std::string &extra_text)
00205 {
00206 user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick.c_str(), extra_text.c_str());
00207 }
00208 };
00209
00210 bool FilterBase::AppliesToMe(User* user, FilterResult* filter, int iflags)
00211 {
00212 if ((filter->flag_no_opers) && IS_OPER(user))
00213 return false;
00214 if ((iflags & FLAG_PRIVMSG) && (!filter->flag_privmsg))
00215 return false;
00216 if ((iflags & FLAG_NOTICE) && (!filter->flag_notice))
00217 return false;
00218 if ((iflags & FLAG_QUIT) && (!filter->flag_quit_message))
00219 return false;
00220 if ((iflags & FLAG_PART) && (!filter->flag_part_message))
00221 return false;
00222 return true;
00223 }
00224
00225 FilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module(Me)
00226 {
00227 filtcommand = new CommandFilter(this, Me, source);
00228 ServerInstance->AddCommand(filtcommand);
00229 Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncOtherMetaData, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash };
00230 ServerInstance->Modules->Attach(eventlist, this, 7);
00231 }
00232
00233 FilterBase::~FilterBase()
00234 {
00235 }
00236
00237 int FilterBase::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00238 {
00239 flags = FLAG_PRIVMSG;
00240 return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
00241 }
00242
00243 int FilterBase::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00244 {
00245 if (!flags)
00246 flags = FLAG_NOTICE;
00247
00248
00249 if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
00250 return 0;
00251
00252 FilterResult* f = this->FilterMatch(user, text, flags);
00253 if (f)
00254 {
00255 std::string target = "";
00256 if (target_type == TYPE_USER)
00257 {
00258 User* t = (User*)dest;
00259 target = std::string(t->nick);
00260 }
00261 else if (target_type == TYPE_CHANNEL)
00262 {
00263 Channel* t = (Channel*)dest;
00264 target = std::string(t->name);
00265 std::vector<std::string>::iterator i = find(exemptfromfilter.begin(), exemptfromfilter.end(), target);
00266 if (i != exemptfromfilter.end()) return 0;
00267 }
00268 if (f->action == "block")
00269 {
00270 ServerInstance->SNO->WriteToSnoMask('A', std::string("FILTER: ")+user->nick+" had their message filtered, target was "+target+": "+f->reason);
00271 user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered and opers notified: "+f->reason);
00272 }
00273 if (f->action == "silent")
00274 {
00275 user->WriteServ("NOTICE "+std::string(user->nick)+" :Your message has been filtered: "+f->reason);
00276 }
00277 if (f->action == "kill")
00278 {
00279 ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
00280 }
00281 if (f->action == "gline")
00282 {
00283 GLine* gl = new GLine(ServerInstance, ServerInstance->Time(), f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), "*", user->GetIPString());
00284 if (ServerInstance->XLines->AddLine(gl,NULL))
00285 {
00286 ServerInstance->XLines->ApplyLines();
00287 }
00288 else
00289 delete gl;
00290 }
00291
00292 ServerInstance->Logs->Log("FILTER",DEFAULT,"FILTER: "+ user->nick + " had their message filtered, target was " + target + ": " + f->reason + " Action: " + f->action);
00293 return 1;
00294 }
00295 return 0;
00296 }
00297
00298 int FilterBase::OnPreCommand(std::string &command, std::vector<std::string> ¶meters, User *user, bool validated, const std::string &original_line)
00299 {
00300 flags = 0;
00301 if (validated && IS_LOCAL(user))
00302 {
00303 std::string checkline;
00304 int replacepoint = 0;
00305 bool parting = false;
00306
00307 if (command == "QUIT")
00308 {
00309
00310 if (parameters.size() < 1)
00311 return 0;
00312
00313 checkline = parameters[0];
00314 replacepoint = 0;
00315 parting = false;
00316 flags = FLAG_QUIT;
00317 }
00318 else if (command == "PART")
00319 {
00320
00321 if (parameters.size() < 2)
00322 return 0;
00323
00324 std::vector<std::string>::iterator i = find(exemptfromfilter.begin(), exemptfromfilter.end(), parameters[0]);
00325 if (i != exemptfromfilter.end()) return 0;
00326 checkline = parameters[1];
00327 replacepoint = 1;
00328 parting = true;
00329 flags = FLAG_PART;
00330 }
00331 else
00332
00333 return 0;
00334
00335 FilterResult* f = NULL;
00336
00337 if (flags)
00338 f = this->FilterMatch(user, checkline, flags);
00339
00340 if (!f)
00341
00342 return 0;
00343
00344
00345 Command* c = ServerInstance->Parser->GetHandler(command);
00346 if (c)
00347 {
00348 std::vector<std::string> params;
00349 for (int item = 0; item < (int)parameters.size(); item++)
00350 params.push_back(parameters[item]);
00351 params[replacepoint] = "Reason filtered";
00352
00353
00354
00355
00356 if ((f->action == "block") || (((!parting) && (f->action == "kill"))) || (f->action == "silent"))
00357 {
00358 c->Handle(params, user);
00359 return 1;
00360 }
00361 else
00362 {
00363
00364 if ((parting) && (f->action == "kill"))
00365 {
00366 user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick.c_str(), f->reason.c_str());
00367 ServerInstance->Users->QuitUser(user, "Filtered: " + f->reason);
00368 }
00369 if (f->action == "gline")
00370 {
00371
00372 GLine* gl = new GLine(ServerInstance, ServerInstance->Time(), f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), "*", user->GetIPString());
00373 if (ServerInstance->XLines->AddLine(gl,NULL))
00374 {
00375 ServerInstance->XLines->ApplyLines();
00376 }
00377 else
00378 delete gl;
00379 }
00380 return 1;
00381 }
00382 }
00383 return 0;
00384 }
00385 return 0;
00386 }
00387
00388 void FilterBase::OnRehash(User* user, const std::string ¶meter)
00389 {
00390 ConfigReader* MyConf = new ConfigReader(ServerInstance);
00391 std::vector<std::string>().swap(exemptfromfilter);
00392 for (int index = 0; index < MyConf->Enumerate("exemptfromfilter"); ++index)
00393 {
00394 std::string chan = MyConf->ReadValue("exemptfromfilter", "channel", index);
00395 if (!chan.empty()) {
00396 exemptfromfilter.push_back(chan);
00397 }
00398 }
00399 delete MyConf;
00400 }
00401
00402 Version FilterBase::GetVersion()
00403 {
00404 return Version("$Id: m_filter.h 10295 2008-08-25 20:50:11Z w00t $", VF_VENDOR | VF_COMMON, API_VERSION);
00405 }
00406
00407
00408 std::string FilterBase::EncodeFilter(FilterResult* filter)
00409 {
00410 std::ostringstream stream;
00411 std::string x = filter->freeform;
00412
00413
00414 for (std::string::iterator n = x.begin(); n != x.end(); n++)
00415 if (*n == ' ')
00416 *n = '\7';
00417
00418 stream << x << " " << filter->action << " " << (filter->flags.empty() ? "-" : filter->flags) << " " << filter->gline_time << " :" << filter->reason;
00419 return stream.str();
00420 }
00421
00422 FilterResult FilterBase::DecodeFilter(const std::string &data)
00423 {
00424 FilterResult res;
00425 irc::tokenstream tokens(data);
00426 tokens.GetToken(res.freeform);
00427 tokens.GetToken(res.action);
00428 tokens.GetToken(res.flags);
00429 if (res.flags == "-")
00430 res.flags = "";
00431 res.FillFlags(res.flags);
00432 tokens.GetToken(res.gline_time);
00433 tokens.GetToken(res.reason);
00434
00435
00436 for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)
00437 if (*n == '\7')
00438 *n = ' ';
00439
00440 return res;
00441 }
00442
00443 void FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
00444 {
00445 this->SyncFilters(proto, opaque);
00446 }
00447
00448 void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)
00449 {
00450 proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));
00451 }
00452
00453 void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
00454 {
00455 if ((target_type == TYPE_OTHER) && (extname == "filter"))
00456 {
00457 FilterResult data = DecodeFilter(extdata);
00458 this->AddFilter(data.freeform, data.action, data.reason, data.gline_time, data.flags);
00459 }
00460 }
00461