]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Convertage.
[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(RPL_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                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
645                                                          * eat any parameter that  came with the mode, and continue to next
646                                                          */
647                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
648                                                         {
649                                                                 if (IS_OPER(user))
650                                                                 {
651                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
652                                                                                         user->nick.c_str(),
653                                                                                         user->oper.c_str(),
654                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
655                                                                                         modehandlers[handler_id]->GetModeChar());
656                                                                 }
657                                                                 else
658                                                                 {
659                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
660                                                                                         user->nick.c_str(),
661                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
662                                                                                         modehandlers[handler_id]->GetModeChar());
663                                                                 }
664                                                                 continue;
665                                                         }
666
667                                                         /* Call the handler for the mode */
668                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
669
670                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
671                                                         {
672                                                                 /* The handler nuked the parameter and they are supposed to have one.
673                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
674                                                                  * so we bail to the next mode character.
675                                                                  */
676                                                                 continue;
677                                                         }
678
679                                                         if (ma == MODEACTION_ALLOW)
680                                                         {
681                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
682                                                                 if (state_change)
683                                                                 {
684                                                                         if (adding != last_successful_state_change)
685                                                                                 output_sequence.append(adding ? "+" : "-");
686                                                                         last_successful_state_change = adding;
687                                                                 }
688                                                                 
689                                                                 /* Add the mode letter */
690                                                                 output_sequence.push_back(modechar);
691
692                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
693
694                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
695                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
696                                                                 {
697                                                                         parameter_list << " " << parameter;
698                                                                         parameter_count++;
699                                                                         /* Does this mode have a prefix? */
700                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
701                                                                         {
702                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
703                                                                                 if (user_to_prefix)
704                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
705                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
706                                                                         }
707                                                                 }
708
709                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
710                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
711                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
712
713                                                                 /* Reset the state change flag */
714                                                                 state_change = false;
715
716                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
717                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
718                                                                 {
719                                                                         /* We cant have a mode sequence this long */
720                                                                         letter = mode_sequence.end() - 1;
721                                                                         continue;
722                                                                 }
723                                                         }
724                                                 }
725                                         }
726                                         else
727                                         {
728                                                 /* No mode handler? Unknown mode character then. */
729                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
730                                         }
731                                 break;
732                         }
733                 }
734
735                 /* Was there at least one valid mode in the sequence? */
736                 if (!output_sequence.empty())
737                 {
738                         if (servermode)
739                         {
740                                 if (type == MODETYPE_CHANNEL)
741                                 {
742                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
743                                         this->LastParse = targetchannel->name;
744                                 }
745                                 else
746                                 {
747                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
748                                         this->LastParse = targetuser->nick;
749                                 }
750                         }
751                         else
752                         {
753                                 if (type == MODETYPE_CHANNEL)
754                                 {
755                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
756                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
757                                         this->LastParse = targetchannel->name;
758                                 }
759                                 else
760                                 {
761                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
762                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
763                                         this->LastParse = targetuser->nick;
764                                 }
765                         }
766
767                         LastParse.append(" ");
768                         LastParse.append(output_sequence);
769                         LastParse.append(parameter_list.str());
770                 }
771         }
772 }
773
774 const std::string& ModeParser::GetLastParse()
775 {
776         return LastParse;
777 }
778
779 void ModeParser::CleanMask(std::string &mask)
780 {
781         std::string::size_type pos_of_pling = mask.find_first_of('!');
782         std::string::size_type pos_of_at = mask.find_first_of('@');
783         std::string::size_type pos_of_dot = mask.find_first_of('.');
784         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
785
786         if (mask.length() >= 2 && mask[1] == ':')
787                 return; // if it's an extban, don't even try guess how it needs to be formed.
788
789         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
790         {
791                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
792                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
793                 {
794                         /* It has no '.' in it, it must be a nick. */
795                         mask.append("!*@*");
796                 }
797                 else
798                 {
799                         /* Got a dot in it? Has to be a host */
800                         mask = "*!*@" + mask;
801                 }
802         }
803         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
804         {
805                 /* Has an @ but no !, its a user@host */
806                  mask = "*!" + mask;
807         }
808         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
809         {
810                 /* Has a ! but no @, it must be a nick!ident */
811                 mask.append("@*");
812         }
813 }
814
815 bool ModeParser::AddMode(ModeHandler* mh)
816 {
817         unsigned char mask = 0;
818         unsigned char pos = 0;
819
820         /* Yes, i know, this might let people declare modes like '_' or '^'.
821          * If they do that, thats their problem, and if i ever EVER see an
822          * official InspIRCd developer do that, i'll beat them with a paddle!
823          */
824         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
825                 return false;
826
827         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
828          * A mode prefix of ':' will fuck up both server to server, and client to server.
829          * A mode prefix of '#' will mess up /whois and /privmsg
830          */
831         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
832                 return false;
833
834         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
835         pos = (mh->GetModeChar()-65) | mask;
836
837         if (modehandlers[pos])
838                 return false;
839
840         modehandlers[pos] = mh;
841         return true;
842 }
843
844 bool ModeParser::DelMode(ModeHandler* mh)
845 {
846         unsigned char mask = 0;
847         unsigned char pos = 0;
848
849         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
850                 return false;
851
852         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
853         pos = (mh->GetModeChar()-65) | mask;
854
855         if (!modehandlers[pos])
856                 return false;
857
858         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
859          * To stack here we have to make the algorithm slower. Discuss.
860          */
861         switch (mh->GetModeType())
862         {
863                 case MODETYPE_USER:
864                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
865                         {
866                                 mh->RemoveMode(i->second);
867                         }
868                 break;
869                 case MODETYPE_CHANNEL:
870                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
871                         {
872                                 mh->RemoveMode(i->second);
873                         }
874                 break;
875         }
876
877         modehandlers[pos] = NULL;
878
879         return true;
880 }
881
882 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
883 {
884         unsigned char mask = 0;
885         unsigned char pos = 0;
886
887         if ((modeletter < 'A') || (modeletter > 'z'))
888                 return NULL;
889
890         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
891         pos = (modeletter-65) | mask;
892
893         return modehandlers[pos];
894 }
895
896 std::string ModeParser::UserModeList()
897 {
898         char modestr[256];
899         int pointer = 0;
900
901         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
902         {
903                 unsigned char pos = (mode-65) | MASK_USER;
904
905                 if (modehandlers[pos])
906                         modestr[pointer++] = mode;
907         }
908         modestr[pointer++] = 0;
909         return modestr;
910 }
911
912 std::string ModeParser::ChannelModeList()
913 {
914         char modestr[256];
915         int pointer = 0;
916
917         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
918         {
919                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
920                         continue;
921
922                 unsigned char pos = (mode-65) | MASK_CHANNEL;
923
924                 if (modehandlers[pos])
925                         modestr[pointer++] = mode;
926         }
927         modestr[pointer++] = 0;
928         return modestr;
929 }
930
931 std::string ModeParser::ParaModeList()
932 {
933         char modestr[256];
934         int pointer = 0;
935
936         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
937         {
938                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
939                         continue;
940
941                 unsigned char pos = (mode-65) | MASK_CHANNEL;
942
943                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
944                         modestr[pointer++] = mode;
945         }
946         modestr[pointer++] = 0;
947         return modestr;
948 }
949
950 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
951 {
952         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
953         {
954                 unsigned char pos = (mode-65) | MASK_CHANNEL;
955
956                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
957                 {
958                         return modehandlers[pos];
959                 }
960         }
961         return NULL;
962 }
963
964 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
965 {
966         std::string types;
967         std::string pars;
968
969         if (!channel || !user)
970                 return "";
971
972         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
973         {
974                 unsigned char pos = (mode-65) | MASK_CHANNEL;
975                 ModeHandler* mh = modehandlers[pos];
976                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
977                 {
978                         ModePair ret;
979                         ret = mh->ModeSet(NULL, user, channel, user->nick);
980                         if ((ret.first) && (ret.second == user->nick))
981                         {
982                                 if (nick_suffix)
983                                 {
984                                         pars.append(" ");
985                                         pars.append(user->nick);
986                                 }
987                                 types.push_back(mh->GetModeChar());
988                         }
989                 }
990         }
991
992         if (nick_suffix)
993                 return types+pars;
994         else
995                 return types;
996 }
997
998 std::string ModeParser::ChanModes()
999 {
1000         std::string type1;      /* Listmodes EXCEPT those with a prefix */
1001         std::string type2;      /* Modes that take a param when adding or removing */
1002         std::string type3;      /* Modes that only take a param when adding */
1003         std::string type4;      /* Modes that dont take a param */
1004
1005         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1006         {
1007                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1008                         continue;
1009
1010                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1011                  /* One parameter when adding */
1012                 if (modehandlers[pos])
1013                 {       
1014                         if (modehandlers[pos]->GetNumParams(true))
1015                         {
1016                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1017                                 {
1018                                         type1 += modehandlers[pos]->GetModeChar();
1019                                 }
1020                                 else
1021                                 {
1022                                         /* ... and one parameter when removing */
1023                                         if (modehandlers[pos]->GetNumParams(false))
1024                                         {
1025                                                 /* But not a list mode */
1026                                                 if (!modehandlers[pos]->GetPrefix())
1027                                                 {
1028                                                         type2 += modehandlers[pos]->GetModeChar();
1029                                                 }
1030                                         }
1031                                         else
1032                                         {
1033                                                 /* No parameters when removing */
1034                                                 type3 += modehandlers[pos]->GetModeChar();
1035                                         }
1036                                 }
1037                         }
1038                         else
1039                         {
1040                                 type4 += modehandlers[pos]->GetModeChar();
1041                         }
1042                 }
1043                          
1044         }
1045
1046         return type1 + "," + type2 + "," + type3 + "," + type4;
1047 }
1048
1049 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1050 {       
1051         return one.second > two.second;
1052 }
1053
1054 std::string ModeParser::BuildPrefixes()
1055 {
1056         std::string mletters;
1057         std::string mprefixes;
1058         pfxcontainer pfx;
1059         std::map<char,char> prefix_to_mode;
1060
1061         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1062         {
1063                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1064                         continue;
1065
1066                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1067
1068                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1069                 {
1070                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1071                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1072                 }
1073         }
1074
1075         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1076
1077         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1078         {
1079                 mletters = mletters + n->first;
1080                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1081         }
1082
1083         return "(" + mprefixes + ")" + mletters;
1084 }
1085
1086 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1087 {
1088         unsigned char mask = 0;
1089         unsigned char pos = 0;
1090
1091         if (!mw)
1092                 return false;
1093
1094         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1095                 return false;
1096
1097         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1098         pos = (mw->GetModeChar()-65) | mask;
1099
1100         modewatchers[pos].push_back(mw);
1101
1102         return true;
1103 }
1104
1105 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1106 {
1107         unsigned char mask = 0;
1108         unsigned char pos = 0;
1109
1110         if (!mw)
1111                 return false;
1112
1113         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1114                 return false;
1115
1116         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1117         pos = (mw->GetModeChar()-65) | mask;
1118
1119         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1120
1121         if (a == modewatchers[pos].end())
1122         {
1123                 return false;
1124         }
1125
1126         modewatchers[pos].erase(a);
1127
1128         return true;
1129 }
1130
1131 /** This default implementation can remove simple user modes
1132  */
1133 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1134 {
1135         char moderemove[MAXBUF];
1136         std::vector<std::string> parameters;
1137
1138         if (user->IsModeSet(this->GetModeChar()))
1139         {
1140                 if (stack)
1141                 {
1142                         stack->Push(this->GetModeChar());
1143                 }
1144                 else
1145                 {
1146                         sprintf(moderemove,"-%c",this->GetModeChar());
1147                         parameters.push_back(user->nick);
1148                         parameters.push_back(moderemove);
1149                         ServerInstance->Parser->CallHandler("MODE", parameters, user);
1150                 }
1151         }
1152 }
1153
1154 /** This default implementation can remove simple channel modes
1155  * (no parameters)
1156  */
1157 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1158 {
1159         char moderemove[MAXBUF];
1160         std::vector<std::string> parameters;
1161
1162         if (channel->IsModeSet(this->GetModeChar()))
1163         {
1164                 if (stack)
1165                 {
1166                         stack->Push(this->GetModeChar());
1167                 }
1168                 else
1169                 {
1170                         sprintf(moderemove,"-%c",this->GetModeChar());
1171                         parameters.push_back(channel->name);
1172                         parameters.push_back(moderemove);
1173                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1174                 }
1175         }
1176 }
1177
1178 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1179 {
1180         ModeHandler* modes[] =
1181         {
1182                 new ModeChannelSecret(Instance),
1183                 new ModeChannelPrivate(Instance),
1184                 new ModeChannelModerated(Instance),
1185                 new ModeChannelTopicOps(Instance),
1186                 new ModeChannelNoExternal(Instance),
1187                 new ModeChannelInviteOnly(Instance),
1188                 new ModeChannelKey(Instance),
1189                 new ModeChannelLimit(Instance),
1190                 new ModeChannelBan(Instance),
1191                 new ModeChannelOp(Instance),
1192                 new ModeChannelHalfOp(Instance),
1193                 new ModeChannelVoice(Instance),
1194                 new ModeUserServerNotice(Instance),
1195                 new ModeUserWallops(Instance),
1196                 new ModeUserInvisible(Instance),
1197                 new ModeUserOperator(Instance),
1198                 new ModeUserServerNoticeMask(Instance),
1199                 NULL
1200         };
1201
1202         /* Clear mode handler list */
1203         memset(modehandlers, 0, sizeof(modehandlers));
1204
1205         /* Last parse string */
1206         LastParse.clear();
1207
1208         /* Initialise the RFC mode letters */
1209         for (int index = 0; modes[index]; index++)
1210                 this->AddMode(modes[index]);
1211
1212         seq = 0;
1213         memset(&sent, 0, 256);
1214 }