]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Remove last vestige of libircdfoo, by changing tag into a single identifier marking...
[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 */
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 /* +w (see wallops) */
47 #include "modes/umode_w.h"
48 /* +i (invisible) */
49 #include "modes/umode_i.h"
50 /* +o (operator) */
51 #include "modes/umode_o.h"
52 /* +s (server notice masks) */
53 #include "modes/umode_s.h"
54
55 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
56         : 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)
57 {
58 }
59
60 ModeHandler::~ModeHandler()
61 {
62 }
63
64 bool ModeHandler::IsListMode()
65 {
66         return list;
67 }
68
69 char ModeHandler::GetNeededPrefix()
70 {
71         return prefixneeded;
72 }
73
74 void ModeHandler::SetNeededPrefix(char needsprefix)
75 {
76         prefixneeded = needsprefix;
77 }
78
79 unsigned int ModeHandler::GetPrefixRank()
80 {
81         return 0;
82 }
83
84 unsigned int ModeHandler::GetCount()
85 {
86         return 0;
87 }
88
89 void ModeHandler::ChangeCount(int modifier)
90 {
91         count += modifier;
92         ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
93 }
94
95 ModeType ModeHandler::GetModeType()
96 {
97         return m_type;
98 }
99
100 bool ModeHandler::NeedsOper()
101 {
102         return oper;
103 }
104
105 char ModeHandler::GetPrefix()
106 {
107         return prefix;
108 }
109
110 int ModeHandler::GetNumParams(bool adding)
111 {
112         return adding ? n_params_on : n_params_off;
113 }
114
115 char ModeHandler::GetModeChar()
116 {
117         return mode;
118 }
119
120 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
121 {
122         return MODEACTION_DENY;
123 }
124
125 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
126 {
127         if (dest)
128         {
129                 return std::make_pair(dest->IsModeSet(this->mode), "");
130         }
131         else
132         {
133                 return std::make_pair(channel->IsModeSet(this->mode), "");
134         }
135 }
136
137 void ModeHandler::DisplayList(User*, Channel*)
138 {
139 }
140
141 void ModeHandler::DisplayEmptyList(User*, Channel*)
142 {
143 }
144
145 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
146 {
147         return (ours < theirs);
148 }
149
150 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
151 {
152 }
153
154 SimpleUserModeHandler::~SimpleUserModeHandler()
155 {
156 }
157
158 SimpleChannelModeHandler::~SimpleChannelModeHandler()
159 {
160 }
161
162 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
163 {
164 }
165
166 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
167 {
168         /* Only opers can change other users modes */
169         if (source != dest)
170                 return MODEACTION_DENY;
171
172         if (adding)
173         {
174                 if (!dest->IsModeSet(this->GetModeChar()))
175                 {
176                         dest->SetMode(this->GetModeChar(),true);
177                         return MODEACTION_ALLOW;
178                 }
179         }
180         else
181         {
182                 if (dest->IsModeSet(this->GetModeChar()))
183                 {
184                         dest->SetMode(this->GetModeChar(),false);
185                         return MODEACTION_ALLOW;
186                 }
187         }
188
189         return MODEACTION_DENY;
190 }
191
192
193 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
194 {
195         if (adding)
196         {
197                 if (!channel->IsModeSet(this->GetModeChar()))
198                 {
199                         channel->SetMode(this->GetModeChar(),true);
200                         return MODEACTION_ALLOW;
201                 }
202         }
203         else
204         {
205                 if (channel->IsModeSet(this->GetModeChar()))
206                 {
207                         channel->SetMode(this->GetModeChar(),false);
208                         return MODEACTION_ALLOW;
209                 }
210         }
211
212         return MODEACTION_DENY;
213 }
214
215 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
216 {
217 }
218
219 ModeWatcher::~ModeWatcher()
220 {
221 }
222
223 char ModeWatcher::GetModeChar()
224 {
225         return mode;
226 }
227
228 ModeType ModeWatcher::GetModeType()
229 {
230         return m_type;
231 }
232
233 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
234 {
235         return true;
236 }
237
238 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
239 {
240 }
241
242 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
243 {
244         User *d;
245         if ((!user) || (!dest) || (!chan) || (!*dest))
246         {
247                 return NULL;
248         }
249         d = ServerInstance->FindNick(dest);
250         if (!d)
251         {
252                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
253                 return NULL;
254         }
255         return d;
256 }
257
258 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
259 {
260         if (!chan)
261                 return "";
262
263         UCListIter n = d->chans.find(chan);
264         if (n != d->chans.end())
265         {
266                 if (n->second & MASK)
267                 {
268                         return "";
269                 }
270                 n->second = n->second | MASK;
271                 switch (MASK)
272                 {
273                         case UCMODE_OP:
274                                 n->first->AddOppedUser(d);
275                         break;
276                         case UCMODE_HOP:
277                                 n->first->AddHalfoppedUser(d);
278                         break;
279                         case UCMODE_VOICE:
280                                 n->first->AddVoicedUser(d);
281                         break;
282                 }
283                 return d->nick.c_str();
284         }
285         return "";
286 }
287
288 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
289 {
290         if (!chan)
291                 return "";
292
293         UCListIter n = d->chans.find(chan);
294         if (n != d->chans.end())
295         {
296                 if ((n->second & MASK) == 0)
297                 {
298                         return "";
299                 }
300                 n->second ^= MASK;
301                 switch (MASK)
302                 {
303                         case UCMODE_OP:
304                                 n->first->DelOppedUser(d);
305                         break;
306                         case UCMODE_HOP:
307                                 n->first->DelHalfoppedUser(d);
308                         break;
309                         case UCMODE_VOICE:
310                                 n->first->DelVoicedUser(d);
311                         break;
312                 }
313                 return d->nick.c_str();
314         }
315         return "";
316 }
317
318 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
319 {
320         if (targetchannel)
321         {
322                 /* Display channel's current mode string */
323                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
324                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
325                 return;
326         }
327         else if (targetuser)
328         {
329                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
330                 {
331                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
332                         return;
333                 }
334
335                 if ((targetuser == user) || (IS_OPER(user)))
336                 {
337                         /* Display user's current mode string */
338                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
339                         if (IS_OPER(targetuser))
340                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
341                         return;
342                 }
343                 else
344                 {
345                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
346                         return;
347                 }
348         }
349
350         /* No such nick/channel */
351         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
352         return;
353 }
354
355 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
356 {
357         std::string target = parameters[0];
358         ModeType type = MODETYPE_USER;
359         unsigned char mask = 0;
360         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
361         User* targetuser  = ServerInstance->FindNick(parameters[0]);
362
363         LastParse.clear();
364
365         /* Special case for displaying the list for listmodes,
366          * e.g. MODE #chan b, or MODE #chan +b without a parameter
367          */
368         if ((targetchannel) && (parameters.size() == 2))
369         {
370                 const char* mode = parameters[1].c_str();
371                 int nonlistmodes_found = 0;
372
373                 seq++;
374
375                 mask = MASK_CHANNEL;
376                 
377                 while (mode && *mode)
378                 {
379                         unsigned char mletter = *mode;
380
381                         if (*mode == '+')
382                         {
383                                 mode++;
384                                 continue;
385                         }
386                         
387                         /* Ensure the user doesnt request the same mode twice,
388                          * so they cant flood themselves off out of idiocy.
389                          */
390                         if (sent[mletter] != seq)
391                         {
392                                 sent[mletter] = seq;
393                         }
394                         else
395                         {
396                                 mode++;
397                                 continue;
398                         }
399
400                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
401                         bool display = true;
402
403                         if ((mh) && (mh->IsListMode()))
404                         {
405                                 int MOD_RESULT = 0;
406                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
407                                 if (MOD_RESULT == ACR_DENY)
408                                 {
409                                         mode++;
410                                         continue;
411                                 }
412
413                                 if (!IS_OPER(user))
414                                 {
415                                         if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
416                                         {
417                                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
418                                                 mh->DisplayEmptyList(user, targetchannel);
419                                                 continue;
420                                         }
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 (parameters.size() == 1)
450         {
451                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
452         }
453         else if (parameters.size() > 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(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
483                                 return;
484                         }
485                 }
486                 else
487                 {
488                         /* No such nick/channel */
489                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
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                 unsigned int parameter_counter = 2; /* Index of first parameter */
500                 unsigned 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 < parameters.size())
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(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
616                                                                                                 user->nick.c_str(), targetchannel->name.c_str(), 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                                                         /* If it's disabled, they have to be an oper.
643                                                          */
644                                                         if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
645                                                         {
646                                                                 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
647                                                                                 user->nick.c_str(),
648                                                                                 type == MODETYPE_CHANNEL ? "channel" : "user",
649                                                                                 modehandlers[handler_id]->GetModeChar());
650                                                                 continue;
651                                                         }
652
653                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
654                                                          * eat any parameter that  came with the mode, and continue to next
655                                                          */
656                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
657                                                         {
658                                                                 if (IS_OPER(user))
659                                                                 {
660                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
661                                                                                         user->nick.c_str(),
662                                                                                         user->oper.c_str(),
663                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
664                                                                                         modehandlers[handler_id]->GetModeChar());
665                                                                 }
666                                                                 else
667                                                                 {
668                                                                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
669                                                                                         user->nick.c_str(),
670                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
671                                                                                         modehandlers[handler_id]->GetModeChar());
672                                                                 }
673                                                                 continue;
674                                                         }
675
676                                                         /* Call the handler for the mode */
677                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
678
679                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
680                                                         {
681                                                                 /* The handler nuked the parameter and they are supposed to have one.
682                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
683                                                                  * so we bail to the next mode character.
684                                                                  */
685                                                                 continue;
686                                                         }
687
688                                                         if (ma == MODEACTION_ALLOW)
689                                                         {
690                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
691                                                                 if (state_change)
692                                                                 {
693                                                                         if (adding != last_successful_state_change)
694                                                                                 output_sequence.append(adding ? "+" : "-");
695                                                                         last_successful_state_change = adding;
696                                                                 }
697                                                                 
698                                                                 /* Add the mode letter */
699                                                                 output_sequence.push_back(modechar);
700
701                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
702
703                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
704                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
705                                                                 {
706                                                                         parameter_list << " " << parameter;
707                                                                         parameter_count++;
708                                                                         /* Does this mode have a prefix? */
709                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
710                                                                         {
711                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
712                                                                                 if (user_to_prefix)
713                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
714                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
715                                                                         }
716                                                                 }
717
718                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
719                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
720                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
721
722                                                                 /* Reset the state change flag */
723                                                                 state_change = false;
724
725                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
726                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
727                                                                 {
728                                                                         /* We cant have a mode sequence this long */
729                                                                         letter = mode_sequence.end() - 1;
730                                                                         continue;
731                                                                 }
732                                                         }
733                                                 }
734                                         }
735                                         else
736                                         {
737                                                 /* No mode handler? Unknown mode character then. */
738                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
739                                         }
740                                 break;
741                         }
742                 }
743
744                 /* Was there at least one valid mode in the sequence? */
745                 if (!output_sequence.empty())
746                 {
747                         if (servermode)
748                         {
749                                 if (type == MODETYPE_CHANNEL)
750                                 {
751                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
752                                         this->LastParse = targetchannel->name;
753                                 }
754                                 else
755                                 {
756                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
757                                         this->LastParse = targetuser->nick;
758                                 }
759                         }
760                         else
761                         {
762                                 if (type == MODETYPE_CHANNEL)
763                                 {
764                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
765                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
766                                         this->LastParse = targetchannel->name;
767                                 }
768                                 else
769                                 {
770                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
771                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
772                                         this->LastParse = targetuser->nick;
773                                 }
774                         }
775
776                         LastParse.append(" ");
777                         LastParse.append(output_sequence);
778                         LastParse.append(parameter_list.str());
779                 }
780         }
781 }
782
783 const std::string& ModeParser::GetLastParse()
784 {
785         return LastParse;
786 }
787
788 void ModeParser::CleanMask(std::string &mask)
789 {
790         std::string::size_type pos_of_pling = mask.find_first_of('!');
791         std::string::size_type pos_of_at = mask.find_first_of('@');
792         std::string::size_type pos_of_dot = mask.find_first_of('.');
793         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
794
795         if (mask.length() >= 2 && mask[1] == ':')
796                 return; // if it's an extban, don't even try guess how it needs to be formed.
797
798         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
799         {
800                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
801                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
802                 {
803                         /* It has no '.' in it, it must be a nick. */
804                         mask.append("!*@*");
805                 }
806                 else
807                 {
808                         /* Got a dot in it? Has to be a host */
809                         mask = "*!*@" + mask;
810                 }
811         }
812         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
813         {
814                 /* Has an @ but no !, its a user@host */
815                  mask = "*!" + mask;
816         }
817         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
818         {
819                 /* Has a ! but no @, it must be a nick!ident */
820                 mask.append("@*");
821         }
822 }
823
824 bool ModeParser::AddMode(ModeHandler* mh)
825 {
826         unsigned char mask = 0;
827         unsigned char pos = 0;
828
829         /* Yes, i know, this might let people declare modes like '_' or '^'.
830          * If they do that, thats their problem, and if i ever EVER see an
831          * official InspIRCd developer do that, i'll beat them with a paddle!
832          */
833         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
834                 return false;
835
836         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
837          * A mode prefix of ':' will fuck up both server to server, and client to server.
838          * A mode prefix of '#' will mess up /whois and /privmsg
839          */
840         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
841                 return false;
842
843         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
844         pos = (mh->GetModeChar()-65) | mask;
845
846         if (modehandlers[pos])
847                 return false;
848
849         modehandlers[pos] = mh;
850         return true;
851 }
852
853 bool ModeParser::DelMode(ModeHandler* mh)
854 {
855         unsigned char mask = 0;
856         unsigned char pos = 0;
857
858         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
859                 return false;
860
861         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
862         pos = (mh->GetModeChar()-65) | mask;
863
864         if (!modehandlers[pos])
865                 return false;
866
867         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
868          * To stack here we have to make the algorithm slower. Discuss.
869          */
870         switch (mh->GetModeType())
871         {
872                 case MODETYPE_USER:
873                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
874                         {
875                                 mh->RemoveMode(i->second);
876                         }
877                 break;
878                 case MODETYPE_CHANNEL:
879                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
880                         {
881                                 mh->RemoveMode(i->second);
882                         }
883                 break;
884         }
885
886         modehandlers[pos] = NULL;
887
888         return true;
889 }
890
891 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
892 {
893         unsigned char mask = 0;
894         unsigned char pos = 0;
895
896         if ((modeletter < 'A') || (modeletter > 'z'))
897                 return NULL;
898
899         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
900         pos = (modeletter-65) | mask;
901
902         return modehandlers[pos];
903 }
904
905 std::string ModeParser::UserModeList()
906 {
907         char modestr[256];
908         int pointer = 0;
909
910         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
911         {
912                 unsigned char pos = (mode-65) | MASK_USER;
913
914                 if (modehandlers[pos])
915                         modestr[pointer++] = mode;
916         }
917         modestr[pointer++] = 0;
918         return modestr;
919 }
920
921 std::string ModeParser::ChannelModeList()
922 {
923         char modestr[256];
924         int pointer = 0;
925
926         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
927         {
928                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
929                         continue;
930
931                 unsigned char pos = (mode-65) | MASK_CHANNEL;
932
933                 if (modehandlers[pos])
934                         modestr[pointer++] = mode;
935         }
936         modestr[pointer++] = 0;
937         return modestr;
938 }
939
940 std::string ModeParser::ParaModeList()
941 {
942         char modestr[256];
943         int pointer = 0;
944
945         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
946         {
947                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
948                         continue;
949
950                 unsigned char pos = (mode-65) | MASK_CHANNEL;
951
952                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
953                         modestr[pointer++] = mode;
954         }
955         modestr[pointer++] = 0;
956         return modestr;
957 }
958
959 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
960 {
961         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
962         {
963                 unsigned char pos = (mode-65) | MASK_CHANNEL;
964
965                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
966                 {
967                         return modehandlers[pos];
968                 }
969         }
970         return NULL;
971 }
972
973 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
974 {
975         std::string types;
976         std::string pars;
977
978         if (!channel || !user)
979                 return "";
980
981         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
982         {
983                 unsigned char pos = (mode-65) | MASK_CHANNEL;
984                 ModeHandler* mh = modehandlers[pos];
985                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
986                 {
987                         ModePair ret;
988                         ret = mh->ModeSet(NULL, user, channel, user->nick);
989                         if ((ret.first) && (ret.second == user->nick))
990                         {
991                                 if (nick_suffix)
992                                 {
993                                         pars.append(" ");
994                                         pars.append(user->nick);
995                                 }
996                                 types.push_back(mh->GetModeChar());
997                         }
998                 }
999         }
1000
1001         if (nick_suffix)
1002                 return types+pars;
1003         else
1004                 return types;
1005 }
1006
1007 std::string ModeParser::ChanModes()
1008 {
1009         std::string type1;      /* Listmodes EXCEPT those with a prefix */
1010         std::string type2;      /* Modes that take a param when adding or removing */
1011         std::string type3;      /* Modes that only take a param when adding */
1012         std::string type4;      /* Modes that dont take a param */
1013
1014         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1015         {
1016                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1017                         continue;
1018
1019                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1020                  /* One parameter when adding */
1021                 if (modehandlers[pos])
1022                 {       
1023                         if (modehandlers[pos]->GetNumParams(true))
1024                         {
1025                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1026                                 {
1027                                         type1 += modehandlers[pos]->GetModeChar();
1028                                 }
1029                                 else
1030                                 {
1031                                         /* ... and one parameter when removing */
1032                                         if (modehandlers[pos]->GetNumParams(false))
1033                                         {
1034                                                 /* But not a list mode */
1035                                                 if (!modehandlers[pos]->GetPrefix())
1036                                                 {
1037                                                         type2 += modehandlers[pos]->GetModeChar();
1038                                                 }
1039                                         }
1040                                         else
1041                                         {
1042                                                 /* No parameters when removing */
1043                                                 type3 += modehandlers[pos]->GetModeChar();
1044                                         }
1045                                 }
1046                         }
1047                         else
1048                         {
1049                                 type4 += modehandlers[pos]->GetModeChar();
1050                         }
1051                 }
1052                          
1053         }
1054
1055         return type1 + "," + type2 + "," + type3 + "," + type4;
1056 }
1057
1058 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1059 {       
1060         return one.second > two.second;
1061 }
1062
1063 std::string ModeParser::BuildPrefixes()
1064 {
1065         std::string mletters;
1066         std::string mprefixes;
1067         pfxcontainer pfx;
1068         std::map<char,char> prefix_to_mode;
1069
1070         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1071         {
1072                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1073                         continue;
1074
1075                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1076
1077                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1078                 {
1079                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1080                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1081                 }
1082         }
1083
1084         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1085
1086         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1087         {
1088                 mletters = mletters + n->first;
1089                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1090         }
1091
1092         return "(" + mprefixes + ")" + mletters;
1093 }
1094
1095 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1096 {
1097         unsigned char mask = 0;
1098         unsigned char pos = 0;
1099
1100         if (!mw)
1101                 return false;
1102
1103         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1104                 return false;
1105
1106         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1107         pos = (mw->GetModeChar()-65) | mask;
1108
1109         modewatchers[pos].push_back(mw);
1110
1111         return true;
1112 }
1113
1114 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1115 {
1116         unsigned char mask = 0;
1117         unsigned char pos = 0;
1118
1119         if (!mw)
1120                 return false;
1121
1122         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1123                 return false;
1124
1125         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1126         pos = (mw->GetModeChar()-65) | mask;
1127
1128         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1129
1130         if (a == modewatchers[pos].end())
1131         {
1132                 return false;
1133         }
1134
1135         modewatchers[pos].erase(a);
1136
1137         return true;
1138 }
1139
1140 /** This default implementation can remove simple user modes
1141  */
1142 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1143 {
1144         char moderemove[MAXBUF];
1145         std::vector<std::string> parameters;
1146
1147         if (user->IsModeSet(this->GetModeChar()))
1148         {
1149                 if (stack)
1150                 {
1151                         stack->Push(this->GetModeChar());
1152                 }
1153                 else
1154                 {
1155                         sprintf(moderemove,"-%c",this->GetModeChar());
1156                         parameters.push_back(user->nick);
1157                         parameters.push_back(moderemove);
1158                         ServerInstance->Parser->CallHandler("MODE", parameters, user);
1159                 }
1160         }
1161 }
1162
1163 /** This default implementation can remove simple channel modes
1164  * (no parameters)
1165  */
1166 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1167 {
1168         char moderemove[MAXBUF];
1169         std::vector<std::string> parameters;
1170
1171         if (channel->IsModeSet(this->GetModeChar()))
1172         {
1173                 if (stack)
1174                 {
1175                         stack->Push(this->GetModeChar());
1176                 }
1177                 else
1178                 {
1179                         sprintf(moderemove,"-%c",this->GetModeChar());
1180                         parameters.push_back(channel->name);
1181                         parameters.push_back(moderemove);
1182                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1183                 }
1184         }
1185 }
1186
1187 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1188 {
1189         ModeHandler* modes[] =
1190         {
1191                 new ModeChannelSecret(Instance),
1192                 new ModeChannelPrivate(Instance),
1193                 new ModeChannelModerated(Instance),
1194                 new ModeChannelTopicOps(Instance),
1195                 new ModeChannelNoExternal(Instance),
1196                 new ModeChannelInviteOnly(Instance),
1197                 new ModeChannelKey(Instance),
1198                 new ModeChannelLimit(Instance),
1199                 new ModeChannelBan(Instance),
1200                 new ModeChannelOp(Instance),
1201                 new ModeChannelHalfOp(Instance),
1202                 new ModeChannelVoice(Instance),
1203                 new ModeUserWallops(Instance),
1204                 new ModeUserInvisible(Instance),
1205                 new ModeUserOperator(Instance),
1206                 new ModeUserServerNoticeMask(Instance),
1207                 NULL
1208         };
1209
1210         /* Clear mode handler list */
1211         memset(modehandlers, 0, sizeof(modehandlers));
1212
1213         /* Last parse string */
1214         LastParse.clear();
1215
1216         /* Initialise the RFC mode letters */
1217         for (int index = 0; modes[index]; index++)
1218                 this->AddMode(modes[index]);
1219
1220         seq = 0;
1221         memset(&sent, 0, sizeof(sent));
1222 }