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