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