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