]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
da8f10294ff89149f9e8f445774b7dc7f17db028
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
18
19 #include "inspircd.h"
20 #include "inspstring.h"
21
22 /* +s (secret) */
23 #include "modes/cmode_s.h"
24 /* +p (private) */
25 #include "modes/cmode_p.h"
26 /* +b (bans) */
27 #include "modes/cmode_b.h"
28 /* +m (moderated) */
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
40 /* +o (channel op) */
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +w (see wallops) */
47 #include "modes/umode_w.h"
48 /* +i (invisible) */
49 #include "modes/umode_i.h"
50 /* +o (operator) */
51 #include "modes/umode_o.h"
52 /* +s (server notice masks) */
53 #include "modes/umode_s.h"
54
55 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
56         : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
57 {
58 }
59
60 ModeHandler::~ModeHandler()
61 {
62 }
63
64 bool ModeHandler::IsListMode()
65 {
66         return list;
67 }
68
69 char ModeHandler::GetNeededPrefix()
70 {
71         return prefixneeded;
72 }
73
74 void ModeHandler::SetNeededPrefix(char needsprefix)
75 {
76         prefixneeded = needsprefix;
77 }
78
79 unsigned int ModeHandler::GetPrefixRank()
80 {
81         return 0;
82 }
83
84 unsigned int ModeHandler::GetCount()
85 {
86         return 0;
87 }
88
89 void ModeHandler::ChangeCount(int modifier)
90 {
91         count += modifier;
92         ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
93 }
94
95 ModeType ModeHandler::GetModeType()
96 {
97         return m_type;
98 }
99
100 TranslateType ModeHandler::GetTranslateType()
101 {
102         return m_paramtype;
103 }
104
105 bool ModeHandler::NeedsOper()
106 {
107         return oper;
108 }
109
110 char ModeHandler::GetPrefix()
111 {
112         return prefix;
113 }
114
115 int ModeHandler::GetNumParams(bool adding)
116 {
117         return adding ? n_params_on : n_params_off;
118 }
119
120 char ModeHandler::GetModeChar()
121 {
122         return mode;
123 }
124
125 std::string ModeHandler::GetUserParameter(User* user)
126 {
127         return "";
128 }
129
130 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
131 {
132         return MODEACTION_DENY;
133 }
134
135 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
136 {
137         if (dest)
138         {
139                 return std::make_pair(dest->IsModeSet(this->mode), "");
140         }
141         else
142         {
143                 return std::make_pair(channel->IsModeSet(this->mode), "");
144         }
145 }
146
147 void ModeHandler::DisplayList(User*, Channel*)
148 {
149 }
150
151 void ModeHandler::DisplayEmptyList(User*, Channel*)
152 {
153 }
154
155 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
156 {
157 }
158
159 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
160 {
161         return (ours < theirs);
162 }
163
164 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
165 {
166 }
167
168 SimpleUserModeHandler::~SimpleUserModeHandler()
169 {
170 }
171
172 SimpleChannelModeHandler::~SimpleChannelModeHandler()
173 {
174 }
175
176 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
177 {
178 }
179
180 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
181 {
182         if (adding)
183         {
184                 if (!dest->IsModeSet(this->GetModeChar()))
185                 {
186                         dest->SetMode(this->GetModeChar(),true);
187                         return MODEACTION_ALLOW;
188                 }
189         }
190         else
191         {
192                 if (dest->IsModeSet(this->GetModeChar()))
193                 {
194                         dest->SetMode(this->GetModeChar(),false);
195                         return MODEACTION_ALLOW;
196                 }
197         }
198
199         return MODEACTION_DENY;
200 }
201
202
203 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
204 {
205         if (adding)
206         {
207                 if (!channel->IsModeSet(this->GetModeChar()))
208                 {
209                         channel->SetMode(this->GetModeChar(),true);
210                         return MODEACTION_ALLOW;
211                 }
212         }
213         else
214         {
215                 if (channel->IsModeSet(this->GetModeChar()))
216                 {
217                         channel->SetMode(this->GetModeChar(),false);
218                         return MODEACTION_ALLOW;
219                 }
220         }
221
222         return MODEACTION_DENY;
223 }
224
225 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
226 {
227 }
228
229 ModeWatcher::~ModeWatcher()
230 {
231 }
232
233 char ModeWatcher::GetModeChar()
234 {
235         return mode;
236 }
237
238 ModeType ModeWatcher::GetModeType()
239 {
240         return m_type;
241 }
242
243 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
244 {
245         return true;
246 }
247
248 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
249 {
250 }
251
252 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
253 {
254         User *d;
255         if ((!user) || (!dest) || (!chan) || (!*dest))
256         {
257                 return NULL;
258         }
259         d = ServerInstance->FindNick(dest);
260         if (!d)
261         {
262                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
263                 return NULL;
264         }
265         return d;
266 }
267
268 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
269 {
270         if (!chan)
271                 return "";
272
273         UCListIter n = d->chans.find(chan);
274         if (n != d->chans.end())
275         {
276                 if (n->second & MASK)
277                 {
278                         return "";
279                 }
280                 n->second = n->second | MASK;
281                 switch (MASK)
282                 {
283                         case UCMODE_OP:
284                                 n->first->AddOppedUser(d);
285                         break;
286                         case UCMODE_HOP:
287                                 n->first->AddHalfoppedUser(d);
288                         break;
289                         case UCMODE_VOICE:
290                                 n->first->AddVoicedUser(d);
291                         break;
292                 }
293                 return d->nick.c_str();
294         }
295         return "";
296 }
297
298 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
299 {
300         if (!chan)
301                 return "";
302
303         UCListIter n = d->chans.find(chan);
304         if (n != d->chans.end())
305         {
306                 if ((n->second & MASK) == 0)
307                 {
308                         return "";
309                 }
310                 n->second ^= MASK;
311                 switch (MASK)
312                 {
313                         case UCMODE_OP:
314                                 n->first->DelOppedUser(d);
315                         break;
316                         case UCMODE_HOP:
317                                 n->first->DelHalfoppedUser(d);
318                         break;
319                         case UCMODE_VOICE:
320                                 n->first->DelVoicedUser(d);
321                         break;
322                 }
323                 return d->nick.c_str();
324         }
325         return "";
326 }
327
328 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
329 {
330         if (targetchannel)
331         {
332                 /* Display channel's current mode string */
333                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
334                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
335                 return;
336         }
337         else if (targetuser)
338         {
339                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
340                 {
341                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
342                         return;
343                 }
344
345                 if (targetuser == user || user->HasPrivPermission("users/auspex"))
346                 {
347                         /* Display user's current mode string */
348                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
349                         if (IS_OPER(targetuser))
350                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
351                         return;
352                 }
353                 else
354                 {
355                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
356                         return;
357                 }
358         }
359
360         /* No such nick/channel */
361         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
362         return;
363 }
364
365 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
366 {
367         std::string target = parameters[0];
368         ModeType type = MODETYPE_USER;
369         unsigned char mask = 0;
370         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
371         User* targetuser  = ServerInstance->FindNick(parameters[0]);
372
373         LastParse.clear();
374
375         /* Special case for displaying the list for listmodes,
376          * e.g. MODE #chan b, or MODE #chan +b without a parameter
377          */
378         if ((targetchannel) && (parameters.size() == 2))
379         {
380                 const char* mode = parameters[1].c_str();
381                 int nonlistmodes_found = 0;
382
383                 seq++;
384
385                 mask = MASK_CHANNEL;
386
387                 while (mode && *mode)
388                 {
389                         unsigned char mletter = *mode;
390
391                         if (*mode == '+')
392                         {
393                                 mode++;
394                                 continue;
395                         }
396
397                         /* Ensure the user doesnt request the same mode twice,
398                          * so they cant flood themselves off out of idiocy.
399                          */
400                         if (sent[mletter] != seq)
401                         {
402                                 sent[mletter] = seq;
403                         }
404                         else
405                         {
406                                 mode++;
407                                 continue;
408                         }
409
410                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
411                         bool display = true;
412
413                         if ((mh) && (mh->IsListMode()))
414                         {
415                                 int MOD_RESULT = 0;
416                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
417                                 if (MOD_RESULT == ACR_DENY)
418                                 {
419                                         mode++;
420                                         continue;
421                                 }
422
423                                 if (!user->HasPrivPermission("channels/auspex"))
424                                 {
425                                         if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
426                                         {
427                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
428                                                 mh->DisplayEmptyList(user, targetchannel);
429                                                 continue;
430                                         }
431                                 }
432
433                                 /** See below for a description of what craq this is :D
434                                  */
435                                 unsigned char handler_id = (*mode - 65) | mask;
436
437                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
438                                 {
439                                         std::string dummyparam;
440
441                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
442                                                 display = false;
443                                 }
444
445                                 if (display)
446                                         mh->DisplayList(user, targetchannel);
447                         }
448                         else
449                                 nonlistmodes_found++;
450
451                         mode++;
452                 }
453
454                 /* We didnt have any modes that were non-list, we can return here */
455                 if (!nonlistmodes_found)
456                         return;
457         }
458
459         if (parameters.size() == 1)
460         {
461                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
462         }
463         else if (parameters.size() > 1)
464         {
465                 bool SkipAccessChecks = false;
466
467                 if (targetchannel)
468                 {
469                         type = MODETYPE_CHANNEL;
470                         mask = MASK_CHANNEL;
471
472                         /* Extra security checks on channel modes
473                          * (e.g. are they a (half)op?
474                          */
475
476                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
477                         {
478                                 /* We don't have halfop */
479                                 int MOD_RESULT = 0;
480                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
481                                 if (MOD_RESULT == ACR_DENY)
482                                         return;
483                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
484                         }
485                 }
486                 else if (targetuser)
487                 {
488                         type = MODETYPE_USER;
489                         mask = MASK_USER;
490                         if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
491                         {
492                                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
493                                 return;
494                         }
495                 }
496                 else
497                 {
498                         /* No such nick/channel */
499                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
500                         return;
501                 }
502
503                 std::string mode_sequence = parameters[1];
504                 std::string parameter;
505                 std::ostringstream parameter_list;
506                 std::vector<TranslateType> parameter_xlate;
507                 parameter_xlate.push_back(TR_TEXT);
508                 std::string output_sequence;
509                 bool adding = true, state_change = false;
510                 unsigned char handler_id = 0;
511                 unsigned int parameter_counter = 2; /* Index of first parameter */
512                 unsigned int parameter_count = 0;
513                 bool last_successful_state_change = false;
514
515                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
516                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
517                         mode_sequence.insert(0, "+");
518
519                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
520                 {
521                         unsigned char modechar = *letter;
522
523                         switch (modechar)
524                         {
525                                 /* NB:
526                                  * For + and - mode characters, we don't just stick the character into the output sequence.
527                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
528                                  * appearing in the output sequence, we store a flag which says there was a state change,
529                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
530                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
531                                  */
532                                 case '+':
533                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
534                                          * however, will allow the + if it is the first item in the sequence, regardless.
535                                          */
536                                         if ((!adding) || (!output_sequence.length()))
537                                                 state_change = true;
538                                         adding = true;
539                                         if (!output_sequence.length())
540                                                 last_successful_state_change = false;
541                                         continue;
542                                 break;
543                                 case '-':
544                                         if ((adding) || (!output_sequence.length()))
545                                                 state_change = true;
546                                         adding = false;
547                                         if (!output_sequence.length())
548                                                 last_successful_state_change = true;
549                                         continue;
550                                 break;
551                                 default:
552
553                                         /**
554                                          * Watch carefully for the sleight of hand trick.
555                                          * 65 is the ascii value of 'A'. We take this from
556                                          * the char we're looking at to get a number between
557                                          * 1 and 127. We then logic-or it to get the hashed
558                                          * position, dependent on wether its a channel or
559                                          * a user mode. This is a little stranger, but a lot
560                                          * faster, than using a map of pairs.
561                                          */
562                                         handler_id = (modechar - 65) | mask;
563
564                                         if (modehandlers[handler_id])
565                                         {
566                                                 bool abort = false;
567
568                                                 if (modehandlers[handler_id]->GetModeType() == type)
569                                                 {
570                                                         int MOD_RESULT = 0;
571
572                                                         if (modehandlers[handler_id]->GetNumParams(adding))
573                                                         {
574                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
575                                                                 if (parameter_counter < parameters.size())
576                                                                 {
577                                                                         parameter = parameters[parameter_counter++];
578
579                                                                         /* Yerk, invalid! */
580                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
581                                                                                 parameter.clear();
582                                                                 }
583                                                                 else
584                                                                 {
585                                                                         /* No parameter, continue to the next mode */
586                                                                         modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
587                                                                         continue;
588                                                                 }
589
590                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
591                                                         }
592                                                         else
593                                                         {
594                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
595                                                         }
596
597                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
598                                                                 continue;
599
600                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
601                                                         {
602                                                                 /* Check access to this mode character */
603                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
604                                                                 {
605                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
606                                                                         ModeHandler* prefixmode = FindPrefix(needed);
607
608                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
609                                                                          * cannot be found, they probably dont have the right module loaded to implement
610                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
611                                                                          * Revert to checking against the minimum core prefix, '%'.
612                                                                          */
613                                                                         if (needed && !prefixmode)
614                                                                                 prefixmode = FindPrefix('%');
615
616                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
617                                                                         /* Compare our rank on the channel against the rank of the required prefix,
618                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
619                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
620                                                                          * first, so we don't need to iterate, we just look up the first instead.
621                                                                          */
622                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
623                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
624                                                                         ModeHandler* ourmode = FindPrefix(ml);
625                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
626                                                                         {
627                                                                                 /* Bog off */
628                                                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
629                                                                                                 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
630                                                                                 continue;
631                                                                         }
632                                                                 }
633                                                         }
634
635                                                         bool had_parameter = !parameter.empty();
636
637                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
638                                                         {
639                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
640                                                                 {
641                                                                         abort = true;
642                                                                         break;
643                                                                 }
644                                                                 /* A module whacked the parameter completely, and there was one. abort. */
645                                                                 if ((had_parameter) && (parameter.empty()))
646                                                                 {
647                                                                         abort = true;
648                                                                         break;
649                                                                 }
650                                                         }
651
652                                                         if (abort)
653                                                                 continue;
654
655                                                         /* If it's disabled, they have to be an oper.
656                                                          */
657                                                         if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
658                                                         {
659                                                                 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
660                                                                                 user->nick.c_str(),
661                                                                                 type == MODETYPE_CHANNEL ? "channel" : "user",
662                                                                                 modehandlers[handler_id]->GetModeChar());
663                                                                 continue;
664                                                         }
665
666                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
667                                                          * eat any parameter that  came with the mode, and continue to next
668                                                          */
669                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
670                                                         {
671                                                                 if (IS_OPER(user))
672                                                                 {
673                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
674                                                                                         user->nick.c_str(),
675                                                                                         user->oper.c_str(),
676                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
677                                                                                         modehandlers[handler_id]->GetModeChar());
678                                                                 }
679                                                                 else
680                                                                 {
681                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
682                                                                                         user->nick.c_str(),
683                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
684                                                                                         modehandlers[handler_id]->GetModeChar());
685                                                                 }
686                                                                 continue;
687                                                         }
688
689                                                         /* Call the handler for the mode */
690                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
691
692                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
693                                                         {
694                                                                 /* The handler nuked the parameter and they are supposed to have one.
695                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
696                                                                  * so we bail to the next mode character.
697                                                                  */
698                                                                 continue;
699                                                         }
700
701                                                         if (ma == MODEACTION_ALLOW)
702                                                         {
703                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
704                                                                 if (state_change)
705                                                                 {
706                                                                         if (adding != last_successful_state_change)
707                                                                                 output_sequence.append(adding ? "+" : "-");
708                                                                         last_successful_state_change = adding;
709                                                                 }
710
711                                                                 /* Add the mode letter */
712                                                                 output_sequence.push_back(modechar);
713
714                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
715
716                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
717                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
718                                                                 {
719                                                                         parameter_list << " " << parameter;
720                                                                         parameter_xlate.push_back(modehandlers[handler_id]->GetTranslateType());
721                                                                         parameter_count++;
722                                                                         /* Does this mode have a prefix? */
723                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
724                                                                         {
725                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
726                                                                                 if (user_to_prefix)
727                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
728                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
729                                                                         }
730                                                                 }
731
732                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
733                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
734                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
735
736                                                                 /* Reset the state change flag */
737                                                                 state_change = false;
738
739                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
740                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
741                                                                 {
742                                                                         /* We cant have a mode sequence this long */
743                                                                         letter = mode_sequence.end() - 1;
744                                                                         continue;
745                                                                 }
746                                                         }
747                                                 }
748                                         }
749                                         else
750                                         {
751                                                 /* No mode handler? Unknown mode character then. */
752                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
753                                         }
754                                 break;
755                         }
756                 }
757
758                 /* Was there at least one valid mode in the sequence? */
759                 if (!output_sequence.empty())
760                 {
761                         if (servermode)
762                         {
763                                 if (type == MODETYPE_CHANNEL)
764                                 {
765                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
766                                         this->LastParse = targetchannel->name;
767                                 }
768                                 else
769                                 {
770                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
771                                         this->LastParse = targetuser->nick;
772                                 }
773                         }
774                         else
775                         {
776                                 if (type == MODETYPE_CHANNEL)
777                                 {
778                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
779                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str(), parameter_xlate));
780                                         this->LastParse = targetchannel->name;
781                                 }
782                                 else
783                                 {
784                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
785                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str(), parameter_xlate));
786                                         this->LastParse = targetuser->nick;
787                                 }
788                         }
789
790                         LastParse.append(" ");
791                         LastParse.append(output_sequence);
792                         LastParse.append(parameter_list.str());
793                 }
794         }
795 }
796
797 const std::string& ModeParser::GetLastParse()
798 {
799         return LastParse;
800 }
801
802 void ModeParser::CleanMask(std::string &mask)
803 {
804         std::string::size_type pos_of_pling = mask.find_first_of('!');
805         std::string::size_type pos_of_at = mask.find_first_of('@');
806         std::string::size_type pos_of_dot = mask.find_first_of('.');
807         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
808
809         if (mask.length() >= 2 && mask[1] == ':')
810                 return; // if it's an extban, don't even try guess how it needs to be formed.
811
812         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
813         {
814                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
815                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
816                 {
817                         /* It has no '.' in it, it must be a nick. */
818                         mask.append("!*@*");
819                 }
820                 else
821                 {
822                         /* Got a dot in it? Has to be a host */
823                         mask = "*!*@" + mask;
824                 }
825         }
826         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
827         {
828                 /* Has an @ but no !, its a user@host */
829                  mask = "*!" + mask;
830         }
831         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
832         {
833                 /* Has a ! but no @, it must be a nick!ident */
834                 mask.append("@*");
835         }
836 }
837
838 bool ModeParser::AddMode(ModeHandler* mh)
839 {
840         unsigned char mask = 0;
841         unsigned char pos = 0;
842
843         /* Yes, i know, this might let people declare modes like '_' or '^'.
844          * If they do that, thats their problem, and if i ever EVER see an
845          * official InspIRCd developer do that, i'll beat them with a paddle!
846          */
847         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
848                 return false;
849
850         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
851          * A mode prefix of ':' will fuck up both server to server, and client to server.
852          * A mode prefix of '#' will mess up /whois and /privmsg
853          */
854         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
855                 return false;
856
857         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
858         pos = (mh->GetModeChar()-65) | mask;
859
860         if (modehandlers[pos])
861                 return false;
862
863         modehandlers[pos] = mh;
864         return true;
865 }
866
867 bool ModeParser::DelMode(ModeHandler* mh)
868 {
869         unsigned char mask = 0;
870         unsigned char pos = 0;
871
872         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
873                 return false;
874
875         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
876         pos = (mh->GetModeChar()-65) | mask;
877
878         if (!modehandlers[pos])
879                 return false;
880
881         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
882          * To stack here we have to make the algorithm slower. Discuss.
883          */
884         switch (mh->GetModeType())
885         {
886                 case MODETYPE_USER:
887                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
888                         {
889                                 mh->RemoveMode(i->second);
890                         }
891                 break;
892                 case MODETYPE_CHANNEL:
893                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
894                         {
895                                 mh->RemoveMode(i->second);
896                         }
897                 break;
898         }
899
900         modehandlers[pos] = NULL;
901
902         return true;
903 }
904
905 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
906 {
907         unsigned char mask = 0;
908         unsigned char pos = 0;
909
910         if ((modeletter < 'A') || (modeletter > 'z'))
911                 return NULL;
912
913         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
914         pos = (modeletter-65) | mask;
915
916         return modehandlers[pos];
917 }
918
919 std::string ModeParser::UserModeList()
920 {
921         char modestr[256];
922         int pointer = 0;
923
924         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
925         {
926                 unsigned char pos = (mode-65) | MASK_USER;
927
928                 if (modehandlers[pos])
929                         modestr[pointer++] = mode;
930         }
931         modestr[pointer++] = 0;
932         return modestr;
933 }
934
935 std::string ModeParser::ChannelModeList()
936 {
937         char modestr[256];
938         int pointer = 0;
939
940         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
941         {
942                 unsigned char pos = (mode-65) | MASK_CHANNEL;
943
944                 if (modehandlers[pos])
945                         modestr[pointer++] = mode;
946         }
947         modestr[pointer++] = 0;
948         return modestr;
949 }
950
951 std::string ModeParser::ParaModeList()
952 {
953         char modestr[256];
954         int pointer = 0;
955
956         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
957         {
958                 unsigned char pos = (mode-65) | MASK_CHANNEL;
959
960                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
961                         modestr[pointer++] = mode;
962         }
963         modestr[pointer++] = 0;
964         return modestr;
965 }
966
967 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
968 {
969         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
970         {
971                 unsigned char pos = (mode-65) | MASK_CHANNEL;
972
973                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
974                 {
975                         return modehandlers[pos];
976                 }
977         }
978         return NULL;
979 }
980
981 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
982 {
983         std::string types;
984         std::string pars;
985
986         if (!channel || !user)
987                 return "";
988
989         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
990         {
991                 unsigned char pos = (mode-65) | MASK_CHANNEL;
992                 ModeHandler* mh = modehandlers[pos];
993                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
994                 {
995                         ModePair ret;
996                         ret = mh->ModeSet(NULL, user, channel, user->nick);
997                         if ((ret.first) && (ret.second == user->nick))
998                         {
999                                 if (nick_suffix)
1000                                 {
1001                                         pars.append(" ");
1002                                         pars.append(user->nick);
1003                                 }
1004                                 types.push_back(mh->GetModeChar());
1005                         }
1006                 }
1007         }
1008
1009         if (nick_suffix)
1010                 return types+pars;
1011         else
1012                 return types;
1013 }
1014
1015 std::string ModeParser::GiveModeList(ModeMasks m)
1016 {
1017         std::string type1;      /* Listmodes EXCEPT those with a prefix */
1018         std::string type2;      /* Modes that take a param when adding or removing */
1019         std::string type3;      /* Modes that only take a param when adding */
1020         std::string type4;      /* Modes that dont take a param */
1021
1022         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1023         {
1024                 unsigned char pos = (mode-65) | m;
1025                  /* One parameter when adding */
1026                 if (modehandlers[pos])
1027                 {
1028                         if (modehandlers[pos]->GetNumParams(true))
1029                         {
1030                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1031                                 {
1032                                         type1 += modehandlers[pos]->GetModeChar();
1033                                 }
1034                                 else
1035                                 {
1036                                         /* ... and one parameter when removing */
1037                                         if (modehandlers[pos]->GetNumParams(false))
1038                                         {
1039                                                 /* But not a list mode */
1040                                                 if (!modehandlers[pos]->GetPrefix())
1041                                                 {
1042                                                         type2 += modehandlers[pos]->GetModeChar();
1043                                                 }
1044                                         }
1045                                         else
1046                                         {
1047                                                 /* No parameters when removing */
1048                                                 type3 += modehandlers[pos]->GetModeChar();
1049                                         }
1050                                 }
1051                         }
1052                         else
1053                         {
1054                                 type4 += modehandlers[pos]->GetModeChar();
1055                         }
1056                 }
1057         }
1058
1059         return type1 + "," + type2 + "," + type3 + "," + type4;
1060 }
1061
1062 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1063 {
1064         return one.second > two.second;
1065 }
1066
1067 std::string ModeParser::BuildPrefixes()
1068 {
1069         std::string mletters;
1070         std::string mprefixes;
1071         pfxcontainer pfx;
1072         std::map<char,char> prefix_to_mode;
1073
1074         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1075         {
1076                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1077
1078                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1079                 {
1080                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1081                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1082                 }
1083         }
1084
1085         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1086
1087         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1088         {
1089                 mletters = mletters + n->first;
1090                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1091         }
1092
1093         return "(" + mprefixes + ")" + mletters;
1094 }
1095
1096 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1097 {
1098         unsigned char mask = 0;
1099         unsigned char pos = 0;
1100
1101         if (!mw)
1102                 return false;
1103
1104         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1105                 return false;
1106
1107         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1108         pos = (mw->GetModeChar()-65) | mask;
1109
1110         modewatchers[pos].push_back(mw);
1111
1112         return true;
1113 }
1114
1115 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1116 {
1117         unsigned char mask = 0;
1118         unsigned char pos = 0;
1119
1120         if (!mw)
1121                 return false;
1122
1123         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1124                 return false;
1125
1126         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1127         pos = (mw->GetModeChar()-65) | mask;
1128
1129         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1130
1131         if (a == modewatchers[pos].end())
1132         {
1133                 return false;
1134         }
1135
1136         modewatchers[pos].erase(a);
1137
1138         return true;
1139 }
1140
1141 /** This default implementation can remove simple user modes
1142  */
1143 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1144 {
1145         char moderemove[MAXBUF];
1146         std::vector<std::string> parameters;
1147
1148         if (user->IsModeSet(this->GetModeChar()))
1149         {
1150                 if (stack)
1151                 {
1152                         stack->Push(this->GetModeChar());
1153                 }
1154                 else
1155                 {
1156                         sprintf(moderemove,"-%c",this->GetModeChar());
1157                         parameters.push_back(user->nick);
1158                         parameters.push_back(moderemove);
1159                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, false);
1160                 }
1161         }
1162 }
1163
1164 /** This default implementation can remove simple channel modes
1165  * (no parameters)
1166  */
1167 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1168 {
1169         char moderemove[MAXBUF];
1170         std::vector<std::string> parameters;
1171
1172         if (channel->IsModeSet(this->GetModeChar()))
1173         {
1174                 if (stack)
1175                 {
1176                         stack->Push(this->GetModeChar());
1177                 }
1178                 else
1179                 {
1180                         sprintf(moderemove,"-%c",this->GetModeChar());
1181                         parameters.push_back(channel->name);
1182                         parameters.push_back(moderemove);
1183                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1184                 }
1185         }
1186 }
1187
1188 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1189 {
1190         ModeHandler* modes[] =
1191         {
1192                 new ModeChannelSecret(Instance),
1193                 new ModeChannelPrivate(Instance),
1194                 new ModeChannelModerated(Instance),
1195                 new ModeChannelTopicOps(Instance),
1196                 new ModeChannelNoExternal(Instance),
1197                 new ModeChannelInviteOnly(Instance),
1198                 new ModeChannelKey(Instance),
1199                 new ModeChannelLimit(Instance),
1200                 new ModeChannelBan(Instance),
1201                 new ModeChannelOp(Instance),
1202                 new ModeChannelHalfOp(Instance),
1203                 new ModeChannelVoice(Instance),
1204                 new ModeUserWallops(Instance),
1205                 new ModeUserInvisible(Instance),
1206                 new ModeUserOperator(Instance),
1207                 new ModeUserServerNoticeMask(Instance),
1208                 NULL
1209         };
1210
1211         /* Clear mode handler list */
1212         memset(modehandlers, 0, sizeof(modehandlers));
1213
1214         /* Last parse string */
1215         LastParse.clear();
1216
1217         /* Initialise the RFC mode letters */
1218         for (int index = 0; modes[index]; index++)
1219                 this->AddMode(modes[index]);
1220
1221         seq = 0;
1222         memset(&sent, 0, sizeof(sent));
1223 }