00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "users.h"
00016 #include "channels.h"
00017 #include "modules.h"
00018 #include "hashcomp.h"
00019 #include "wildcard.h"
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 typedef std::pair<std::string, int> silenceset;
00044
00045
00046 typedef std::deque<silenceset> silencelist;
00047
00048
00049 static int SILENCE_PRIVATE = 0x0001;
00050 static int SILENCE_CHANNEL = 0x0002;
00051 static int SILENCE_INVITE = 0x0004;
00052 static int SILENCE_NOTICE = 0x0008;
00053 static int SILENCE_CNOTICE = 0x0010;
00054 static int SILENCE_ALL = 0x0020;
00055 static int SILENCE_EXCLUDE = 0x0040;
00056
00057
00058 class cmd_silence : public command_t
00059 {
00060 unsigned int& maxsilence;
00061 public:
00062 cmd_silence (InspIRCd* Instance, unsigned int &max) : command_t(Instance,"SILENCE", 0, 0), maxsilence(max)
00063 {
00064 this->source = "m_silence_ext.so";
00065 syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
00066 }
00067
00068 CmdResult Handle (const char** parameters, int pcnt, userrec *user)
00069 {
00070 if (!pcnt)
00071 {
00072
00073
00074 silencelist* sl;
00075 user->GetExt("silence_list", sl);
00076
00077 if (sl)
00078 {
00079 for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
00080 {
00081 user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str());
00082 }
00083 }
00084 user->WriteServ("272 %s :End of Silence List",user->nick);
00085
00086 return CMD_LOCALONLY;
00087 }
00088 else if (pcnt > 0)
00089 {
00090
00091 std::string mask = parameters[0] + 1;
00092 char action = *parameters[0];
00093
00094 int pattern = CompilePattern("pn");
00095
00096
00097 if (pcnt > 1) {
00098 pattern = CompilePattern(parameters[1]);
00099 }
00100
00101 if (!mask.length())
00102 {
00103
00104 mask = "*!*@*";
00105 }
00106
00107 ModeParser::CleanMask(mask);
00108
00109 if (action == '-')
00110 {
00111
00112 silencelist* sl;
00113 user->GetExt("silence_list", sl);
00114
00115 if (sl)
00116 {
00117 for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)
00118 {
00119
00120 irc::string listitem = i->first.c_str();
00121 if (listitem == mask && i->second == pattern)
00122 {
00123 sl->erase(i);
00124 user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
00125 if (!sl->size())
00126 {
00127 DELETE(sl);
00128 user->Shrink("silence_list");
00129 }
00130 return CMD_SUCCESS;
00131 }
00132 }
00133 }
00134 user->WriteServ("952 %s %s :%s %s does not exist on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
00135 }
00136 else if (action == '+')
00137 {
00138
00139 silencelist* sl;
00140 user->GetExt("silence_list", sl);
00141
00142 if (!sl)
00143 {
00144 sl = new silencelist;
00145 user->Extend("silence_list", sl);
00146 }
00147 if (sl->size() > maxsilence)
00148 {
00149 user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick);
00150 return CMD_FAILURE;
00151 }
00152 for (silencelist::iterator n = sl->begin(); n != sl->end(); n++)
00153 {
00154 irc::string listitem = n->first.c_str();
00155 if (listitem == mask && n->second == pattern)
00156 {
00157 user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
00158 return CMD_FAILURE;
00159 }
00160 }
00161 if (((pattern & SILENCE_EXCLUDE) > 0))
00162 {
00163 sl->push_front(silenceset(mask,pattern));
00164 }
00165 else
00166 {
00167 sl->push_back(silenceset(mask,pattern));
00168 }
00169 user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
00170 return CMD_SUCCESS;
00171 }
00172 }
00173 return CMD_LOCALONLY;
00174 }
00175
00176
00177 int CompilePattern(const char* pattern)
00178 {
00179 int p = 0;
00180 for (const char* n = pattern; *n; n++)
00181 {
00182 switch (*n)
00183 {
00184 case 'p':
00185 p |= SILENCE_PRIVATE;
00186 break;
00187 case 'c':
00188 p |= SILENCE_CHANNEL;
00189 break;
00190 case 'i':
00191 p |= SILENCE_INVITE;
00192 break;
00193 case 'n':
00194 p |= SILENCE_NOTICE;
00195 break;
00196 case 't':
00197 p |= SILENCE_CNOTICE;
00198 break;
00199 case 'a':
00200 p |= SILENCE_ALL;
00201 break;
00202 case 'x':
00203 p |= SILENCE_EXCLUDE;
00204 break;
00205 default:
00206 break;
00207 }
00208 }
00209 return p;
00210 }
00211
00212
00213 std::string DecompPattern (const int pattern)
00214 {
00215 std::string out;
00216 if ((pattern & SILENCE_PRIVATE) > 0)
00217 out += ",privatemessages";
00218 if ((pattern & SILENCE_CHANNEL) > 0)
00219 out += ",channelmessages";
00220 if ((pattern & SILENCE_INVITE) > 0)
00221 out += ",invites";
00222 if ((pattern & SILENCE_NOTICE) > 0)
00223 out += ",privatenotices";
00224 if ((pattern & SILENCE_CNOTICE) > 0)
00225 out += ",channelnotices";
00226 if ((pattern & SILENCE_ALL) > 0)
00227 out = ",all";
00228 if ((pattern & SILENCE_EXCLUDE) > 0)
00229 out += ",exclude";
00230 return "<" + out.substr(1) + ">";
00231 }
00232
00233 };
00234
00235 class ModuleSilence : public Module
00236 {
00237 cmd_silence* mycommand;
00238 unsigned int maxsilence;
00239 public:
00240
00241 ModuleSilence(InspIRCd* Me)
00242 : Module(Me), maxsilence(32)
00243 {
00244 OnRehash(NULL, "");
00245 mycommand = new cmd_silence(ServerInstance,maxsilence);
00246 ServerInstance->AddCommand(mycommand);
00247 }
00248
00249 virtual void OnRehash(userrec* user, const std::string ¶meter)
00250 {
00251 ConfigReader Conf(ServerInstance);
00252 maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
00253 if (!maxsilence)
00254 maxsilence = 32;
00255 }
00256
00257 void Implements(char* List)
00258 {
00259 List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1;
00260 }
00261
00262 virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
00263 {
00264
00265 silencelist* sl;
00266 user->GetExt("silence_list", sl);
00267 if (sl)
00268 {
00269 DELETE(sl);
00270 user->Shrink("silence_list");
00271 }
00272 }
00273
00274 virtual void On005Numeric(std::string &output)
00275 {
00276
00277 output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);
00278 }
00279
00280 virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list)
00281 {
00282 int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);
00283 CUList *ulist;
00284 switch (status)
00285 {
00286 case '@':
00287 ulist = chan->GetOppedUsers();
00288 break;
00289 case '%':
00290 ulist = chan->GetHalfoppedUsers();
00291 break;
00292 case '+':
00293 ulist = chan->GetVoicedUsers();
00294 break;
00295 default:
00296 ulist = chan->GetUsers();
00297 break;
00298 }
00299
00300 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
00301 {
00302 if (IS_LOCAL(i->first))
00303 {
00304 if (MatchPattern(i->first, sender, public_silence) == 1)
00305 {
00306 exempt_list[i->first] = i->first->nick;
00307 }
00308 }
00309 }
00310 }
00311
00312 virtual int PreText(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)
00313 {
00314 if (target_type == TYPE_USER && IS_LOCAL(((userrec*)dest)))
00315 {
00316 return MatchPattern((userrec*)dest, user, silence_type);
00317 }
00318 else if (target_type == TYPE_CHANNEL)
00319 {
00320 chanrec* chan = (chanrec*)dest;
00321 if (chan)
00322 {
00323 this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list);
00324 }
00325 }
00326 return 0;
00327 }
00328
00329 virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00330 {
00331 return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);
00332 }
00333
00334 virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00335 {
00336 return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);
00337 }
00338
00339 virtual int OnUserPreInvite(userrec* source,userrec* dest,chanrec* channel)
00340 {
00341 return MatchPattern(dest, source, SILENCE_INVITE);
00342 }
00343
00344 int MatchPattern(userrec* dest, userrec* source, int pattern)
00345 {
00346 silencelist* sl;
00347 dest->GetExt("silence_list", sl);
00348 if (sl)
00349 {
00350 for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
00351 {
00352 if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first)))
00353 return !(((c->second & SILENCE_EXCLUDE) > 0));
00354 }
00355 }
00356 return 0;
00357 }
00358
00359 virtual ~ModuleSilence()
00360 {
00361 }
00362
00363 virtual Version GetVersion()
00364 {
00365 return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);
00366 }
00367 };
00368
00369 MODULE_INIT(ModuleSilence)