]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Implement <disabled:usermodes> and <disabled:chanmodes>.
[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(ERR_NOSUCHNICK, "%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(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
326                 user->WriteNumeric(RPL_CHANNELCREATED, "%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(ERR_NOSUCHNICK, "%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(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
341                         if (IS_OPER(targetuser))
342                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
343                         return;
344                 }
345                 else
346                 {
347                         user->WriteNumeric(ERR_USERSDONTMATCH, "%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(ERR_NOSUCHNICK, "%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 (!IS_OPER(user))
416                                 {
417                                         if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
418                                         {
419                                                 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++);
420                                                 mh->DisplayEmptyList(user, targetchannel);
421                                                 continue;
422                                         }
423                                 }
424
425                                 /** See below for a description of what craq this is :D
426                                  */
427                                 unsigned char handler_id = (*mode - 65) | mask;
428
429                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
430                                 {
431                                         std::string dummyparam;
432                                         
433                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
434                                                 display = false;
435                                 }
436
437                                 if (display)
438                                         mh->DisplayList(user, targetchannel);
439                         }
440                         else
441                                 nonlistmodes_found++;
442
443                         mode++;
444                 }
445
446                 /* We didnt have any modes that were non-list, we can return here */
447                 if (!nonlistmodes_found)
448                         return;
449         }
450
451         if (parameters.size() == 1)
452         {
453                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
454         }
455         else if (parameters.size() > 1)
456         {
457                 bool SkipAccessChecks = false;
458
459                 if (targetchannel)
460                 {
461                         type = MODETYPE_CHANNEL;
462                         mask = MASK_CHANNEL;
463
464                         /* Extra security checks on channel modes
465                          * (e.g. are they a (half)op?
466                          */
467
468                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
469                         {
470                                 /* We don't have halfop */
471                                 int MOD_RESULT = 0;
472                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
473                                 if (MOD_RESULT == ACR_DENY)
474                                         return;
475                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
476                         }
477                 }
478                 else if (targetuser)
479                 {
480                         type = MODETYPE_USER;
481                         mask = MASK_USER;
482                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
483                         {
484                                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
485                                 return;
486                         }
487                 }
488                 else
489                 {
490                         /* No such nick/channel */
491                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
492                         return;
493                 }
494
495                 std::string mode_sequence = parameters[1];
496                 std::string parameter;
497                 std::ostringstream parameter_list;
498                 std::string output_sequence;
499                 bool adding = true, state_change = false;
500                 unsigned char handler_id = 0;
501                 unsigned int parameter_counter = 2; /* Index of first parameter */
502                 unsigned int parameter_count = 0;
503                 bool last_successful_state_change = false;
504
505                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
506                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
507                         mode_sequence.insert(0, "+");
508
509                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
510                 {
511                         unsigned char modechar = *letter;
512
513                         switch (modechar)
514                         {
515                                 /* NB:
516                                  * For + and - mode characters, we don't just stick the character into the output sequence.
517                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
518                                  * appearing in the output sequence, we store a flag which says there was a state change,
519                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
520                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
521                                  */
522                                 case '+':
523                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
524                                          * however, will allow the + if it is the first item in the sequence, regardless.
525                                          */
526                                         if ((!adding) || (!output_sequence.length()))
527                                                 state_change = true;
528                                         adding = true;
529                                         if (!output_sequence.length())
530                                                 last_successful_state_change = false;
531                                         continue;
532                                 break;
533                                 case '-':
534                                         if ((adding) || (!output_sequence.length()))
535                                                 state_change = true;
536                                         adding = false;
537                                         if (!output_sequence.length())
538                                                 last_successful_state_change = true;
539                                         continue;
540                                 break;
541                                 default:
542
543                                         /**
544                                          * Watch carefully for the sleight of hand trick.
545                                          * 65 is the ascii value of 'A'. We take this from
546                                          * the char we're looking at to get a number between
547                                          * 1 and 127. We then logic-or it to get the hashed
548                                          * position, dependent on wether its a channel or
549                                          * a user mode. This is a little stranger, but a lot
550                                          * faster, than using a map of pairs.
551                                          */
552                                         handler_id = (modechar - 65) | mask;
553
554                                         if (modehandlers[handler_id])
555                                         {
556                                                 bool abort = false;
557
558                                                 if (modehandlers[handler_id]->GetModeType() == type)
559                                                 {
560                                                         int MOD_RESULT = 0;
561
562                                                         if (modehandlers[handler_id]->GetNumParams(adding))
563                                                         {
564                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
565                                                                 if (parameter_counter < parameters.size())
566                                                                 {
567                                                                         parameter = parameters[parameter_counter++];
568
569                                                                         /* Yerk, invalid! */
570                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
571                                                                                 parameter.clear();
572                                                                 }
573                                                                 else
574                                                                 {
575                                                                         /* No parameter, continue to the next mode */
576                                                                         continue;
577                                                                 }
578
579                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
580                                                         }
581                                                         else
582                                                         {
583                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
584                                                         }
585
586                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
587                                                                 continue;
588
589                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
590                                                         {
591                                                                 /* Check access to this mode character */
592                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
593                                                                 {
594                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
595                                                                         ModeHandler* prefixmode = FindPrefix(needed);
596
597                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
598                                                                          * cannot be found, they probably dont have the right module loaded to implement
599                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
600                                                                          * Revert to checking against the minimum core prefix, '%'.
601                                                                          */
602                                                                         if (needed && !prefixmode)
603                                                                                 prefixmode = FindPrefix('%');
604                                                 
605                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
606                                                                         /* Compare our rank on the channel against the rank of the required prefix,
607                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
608                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
609                                                                          * first, so we don't need to iterate, we just look up the first instead.
610                                                                          */
611                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
612                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
613                                                                         ModeHandler* ourmode = FindPrefix(ml);
614                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
615                                                                         {
616                                                                                 /* Bog off */
617                                                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
618                                                                                                 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
619                                                                                 continue;
620                                                                         }
621                                                                 }
622                                                         }
623
624                                                         bool had_parameter = !parameter.empty();
625                                                                 
626                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
627                                                         {
628                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
629                                                                 {
630                                                                         abort = true;
631                                                                         break;
632                                                                 }
633                                                                 /* A module whacked the parameter completely, and there was one. abort. */
634                                                                 if ((had_parameter) && (parameter.empty()))
635                                                                 {
636                                                                         abort = true;
637                                                                         break;
638                                                                 }
639                                                         }
640
641                                                         if (abort)
642                                                                 continue;
643
644                                                         /* If it's disabled, they have to be an oper.
645                                                          */
646                                                         if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
647                                                         {
648                                                                 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
649                                                                                 user->nick.c_str(),
650                                                                                 type == MODETYPE_CHANNEL ? "channel" : "user",
651                                                                                 modehandlers[handler_id]->GetModeChar());
652                                                                 continue;
653                                                         }
654
655                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
656                                                          * eat any parameter that  came with the mode, and continue to next
657                                                          */
658                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
659                                                         {
660                                                                 if (IS_OPER(user))
661                                                                 {
662                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
663                                                                                         user->nick.c_str(),
664                                                                                         user->oper.c_str(),
665                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
666                                                                                         modehandlers[handler_id]->GetModeChar());
667                                                                 }
668                                                                 else
669                                                                 {
670                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
671                                                                                         user->nick.c_str(),
672                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
673                                                                                         modehandlers[handler_id]->GetModeChar());
674                                                                 }
675                                                                 continue;
676                                                         }
677
678                                                         /* Call the handler for the mode */
679                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
680
681                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
682                                                         {
683                                                                 /* The handler nuked the parameter and they are supposed to have one.
684                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
685                                                                  * so we bail to the next mode character.
686                                                                  */
687                                                                 continue;
688                                                         }
689
690                                                         if (ma == MODEACTION_ALLOW)
691                                                         {
692                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
693                                                                 if (state_change)
694                                                                 {
695                                                                         if (adding != last_successful_state_change)
696                                                                                 output_sequence.append(adding ? "+" : "-");
697                                                                         last_successful_state_change = adding;
698                                                                 }
699                                                                 
700                                                                 /* Add the mode letter */
701                                                                 output_sequence.push_back(modechar);
702
703                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
704
705                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
706                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
707                                                                 {
708                                                                         parameter_list << " " << parameter;
709                                                                         parameter_count++;
710                                                                         /* Does this mode have a prefix? */
711                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
712                                                                         {
713                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
714                                                                                 if (user_to_prefix)
715                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
716                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
717                                                                         }
718                                                                 }
719
720                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
721                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
722                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
723
724                                                                 /* Reset the state change flag */
725                                                                 state_change = false;
726
727                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
728                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
729                                                                 {
730                                                                         /* We cant have a mode sequence this long */
731                                                                         letter = mode_sequence.end() - 1;
732                                                                         continue;
733                                                                 }
734                                                         }
735                                                 }
736                                         }
737                                         else
738                                         {
739                                                 /* No mode handler? Unknown mode character then. */
740                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
741                                         }
742                                 break;
743                         }
744                 }
745
746                 /* Was there at least one valid mode in the sequence? */
747                 if (!output_sequence.empty())
748                 {
749                         if (servermode)
750                         {
751                                 if (type == MODETYPE_CHANNEL)
752                                 {
753                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
754                                         this->LastParse = targetchannel->name;
755                                 }
756                                 else
757                                 {
758                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
759                                         this->LastParse = targetuser->nick;
760                                 }
761                         }
762                         else
763                         {
764                                 if (type == MODETYPE_CHANNEL)
765                                 {
766                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
767                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
768                                         this->LastParse = targetchannel->name;
769                                 }
770                                 else
771                                 {
772                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
773                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
774                                         this->LastParse = targetuser->nick;
775                                 }
776                         }
777
778                         LastParse.append(" ");
779                         LastParse.append(output_sequence);
780                         LastParse.append(parameter_list.str());
781                 }
782         }
783 }
784
785 const std::string& ModeParser::GetLastParse()
786 {
787         return LastParse;
788 }
789
790 void ModeParser::CleanMask(std::string &mask)
791 {
792         std::string::size_type pos_of_pling = mask.find_first_of('!');
793         std::string::size_type pos_of_at = mask.find_first_of('@');
794         std::string::size_type pos_of_dot = mask.find_first_of('.');
795         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
796
797         if (mask.length() >= 2 && mask[1] == ':')
798                 return; // if it's an extban, don't even try guess how it needs to be formed.
799
800         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
801         {
802                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
803                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
804                 {
805                         /* It has no '.' in it, it must be a nick. */
806                         mask.append("!*@*");
807                 }
808                 else
809                 {
810                         /* Got a dot in it? Has to be a host */
811                         mask = "*!*@" + mask;
812                 }
813         }
814         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
815         {
816                 /* Has an @ but no !, its a user@host */
817                  mask = "*!" + mask;
818         }
819         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
820         {
821                 /* Has a ! but no @, it must be a nick!ident */
822                 mask.append("@*");
823         }
824 }
825
826 bool ModeParser::AddMode(ModeHandler* mh)
827 {
828         unsigned char mask = 0;
829         unsigned char pos = 0;
830
831         /* Yes, i know, this might let people declare modes like '_' or '^'.
832          * If they do that, thats their problem, and if i ever EVER see an
833          * official InspIRCd developer do that, i'll beat them with a paddle!
834          */
835         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
836                 return false;
837
838         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
839          * A mode prefix of ':' will fuck up both server to server, and client to server.
840          * A mode prefix of '#' will mess up /whois and /privmsg
841          */
842         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
843                 return false;
844
845         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
846         pos = (mh->GetModeChar()-65) | mask;
847
848         if (modehandlers[pos])
849                 return false;
850
851         modehandlers[pos] = mh;
852         return true;
853 }
854
855 bool ModeParser::DelMode(ModeHandler* mh)
856 {
857         unsigned char mask = 0;
858         unsigned char pos = 0;
859
860         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
861                 return false;
862
863         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
864         pos = (mh->GetModeChar()-65) | mask;
865
866         if (!modehandlers[pos])
867                 return false;
868
869         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
870          * To stack here we have to make the algorithm slower. Discuss.
871          */
872         switch (mh->GetModeType())
873         {
874                 case MODETYPE_USER:
875                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
876                         {
877                                 mh->RemoveMode(i->second);
878                         }
879                 break;
880                 case MODETYPE_CHANNEL:
881                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
882                         {
883                                 mh->RemoveMode(i->second);
884                         }
885                 break;
886         }
887
888         modehandlers[pos] = NULL;
889
890         return true;
891 }
892
893 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
894 {
895         unsigned char mask = 0;
896         unsigned char pos = 0;
897
898         if ((modeletter < 'A') || (modeletter > 'z'))
899                 return NULL;
900
901         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
902         pos = (modeletter-65) | mask;
903
904         return modehandlers[pos];
905 }
906
907 std::string ModeParser::UserModeList()
908 {
909         char modestr[256];
910         int pointer = 0;
911
912         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
913         {
914                 unsigned char pos = (mode-65) | MASK_USER;
915
916                 if (modehandlers[pos])
917                         modestr[pointer++] = mode;
918         }
919         modestr[pointer++] = 0;
920         return modestr;
921 }
922
923 std::string ModeParser::ChannelModeList()
924 {
925         char modestr[256];
926         int pointer = 0;
927
928         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
929         {
930                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
931                         continue;
932
933                 unsigned char pos = (mode-65) | MASK_CHANNEL;
934
935                 if (modehandlers[pos])
936                         modestr[pointer++] = mode;
937         }
938         modestr[pointer++] = 0;
939         return modestr;
940 }
941
942 std::string ModeParser::ParaModeList()
943 {
944         char modestr[256];
945         int pointer = 0;
946
947         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
948         {
949                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
950                         continue;
951
952                 unsigned char pos = (mode-65) | MASK_CHANNEL;
953
954                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
955                         modestr[pointer++] = mode;
956         }
957         modestr[pointer++] = 0;
958         return modestr;
959 }
960
961 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
962 {
963         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
964         {
965                 unsigned char pos = (mode-65) | MASK_CHANNEL;
966
967                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
968                 {
969                         return modehandlers[pos];
970                 }
971         }
972         return NULL;
973 }
974
975 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
976 {
977         std::string types;
978         std::string pars;
979
980         if (!channel || !user)
981                 return "";
982
983         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
984         {
985                 unsigned char pos = (mode-65) | MASK_CHANNEL;
986                 ModeHandler* mh = modehandlers[pos];
987                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
988                 {
989                         ModePair ret;
990                         ret = mh->ModeSet(NULL, user, channel, user->nick);
991                         if ((ret.first) && (ret.second == user->nick))
992                         {
993                                 if (nick_suffix)
994                                 {
995                                         pars.append(" ");
996                                         pars.append(user->nick);
997                                 }
998                                 types.push_back(mh->GetModeChar());
999                         }
1000                 }
1001         }
1002
1003         if (nick_suffix)
1004                 return types+pars;
1005         else
1006                 return types;
1007 }
1008
1009 std::string ModeParser::ChanModes()
1010 {
1011         std::string type1;      /* Listmodes EXCEPT those with a prefix */
1012         std::string type2;      /* Modes that take a param when adding or removing */
1013         std::string type3;      /* Modes that only take a param when adding */
1014         std::string type4;      /* Modes that dont take a param */
1015
1016         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1017         {
1018                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1019                         continue;
1020
1021                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1022                  /* One parameter when adding */
1023                 if (modehandlers[pos])
1024                 {       
1025                         if (modehandlers[pos]->GetNumParams(true))
1026                         {
1027                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1028                                 {
1029                                         type1 += modehandlers[pos]->GetModeChar();
1030                                 }
1031                                 else
1032                                 {
1033                                         /* ... and one parameter when removing */
1034                                         if (modehandlers[pos]->GetNumParams(false))
1035                                         {
1036                                                 /* But not a list mode */
1037                                                 if (!modehandlers[pos]->GetPrefix())
1038                                                 {
1039                                                         type2 += modehandlers[pos]->GetModeChar();
1040                                                 }
1041                                         }
1042                                         else
1043                                         {
1044                                                 /* No parameters when removing */
1045                                                 type3 += modehandlers[pos]->GetModeChar();
1046                                         }
1047                                 }
1048                         }
1049                         else
1050                         {
1051                                 type4 += modehandlers[pos]->GetModeChar();
1052                         }
1053                 }
1054                          
1055         }
1056
1057         return type1 + "," + type2 + "," + type3 + "," + type4;
1058 }
1059
1060 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1061 {       
1062         return one.second > two.second;
1063 }
1064
1065 std::string ModeParser::BuildPrefixes()
1066 {
1067         std::string mletters;
1068         std::string mprefixes;
1069         pfxcontainer pfx;
1070         std::map<char,char> prefix_to_mode;
1071
1072         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1073         {
1074                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1075                         continue;
1076
1077                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1078
1079                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1080                 {
1081                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1082                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1083                 }
1084         }
1085
1086         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1087
1088         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1089         {
1090                 mletters = mletters + n->first;
1091                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1092         }
1093
1094         return "(" + mprefixes + ")" + mletters;
1095 }
1096
1097 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1098 {
1099         unsigned char mask = 0;
1100         unsigned char pos = 0;
1101
1102         if (!mw)
1103                 return false;
1104
1105         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1106                 return false;
1107
1108         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1109         pos = (mw->GetModeChar()-65) | mask;
1110
1111         modewatchers[pos].push_back(mw);
1112
1113         return true;
1114 }
1115
1116 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1117 {
1118         unsigned char mask = 0;
1119         unsigned char pos = 0;
1120
1121         if (!mw)
1122                 return false;
1123
1124         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1125                 return false;
1126
1127         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1128         pos = (mw->GetModeChar()-65) | mask;
1129
1130         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1131
1132         if (a == modewatchers[pos].end())
1133         {
1134                 return false;
1135         }
1136
1137         modewatchers[pos].erase(a);
1138
1139         return true;
1140 }
1141
1142 /** This default implementation can remove simple user modes
1143  */
1144 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1145 {
1146         char moderemove[MAXBUF];
1147         std::vector<std::string> parameters;
1148
1149         if (user->IsModeSet(this->GetModeChar()))
1150         {
1151                 if (stack)
1152                 {
1153                         stack->Push(this->GetModeChar());
1154                 }
1155                 else
1156                 {
1157                         sprintf(moderemove,"-%c",this->GetModeChar());
1158                         parameters.push_back(user->nick);
1159                         parameters.push_back(moderemove);
1160                         ServerInstance->Parser->CallHandler("MODE", parameters, user);
1161                 }
1162         }
1163 }
1164
1165 /** This default implementation can remove simple channel modes
1166  * (no parameters)
1167  */
1168 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1169 {
1170         char moderemove[MAXBUF];
1171         std::vector<std::string> parameters;
1172
1173         if (channel->IsModeSet(this->GetModeChar()))
1174         {
1175                 if (stack)
1176                 {
1177                         stack->Push(this->GetModeChar());
1178                 }
1179                 else
1180                 {
1181                         sprintf(moderemove,"-%c",this->GetModeChar());
1182                         parameters.push_back(channel->name);
1183                         parameters.push_back(moderemove);
1184                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1185                 }
1186         }
1187 }
1188
1189 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1190 {
1191         ModeHandler* modes[] =
1192         {
1193                 new ModeChannelSecret(Instance),
1194                 new ModeChannelPrivate(Instance),
1195                 new ModeChannelModerated(Instance),
1196                 new ModeChannelTopicOps(Instance),
1197                 new ModeChannelNoExternal(Instance),
1198                 new ModeChannelInviteOnly(Instance),
1199                 new ModeChannelKey(Instance),
1200                 new ModeChannelLimit(Instance),
1201                 new ModeChannelBan(Instance),
1202                 new ModeChannelOp(Instance),
1203                 new ModeChannelHalfOp(Instance),
1204                 new ModeChannelVoice(Instance),
1205                 new ModeUserServerNotice(Instance),
1206                 new ModeUserWallops(Instance),
1207                 new ModeUserInvisible(Instance),
1208                 new ModeUserOperator(Instance),
1209                 new ModeUserServerNoticeMask(Instance),
1210                 NULL
1211         };
1212
1213         /* Clear mode handler list */
1214         memset(modehandlers, 0, sizeof(modehandlers));
1215
1216         /* Last parse string */
1217         LastParse.clear();
1218
1219         /* Initialise the RFC mode letters */
1220         for (int index = 0; modes[index]; index++)
1221                 this->AddMode(modes[index]);
1222
1223         seq = 0;
1224         memset(&sent, 0, 256);
1225 }