]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Someone please help me fix the warnings in modules caused by this change. All mode...
[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->Log(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->WriteServ("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->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261                 user->WriteServ("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->WriteServ("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->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
276                         if (IS_OPER(targetuser))
277                                 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
278                         return;
279                 }
280                 else
281                 {
282                         user->WriteServ("502 %s :Can't change mode for other users", user->nick);
283                         return;
284                 }
285         }
286
287         /* No such nick/channel */
288         user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
289         return;
290 }
291
292 void ModeParser::Process(const char** 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->WriteServ("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->WriteServ("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->WriteServ("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                                                                 ServerInstance->Log(DEBUG,"Enter minimum prefix check");
525                                                                 /* Check access to this mode character */
526                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
527                                                                 {
528                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
529                                                                         ModeHandler* prefixmode = FindPrefix(needed);
530                                                                         ServerInstance->Log(DEBUG,"Needed prefix: %c", needed);
531
532                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
533                                                                          * cannot be found, they probably dont have the right module loaded to implement
534                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
535                                                                          * Revert to checking against the minimum core prefix, '%'.
536                                                                          */
537                                                                         if (needed && !prefixmode)
538                                                                                 prefixmode = FindPrefix('%');
539                                                 
540                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
541                                                                         /* Compare our rank on the channel against the rank of the required prefix,
542                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
543                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
544                                                                          * first, so we don't need to iterate, we just look up the first instead.
545                                                                          */
546                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
547                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
548                                                                         ModeHandler* ourmode = FindPrefix(ml);
549                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
550                                                                         {
551                                                                                 /* Bog off */
552                                                                                 user->WriteServ("482 %s %s :You must have channel privilege %c or above to %sset channel mode %c",
553                                                                                                 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
554                                                                                 continue;
555                                                                         }
556                                                                 }
557                                                         }
558
559                                                         bool had_parameter = !parameter.empty();
560                                                                 
561                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
562                                                         {
563                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
564                                                                 {
565                                                                         abort = true;
566                                                                         break;
567                                                                 }
568                                                                 /* A module whacked the parameter completely, and there was one. abort. */
569                                                                 if ((had_parameter) && (parameter.empty()))
570                                                                 {
571                                                                         abort = true;
572                                                                         break;
573                                                                 }
574                                                         }
575
576                                                         if (abort)
577                                                                 continue;
578
579                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
580                                                          * eat any parameter that  came with the mode, and continue to next
581                                                          */
582                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
583                                                         {
584                                                                 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
585                                                                                 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
586                                                                                 modehandlers[handler_id]->GetModeChar());
587                                                                 continue;
588                                                         }
589
590                                                         /* Call the handler for the mode */
591                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
592
593                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
594                                                         {
595                                                                 /* The handler nuked the parameter and they are supposed to have one.
596                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
597                                                                  * so we bail to the next mode character.
598                                                                  */
599                                                                 continue;
600                                                         }
601
602                                                         if (ma == MODEACTION_ALLOW)
603                                                         {
604                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
605                                                                 if (state_change)
606                                                                 {
607                                                                         if (adding != last_successful_state_change)
608                                                                                 output_sequence.append(adding ? "+" : "-");
609                                                                         last_successful_state_change = adding;
610                                                                 }
611                                                                 
612                                                                 /* Add the mode letter */
613                                                                 output_sequence.push_back(modechar);
614
615                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
616
617                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
618                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
619                                                                 {
620                                                                         parameter_list << " " << parameter;
621                                                                         parameter_count++;
622                                                                         /* Does this mode have a prefix? */
623                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
624                                                                         {
625                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
626                                                                                 if (user_to_prefix)
627                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
628                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
629                                                                         }
630                                                                 }
631
632                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
633                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
634                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
635
636                                                                 /* Reset the state change flag */
637                                                                 state_change = false;
638
639                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
640                                                                                 || (parameter_count > MAXMODES))
641                                                                 {
642                                                                         /* We cant have a mode sequence this long */
643                                                                         letter = mode_sequence.end() - 1;
644                                                                         continue;
645                                                                 }
646                                                         }
647                                                 }
648                                         }
649                                         else
650                                         {
651                                                 /* No mode handler? Unknown mode character then. */
652                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
653                                         }
654                                 break;
655                         }
656                 }
657
658                 /* Was there at least one valid mode in the sequence? */
659                 if (!output_sequence.empty())
660                 {
661                         if (servermode)
662                         {
663                                 if (type == MODETYPE_CHANNEL)
664                                 {
665                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
666                                         this->LastParse = targetchannel->name;
667                                 }
668                                 else
669                                 {
670                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
671                                         this->LastParse = targetuser->nick;
672                                 }
673                         }
674                         else
675                         {
676                                 if (type == MODETYPE_CHANNEL)
677                                 {
678                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
679                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
680                                         this->LastParse = targetchannel->name;
681                                 }
682                                 else
683                                 {
684                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
685                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
686                                         this->LastParse = targetuser->nick;
687                                 }
688                         }
689
690                         LastParse.append(" ");
691                         LastParse.append(output_sequence);
692                         LastParse.append(parameter_list.str());
693                 }
694         }
695 }
696
697 const std::string& ModeParser::GetLastParse()
698 {
699         return LastParse;
700 }
701
702 void ModeParser::CleanMask(std::string &mask)
703 {
704         std::string::size_type pos_of_pling = mask.find_first_of('!');
705         std::string::size_type pos_of_at = mask.find_first_of('@');
706         std::string::size_type pos_of_dot = mask.find_first_of('.');
707         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
708
709         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
710         {
711                 /* Just a nick, or just a host */
712                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
713                 {
714                         /* It has no '.' in it, it must be a nick. */
715                         mask.append("!*@*");
716                 }
717                 else
718                 {
719                         /* Got a dot in it? Has to be a host */
720                         mask = "*!*@" + mask;
721                 }
722         }
723         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
724         {
725                 /* Has an @ but no !, its a user@host */
726                  mask = "*!" + mask;
727         }
728         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
729         {
730                 /* Has a ! but no @, it must be a nick!ident */
731                 mask.append("@*");
732         }
733 }
734
735 bool ModeParser::AddMode(ModeHandler* mh)
736 {
737         unsigned char mask = 0;
738         unsigned char pos = 0;
739
740         /* Yes, i know, this might let people declare modes like '_' or '^'.
741          * If they do that, thats their problem, and if i ever EVER see an
742          * official InspIRCd developer do that, i'll beat them with a paddle!
743          */
744         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
745                 return false;
746
747         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
748          * A mode prefix of ':' will fuck up both server to server, and client to server.
749          * A mode prefix of '#' will mess up /whois and /privmsg
750          */
751         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
752                 return false;
753
754         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
755         pos = (mh->GetModeChar()-65) | mask;
756
757         if (modehandlers[pos])
758                 return false;
759
760         modehandlers[pos] = mh;
761         return true;
762 }
763
764 bool ModeParser::DelMode(ModeHandler* mh)
765 {
766         unsigned char mask = 0;
767         unsigned char pos = 0;
768
769         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
770                 return false;
771
772         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
773         pos = (mh->GetModeChar()-65) | mask;
774
775         if (!modehandlers[pos])
776                 return false;
777
778         switch (mh->GetModeType())
779         {
780                 case MODETYPE_USER:
781                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
782                         {
783                                 mh->RemoveMode(i->second);
784                         }
785                 break;
786                 case MODETYPE_CHANNEL:
787                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
788                         {
789                                 mh->RemoveMode(i->second);
790                         }
791                 break;
792         }
793
794         modehandlers[pos] = NULL;
795
796         return true;
797 }
798
799 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
800 {
801         unsigned char mask = 0;
802         unsigned char pos = 0;
803
804         if ((modeletter < 'A') || (modeletter > 'z'))
805                 return NULL;
806
807         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
808         pos = (modeletter-65) | mask;
809
810         return modehandlers[pos];
811 }
812
813 std::string ModeParser::UserModeList()
814 {
815         char modestr[256];
816         int pointer = 0;
817
818         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
819         {
820                 unsigned char pos = (mode-65) | MASK_USER;
821
822                 if (modehandlers[pos])
823                         modestr[pointer++] = mode;
824         }
825         modestr[pointer++] = 0;
826         return modestr;
827 }
828
829 std::string ModeParser::ChannelModeList()
830 {
831         char modestr[256];
832         int pointer = 0;
833
834         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
835         {
836                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
837                         continue;
838
839                 unsigned char pos = (mode-65) | MASK_CHANNEL;
840
841                 if (modehandlers[pos])
842                         modestr[pointer++] = mode;
843         }
844         modestr[pointer++] = 0;
845         return modestr;
846 }
847
848 std::string ModeParser::ParaModeList()
849 {
850         char modestr[256];
851         int pointer = 0;
852
853         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
854         {
855                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
856                         continue;
857
858                 unsigned char pos = (mode-65) | MASK_CHANNEL;
859
860                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
861                         modestr[pointer++] = mode;
862         }
863         modestr[pointer++] = 0;
864         return modestr;
865 }
866
867 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
868 {
869         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
870         {
871                 unsigned char pos = (mode-65) | MASK_CHANNEL;
872
873                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
874                 {
875                         return modehandlers[pos];
876                 }
877         }
878         return NULL;
879 }
880
881 std::string ModeParser::ModeString(User* user, Channel* channel)
882 {
883         std::string types;
884         std::string pars;
885
886         if (!channel || !user)
887                 return "";
888
889         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
890         {
891                 unsigned char pos = (mode-65) | MASK_CHANNEL;
892                 ModeHandler* mh = modehandlers[pos];
893                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
894                 {
895                         ModePair ret;
896                         ret = mh->ModeSet(NULL, user, channel, user->nick);
897                         if ((ret.first) && (ret.second == user->nick))
898                         {
899                                 pars.append(" ");
900                                 pars.append(user->nick);
901                                 types.push_back(mh->GetModeChar());
902                         }
903                 }
904         }
905
906         return types+pars;
907 }
908
909 std::string ModeParser::ChanModes()
910 {
911         std::string type1;      /* Listmodes EXCEPT those with a prefix */
912         std::string type2;      /* Modes that take a param when adding or removing */
913         std::string type3;      /* Modes that only take a param when adding */
914         std::string type4;      /* Modes that dont take a param */
915
916         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
917         {
918                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
919                         continue;
920
921                 unsigned char pos = (mode-65) | MASK_CHANNEL;
922                  /* One parameter when adding */
923                 if (modehandlers[pos])
924                 {       
925                         if (modehandlers[pos]->GetNumParams(true))
926                         {
927                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
928                                 {
929                                         type1 += modehandlers[pos]->GetModeChar();
930                                 }
931                                 else
932                                 {
933                                         /* ... and one parameter when removing */
934                                         if (modehandlers[pos]->GetNumParams(false))
935                                         {
936                                                 /* But not a list mode */
937                                                 if (!modehandlers[pos]->GetPrefix())
938                                                 {
939                                                         type2 += modehandlers[pos]->GetModeChar();
940                                                 }
941                                         }
942                                         else
943                                         {
944                                                 /* No parameters when removing */
945                                                 type3 += modehandlers[pos]->GetModeChar();
946                                         }
947                                 }
948                         }
949                         else
950                         {
951                                 type4 += modehandlers[pos]->GetModeChar();
952                         }
953                 }
954                          
955         }
956
957         return type1 + "," + type2 + "," + type3 + "," + type4;
958 }
959
960 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
961 {       
962         return one.second > two.second;
963 }
964
965 std::string ModeParser::BuildPrefixes()
966 {
967         std::string mletters;
968         std::string mprefixes;
969         pfxcontainer pfx;
970         std::map<char,char> prefix_to_mode;
971
972         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
973         {
974                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
975                         continue;
976
977                 unsigned char pos = (mode-65) | MASK_CHANNEL;
978
979                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
980                 {
981                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
982                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
983                 }
984         }
985
986         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
987
988         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
989         {
990                 mletters = mletters + n->first;
991                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
992         }
993
994         return "(" + mprefixes + ")" + mletters;
995 }
996
997 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
998 {
999         unsigned char mask = 0;
1000         unsigned char pos = 0;
1001
1002         if (!mw)
1003                 return false;
1004
1005         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1006                 return false;
1007
1008         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1009         pos = (mw->GetModeChar()-65) | mask;
1010
1011         modewatchers[pos].push_back(mw);
1012
1013         return true;
1014 }
1015
1016 bool ModeParser::DelModeWatcher(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         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1031
1032         if (a == modewatchers[pos].end())
1033         {
1034                 return false;
1035         }
1036
1037         modewatchers[pos].erase(a);
1038
1039         return true;
1040 }
1041
1042 /** This default implementation can remove simple user modes
1043  */
1044 void ModeHandler::RemoveMode(User* user)
1045 {
1046         char moderemove[MAXBUF];
1047         const char* parameters[] = { user->nick, moderemove };
1048
1049         if (user->IsModeSet(this->GetModeChar()))
1050         {
1051                 sprintf(moderemove,"-%c",this->GetModeChar());
1052                 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1053         }
1054 }
1055
1056 /** This default implementation can remove simple channel modes
1057  * (no parameters)
1058  */
1059 void ModeHandler::RemoveMode(Channel* channel)
1060 {
1061         char moderemove[MAXBUF];
1062         const char* parameters[] = { channel->name, moderemove };
1063
1064         if (channel->IsModeSet(this->GetModeChar()))
1065         {
1066                 sprintf(moderemove,"-%c",this->GetModeChar());
1067                 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1068         }
1069 }
1070
1071 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1072 {
1073         ModeHandler* modes[] =
1074         {
1075                 new ModeChannelSecret(Instance),
1076                 new ModeChannelPrivate(Instance),
1077                 new ModeChannelModerated(Instance),
1078                 new ModeChannelTopicOps(Instance),
1079                 new ModeChannelNoExternal(Instance),
1080                 new ModeChannelInviteOnly(Instance),
1081                 new ModeChannelKey(Instance),
1082                 new ModeChannelLimit(Instance),
1083                 new ModeChannelBan(Instance),
1084                 new ModeChannelOp(Instance),
1085                 new ModeChannelHalfOp(Instance),
1086                 new ModeChannelVoice(Instance),
1087                 new ModeUserServerNotice(Instance),
1088                 new ModeUserWallops(Instance),
1089                 new ModeUserInvisible(Instance),
1090                 new ModeUserOperator(Instance),
1091                 new ModeUserServerNoticeMask(Instance),
1092                 NULL
1093         };
1094
1095         /* Clear mode list */
1096         memset(modehandlers, 0, sizeof(modehandlers));
1097         memset(modewatchers, 0, sizeof(modewatchers));
1098
1099         /* Last parse string */
1100         LastParse.clear();
1101
1102         /* Initialise the RFC mode letters */
1103         for (int index = 0; modes[index]; index++)
1104                 this->AddMode(modes[index]);
1105 }