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