]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
More OnRawMode fix
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDmode */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
18
19 #include "inspircd.h"
20 #include "inspstring.h"
21
22 /* +s (secret) */
23 #include "modes/cmode_s.h"
24 /* +p (private) */
25 #include "modes/cmode_p.h"
26 /* +b (bans) */
27 #include "modes/cmode_b.h"
28 /* +m (moderated) */
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
40 /* +o (channel op) */
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
50 /* +i (invisible) */
51 #include "modes/umode_i.h"
52 /* +o (operator) */
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
56
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix)
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                                 int MOD_RESULT = 0;
334                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
335                                 if (MOD_RESULT == ACR_DENY)
336                                 {
337                                         mode++;
338                                         continue;
339                                 }
340
341                                 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
342                                 {
343                                         user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
344                                         mh->DisplayEmptyList(user, targetchannel);
345                                         continue;
346                                 }
347
348                                 /** See below for a description of what craq this is :D
349                                  */
350                                 unsigned char handler_id = (*mode - 65) | mask;
351
352                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
353                                 {
354                                         std::string dummyparam;
355                                         
356                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
357                                                 display = false;
358                                 }
359
360                                 if (display)
361                                         mh->DisplayList(user, targetchannel);
362                         }
363                         else
364                                 nonlistmodes_found++;
365
366                         mode++;
367                 }
368
369                 /* We didnt have any modes that were non-list, we can return here */
370                 if (!nonlistmodes_found)
371                         return;
372         }
373
374         if (pcnt == 1)
375         {
376                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
377         }
378         else if (pcnt > 1)
379         {
380                 if (targetchannel)
381                 {
382                         type = MODETYPE_CHANNEL;
383                         mask = MASK_CHANNEL;
384
385                         /* Extra security checks on channel modes
386                          * (e.g. are they a (half)op?
387                          */
388
389                         if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
390                         {
391                                 /* We don't have halfop */
392                                 int MOD_RESULT = 0;
393                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
394                                 if (MOD_RESULT == ACR_DENY)
395                                         return;
396
397                                 if (MOD_RESULT == ACR_DEFAULT)
398                                 {
399                                         /* Are we a uline or is it a servermode? */
400                                         if ((!ServerInstance->ULine(user->server)) && (!servermode))
401                                         {
402                                                 /* Not enough permission:
403                                                  * NOT a uline and NOT a servermode,
404                                                  * OR, NOT halfop or above.
405                                                  */
406                                                 user->WriteServ("482 %s %s :You're not a channel %soperator",user->nick, targetchannel->name,
407                                                                 ServerInstance->Config->AllowHalfop ? "(half)" : "");
408                                                 return;
409                                         }
410                                 }
411                         }
412                 }
413                 else if (targetuser)
414                 {
415                         type = MODETYPE_USER;
416                         mask = MASK_USER;
417                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
418                         {
419                                 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
420                                 return;
421                         }
422                 }
423                 else
424                 {
425                         /* No such nick/channel */
426                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
427                         return;
428                 }
429
430                 std::string mode_sequence = parameters[1];
431                 std::string parameter;
432                 std::ostringstream parameter_list;
433                 std::string output_sequence;
434                 bool adding = true, state_change = false;
435                 unsigned char handler_id = 0;
436                 int parameter_counter = 2; /* Index of first parameter */
437                 int parameter_count = 0;
438                 bool last_successful_state_change = false;
439
440                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
441                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
442                         mode_sequence.insert(0, "+");
443
444                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
445                 {
446                         unsigned char modechar = *letter;
447
448                         switch (modechar)
449                         {
450                                 /* NB:
451                                  * For + and - mode characters, we don't just stick the character into the output sequence.
452                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
453                                  * appearing in the output sequence, we store a flag which says there was a state change,
454                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
455                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
456                                  */
457                                 case '+':
458                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
459                                          * however, will allow the + if it is the first item in the sequence, regardless.
460                                          */
461                                         if ((!adding) || (!output_sequence.length()))
462                                                 state_change = true;
463                                         adding = true;
464                                         if (!output_sequence.length())
465                                                 last_successful_state_change = false;
466                                         continue;
467                                 break;
468                                 case '-':
469                                         if ((adding) || (!output_sequence.length()))
470                                                 state_change = true;
471                                         adding = false;
472                                         if (!output_sequence.length())
473                                                 last_successful_state_change = true;
474                                         continue;
475                                 break;
476                                 default:
477
478                                         /**
479                                          * Watch carefully for the sleight of hand trick.
480                                          * 65 is the ascii value of 'A'. We take this from
481                                          * the char we're looking at to get a number between
482                                          * 1 and 127. We then logic-or it to get the hashed
483                                          * position, dependent on wether its a channel or
484                                          * a user mode. This is a little stranger, but a lot
485                                          * faster, than using a map of pairs.
486                                          */
487                                         handler_id = (modechar - 65) | mask;
488
489                                         if (modehandlers[handler_id])
490                                         {
491                                                 bool abort = false;
492
493                                                 if (modehandlers[handler_id]->GetModeType() == type)
494                                                 {
495                                                         if (modehandlers[handler_id]->GetNumParams(adding))
496                                                         {
497                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
498                                                                 if (parameter_counter < pcnt)
499                                                                 {
500                                                                         parameter = parameters[parameter_counter++];
501
502                                                                         /* Yerk, invalid! */
503                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
504                                                                                 parameter.clear();
505                                                                 }
506                                                                 else
507                                                                 {
508                                                                         /* No parameter, continue to the next mode */
509                                                                         continue;
510                                                                 }
511
512                                                                 int MOD_RESULT = 0;
513                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1));
514                                                                 if (MOD_RESULT == ACR_DENY)
515                                                                         continue;
516
517                                                                 bool had_parameter = !parameter.empty();
518                                                                 
519                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
520                                                                 {
521                                                                         if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
522                                                                         {
523                                                                                 abort = true;
524                                                                                 break;
525                                                                         }
526                                                                         /* A module whacked the parameter completely, and there was one. abort. */
527                                                                         if ((had_parameter) && (parameter.empty()))
528                                                                         {
529                                                                                 abort = true;
530                                                                                 break;
531                                                                         }
532                                                                 }
533
534                                                                 if (abort)
535                                                                         continue;
536                                                         }
537                                                         else
538                                                         {
539                                                                 int MOD_RESULT = 0;
540                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0));
541                                                                 if (MOD_RESULT == ACR_DENY)
542                                                                         continue;
543
544                                                                 /* Fix by brain: mode watchers not being called for parameterless modes */
545                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
546                                                                 {
547                                                                         if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
548                                                                         {
549                                                                                 abort = true;
550                                                                                 break;
551                                                                         }
552                                                                 }
553
554                                                                 if (abort)
555                                                                         continue;
556                                                         }
557
558                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
559                                                          * eat any parameter that  came with the mode, and continue to next
560                                                          */
561                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
562                                                         {
563                                                                 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
564                                                                                 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
565                                                                                 modehandlers[handler_id]->GetModeChar());
566                                                                 continue;
567                                                         }
568
569                                                         /* Call the handler for the mode */
570                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
571
572                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
573                                                         {
574                                                                 /* The handler nuked the parameter and they are supposed to have one.
575                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
576                                                                  * so we bail to the next mode character.
577                                                                  */
578                                                                 continue;
579                                                         }
580
581                                                         if (ma == MODEACTION_ALLOW)
582                                                         {
583                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
584                                                                 if (state_change)
585                                                                 {
586                                                                         if (adding != last_successful_state_change)
587                                                                                 output_sequence.append(adding ? "+" : "-");
588                                                                         last_successful_state_change = adding;
589                                                                 }
590                                                                 
591                                                                 /* Add the mode letter */
592                                                                 output_sequence.push_back(modechar);
593
594                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
595
596                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
597                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
598                                                                 {
599                                                                         parameter_list << " " << parameter;
600                                                                         parameter_count++;
601                                                                         /* Does this mode have a prefix? */
602                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
603                                                                         {
604                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
605                                                                                 if (user_to_prefix)
606                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
607                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
608                                                                         }
609                                                                 }
610
611                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
612                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
613                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
614
615                                                                 /* Reset the state change flag */
616                                                                 state_change = false;
617
618                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
619                                                                                 || (parameter_count > MAXMODES))
620                                                                 {
621                                                                         /* We cant have a mode sequence this long */
622                                                                         letter = mode_sequence.end() - 1;
623                                                                         continue;
624                                                                 }
625                                                         }
626                                                 }
627                                         }
628                                         else
629                                         {
630                                                 /* No mode handler? Unknown mode character then. */
631                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
632                                         }
633                                 break;
634                         }
635                 }
636
637                 /* Was there at least one valid mode in the sequence? */
638                 if (!output_sequence.empty())
639                 {
640                         if (servermode)
641                         {
642                                 if (type == MODETYPE_CHANNEL)
643                                 {
644                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
645                                         this->LastParse = targetchannel->name;
646                                 }
647                                 else
648                                 {
649                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
650                                         this->LastParse = targetuser->nick;
651                                 }
652                         }
653                         else
654                         {
655                                 if (type == MODETYPE_CHANNEL)
656                                 {
657                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
658                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
659                                         this->LastParse = targetchannel->name;
660                                 }
661                                 else
662                                 {
663                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
664                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
665                                         this->LastParse = targetuser->nick;
666                                 }
667                         }
668
669                         LastParse.append(" ");
670                         LastParse.append(output_sequence);
671                         LastParse.append(parameter_list.str());
672                 }
673         }
674 }
675
676 const std::string& ModeParser::GetLastParse()
677 {
678         return LastParse;
679 }
680
681 void ModeParser::CleanMask(std::string &mask)
682 {
683         std::string::size_type pos_of_pling = mask.find_first_of('!');
684         std::string::size_type pos_of_at = mask.find_first_of('@');
685         std::string::size_type pos_of_dot = mask.find_first_of('.');
686         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
687
688         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
689         {
690                 /* Just a nick, or just a host */
691                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
692                 {
693                         /* It has no '.' in it, it must be a nick. */
694                         mask.append("!*@*");
695                 }
696                 else
697                 {
698                         /* Got a dot in it? Has to be a host */
699                         mask = "*!*@" + mask;
700                 }
701         }
702         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
703         {
704                 /* Has an @ but no !, its a user@host */
705                  mask = "*!" + mask;
706         }
707         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
708         {
709                 /* Has a ! but no @, it must be a nick!ident */
710                 mask.append("@*");
711         }
712 }
713
714 bool ModeParser::AddMode(ModeHandler* mh)
715 {
716         unsigned char mask = 0;
717         unsigned char pos = 0;
718
719         /* Yes, i know, this might let people declare modes like '_' or '^'.
720          * If they do that, thats their problem, and if i ever EVER see an
721          * official InspIRCd developer do that, i'll beat them with a paddle!
722          */
723         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
724                 return false;
725
726         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
727          * A mode prefix of ':' will fuck up both server to server, and client to server.
728          * A mode prefix of '#' will mess up /whois and /privmsg
729          */
730         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
731                 return false;
732
733         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
734         pos = (mh->GetModeChar()-65) | mask;
735
736         if (modehandlers[pos])
737                 return false;
738
739         modehandlers[pos] = mh;
740         return true;
741 }
742
743 bool ModeParser::DelMode(ModeHandler* mh)
744 {
745         unsigned char mask = 0;
746         unsigned char pos = 0;
747
748         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
749                 return false;
750
751         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
752         pos = (mh->GetModeChar()-65) | mask;
753
754         if (!modehandlers[pos])
755                 return false;
756
757         switch (mh->GetModeType())
758         {
759                 case MODETYPE_USER:
760                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
761                         {
762                                 mh->RemoveMode(i->second);
763                         }
764                 break;
765                 case MODETYPE_CHANNEL:
766                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
767                         {
768                                 mh->RemoveMode(i->second);
769                         }
770                 break;
771         }
772
773         modehandlers[pos] = NULL;
774
775         return true;
776 }
777
778 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
779 {
780         unsigned char mask = 0;
781         unsigned char pos = 0;
782
783         if ((modeletter < 'A') || (modeletter > 'z'))
784                 return NULL;
785
786         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
787         pos = (modeletter-65) | mask;
788
789         return modehandlers[pos];
790 }
791
792 std::string ModeParser::UserModeList()
793 {
794         char modestr[256];
795         int pointer = 0;
796
797         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
798         {
799                 unsigned char pos = (mode-65) | MASK_USER;
800
801                 if (modehandlers[pos])
802                         modestr[pointer++] = mode;
803         }
804         modestr[pointer++] = 0;
805         return modestr;
806 }
807
808 std::string ModeParser::ChannelModeList()
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])
821                         modestr[pointer++] = mode;
822         }
823         modestr[pointer++] = 0;
824         return modestr;
825 }
826
827 std::string ModeParser::ParaModeList()
828 {
829         char modestr[256];
830         int pointer = 0;
831
832         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
833         {
834                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
835                         continue;
836
837                 unsigned char pos = (mode-65) | MASK_CHANNEL;
838
839                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
840                         modestr[pointer++] = mode;
841         }
842         modestr[pointer++] = 0;
843         return modestr;
844 }
845
846 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
847 {
848         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
849         {
850                 unsigned char pos = (mode-65) | MASK_CHANNEL;
851
852                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
853                 {
854                         return modehandlers[pos];
855                 }
856         }
857         return NULL;
858 }
859
860 std::string ModeParser::ModeString(User* user, Channel* channel)
861 {
862         std::string types;
863         std::string pars;
864
865         if (!channel || !user)
866                 return "";
867
868         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
869         {
870                 unsigned char pos = (mode-65) | MASK_CHANNEL;
871                 ModeHandler* mh = modehandlers[pos];
872                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
873                 {
874                         ModePair ret;
875                         ret = mh->ModeSet(NULL, user, channel, user->nick);
876                         if ((ret.first) && (ret.second == user->nick))
877                         {
878                                 pars.append(" ");
879                                 pars.append(user->nick);
880                                 types.push_back(mh->GetModeChar());
881                         }
882                 }
883         }
884
885         return types+pars;
886 }
887
888 std::string ModeParser::ChanModes()
889 {
890         std::string type1;      /* Listmodes EXCEPT those with a prefix */
891         std::string type2;      /* Modes that take a param when adding or removing */
892         std::string type3;      /* Modes that only take a param when adding */
893         std::string type4;      /* Modes that dont take a param */
894
895         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
896         {
897                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
898                         continue;
899
900                 unsigned char pos = (mode-65) | MASK_CHANNEL;
901                  /* One parameter when adding */
902                 if (modehandlers[pos])
903                 {       
904                         if (modehandlers[pos]->GetNumParams(true))
905                         {
906                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
907                                 {
908                                         type1 += modehandlers[pos]->GetModeChar();
909                                 }
910                                 else
911                                 {
912                                         /* ... and one parameter when removing */
913                                         if (modehandlers[pos]->GetNumParams(false))
914                                         {
915                                                 /* But not a list mode */
916                                                 if (!modehandlers[pos]->GetPrefix())
917                                                 {
918                                                         type2 += modehandlers[pos]->GetModeChar();
919                                                 }
920                                         }
921                                         else
922                                         {
923                                                 /* No parameters when removing */
924                                                 type3 += modehandlers[pos]->GetModeChar();
925                                         }
926                                 }
927                         }
928                         else
929                         {
930                                 type4 += modehandlers[pos]->GetModeChar();
931                         }
932                 }
933                          
934         }
935
936         return type1 + "," + type2 + "," + type3 + "," + type4;
937 }
938
939 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
940 {       
941         return one.second > two.second;
942 }
943
944 std::string ModeParser::BuildPrefixes()
945 {
946         std::string mletters;
947         std::string mprefixes;
948         pfxcontainer pfx;
949         std::map<char,char> prefix_to_mode;
950
951         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
952         {
953                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
954                         continue;
955
956                 unsigned char pos = (mode-65) | MASK_CHANNEL;
957
958                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
959                 {
960                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
961                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
962                 }
963         }
964
965         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
966
967         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
968         {
969                 mletters = mletters + n->first;
970                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
971         }
972
973         return "(" + mprefixes + ")" + mletters;
974 }
975
976 bool ModeParser::AddModeWatcher(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         modewatchers[pos].push_back(mw);
991
992         return true;
993 }
994
995 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
996 {
997         unsigned char mask = 0;
998         unsigned char pos = 0;
999
1000         if (!mw)
1001                 return false;
1002
1003         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1004                 return false;
1005
1006         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1007         pos = (mw->GetModeChar()-65) | mask;
1008
1009         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1010
1011         if (a == modewatchers[pos].end())
1012         {
1013                 return false;
1014         }
1015
1016         modewatchers[pos].erase(a);
1017
1018         return true;
1019 }
1020
1021 /** This default implementation can remove simple user modes
1022  */
1023 void ModeHandler::RemoveMode(User* user)
1024 {
1025         char moderemove[MAXBUF];
1026         const char* parameters[] = { user->nick, moderemove };
1027
1028         if (user->IsModeSet(this->GetModeChar()))
1029         {
1030                 sprintf(moderemove,"-%c",this->GetModeChar());
1031                 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1032         }
1033 }
1034
1035 /** This default implementation can remove simple channel modes
1036  * (no parameters)
1037  */
1038 void ModeHandler::RemoveMode(Channel* channel)
1039 {
1040         char moderemove[MAXBUF];
1041         const char* parameters[] = { channel->name, moderemove };
1042
1043         if (channel->IsModeSet(this->GetModeChar()))
1044         {
1045                 sprintf(moderemove,"-%c",this->GetModeChar());
1046                 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1047         }
1048 }
1049
1050 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1051 {
1052         ModeHandler* modes[] =
1053         {
1054                 new ModeChannelSecret(Instance),
1055                 new ModeChannelPrivate(Instance),
1056                 new ModeChannelModerated(Instance),
1057                 new ModeChannelTopicOps(Instance),
1058                 new ModeChannelNoExternal(Instance),
1059                 new ModeChannelInviteOnly(Instance),
1060                 new ModeChannelKey(Instance),
1061                 new ModeChannelLimit(Instance),
1062                 new ModeChannelBan(Instance),
1063                 new ModeChannelOp(Instance),
1064                 new ModeChannelHalfOp(Instance),
1065                 new ModeChannelVoice(Instance),
1066                 new ModeUserServerNotice(Instance),
1067                 new ModeUserWallops(Instance),
1068                 new ModeUserInvisible(Instance),
1069                 new ModeUserOperator(Instance),
1070                 new ModeUserServerNoticeMask(Instance),
1071                 NULL
1072         };
1073
1074         /* Clear mode list */
1075         memset(modehandlers, 0, sizeof(modehandlers));
1076         memset(modewatchers, 0, sizeof(modewatchers));
1077
1078         /* Last parse string */
1079         LastParse.clear();
1080
1081         /* Initialise the RFC mode letters */
1082         for (int index = 0; modes[index]; index++)
1083                 this->AddMode(modes[index]);
1084 }