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
43 #include "s_newconf.h"
46 #include "inline/stringops.h"
47 #include "irc_dictionary.h"
50 static int m_message(int, const char *, struct Client
*, struct Client
*, int, const char **);
51 static int m_privmsg(struct Client
*, struct Client
*, int, const char **);
52 static int m_notice(struct Client
*, struct Client
*, int, const char **);
54 static void expire_tgchange(void *unused
);
55 static struct ev_entry
*expire_tgchange_event
;
57 struct module_modes ModuleModes
;
62 expire_tgchange_event
= rb_event_addish("expire_tgchange", expire_tgchange
, NULL
, 300);
63 expire_tgchange(NULL
);
70 rb_event_delete(expire_tgchange_event
);
73 struct Message privmsg_msgtab
= {
74 "PRIVMSG", 0, 0, 0, MFLG_SLOW
| MFLG_UNREG
,
75 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
77 struct Message notice_msgtab
= {
78 "NOTICE", 0, 0, 0, MFLG_SLOW
,
79 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
82 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, NULL
};
84 DECLARE_MODULE_AV1(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, "$Revision: 3173 $");
93 static int build_target_list(int p_or_n
, const char *command
,
94 struct Client
*client_p
,
95 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
97 static int flood_attack_client(int p_or_n
, struct Client
*source_p
, struct Client
*target_p
);
98 static int flood_attack_channel(int p_or_n
, struct Client
*source_p
,
99 struct Channel
*chptr
, char *chname
);
101 /* Fifteen seconds should be plenty for a client to reply a ctcp */
102 #define LARGE_CTCP_TIME 15
104 #define ENTITY_NONE 0
105 #define ENTITY_CHANNEL 1
106 #define ENTITY_CHANNEL_OPMOD 2
107 #define ENTITY_CHANOPS_ON_CHANNEL 3
108 #define ENTITY_CLIENT 4
110 static struct entity targets
[512];
111 static int ntargets
= 0;
113 static int duplicate_ptr(void *);
115 static void msg_channel(int p_or_n
, const char *command
,
116 struct Client
*client_p
,
117 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
119 static void msg_channel_opmod(int p_or_n
, const char *command
,
120 struct Client
*client_p
,
121 struct Client
*source_p
, struct Channel
*chptr
,
124 static void msg_channel_flags(int p_or_n
, const char *command
,
125 struct Client
*client_p
,
126 struct Client
*source_p
,
127 struct Channel
*chptr
, int flags
, const char *text
);
129 static void msg_client(int p_or_n
, const char *command
,
130 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
132 static void handle_special(int p_or_n
, const char *command
,
133 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
142 ** Another massive cleanup Nov, 2000
143 ** (I don't think there is a single line left from 6/91. Maybe.)
144 ** m_privmsg and m_notice do basically the same thing.
145 ** in the original 2.8.2 code base, they were the same function
146 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
147 ** of ircu fame, we split m_privmsg.c and m_notice.c.
148 ** I don't see the point of that now. Its harder to maintain, its
149 ** easier to introduce bugs into one version and not the other etc.
150 ** Really, the penalty of an extra function call isn't that big a deal folks.
159 m_privmsg(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
161 return m_message(PRIVMSG
, "PRIVMSG", client_p
, source_p
, parc
, parv
);
165 m_notice(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
167 return m_message(NOTICE
, "NOTICE", client_p
, source_p
, parc
, parv
);
171 * inputs - flag privmsg or notice
172 * - pointer to command "PRIVMSG" or "NOTICE"
173 * - pointer to client_p
174 * - pointer to source_p
175 * - pointer to channel
178 m_message(int p_or_n
,
180 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
184 if(parc
< 2 || EmptyString(parv
[1]))
187 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
188 source_p
->name
, command
);
192 if(parc
< 3 || EmptyString(parv
[2]))
195 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
199 /* Finish the flood grace period if theyre not messaging themselves
200 * as some clients (ircN) do this as a "lag check"
202 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
203 flood_endgrace(source_p
);
205 if(build_target_list(p_or_n
, command
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
210 for(i
= 0; i
< ntargets
; i
++)
212 switch (targets
[i
].type
)
215 msg_channel(p_or_n
, command
, client_p
, source_p
,
216 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
219 case ENTITY_CHANNEL_OPMOD
:
220 msg_channel_opmod(p_or_n
, command
, client_p
, source_p
,
221 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
224 case ENTITY_CHANOPS_ON_CHANNEL
:
225 msg_channel_flags(p_or_n
, command
, client_p
, source_p
,
226 (struct Channel
*) targets
[i
].ptr
,
227 targets
[i
].flags
, parv
[2]);
231 msg_client(p_or_n
, command
, source_p
,
232 (struct Client
*) targets
[i
].ptr
, parv
[2]);
243 * inputs - pointer to given client_p (server)
244 * - pointer to given source (oper/client etc.)
245 * - pointer to list of nicks/channels
246 * - pointer to table to place results
247 * - pointer to text (only used if source_p is an oper)
248 * output - number of valid entities
249 * side effects - target_table is modified to contain a list of
250 * pointers to channels or clients
251 * if source client is an oper
252 * all the classic old bizzare oper privmsg tricks
253 * are parsed and sent as is, if prefixed with $
259 build_target_list(int p_or_n
, const char *command
, struct Client
*client_p
,
260 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
263 char *p
, *nick
, *target_list
;
264 struct Channel
*chptr
= NULL
;
265 struct Client
*target_p
;
267 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
271 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
275 * channels are privmsg'd a lot more than other clients, moved up
276 * here plain old channel msg?
279 if(IsChanPrefix(*nick
))
281 /* ignore send of local channel to a server (should not happen) */
282 if(IsServer(client_p
) && *nick
== '&')
285 if((chptr
= find_channel(nick
)) != NULL
)
287 if(!duplicate_ptr(chptr
))
289 if(ntargets
>= ConfigFileEntry
.max_targets
)
291 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
292 me
.name
, source_p
->name
, nick
);
295 targets
[ntargets
].ptr
= (void *) chptr
;
296 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
300 /* non existant channel */
301 else if(p_or_n
!= NOTICE
)
302 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
303 form_str(ERR_NOSUCHNICK
), nick
);
308 if(MyClient(source_p
))
309 target_p
= find_named_person(nick
);
311 target_p
= find_person(nick
);
313 /* look for a privmsg to another client */
316 if(!duplicate_ptr(target_p
))
318 if(ntargets
>= ConfigFileEntry
.max_targets
)
320 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
321 me
.name
, source_p
->name
, nick
);
324 targets
[ntargets
].ptr
= (void *) target_p
;
325 targets
[ntargets
].type
= ENTITY_CLIENT
;
326 targets
[ntargets
++].flags
= 0;
331 /* @#channel or +#channel message ? */
335 /* allow %+@ if someone wants to do that */
340 else if(*nick
== '+')
341 type
|= CHFL_CHANOP
| CHFL_VOICE
;
350 if(EmptyString(nick
))
352 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
353 me
.name
, source_p
->name
, command
);
357 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
358 * if the channel is found, fine, if not report an error
361 if((chptr
= find_channel(nick
)) != NULL
)
363 struct membership
*msptr
;
365 msptr
= find_channel_membership(chptr
, source_p
);
367 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
369 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
370 get_id(&me
, source_p
),
371 get_id(source_p
, source_p
),
376 if(!duplicate_ptr(chptr
))
378 if(ntargets
>= ConfigFileEntry
.max_targets
)
380 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
381 me
.name
, source_p
->name
, nick
);
384 targets
[ntargets
].ptr
= (void *) chptr
;
385 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
386 targets
[ntargets
++].flags
= type
;
389 else if(p_or_n
!= NOTICE
)
391 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
392 form_str(ERR_NOSUCHNICK
), nick
);
398 if(IsServer(client_p
) && *nick
== '=' && nick
[1] == '#')
401 if((chptr
= find_channel(nick
)) != NULL
)
403 if(!duplicate_ptr(chptr
))
405 if(ntargets
>= ConfigFileEntry
.max_targets
)
407 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
408 me
.name
, source_p
->name
, nick
);
411 targets
[ntargets
].ptr
= (void *) chptr
;
412 targets
[ntargets
++].type
= ENTITY_CHANNEL_OPMOD
;
416 /* non existant channel */
417 else if(p_or_n
!= NOTICE
)
418 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
419 form_str(ERR_NOSUCHNICK
), nick
);
424 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
426 handle_special(p_or_n
, command
, client_p
, source_p
, nick
, text
);
430 /* no matching anything found - error if not NOTICE */
433 /* dont give this numeric when source is local,
434 * because its misleading --anfl
436 if(!MyClient(source_p
) && IsDigit(*nick
))
437 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
438 "Failed to deliver: [%.20s]",
439 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
440 get_id(source_p
, source_p
), text
);
442 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
443 form_str(ERR_NOSUCHNICK
), nick
);
453 * inputs - pointer to check
454 * - pointer to table of entities
455 * - number of valid entities so far
456 * output - YES if duplicate pointer in table, NO if not.
457 * note, this does the canonize using pointers
458 * side effects - NONE
461 duplicate_ptr(void *ptr
)
464 for(i
= 0; i
< ntargets
; i
++)
465 if(targets
[i
].ptr
== ptr
)
473 * inputs - flag privmsg or notice
474 * - pointer to command "PRIVMSG" or "NOTICE"
475 * - pointer to client_p
476 * - pointer to source_p
477 * - pointer to channel
479 * side effects - message given channel
481 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
484 msg_channel(int p_or_n
, const char *command
,
485 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
493 struct membership
*msptr
= find_channel_membership(chptr
, source_p
);
496 if(MyClient(source_p
))
498 /* idle time shouldnt be reset by notices --fl */
500 source_p
->localClient
->last
= rb_current_time();
503 if(chptr
->mode
.mode
& ModuleModes
.MODE_NOREPEAT
)
505 rb_strlcpy(text2
, text
, BUFSIZE
);
506 strip_unprintable(text2
);
507 md
= channel_metadata_find(chptr
, "NOREPEAT");
508 if(md
&& (!ConfigChannel
.exempt_cmode_K
|| !is_any_op(msptr
)))
510 if(!(strcmp(md
->value
, text2
)))
513 sendto_one_numeric(source_p
, 404, "%s :Cannot send to channel - Message blocked due to repeating (+K set)", chptr
->chname
);
517 channel_metadata_delete(chptr
, "NOREPEAT", 0);
518 channel_metadata_add(chptr
, "NOREPEAT", text2
, 0);
521 if(chptr
->mode
.mode
& ModuleModes
.MODE_NOCOLOR
&& (!ConfigChannel
.exempt_cmode_c
|| !is_any_op(msptr
)))
523 rb_strlcpy(text2
, text
, BUFSIZE
);
526 if (EmptyString(text
))
528 /* could be empty after colour stripping and
529 * that would cause problems later */
531 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
536 /* chanops and voiced can flood their own channel with impunity */
537 if((result
= can_send(chptr
, source_p
, NULL
)))
539 if(result
!= CAN_SEND_OPV
&& MyClient(source_p
) &&
541 !add_channel_target(source_p
, chptr
))
543 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
544 me
.name
, source_p
->name
, chptr
->chname
);
547 if(result
== CAN_SEND_OPV
||
548 !flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
550 if (strlen(text
) > 10 && chptr
->mode
.mode
& ModuleModes
.MODE_NOCAPS
&& (!ConfigChannel
.exempt_cmode_G
|| !is_any_op(msptr
)))
552 rb_strlcpy(text2
, text
, BUFSIZE
);
553 strip_unprintable(text2
);
554 for(contor
=0; contor
< strlen(text2
); contor
++)
556 if(IsUpper(text2
[contor
]) && !isdigit(text2
[contor
]))
560 if(((caps
*100)/(len
)) >= 50)
562 sendto_one_numeric(source_p
, 404, "%s :Cannot send to channel - Your message contains mostly capital letters (+G set)", chptr
->chname
);
566 if (p_or_n
!= PRIVMSG
&& chptr
->mode
.mode
& ModuleModes
.MODE_NONOTICE
&& (!ConfigChannel
.exempt_cmode_T
|| !is_any_op(msptr
)))
568 sendto_one_numeric(source_p
, 404, "%s :Cannot send to channel - Notices are disallowed (+T set)", chptr
->chname
);
571 if (p_or_n
!= NOTICE
&& chptr
->mode
.mode
& ModuleModes
.MODE_NOACTION
&&
572 !strncasecmp(text
+ 1, "ACTION", 6) &&
573 (!ConfigChannel
.exempt_cmode_D
|| !is_any_op(msptr
)))
575 sendto_one_numeric(source_p
, 404, "%s :Cannot send to channel - ACTIONs are disallowed (+D set)", chptr
->chname
);
578 if (p_or_n
!= NOTICE
&& *text
== '\001' &&
579 strncasecmp(text
+ 1, "ACTION", 6))
581 if (chptr
->mode
.mode
& ModuleModes
.MODE_NOCTCP
&& (!ConfigChannel
.exempt_cmode_C
|| !is_any_op(msptr
)))
583 sendto_one_numeric(source_p
, 404, "%s :Cannot send to channel - CTCPs to this channel are disallowed (+C set)", chptr
->chname
);
586 else if (rb_dlink_list_length(&chptr
->locmembers
) > (unsigned)(GlobalSetOptions
.floodcount
/ 2))
587 source_p
->large_ctcp_sent
= rb_current_time();
589 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
590 "%s %s :%s", command
, chptr
->chname
, text
);
593 else if(chptr
->mode
.mode
& ModuleModes
.MODE_OPMODERATE
&&
594 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
595 IsMember(source_p
, chptr
)))
597 if(MyClient(source_p
) && !IsOper(source_p
) &&
598 !add_channel_target(source_p
, chptr
))
600 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
601 me
.name
, source_p
->name
, chptr
->chname
);
604 if(!flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
606 sendto_channel_opmod(client_p
, source_p
, chptr
,
613 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
614 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
620 * inputs - flag privmsg or notice
621 * - pointer to command "PRIVMSG" or "NOTICE"
622 * - pointer to client_p
623 * - pointer to source_p
624 * - pointer to channel
626 * side effects - message given channel ops
628 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
631 msg_channel_opmod(int p_or_n
, const char *command
,
632 struct Client
*client_p
, struct Client
*source_p
,
633 struct Channel
*chptr
, const char *text
)
637 if(chptr
->mode
.mode
& ModuleModes
.MODE_NOCOLOR
)
639 rb_strlcpy(text2
, text
, BUFSIZE
);
642 if (EmptyString(text
))
644 /* could be empty after colour stripping and
645 * that would cause problems later */
647 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
652 if(chptr
->mode
.mode
& ModuleModes
.MODE_OPMODERATE
&&
653 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
654 IsMember(source_p
, chptr
)))
656 if(!flood_attack_channel(p_or_n
, source_p
, chptr
, chptr
->chname
))
658 sendto_channel_opmod(client_p
, source_p
, chptr
,
665 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
666 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
673 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
674 * say NOTICE must not auto reply
675 * - pointer to command, "PRIVMSG" or "NOTICE"
676 * - pointer to client_p
677 * - pointer to source_p
678 * - pointer to channel
680 * - pointer to text to send
682 * side effects - message given channel either chanop or voice
685 msg_channel_flags(int p_or_n
, const char *command
, struct Client
*client_p
,
686 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
691 if(flags
& CHFL_VOICE
)
693 type
= ONLY_CHANOPSVOICED
;
702 if(MyClient(source_p
))
704 /* idletime shouldnt be reset by notice --fl */
706 source_p
->localClient
->last
= rb_current_time();
709 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
710 command
, c
, chptr
->chname
, text
);
714 expire_tgchange(void *unused
)
717 rb_dlink_node
*ptr
, *next_ptr
;
719 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
723 if(target
->expiry
< rb_current_time())
725 rb_dlinkDelete(ptr
, &tgchange_list
);
726 rb_patricia_remove(tgchange_tree
, target
->pnode
);
736 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
737 * say NOTICE must not auto reply
738 * - pointer to command, "PRIVMSG" or "NOTICE"
739 * - pointer to source_p source (struct Client *)
740 * - pointer to target_p target (struct Client *)
743 * side effects - message given channel either chanop or voice
746 msg_client(int p_or_n
, const char *command
,
747 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
749 int do_floodcount
= 0;
751 struct DictionaryIter iter
;
755 if(MyClient(source_p
))
758 * XXX: Controversial? Allow target users to send replies
759 * through a +g. Rationale is that people can presently use +g
760 * as a way to taunt users, e.g. harass them and hide behind +g
761 * as a way of griefing. --nenolod
763 if(p_or_n
!= NOTICE
&& MyClient(source_p
) &&
764 IsSetCallerId(source_p
) &&
765 IsSetSCallerId(source_p
) &&
766 !accept_message(target_p
, source_p
))
768 if(rb_dlink_list_length(&source_p
->localClient
->allow_list
) <
769 ConfigFileEntry
.max_accept
)
771 rb_dlinkAddAlloc(target_p
, &source_p
->localClient
->allow_list
);
772 rb_dlinkAddAlloc(source_p
, &target_p
->on_allow_list
);
776 sendto_one_numeric(source_p
, ERR_OWNMODE
,
777 form_str(ERR_OWNMODE
),
778 target_p
->name
, "+g");
783 /* reset idle time for message only if its not to self
784 * and its not a notice */
786 source_p
->localClient
->last
= rb_current_time();
788 /* auto cprivmsg/cnotice */
789 do_floodcount
= !IsOper(source_p
) &&
790 !find_allowing_channel(source_p
, target_p
);
792 /* target change stuff, dont limit ctcp replies as that
793 * would allow people to start filling up random users
794 * targets just by ctcping them
796 if((p_or_n
!= NOTICE
|| *text
!= '\001') &&
797 ConfigFileEntry
.target_change
&& do_floodcount
)
799 if(!add_target(source_p
, target_p
))
801 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
802 me
.name
, source_p
->name
, target_p
->name
);
807 if (do_floodcount
&& p_or_n
== NOTICE
&& *text
== '\001' &&
808 target_p
->large_ctcp_sent
+ LARGE_CTCP_TIME
>= rb_current_time())
812 flood_attack_client(p_or_n
, source_p
, target_p
))
815 else if(source_p
->from
== target_p
->from
)
817 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
818 "Send message to %s[%s] dropped from %s(Fake Dir)",
819 target_p
->name
, target_p
->from
->name
, source_p
->name
);
823 if(MyConnect(source_p
) && (p_or_n
!= NOTICE
) && target_p
->user
&& target_p
->user
->away
)
824 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
825 target_p
->name
, target_p
->user
->away
);
827 if(MyClient(target_p
))
829 if (IsSetNoCTCP(target_p
) && p_or_n
!= NOTICE
&& *text
== '\001' && strncasecmp(text
+ 1, "ACTION", 6))
831 sendto_one_numeric(source_p
, ERR_NOCTCP
,
832 form_str(ERR_NOCTCP
),
835 /* If opers want to go through +g, they should load oaccept.*/
836 else if(!IsServer(source_p
) && !IsService(source_p
) && (IsSetCallerId(target_p
) ||
837 (IsSetSCallerId(target_p
) && !has_common_channel(source_p
, target_p
)) ||
838 (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])))
840 if (IsOper(source_p
))
842 rb_snprintf(text3
, sizeof(text3
), "O%s", source_p
->id
);
843 DICTIONARY_FOREACH(md
, &iter
, target_p
->user
->metadata
)
845 if(!strcmp(md
->value
, "OACCEPT") && !strcmp(md
->name
, text3
))
852 /* Here is the anti-flood bot/spambot code -db */
853 if(accept_message(source_p
, target_p
) || oaccept
)
855 add_reply_target(target_p
, source_p
);
856 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
859 source_p
->host
, command
, target_p
->name
, text
);
861 else if (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])
863 if (p_or_n
!= NOTICE
)
864 sendto_one_numeric(source_p
, ERR_NONONREG
,
865 form_str(ERR_NONONREG
),
868 else if (IsSetSCallerId(target_p
) && !has_common_channel(source_p
, target_p
))
870 if (p_or_n
!= NOTICE
)
871 sendto_one_numeric(source_p
, ERR_NOCOMMONCHAN
,
872 form_str(ERR_NOCOMMONCHAN
),
877 /* check for accept, flag recipient incoming message */
880 sendto_one_numeric(source_p
, ERR_TARGUMODEG
,
881 form_str(ERR_TARGUMODEG
),
885 if((target_p
->localClient
->last_caller_id_time
+
886 ConfigFileEntry
.caller_id_wait
) < rb_current_time())
889 sendto_one_numeric(source_p
, RPL_TARGNOTIFY
,
890 form_str(RPL_TARGNOTIFY
),
893 add_reply_target(target_p
, source_p
);
894 sendto_one(target_p
, form_str(RPL_UMODEGMSG
),
895 me
.name
, target_p
->name
, source_p
->name
,
896 source_p
->username
, source_p
->host
);
898 target_p
->localClient
->last_caller_id_time
= rb_current_time();
904 add_reply_target(target_p
, source_p
);
905 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
909 sendto_anywhere(target_p
, source_p
, command
, ":%s", text
);
915 * flood_attack_client
916 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
917 * say NOTICE must not auto reply
918 * - pointer to source Client
919 * - pointer to target Client
920 * output - 1 if target is under flood attack
921 * side effects - check for flood attack on target target_p
924 flood_attack_client(int p_or_n
, struct Client
*source_p
, struct Client
*target_p
)
928 /* Services could get many messages legitimately and
929 * can be messaged without rate limiting via aliases
930 * and msg user@server.
933 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
) && (!IsOper(source_p
) || !ConfigFileEntry
.true_no_oper_flood
))
935 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
937 delta
= rb_current_time() - target_p
->first_received_message_time
;
938 target_p
->received_number_of_privmsgs
-= delta
;
939 target_p
->first_received_message_time
= rb_current_time();
940 if(target_p
->received_number_of_privmsgs
<= 0)
942 target_p
->received_number_of_privmsgs
= 0;
943 target_p
->flood_noticed
= 0;
947 if((target_p
->received_number_of_privmsgs
>=
948 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
950 if(target_p
->flood_noticed
== 0)
952 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
953 "Possible Flooder %s[%s@%s] on %s target: %s",
954 source_p
->name
, source_p
->username
,
956 source_p
->servptr
->name
, target_p
->name
);
957 target_p
->flood_noticed
= 1;
958 /* add a bit of penalty */
959 target_p
->received_number_of_privmsgs
+= 2;
961 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
963 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
964 me
.name
, source_p
->name
, target_p
->name
);
968 target_p
->received_number_of_privmsgs
++;
975 * flood_attack_channel
976 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
977 * says NOTICE must not auto reply
978 * - pointer to source Client
979 * - pointer to target channel
980 * output - 1 if target is under flood attack
981 * side effects - check for flood attack on target chptr
984 flood_attack_channel(int p_or_n
, struct Client
*source_p
, struct Channel
*chptr
, char *chname
)
988 if(GlobalSetOptions
.floodcount
&& MyClient(source_p
) && (!IsOper(source_p
) || !ConfigFileEntry
.true_no_oper_flood
))
990 if((chptr
->first_received_message_time
+ 1) < rb_current_time())
992 delta
= rb_current_time() - chptr
->first_received_message_time
;
993 chptr
->received_number_of_privmsgs
-= delta
;
994 chptr
->first_received_message_time
= rb_current_time();
995 if(chptr
->received_number_of_privmsgs
<= 0)
997 chptr
->received_number_of_privmsgs
= 0;
998 chptr
->flood_noticed
= 0;
1002 if((chptr
->received_number_of_privmsgs
>= GlobalSetOptions
.floodcount
)
1003 || chptr
->flood_noticed
)
1005 if(chptr
->flood_noticed
== 0)
1007 sendto_realops_snomask(SNO_BOTS
, *chptr
->chname
== '&' ? L_ALL
: L_NETWIDE
,
1008 "Possible Flooder %s[%s@%s] on %s target: %s",
1009 source_p
->name
, source_p
->username
,
1011 source_p
->servptr
->name
, chptr
->chname
);
1012 chptr
->flood_noticed
= 1;
1014 /* Add a bit of penalty */
1015 chptr
->received_number_of_privmsgs
+= 2;
1017 if(MyClient(source_p
) && (p_or_n
!= NOTICE
))
1018 sendto_one(source_p
,
1019 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
1020 me
.name
, source_p
->name
, chptr
->chname
);
1024 chptr
->received_number_of_privmsgs
++;
1034 * inputs - server pointer
1036 * - nick stuff to grok for opers
1037 * - text to send if grok
1039 * side effects - all the traditional oper type messages are parsed here.
1040 * i.e. "/msg #some.host."
1041 * However, syntax has been changed.
1042 * previous syntax "/msg #some.host.mask"
1043 * now becomes "/msg $#some.host.mask"
1044 * previous syntax of: "/msg $some.server.mask" remains
1045 * This disambiguates the syntax.
1048 handle_special(int p_or_n
, const char *command
, struct Client
*client_p
,
1049 struct Client
*source_p
, const char *nick
, const char *text
)
1051 struct Client
*target_p
;
1055 /* user[%host]@server addressed?
1056 * NOTE: users can send to user@server, but not user%host@server
1059 if((server
= strchr(nick
, '@')) != NULL
)
1061 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
1063 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
1064 form_str(ERR_NOSUCHSERVER
), server
+ 1);
1068 if(!IsOper(source_p
))
1070 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
1072 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
1073 form_str(ERR_NOSUCHNICK
), nick
);
1078 /* somewhere else.. */
1081 sendto_one(target_p
, ":%s %s %s :%s",
1082 get_id(source_p
, target_p
), command
, nick
, text
);
1086 /* Check if someones msg'ing opers@our.server */
1087 if(strncmp(nick
, "opers@", 6) == 0)
1089 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
1090 source_p
->name
, text
);
1094 /* This was not very useful except for bypassing certain
1095 * restrictions. Note that we still allow sending to
1096 * remote servers this way, for messaging pseudoservers
1097 * securely whether they have a service{} block or not.
1100 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
1101 form_str(ERR_NOSUCHNICK
), nick
);
1106 * the following two cases allow masks in NOTICEs
1109 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1111 if(IsOper(source_p
) && *nick
== '$')
1113 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
1115 else if(MyOper(source_p
))
1117 sendto_one(source_p
,
1118 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1119 me
.name
, source_p
->name
, command
, nick
, nick
);
1123 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
1125 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
1126 me
.name
, source_p
->name
, "mass_notice");
1130 if((s
= strrchr(nick
, '.')) == NULL
)
1132 sendto_one_numeric(source_p
, ERR_NOTOPLEVEL
,
1133 form_str(ERR_NOTOPLEVEL
), nick
);
1137 if(*s
== '.' || *s
== '*' || *s
== '?')
1139 if(*s
== '*' || *s
== '?')
1141 sendto_one_numeric(source_p
, ERR_WILDTOPLEVEL
,
1142 form_str(ERR_WILDTOPLEVEL
), nick
);
1146 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1148 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1149 "%s $%s :%s", command
, nick
, text
);
1150 if (p_or_n
!= NOTICE
&& *text
== '\001')
1151 source_p
->large_ctcp_sent
= rb_current_time();