1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 /* $ModDesc: Provides support for the /SILENCE command */
19 /* Improved drop-in replacement for the /SILENCE command
20 * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>
22 * example that blocks all except private messages
26 * example that blocks all invites except from channel services
28 * /SILENCE +chanserv!services@chatters.net ix
30 * example that blocks some bad dude from private, notice and inviting you
31 * /SILENCE +*!kiddie@lamerz.net pin
33 * TODO: possibly have add and remove check for existing host and only modify flags according to
34 * what's been changed instead of having to remove first, then add if you want to change
38 // pair of hostmask and flags
39 typedef std::pair<std::string, int> silenceset;
41 // deque list of pairs
42 typedef std::deque<silenceset> silencelist;
45 static int SILENCE_PRIVATE = 0x0001; /* p private messages */
46 static int SILENCE_CHANNEL = 0x0002; /* c channel messages */
47 static int SILENCE_INVITE = 0x0004; /* i invites */
48 static int SILENCE_NOTICE = 0x0008; /* n notices */
49 static int SILENCE_CNOTICE = 0x0010; /* t channel notices */
50 static int SILENCE_ALL = 0x0020; /* a all, (pcint) */
51 static int SILENCE_EXCLUDE = 0x0040; /* x exclude this pattern */
54 class CommandSilence : public Command
56 unsigned int& maxsilence;
58 CommandSilence (InspIRCd* Instance, unsigned int &max) : Command(Instance,"SILENCE", 0, 0), maxsilence(max)
60 this->source = "m_silence_ext.so";
61 syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
62 TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
65 CmdResult Handle (const char** parameters, int pcnt, User *user)
69 // no parameters, show the current silence list.
70 // Use Extensible::GetExt to fetch the silence list
72 user->GetExt("silence_list", sl);
73 // if the user has a silence list associated with their user record, show it
76 for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
78 user->WriteServ("271 %s %s %s %s",user->nick, user->nick,c->first.c_str(), DecompPattern(c->second).c_str());
81 user->WriteServ("272 %s :End of Silence List",user->nick);
87 // one or more parameters, add or delete entry from the list (only the first parameter is used)
88 std::string mask = parameters[0] + 1;
89 char action = *parameters[0];
90 // Default is private and notice so clients do not break
91 int pattern = CompilePattern("pn");
93 // if pattern supplied, use it
95 pattern = CompilePattern(parameters[1]);
100 // 'SILENCE +' or 'SILENCE -', assume *!*@*
104 ModeParser::CleanMask(mask);
108 // fetch their silence list
110 user->GetExt("silence_list", sl);
111 // does it contain any entries and does it exist?
114 for (silencelist::iterator i = sl->begin(); i != sl->end(); i++)
116 // search through for the item
117 irc::string listitem = i->first.c_str();
118 if (listitem == mask && i->second == pattern)
121 user->WriteServ("950 %s %s :Removed %s %s from silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
125 user->Shrink("silence_list");
131 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());
133 else if (action == '+')
135 // fetch the user's current silence list
137 user->GetExt("silence_list", sl);
138 // what, they dont have one??? WE'RE ALL GONNA DIE! ...no, we just create an empty one.
141 sl = new silencelist;
142 user->Extend("silence_list", sl);
144 if (sl->size() > maxsilence)
146 user->WriteServ("952 %s %s :Your silence list is full",user->nick, user->nick);
149 for (silencelist::iterator n = sl->begin(); n != sl->end(); n++)
151 irc::string listitem = n->first.c_str();
152 if (listitem == mask && n->second == pattern)
154 user->WriteServ("952 %s %s :%s %s is already on your silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
158 if (((pattern & SILENCE_EXCLUDE) > 0))
160 sl->push_front(silenceset(mask,pattern));
164 sl->push_back(silenceset(mask,pattern));
166 user->WriteServ("951 %s %s :Added %s %s to silence list",user->nick, user->nick, mask.c_str(), DecompPattern(pattern).c_str());
170 return CMD_LOCALONLY;
173 /* turn the nice human readable pattern into a mask */
174 int CompilePattern(const char* pattern)
177 for (const char* n = pattern; *n; n++)
182 p |= SILENCE_PRIVATE;
185 p |= SILENCE_CHANNEL;
194 p |= SILENCE_CNOTICE;
200 p |= SILENCE_EXCLUDE;
209 /* turn the mask into a nice human readable format */
210 std::string DecompPattern (const int pattern)
213 if ((pattern & SILENCE_PRIVATE) > 0)
214 out += ",privatemessages";
215 if ((pattern & SILENCE_CHANNEL) > 0)
216 out += ",channelmessages";
217 if ((pattern & SILENCE_INVITE) > 0)
219 if ((pattern & SILENCE_NOTICE) > 0)
220 out += ",privatenotices";
221 if ((pattern & SILENCE_CNOTICE) > 0)
222 out += ",channelnotices";
223 if ((pattern & SILENCE_ALL) > 0)
225 if ((pattern & SILENCE_EXCLUDE) > 0)
227 return "<" + out.substr(1) + ">";
232 class ModuleSilence : public Module
234 CommandSilence* mycommand;
235 unsigned int maxsilence;
238 ModuleSilence(InspIRCd* Me)
239 : Module(Me), maxsilence(32)
242 mycommand = new CommandSilence(ServerInstance,maxsilence);
243 ServerInstance->AddCommand(mycommand);
244 Implementation eventlist[] = { I_OnRehash, I_OnBuildExemptList, I_OnUserQuit, I_On005Numeric, I_OnUserPreNotice, I_OnUserPreMessage, I_OnUserPreInvite };
245 ServerInstance->Modules->Attach(eventlist, this, 7);
248 virtual void OnRehash(User* user, const std::string ¶meter)
250 ConfigReader Conf(ServerInstance);
251 maxsilence = Conf.ReadInteger("silence", "maxentries", 0, true);
256 void Implements(char* List)
258 List[I_OnRehash] = List[I_OnBuildExemptList] = List[I_OnUserQuit] = List[I_On005Numeric] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = List[I_OnUserPreInvite] = 1;
261 virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
263 // when the user quits tidy up any silence list they might have just to keep things tidy
265 user->GetExt("silence_list", sl);
269 user->Shrink("silence_list");
273 virtual void On005Numeric(std::string &output)
275 // we don't really have a limit...
276 output = output + " ESILENCE SILENCE=" + ConvToStr(maxsilence);
279 virtual void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text)
281 int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE);
286 ulist = chan->GetOppedUsers();
289 ulist = chan->GetHalfoppedUsers();
292 ulist = chan->GetVoicedUsers();
295 ulist = chan->GetUsers();
299 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
301 if (IS_LOCAL(i->first))
303 if (MatchPattern(i->first, sender, public_silence) == 1)
305 exempt_list[i->first] = i->first->nick;
311 virtual int PreText(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list, int silence_type)
316 if (target_type == TYPE_USER)
318 return MatchPattern((User*)dest, user, silence_type);
320 else if (target_type == TYPE_CHANNEL)
322 Channel* chan = (Channel*)dest;
325 this->OnBuildExemptList((silence_type == SILENCE_PRIVATE ? MSG_PRIVMSG : MSG_NOTICE), chan, user, status, exempt_list, "");
331 virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
333 return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_PRIVATE);
336 virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
338 return PreText(user, dest, target_type, text, status, exempt_list, SILENCE_NOTICE);
341 virtual int OnUserPreInvite(User* source,User* dest,Channel* channel)
343 return MatchPattern(dest, source, SILENCE_INVITE);
346 int MatchPattern(User* dest, User* source, int pattern)
349 dest->GetExt("silence_list", sl);
352 for (silencelist::const_iterator c = sl->begin(); c != sl->end(); c++)
354 if (((((c->second & pattern) > 0)) || ((c->second & SILENCE_ALL) > 0)) && (ServerInstance->MatchText(source->GetFullHost(), c->first)))
355 return !(((c->second & SILENCE_EXCLUDE) > 0));
361 virtual ~ModuleSilence()
365 virtual Version GetVersion()
367 return Version(1, 1, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);
371 MODULE_INIT(ModuleSilence)