2 * ircd-ratbox: A slightly useful ircd.
3 * m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 * $Id: m_message.c 3173 2007-01-31 23:57:18Z jilles $
44 #include "s_newconf.h"
46 #include "inline/stringops.h"
48 static int m_message(int, const char *, struct Client
*, struct Client
*, int, const char **);
49 static int m_privmsg(struct Client
*, struct Client
*, int, const char **);
50 static int m_notice(struct Client
*, struct Client
*, int, const char **);
52 static void expire_tgchange(void *unused
);
53 static struct ev_entry
*expire_tgchange_event
;
58 expire_tgchange_event
= rb_event_addish("expire_tgchange", expire_tgchange
, NULL
, 300);
59 expire_tgchange(NULL
);
66 rb_event_delete(expire_tgchange_event
);
69 struct Message privmsg_msgtab
= {
70 "PRIVMSG", 0, 0, 0, MFLG_SLOW
| MFLG_UNREG
,
71 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
73 struct Message notice_msgtab
= {
74 "NOTICE", 0, 0, 0, MFLG_SLOW
,
75 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
78 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, NULL
};
80 DECLARE_MODULE_AV1(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, "$Revision: 3173 $");
89 static int build_target_list(int p_or_n
, const char *command
,
90 struct Client
*client_p
,
91 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
93 static struct Channel
*find_allowing_channel(struct Client
*source_p
, struct Client
*target_p
);
94 static int flood_attack_client(int p_or_n
, struct Client
*source_p
, struct Client
*target_p
);
95 static int flood_attack_channel(int p_or_n
, struct Client
*source_p
,
96 struct Channel
*chptr
, char *chname
);
99 #define ENTITY_CHANNEL 1
100 #define ENTITY_CHANOPS_ON_CHANNEL 2
101 #define ENTITY_CLIENT 3
103 static struct entity targets
[512];
104 static int ntargets
= 0;
106 static int duplicate_ptr(void *);
108 static void msg_channel(int p_or_n
, const char *command
,
109 struct Client
*client_p
,
110 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
112 static void msg_channel_flags(int p_or_n
, const char *command
,
113 struct Client
*client_p
,
114 struct Client
*source_p
,
115 struct Channel
*chptr
, int flags
, const char *text
);
117 static void msg_client(int p_or_n
, const char *command
,
118 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
120 static void handle_special(int p_or_n
, const char *command
,
121 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
130 ** Another massive cleanup Nov, 2000
131 ** (I don't think there is a single line left from 6/91. Maybe.)
132 ** m_privmsg and m_notice do basically the same thing.
133 ** in the original 2.8.2 code base, they were the same function
134 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
135 ** of ircu fame, we split m_privmsg.c and m_notice.c.
136 ** I don't see the point of that now. Its harder to maintain, its
137 ** easier to introduce bugs into one version and not the other etc.
138 ** Really, the penalty of an extra function call isn't that big a deal folks.
147 m_privmsg(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
149 return m_message(PRIVMSG
, "PRIVMSG", client_p
, source_p
, parc
, parv
);
153 m_notice(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
155 return m_message(NOTICE
, "NOTICE", client_p
, source_p
, parc
, parv
);
159 * inputs - flag privmsg or notice
160 * - pointer to command "PRIVMSG" or "NOTICE"
161 * - pointer to client_p
162 * - pointer to source_p
163 * - pointer to channel
166 m_message(int p_or_n
,
168 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
172 if(parc
< 2 || EmptyString(parv
[1]))
175 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
176 source_p
->name
, command
);
180 if(parc
< 3 || EmptyString(parv
[2]))
183 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
187 /* Finish the flood grace period if theyre not messaging themselves
188 * as some clients (ircN) do this as a "lag check"
190 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
191 flood_endgrace(source_p
);
193 if(build_target_list(p_or_n
, command
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
198 for(i
= 0; i
< ntargets
; i
++)
200 switch (targets
[i
].type
)
203 msg_channel(p_or_n
, command
, client_p
, source_p
,
204 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
207 case ENTITY_CHANOPS_ON_CHANNEL
:
208 msg_channel_flags(p_or_n
, command
, client_p
, source_p
,
209 (struct Channel
*) targets
[i
].ptr
,
210 targets
[i
].flags
, parv
[2]);
214 msg_client(p_or_n
, command
, source_p
,
215 (struct Client
*) targets
[i
].ptr
, parv
[2]);
226 * inputs - pointer to given client_p (server)
227 * - pointer to given source (oper/client etc.)
228 * - pointer to list of nicks/channels
229 * - pointer to table to place results
230 * - pointer to text (only used if source_p is an oper)
231 * output - number of valid entities
232 * side effects - target_table is modified to contain a list of
233 * pointers to channels or clients
234 * if source client is an oper
235 * all the classic old bizzare oper privmsg tricks
236 * are parsed and sent as is, if prefixed with $
242 build_target_list(int p_or_n
, const char *command
, struct Client
*client_p
,
243 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
246 char *p
, *nick
, *target_list
;
247 struct Channel
*chptr
= NULL
;
248 struct Client
*target_p
;
250 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
254 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
258 * channels are privmsg'd a lot more than other clients, moved up
259 * here plain old channel msg?
262 if(IsChanPrefix(*nick
))
264 /* ignore send of local channel to a server (should not happen) */
265 if(IsServer(client_p
) && *nick
== '&')
268 if((chptr
= find_channel(nick
)) != NULL
)
270 if(!duplicate_ptr(chptr
))
272 if(ntargets
>= ConfigFileEntry
.max_targets
)
274 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
275 me
.name
, source_p
->name
, nick
);
278 targets
[ntargets
].ptr
= (void *) chptr
;
279 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
283 /* non existant channel */
284 else if(p_or_n
!= NOTICE
)
285 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
286 form_str(ERR_NOSUCHNICK
), nick
);
291 if(MyClient(source_p
))
292 target_p
= find_named_person(nick
);
294 target_p
= find_person(nick
);
296 /* look for a privmsg to another client */
299 if(!duplicate_ptr(target_p
))
301 if(ntargets
>= ConfigFileEntry
.max_targets
)
303 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
304 me
.name
, source_p
->name
, nick
);
307 targets
[ntargets
].ptr
= (void *) target_p
;
308 targets
[ntargets
].type
= ENTITY_CLIENT
;
309 targets
[ntargets
++].flags
= 0;
314 /* @#channel or +#channel message ? */
318 /* allow %+@ if someone wants to do that */
323 else if(*nick
== '+')
324 type
|= CHFL_CHANOP
| CHFL_VOICE
;
333 if(EmptyString(nick
))
335 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
336 me
.name
, source_p
->name
, command
);
340 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
341 * if the channel is found, fine, if not report an error
344 if((chptr
= find_channel(nick
)) != NULL
)
346 struct membership
*msptr
;
348 msptr
= find_channel_membership(chptr
, source_p
);
350 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
352 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
353 me
.name
, source_p
->name
, with_prefix
);
357 if(!duplicate_ptr(chptr
))
359 if(ntargets
>= ConfigFileEntry
.max_targets
)
361 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
362 me
.name
, source_p
->name
, nick
);
365 targets
[ntargets
].ptr
= (void *) chptr
;
366 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
367 targets
[ntargets
++].flags
= type
;
370 else if(p_or_n
!= NOTICE
)
372 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
373 form_str(ERR_NOSUCHNICK
), nick
);
379 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
381 handle_special(p_or_n
, command
, client_p
, source_p
, nick
, text
);
385 /* no matching anything found - error if not NOTICE */
388 /* dont give this numeric when source is local,
389 * because its misleading --anfl
391 if(!MyClient(source_p
) && IsDigit(*nick
))
392 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
393 "Failed to deliver: [%.20s]",
394 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
395 get_id(source_p
, source_p
), text
);
397 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
398 form_str(ERR_NOSUCHNICK
), nick
);
408 * inputs - pointer to check
409 * - pointer to table of entities
410 * - number of valid entities so far
411 * output - YES if duplicate pointer in table, NO if not.
412 * note, this does the canonize using pointers
413 * side effects - NONE
416 duplicate_ptr(void *ptr
)
419 for(i
= 0; i
< ntargets
; i
++)
420 if(targets
[i
].ptr
== ptr
)
428 * inputs - flag privmsg or notice
429 * - pointer to command "PRIVMSG" or "NOTICE"
430 * - pointer to client_p
431 * - pointer to source_p
432 * - pointer to channel
434 * side effects - message given channel
436 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
439 msg_channel(int p_or_n
, const char *command
,
440 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
446 if(MyClient(source_p
))
448 /* idle time shouldnt be reset by notices --fl */
450 source_p
->localClient
->last
= rb_current_time();
453 if(chptr
->mode
.mode
& MODE_NOCOLOR
)
455 rb_strlcpy(text2
, text
, BUFSIZE
);
458 if (EmptyString(text
))
460 /* could be empty after colour stripping and
461 * that would cause problems later */
463 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
468 /* chanops and voiced can flood their own channel with impunity */
469 if((result
= can_send(chptr
, source_p
, NULL
)))
471 if(result
== CAN_SEND_OPV
||
472 !flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
474 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
475 "%s %s :%s", command
, chptr
->chname
, text
);
478 else if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
479 chptr
->mode
.mode
& MODE_MODERATED
&&
480 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
481 IsMember(source_p
, chptr
)))
483 /* only do +z for +m channels for now, as bans/quiets
484 * aren't tested for remote clients -- jilles */
485 if(!flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
487 sendto_channel_flags(client_p
, ONLY_CHANOPS
, source_p
, chptr
,
488 "%s %s :%s", command
, chptr
->chname
, text
);
494 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
495 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
502 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
503 * say NOTICE must not auto reply
504 * - pointer to command, "PRIVMSG" or "NOTICE"
505 * - pointer to client_p
506 * - pointer to source_p
507 * - pointer to channel
509 * - pointer to text to send
511 * side effects - message given channel either chanop or voice
514 msg_channel_flags(int p_or_n
, const char *command
, struct Client
*client_p
,
515 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
520 if(flags
& CHFL_VOICE
)
522 type
= ONLY_CHANOPSVOICED
;
531 if(MyClient(source_p
))
533 /* idletime shouldnt be reset by notice --fl */
535 source_p
->localClient
->last
= rb_current_time();
538 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
539 command
, c
, chptr
->chname
, text
);
542 #define PREV_FREE_TARGET(x) ((FREE_TARGET(x) == 0) ? 9 : FREE_TARGET(x) - 1)
543 #define PREV_TARGET(i) ((i == 0) ? i = 9 : --i)
544 #define NEXT_TARGET(i) ((i == 9) ? i = 0 : ++i)
547 expire_tgchange(void *unused
)
550 rb_dlink_node
*ptr
, *next_ptr
;
552 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
556 if(target
->expiry
< rb_current_time())
558 rb_dlinkDelete(ptr
, &tgchange_list
);
559 rb_patricia_remove(tgchange_tree
, target
->pnode
);
567 add_target(struct Client
*source_p
, struct Client
*target_p
)
572 /* can msg themselves or services without using any target slots */
573 if(source_p
== target_p
|| IsService(target_p
))
576 /* special condition for those who have had PRIVMSG crippled to allow them
577 * to talk to IRCops still.
579 * XXX: is this controversial?
581 if(source_p
->localClient
->target_last
> rb_current_time() && IsOper(target_p
))
584 hashv
= fnv_hash_upper((const unsigned char *)use_id(target_p
), 32);
586 if(USED_TARGETS(source_p
))
588 /* hunt for an existing target */
589 for(i
= PREV_FREE_TARGET(source_p
), j
= USED_TARGETS(source_p
);
590 j
; --j
, PREV_TARGET(i
))
592 if(source_p
->localClient
->targets
[i
] == hashv
)
596 /* first message after connect, we may only start clearing
597 * slots after this message --anfl
599 if(!IsTGChange(source_p
))
601 SetTGChange(source_p
);
602 source_p
->localClient
->target_last
= rb_current_time();
604 /* clear as many targets as we can */
605 else if((i
= (rb_current_time() - source_p
->localClient
->target_last
) / 60))
607 if(i
> USED_TARGETS(source_p
))
608 USED_TARGETS(source_p
) = 0;
610 USED_TARGETS(source_p
) -= i
;
612 source_p
->localClient
->target_last
= rb_current_time();
614 /* cant clear any, full target list */
615 else if(USED_TARGETS(source_p
) == 10)
617 ServerStats
.is_tgch
++;
618 add_tgchange(source_p
->sockhost
);
622 /* no targets in use, reset their target_last so that they cant
623 * abuse a long idle to get targets back more quickly
627 source_p
->localClient
->target_last
= rb_current_time();
628 SetTGChange(source_p
);
631 source_p
->localClient
->targets
[FREE_TARGET(source_p
)] = hashv
;
632 NEXT_TARGET(FREE_TARGET(source_p
));
633 ++USED_TARGETS(source_p
);
640 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
641 * say NOTICE must not auto reply
642 * - pointer to command, "PRIVMSG" or "NOTICE"
643 * - pointer to source_p source (struct Client *)
644 * - pointer to target_p target (struct Client *)
647 * side effects - message given channel either chanop or voice
650 msg_client(int p_or_n
, const char *command
,
651 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
653 int do_floodcount
= 0;
655 if(MyClient(source_p
))
657 /* reset idle time for message only if its not to self
658 * and its not a notice */
660 source_p
->localClient
->last
= rb_current_time();
662 /* auto cprivmsg/cnotice */
663 do_floodcount
= !IsOper(source_p
) &&
664 !find_allowing_channel(source_p
, target_p
);
666 /* target change stuff, dont limit ctcp replies as that
667 * would allow people to start filling up random users
668 * targets just by ctcping them
670 if((p_or_n
!= NOTICE
|| *text
!= '\001') &&
671 ConfigFileEntry
.target_change
&& do_floodcount
)
673 if(!add_target(source_p
, target_p
))
675 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
676 me
.name
, source_p
->name
, target_p
->name
);
681 else if(source_p
->from
== target_p
->from
)
683 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
684 "Send message to %s[%s] dropped from %s(Fake Dir)",
685 target_p
->name
, target_p
->from
->name
, source_p
->name
);
689 if(MyConnect(source_p
) && (p_or_n
!= NOTICE
) && target_p
->user
&& target_p
->user
->away
)
690 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
691 target_p
->name
, target_p
->user
->away
);
693 if(MyClient(target_p
))
695 /* XXX Controversial? allow opers always to send through a +g */
696 if(!IsServer(source_p
) && (IsSetCallerId(target_p
) ||
697 (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])))
699 /* Here is the anti-flood bot/spambot code -db */
700 if(accept_message(source_p
, target_p
) || IsOper(source_p
))
702 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
705 source_p
->host
, command
, target_p
->name
, text
);
707 else if (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])
709 if (p_or_n
!= NOTICE
)
710 sendto_one_numeric(source_p
, ERR_NONONREG
,
711 form_str(ERR_NONONREG
),
713 /* Only so opers can watch for floods */
715 (void) flood_attack_client(p_or_n
, source_p
, target_p
);
719 /* check for accept, flag recipient incoming message */
722 sendto_one_numeric(source_p
, ERR_TARGUMODEG
,
723 form_str(ERR_TARGUMODEG
),
727 if((target_p
->localClient
->last_caller_id_time
+
728 ConfigFileEntry
.caller_id_wait
) < rb_current_time())
731 sendto_one_numeric(source_p
, RPL_TARGNOTIFY
,
732 form_str(RPL_TARGNOTIFY
),
735 sendto_one(target_p
, form_str(RPL_UMODEGMSG
),
736 me
.name
, target_p
->name
, source_p
->name
,
737 source_p
->username
, source_p
->host
);
739 target_p
->localClient
->last_caller_id_time
= rb_current_time();
741 /* Only so opers can watch for floods */
743 (void) flood_attack_client(p_or_n
, source_p
, target_p
);
748 /* If the client is remote, we dont perform a special check for
749 * flooding.. as we wouldnt block their message anyway.. this means
750 * we dont give warnings.. we then check if theyre opered
751 * (to avoid flood warnings), lastly if theyre our client
752 * and flooding -- fl */
754 !flood_attack_client(p_or_n
, source_p
, target_p
))
755 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
758 else if(!do_floodcount
||
759 !flood_attack_client(p_or_n
, source_p
, target_p
))
760 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
765 static struct Channel
*
766 find_allowing_channel(struct Client
*source_p
, struct Client
*target_p
)
769 struct membership
*msptr
;
771 RB_DLINK_FOREACH(ptr
, source_p
->user
->channel
.head
)
774 if (is_chanop_voiced(msptr
) && IsMember(target_p
, msptr
->chptr
))
781 * flood_attack_client
782 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
783 * say NOTICE must not auto reply
784 * - pointer to source Client
785 * - pointer to target Client
786 * output - 1 if target is under flood attack
787 * side effects - check for flood attack on target target_p
790 flood_attack_client(int p_or_n
, struct Client
*source_p
, struct Client
*target_p
)
794 /* Services could get many messages legitimately and
795 * can be messaged without rate limiting via aliases
796 * and msg user@server.
799 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
))
801 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
803 delta
= rb_current_time() - target_p
->first_received_message_time
;
804 target_p
->received_number_of_privmsgs
-= delta
;
805 target_p
->first_received_message_time
= rb_current_time();
806 if(target_p
->received_number_of_privmsgs
<= 0)
808 target_p
->received_number_of_privmsgs
= 0;
809 target_p
->flood_noticed
= 0;
813 if((target_p
->received_number_of_privmsgs
>=
814 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
816 if(target_p
->flood_noticed
== 0)
818 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
819 "Possible Flooder %s[%s@%s] on %s target: %s",
820 source_p
->name
, source_p
->username
,
822 source_p
->servptr
->name
, target_p
->name
);
823 target_p
->flood_noticed
= 1;
824 /* add a bit of penalty */
825 target_p
->received_number_of_privmsgs
+= 2;
827 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
829 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
830 me
.name
, source_p
->name
, target_p
->name
);
834 target_p
->received_number_of_privmsgs
++;
841 * flood_attack_channel
842 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
843 * says NOTICE must not auto reply
844 * - pointer to source Client
845 * - pointer to target channel
846 * output - 1 if target is under flood attack
847 * side effects - check for flood attack on target chptr
850 flood_attack_channel(int p_or_n
, struct Client
*source_p
, struct Channel
*chptr
, char *chname
)
854 if(GlobalSetOptions
.floodcount
&& MyClient(source_p
))
856 if((chptr
->first_received_message_time
+ 1) < rb_current_time())
858 delta
= rb_current_time() - chptr
->first_received_message_time
;
859 chptr
->received_number_of_privmsgs
-= delta
;
860 chptr
->first_received_message_time
= rb_current_time();
861 if(chptr
->received_number_of_privmsgs
<= 0)
863 chptr
->received_number_of_privmsgs
= 0;
864 chptr
->flood_noticed
= 0;
868 if((chptr
->received_number_of_privmsgs
>= GlobalSetOptions
.floodcount
)
869 || chptr
->flood_noticed
)
871 if(chptr
->flood_noticed
== 0)
873 sendto_realops_snomask(SNO_BOTS
, *chptr
->chname
== '&' ? L_ALL
: L_NETWIDE
,
874 "Possible Flooder %s[%s@%s] on %s target: %s",
875 source_p
->name
, source_p
->username
,
877 source_p
->servptr
->name
, chptr
->chname
);
878 chptr
->flood_noticed
= 1;
880 /* Add a bit of penalty */
881 chptr
->received_number_of_privmsgs
+= 2;
883 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
885 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
886 me
.name
, source_p
->name
, chptr
->chname
);
890 chptr
->received_number_of_privmsgs
++;
900 * inputs - server pointer
902 * - nick stuff to grok for opers
903 * - text to send if grok
905 * side effects - all the traditional oper type messages are parsed here.
906 * i.e. "/msg #some.host."
907 * However, syntax has been changed.
908 * previous syntax "/msg #some.host.mask"
909 * now becomes "/msg $#some.host.mask"
910 * previous syntax of: "/msg $some.server.mask" remains
911 * This disambiguates the syntax.
914 handle_special(int p_or_n
, const char *command
, struct Client
*client_p
,
915 struct Client
*source_p
, const char *nick
, const char *text
)
917 struct Client
*target_p
;
921 /* user[%host]@server addressed?
922 * NOTE: users can send to user@server, but not user%host@server
925 if((server
= strchr(nick
, '@')) != NULL
)
927 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
929 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
930 form_str(ERR_NOSUCHSERVER
), server
+ 1);
934 if(!IsOper(source_p
))
936 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
938 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
939 form_str(ERR_NOSUCHNICK
), nick
);
944 /* somewhere else.. */
947 sendto_one(target_p
, ":%s %s %s :%s",
948 get_id(source_p
, target_p
), command
, nick
, text
);
952 /* Check if someones msg'ing opers@our.server */
953 if(strncmp(nick
, "opers@", 6) == 0)
955 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
956 source_p
->name
, text
);
960 /* This was not very useful except for bypassing certain
961 * restrictions. Note that we still allow sending to
962 * remote servers this way, for messaging pseudoservers
963 * securely whether they have a service{} block or not.
966 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
967 form_str(ERR_NOSUCHNICK
), nick
);
972 * the following two cases allow masks in NOTICEs
975 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
977 if(IsOper(source_p
) && *nick
== '$')
979 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
981 else if(MyOper(source_p
))
984 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
985 me
.name
, source_p
->name
, command
, nick
, nick
);
989 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
991 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
992 me
.name
, source_p
->name
, "mass_notice");
996 if((s
= strrchr(nick
, '.')) == NULL
)
998 sendto_one_numeric(source_p
, ERR_NOTOPLEVEL
,
999 form_str(ERR_NOTOPLEVEL
), nick
);
1003 if(*s
== '.' || *s
== '*' || *s
== '?')
1005 if(*s
== '*' || *s
== '?')
1007 sendto_one_numeric(source_p
, ERR_WILDTOPLEVEL
,
1008 form_str(ERR_WILDTOPLEVEL
), nick
);
1012 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1014 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1015 "%s $%s :%s", command
, nick
, text
);