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