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