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"
47 #include "inline/stringops.h"
49 static int m_message(int, const char *, struct Client
*, struct Client
*, int, const char **);
50 static int m_privmsg(struct Client
*, struct Client
*, int, const char **);
51 static int m_notice(struct Client
*, struct Client
*, int, const char **);
53 static void expire_tgchange(void *unused
);
54 static struct ev_entry
*expire_tgchange_event
;
59 expire_tgchange_event
= rb_event_addish("expire_tgchange", expire_tgchange
, NULL
, 300);
60 expire_tgchange(NULL
);
67 rb_event_delete(expire_tgchange_event
);
70 struct Message privmsg_msgtab
= {
71 "PRIVMSG", 0, 0, 0, MFLG_SLOW
| MFLG_UNREG
,
72 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
74 struct Message notice_msgtab
= {
75 "NOTICE", 0, 0, 0, MFLG_SLOW
,
76 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
79 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, NULL
};
81 DECLARE_MODULE_AV1(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, "$Revision: 3173 $");
90 static int build_target_list(int p_or_n
, const char *command
,
91 struct Client
*client_p
,
92 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
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
);
98 /* Fifteen seconds should be plenty for a client to reply a ctcp */
99 #define LARGE_CTCP_TIME 15
101 #define ENTITY_NONE 0
102 #define ENTITY_CHANNEL 1
103 #define ENTITY_CHANNEL_OPMOD 2
104 #define ENTITY_CHANOPS_ON_CHANNEL 3
105 #define ENTITY_CLIENT 4
107 static struct entity targets
[512];
108 static int ntargets
= 0;
110 static int duplicate_ptr(void *);
112 static void msg_channel(int p_or_n
, const char *command
,
113 struct Client
*client_p
,
114 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
116 static void msg_channel_opmod(int p_or_n
, const char *command
,
117 struct Client
*client_p
,
118 struct Client
*source_p
, struct Channel
*chptr
,
121 static void msg_channel_flags(int p_or_n
, const char *command
,
122 struct Client
*client_p
,
123 struct Client
*source_p
,
124 struct Channel
*chptr
, int flags
, const char *text
);
126 static void msg_client(int p_or_n
, const char *command
,
127 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
129 static void handle_special(int p_or_n
, const char *command
,
130 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
139 ** Another massive cleanup Nov, 2000
140 ** (I don't think there is a single line left from 6/91. Maybe.)
141 ** m_privmsg and m_notice do basically the same thing.
142 ** in the original 2.8.2 code base, they were the same function
143 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
144 ** of ircu fame, we split m_privmsg.c and m_notice.c.
145 ** I don't see the point of that now. Its harder to maintain, its
146 ** easier to introduce bugs into one version and not the other etc.
147 ** Really, the penalty of an extra function call isn't that big a deal folks.
156 m_privmsg(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
158 return m_message(PRIVMSG
, "PRIVMSG", client_p
, source_p
, parc
, parv
);
162 m_notice(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
164 return m_message(NOTICE
, "NOTICE", client_p
, source_p
, parc
, parv
);
168 * inputs - flag privmsg or notice
169 * - pointer to command "PRIVMSG" or "NOTICE"
170 * - pointer to client_p
171 * - pointer to source_p
172 * - pointer to channel
175 m_message(int p_or_n
,
177 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
181 if(parc
< 2 || EmptyString(parv
[1]))
184 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
185 source_p
->name
, command
);
189 if(parc
< 3 || EmptyString(parv
[2]))
192 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
196 /* Finish the flood grace period if theyre not messaging themselves
197 * as some clients (ircN) do this as a "lag check"
199 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
200 flood_endgrace(source_p
);
202 if(build_target_list(p_or_n
, command
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
207 for(i
= 0; i
< ntargets
; i
++)
209 switch (targets
[i
].type
)
212 msg_channel(p_or_n
, command
, client_p
, source_p
,
213 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
216 case ENTITY_CHANNEL_OPMOD
:
217 msg_channel_opmod(p_or_n
, command
, client_p
, source_p
,
218 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
221 case ENTITY_CHANOPS_ON_CHANNEL
:
222 msg_channel_flags(p_or_n
, command
, client_p
, source_p
,
223 (struct Channel
*) targets
[i
].ptr
,
224 targets
[i
].flags
, parv
[2]);
228 msg_client(p_or_n
, command
, source_p
,
229 (struct Client
*) targets
[i
].ptr
, parv
[2]);
240 * inputs - pointer to given client_p (server)
241 * - pointer to given source (oper/client etc.)
242 * - pointer to list of nicks/channels
243 * - pointer to table to place results
244 * - pointer to text (only used if source_p is an oper)
245 * output - number of valid entities
246 * side effects - target_table is modified to contain a list of
247 * pointers to channels or clients
248 * if source client is an oper
249 * all the classic old bizzare oper privmsg tricks
250 * are parsed and sent as is, if prefixed with $
256 build_target_list(int p_or_n
, const char *command
, struct Client
*client_p
,
257 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
260 char *p
, *nick
, *target_list
;
261 struct Channel
*chptr
= NULL
;
262 struct Client
*target_p
;
264 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
268 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
272 * channels are privmsg'd a lot more than other clients, moved up
273 * here plain old channel msg?
276 if(IsChanPrefix(*nick
))
278 /* ignore send of local channel to a server (should not happen) */
279 if(IsServer(client_p
) && *nick
== '&')
282 if((chptr
= find_channel(nick
)) != NULL
)
284 if(!duplicate_ptr(chptr
))
286 if(ntargets
>= ConfigFileEntry
.max_targets
)
288 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
289 me
.name
, source_p
->name
, nick
);
292 targets
[ntargets
].ptr
= (void *) chptr
;
293 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
297 /* non existant channel */
298 else if(p_or_n
!= NOTICE
)
299 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
300 form_str(ERR_NOSUCHNICK
), nick
);
305 if(MyClient(source_p
))
306 target_p
= find_named_person(nick
);
308 target_p
= find_person(nick
);
310 /* look for a privmsg to another client */
313 if(!duplicate_ptr(target_p
))
315 if(ntargets
>= ConfigFileEntry
.max_targets
)
317 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
318 me
.name
, source_p
->name
, nick
);
321 targets
[ntargets
].ptr
= (void *) target_p
;
322 targets
[ntargets
].type
= ENTITY_CLIENT
;
323 targets
[ntargets
++].flags
= 0;
328 /* @#channel or +#channel message ? */
332 /* allow %+@ if someone wants to do that */
337 else if(*nick
== '+')
338 type
|= CHFL_CHANOP
| CHFL_VOICE
;
347 if(EmptyString(nick
))
349 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
350 me
.name
, source_p
->name
, command
);
354 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
355 * if the channel is found, fine, if not report an error
358 if((chptr
= find_channel(nick
)) != NULL
)
360 struct membership
*msptr
;
362 msptr
= find_channel_membership(chptr
, source_p
);
364 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
366 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
367 get_id(&me
, source_p
),
368 get_id(source_p
, source_p
),
373 if(!duplicate_ptr(chptr
))
375 if(ntargets
>= ConfigFileEntry
.max_targets
)
377 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
378 me
.name
, source_p
->name
, nick
);
381 targets
[ntargets
].ptr
= (void *) chptr
;
382 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
383 targets
[ntargets
++].flags
= type
;
386 else if(p_or_n
!= NOTICE
)
388 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
389 form_str(ERR_NOSUCHNICK
), nick
);
395 if(IsServer(client_p
) && *nick
== '=' && nick
[1] == '#')
398 if((chptr
= find_channel(nick
)) != NULL
)
400 if(!duplicate_ptr(chptr
))
402 if(ntargets
>= ConfigFileEntry
.max_targets
)
404 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
405 me
.name
, source_p
->name
, nick
);
408 targets
[ntargets
].ptr
= (void *) chptr
;
409 targets
[ntargets
++].type
= ENTITY_CHANNEL_OPMOD
;
413 /* non existant channel */
414 else if(p_or_n
!= NOTICE
)
415 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
416 form_str(ERR_NOSUCHNICK
), nick
);
421 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
423 handle_special(p_or_n
, command
, client_p
, source_p
, nick
, text
);
427 /* no matching anything found - error if not NOTICE */
430 /* dont give this numeric when source is local,
431 * because its misleading --anfl
433 if(!MyClient(source_p
) && IsDigit(*nick
))
434 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
435 "Failed to deliver: [%.20s]",
436 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
437 get_id(source_p
, source_p
), text
);
439 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
440 form_str(ERR_NOSUCHNICK
), nick
);
450 * inputs - pointer to check
451 * - pointer to table of entities
452 * - number of valid entities so far
453 * output - YES if duplicate pointer in table, NO if not.
454 * note, this does the canonize using pointers
455 * side effects - NONE
458 duplicate_ptr(void *ptr
)
461 for(i
= 0; i
< ntargets
; i
++)
462 if(targets
[i
].ptr
== ptr
)
470 * inputs - flag privmsg or notice
471 * - pointer to command "PRIVMSG" or "NOTICE"
472 * - pointer to client_p
473 * - pointer to source_p
474 * - pointer to channel
476 * side effects - message given channel
478 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
481 msg_channel(int p_or_n
, const char *command
,
482 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
488 if(MyClient(source_p
))
490 /* idle time shouldnt be reset by notices --fl */
492 source_p
->localClient
->last
= rb_current_time();
495 if(chptr
->mode
.mode
& MODE_NOCOLOR
)
497 rb_strlcpy(text2
, text
, BUFSIZE
);
500 if (EmptyString(text
))
502 /* could be empty after colour stripping and
503 * that would cause problems later */
505 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
510 /* chanops and voiced can flood their own channel with impunity */
511 if((result
= can_send(chptr
, source_p
, NULL
)))
513 if(result
!= CAN_SEND_OPV
&& MyClient(source_p
) &&
515 !add_channel_target(source_p
, chptr
))
517 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
518 me
.name
, source_p
->name
, chptr
->chname
);
521 if(result
== CAN_SEND_OPV
||
522 !flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
524 if (p_or_n
!= NOTICE
&& *text
== '\001' &&
525 strncasecmp(text
+ 1, "ACTION", 6))
527 if (chptr
->mode
.mode
& MODE_NOCTCP
)
529 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
530 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
533 else if (rb_dlink_list_length(&chptr
->locmembers
) > (unsigned)(GlobalSetOptions
.floodcount
/ 2))
534 source_p
->large_ctcp_sent
= rb_current_time();
536 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
537 "%s %s :%s", command
, chptr
->chname
, text
);
540 else if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
541 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
542 IsMember(source_p
, chptr
)))
544 if(MyClient(source_p
) && !IsOper(source_p
) &&
545 !add_channel_target(source_p
, chptr
))
547 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
548 me
.name
, source_p
->name
, chptr
->chname
);
551 if(!flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
553 sendto_channel_opmod(client_p
, source_p
, chptr
,
560 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
561 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
567 * inputs - flag privmsg or notice
568 * - pointer to command "PRIVMSG" or "NOTICE"
569 * - pointer to client_p
570 * - pointer to source_p
571 * - pointer to channel
573 * side effects - message given channel ops
575 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
578 msg_channel_opmod(int p_or_n
, const char *command
,
579 struct Client
*client_p
, struct Client
*source_p
,
580 struct Channel
*chptr
, const char *text
)
584 if(chptr
->mode
.mode
& MODE_NOCOLOR
)
586 rb_strlcpy(text2
, text
, BUFSIZE
);
589 if (EmptyString(text
))
591 /* could be empty after colour stripping and
592 * that would cause problems later */
594 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
599 if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
600 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
601 IsMember(source_p
, chptr
)))
603 if(!flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
605 sendto_channel_opmod(client_p
, source_p
, chptr
,
612 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
613 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
620 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
621 * say NOTICE must not auto reply
622 * - pointer to command, "PRIVMSG" or "NOTICE"
623 * - pointer to client_p
624 * - pointer to source_p
625 * - pointer to channel
627 * - pointer to text to send
629 * side effects - message given channel either chanop or voice
632 msg_channel_flags(int p_or_n
, const char *command
, struct Client
*client_p
,
633 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
638 if(flags
& CHFL_VOICE
)
640 type
= ONLY_CHANOPSVOICED
;
649 if(MyClient(source_p
))
651 /* idletime shouldnt be reset by notice --fl */
653 source_p
->localClient
->last
= rb_current_time();
656 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
657 command
, c
, chptr
->chname
, text
);
661 expire_tgchange(void *unused
)
664 rb_dlink_node
*ptr
, *next_ptr
;
666 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
670 if(target
->expiry
< rb_current_time())
672 rb_dlinkDelete(ptr
, &tgchange_list
);
673 rb_patricia_remove(tgchange_tree
, target
->pnode
);
683 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
684 * say NOTICE must not auto reply
685 * - pointer to command, "PRIVMSG" or "NOTICE"
686 * - pointer to source_p source (struct Client *)
687 * - pointer to target_p target (struct Client *)
690 * side effects - message given channel either chanop or voice
693 msg_client(int p_or_n
, const char *command
,
694 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
696 int do_floodcount
= 0;
698 if(MyClient(source_p
))
701 * XXX: Controversial? Allow target users to send replies
702 * through a +g. Rationale is that people can presently use +g
703 * as a way to taunt users, e.g. harass them and hide behind +g
704 * as a way of griefing. --nenolod
706 if(p_or_n
!= NOTICE
&& IsSetCallerId(source_p
) &&
707 !accept_message(target_p
, source_p
) &&
710 if(rb_dlink_list_length(&source_p
->localClient
->allow_list
) <
711 ConfigFileEntry
.max_accept
)
713 rb_dlinkAddAlloc(target_p
, &source_p
->localClient
->allow_list
);
714 rb_dlinkAddAlloc(source_p
, &target_p
->on_allow_list
);
718 sendto_one_numeric(source_p
, ERR_OWNMODE
,
719 form_str(ERR_OWNMODE
),
720 target_p
->name
, "+g");
725 /* reset idle time for message only if its not to self
726 * and its not a notice */
728 source_p
->localClient
->last
= rb_current_time();
730 /* auto cprivmsg/cnotice */
731 do_floodcount
= !IsOper(source_p
) &&
732 !find_allowing_channel(source_p
, target_p
);
734 /* target change stuff, dont limit ctcp replies as that
735 * would allow people to start filling up random users
736 * targets just by ctcping them
738 if((p_or_n
!= NOTICE
|| *text
!= '\001') &&
739 ConfigFileEntry
.target_change
&& do_floodcount
)
741 if(!add_target(source_p
, target_p
))
743 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
744 me
.name
, source_p
->name
, target_p
->name
);
749 if (do_floodcount
&& p_or_n
== NOTICE
&& *text
== '\001' &&
750 target_p
->large_ctcp_sent
+ LARGE_CTCP_TIME
>= rb_current_time())
754 flood_attack_client(p_or_n
, source_p
, target_p
))
757 else if(source_p
->from
== target_p
->from
)
759 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
760 "Send message to %s[%s] dropped from %s(Fake Dir)",
761 target_p
->name
, target_p
->from
->name
, source_p
->name
);
765 if(MyConnect(source_p
) && (p_or_n
!= NOTICE
) && target_p
->user
&& target_p
->user
->away
)
766 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
767 target_p
->name
, target_p
->user
->away
);
769 if(MyClient(target_p
))
771 /* XXX Controversial? allow opers always to send through a +g */
772 if(!IsServer(source_p
) && (IsSetCallerId(target_p
) ||
773 (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])))
775 /* Here is the anti-flood bot/spambot code -db */
776 if(accept_message(source_p
, target_p
) || IsOper(source_p
))
778 add_reply_target(target_p
, source_p
);
779 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
782 source_p
->host
, command
, target_p
->name
, text
);
784 else if (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])
786 if (p_or_n
!= NOTICE
)
787 sendto_one_numeric(source_p
, ERR_NONONREG
,
788 form_str(ERR_NONONREG
),
793 /* check for accept, flag recipient incoming message */
796 sendto_one_numeric(source_p
, ERR_TARGUMODEG
,
797 form_str(ERR_TARGUMODEG
),
801 if((target_p
->localClient
->last_caller_id_time
+
802 ConfigFileEntry
.caller_id_wait
) < rb_current_time())
805 sendto_one_numeric(source_p
, RPL_TARGNOTIFY
,
806 form_str(RPL_TARGNOTIFY
),
809 add_reply_target(target_p
, source_p
);
810 sendto_one(target_p
, form_str(RPL_UMODEGMSG
),
811 me
.name
, target_p
->name
, source_p
->name
,
812 source_p
->username
, source_p
->host
);
814 target_p
->localClient
->last_caller_id_time
= rb_current_time();
820 add_reply_target(target_p
, source_p
);
821 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
825 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
831 * flood_attack_client
832 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
833 * say NOTICE must not auto reply
834 * - pointer to source Client
835 * - pointer to target Client
836 * output - 1 if target is under flood attack
837 * side effects - check for flood attack on target target_p
840 flood_attack_client(int p_or_n
, struct Client
*source_p
, struct Client
*target_p
)
844 /* Services could get many messages legitimately and
845 * can be messaged without rate limiting via aliases
846 * and msg user@server.
849 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
))
851 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
853 delta
= rb_current_time() - target_p
->first_received_message_time
;
854 target_p
->received_number_of_privmsgs
-= delta
;
855 target_p
->first_received_message_time
= rb_current_time();
856 if(target_p
->received_number_of_privmsgs
<= 0)
858 target_p
->received_number_of_privmsgs
= 0;
859 target_p
->flood_noticed
= 0;
863 if((target_p
->received_number_of_privmsgs
>=
864 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
866 if(target_p
->flood_noticed
== 0)
868 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
869 "Possible Flooder %s[%s@%s] on %s target: %s",
870 source_p
->name
, source_p
->username
,
872 source_p
->servptr
->name
, target_p
->name
);
873 target_p
->flood_noticed
= 1;
874 /* add a bit of penalty */
875 target_p
->received_number_of_privmsgs
+= 2;
877 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
879 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
880 me
.name
, source_p
->name
, target_p
->name
);
884 target_p
->received_number_of_privmsgs
++;
891 * flood_attack_channel
892 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
893 * says NOTICE must not auto reply
894 * - pointer to source Client
895 * - pointer to target channel
896 * output - 1 if target is under flood attack
897 * side effects - check for flood attack on target chptr
900 flood_attack_channel(int p_or_n
, struct Client
*source_p
, struct Channel
*chptr
, char *chname
)
904 if(GlobalSetOptions
.floodcount
&& MyClient(source_p
))
906 if((chptr
->first_received_message_time
+ 1) < rb_current_time())
908 delta
= rb_current_time() - chptr
->first_received_message_time
;
909 chptr
->received_number_of_privmsgs
-= delta
;
910 chptr
->first_received_message_time
= rb_current_time();
911 if(chptr
->received_number_of_privmsgs
<= 0)
913 chptr
->received_number_of_privmsgs
= 0;
914 chptr
->flood_noticed
= 0;
918 if((chptr
->received_number_of_privmsgs
>= GlobalSetOptions
.floodcount
)
919 || chptr
->flood_noticed
)
921 if(chptr
->flood_noticed
== 0)
923 sendto_realops_snomask(SNO_BOTS
, *chptr
->chname
== '&' ? L_ALL
: L_NETWIDE
,
924 "Possible Flooder %s[%s@%s] on %s target: %s",
925 source_p
->name
, source_p
->username
,
927 source_p
->servptr
->name
, chptr
->chname
);
928 chptr
->flood_noticed
= 1;
930 /* Add a bit of penalty */
931 chptr
->received_number_of_privmsgs
+= 2;
933 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
935 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
936 me
.name
, source_p
->name
, chptr
->chname
);
940 chptr
->received_number_of_privmsgs
++;
950 * inputs - server pointer
952 * - nick stuff to grok for opers
953 * - text to send if grok
955 * side effects - all the traditional oper type messages are parsed here.
956 * i.e. "/msg #some.host."
957 * However, syntax has been changed.
958 * previous syntax "/msg #some.host.mask"
959 * now becomes "/msg $#some.host.mask"
960 * previous syntax of: "/msg $some.server.mask" remains
961 * This disambiguates the syntax.
964 handle_special(int p_or_n
, const char *command
, struct Client
*client_p
,
965 struct Client
*source_p
, const char *nick
, const char *text
)
967 struct Client
*target_p
;
971 /* user[%host]@server addressed?
972 * NOTE: users can send to user@server, but not user%host@server
975 if((server
= strchr(nick
, '@')) != NULL
)
977 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
979 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
980 form_str(ERR_NOSUCHSERVER
), server
+ 1);
984 if(!IsOper(source_p
))
986 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
988 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
989 form_str(ERR_NOSUCHNICK
), nick
);
994 /* somewhere else.. */
997 sendto_one(target_p
, ":%s %s %s :%s",
998 get_id(source_p
, target_p
), command
, nick
, text
);
1002 /* Check if someones msg'ing opers@our.server */
1003 if(strncmp(nick
, "opers@", 6) == 0)
1005 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
1006 source_p
->name
, text
);
1010 /* This was not very useful except for bypassing certain
1011 * restrictions. Note that we still allow sending to
1012 * remote servers this way, for messaging pseudoservers
1013 * securely whether they have a service{} block or not.
1016 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
1017 form_str(ERR_NOSUCHNICK
), nick
);
1022 * the following two cases allow masks in NOTICEs
1025 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1027 if(IsOper(source_p
) && *nick
== '$')
1029 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
1031 else if(MyOper(source_p
))
1033 sendto_one(source_p
,
1034 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1035 me
.name
, source_p
->name
, command
, nick
, nick
);
1039 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
1041 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
1042 me
.name
, source_p
->name
, "mass_notice");
1046 if((s
= strrchr(nick
, '.')) == NULL
)
1048 sendto_one_numeric(source_p
, ERR_NOTOPLEVEL
,
1049 form_str(ERR_NOTOPLEVEL
), nick
);
1053 if(*s
== '.' || *s
== '*' || *s
== '?')
1055 if(*s
== '*' || *s
== '?')
1057 sendto_one_numeric(source_p
, ERR_WILDTOPLEVEL
,
1058 form_str(ERR_WILDTOPLEVEL
), nick
);
1062 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1064 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1065 "%s $%s :%s", command
, nick
, text
);
1066 if (p_or_n
!= NOTICE
&& *text
== '\001')
1067 source_p
->large_ctcp_sent
= rb_current_time();