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