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
42 #include "s_newconf.h"
45 #include "inline/stringops.h"
47 static const char message_desc
[] =
48 "Provides the PRIVMSG and NOTICE commands to send messages to users and channels";
50 static void m_message(enum message_type
, struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
51 static void m_privmsg(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
52 static void m_notice(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
54 static void expire_tgchange(void *unused
);
55 static struct ev_entry
*expire_tgchange_event
;
60 expire_tgchange_event
= rb_event_addish("expire_tgchange", expire_tgchange
, NULL
, 300);
61 expire_tgchange(NULL
);
68 rb_event_delete(expire_tgchange_event
);
71 struct Message privmsg_msgtab
= {
72 "PRIVMSG", 0, 0, 0, 0,
73 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
75 struct Message notice_msgtab
= {
77 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
80 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, NULL
};
82 DECLARE_MODULE_AV2(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, NULL
, NULL
, message_desc
);
91 static int build_target_list(enum message_type msgtype
,
92 struct Client
*client_p
,
93 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
95 static bool flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
);
97 /* Fifteen seconds should be plenty for a client to reply a ctcp */
98 #define LARGE_CTCP_TIME 15
100 #define ENTITY_NONE 0
101 #define ENTITY_CHANNEL 1
102 #define ENTITY_CHANNEL_OPMOD 2
103 #define ENTITY_CHANOPS_ON_CHANNEL 3
104 #define ENTITY_CLIENT 4
106 static struct entity targets
[512];
107 static int ntargets
= 0;
109 static bool duplicate_ptr(void *);
111 static void msg_channel(enum message_type msgtype
,
112 struct Client
*client_p
,
113 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
115 static void msg_channel_opmod(enum message_type msgtype
,
116 struct Client
*client_p
,
117 struct Client
*source_p
, struct Channel
*chptr
,
120 static void msg_channel_flags(enum message_type msgtype
,
121 struct Client
*client_p
,
122 struct Client
*source_p
,
123 struct Channel
*chptr
, int flags
, const char *text
);
125 static void msg_client(enum message_type msgtype
,
126 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
128 static void handle_special(enum message_type msgtype
,
129 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
138 ** Another massive cleanup Nov, 2000
139 ** (I don't think there is a single line left from 6/91. Maybe.)
140 ** m_privmsg and m_notice do basically the same thing.
141 ** in the original 2.8.2 code base, they were the same function
142 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
143 ** of ircu fame, we split m_privmsg.c and m_notice.c.
144 ** I don't see the point of that now. Its harder to maintain, its
145 ** easier to introduce bugs into one version and not the other etc.
146 ** Really, the penalty of an extra function call isn't that big a deal folks.
150 const char *cmdname
[MESSAGE_TYPE_COUNT
] = {
151 [MESSAGE_TYPE_PRIVMSG
] = "PRIVMSG",
152 [MESSAGE_TYPE_NOTICE
] = "NOTICE",
156 m_privmsg(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
158 m_message(MESSAGE_TYPE_PRIVMSG
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
162 m_notice(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
164 m_message(MESSAGE_TYPE_NOTICE
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
168 * inputs - flag privmsg or notice
169 * - pointer to client_p
170 * - pointer to source_p
171 * - pointer to channel
174 m_message(enum message_type msgtype
, struct MsgBuf
*msgbuf_p
,
175 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
179 if(parc
< 2 || EmptyString(parv
[1]))
181 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
182 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
183 source_p
->name
, cmdname
[msgtype
]);
187 if(parc
< 3 || EmptyString(parv
[2]))
189 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
190 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
194 /* Finish the flood grace period if theyre not messaging themselves
195 * as some clients (ircN) do this as a "lag check"
197 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
198 flood_endgrace(source_p
);
200 if(build_target_list(msgtype
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
205 for(i
= 0; i
< ntargets
; i
++)
207 switch (targets
[i
].type
)
210 msg_channel(msgtype
, client_p
, source_p
,
211 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
214 case ENTITY_CHANNEL_OPMOD
:
215 msg_channel_opmod(msgtype
, client_p
, source_p
,
216 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
219 case ENTITY_CHANOPS_ON_CHANNEL
:
220 msg_channel_flags(msgtype
, client_p
, source_p
,
221 (struct Channel
*) targets
[i
].ptr
,
222 targets
[i
].flags
, parv
[2]);
226 msg_client(msgtype
, source_p
,
227 (struct Client
*) targets
[i
].ptr
, parv
[2]);
236 * inputs - pointer to given client_p (server)
237 * - pointer to given source (oper/client etc.)
238 * - pointer to list of nicks/channels
239 * - pointer to table to place results
240 * - pointer to text (only used if source_p is an oper)
241 * output - number of valid entities
242 * side effects - target_table is modified to contain a list of
243 * pointers to channels or clients
244 * if source client is an oper
245 * all the classic old bizzare oper privmsg tricks
246 * are parsed and sent as is, if prefixed with $
251 build_target_list(enum message_type msgtype
, struct Client
*client_p
,
252 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
255 char *p
, *nick
, *target_list
;
256 struct Channel
*chptr
= NULL
;
257 struct Client
*target_p
;
259 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
263 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
267 * channels are privmsg'd a lot more than other clients, moved up
268 * here plain old channel msg?
271 if(IsChanPrefix(*nick
))
273 /* ignore send of local channel to a server (should not happen) */
274 if(IsServer(client_p
) && *nick
== '&')
277 if((chptr
= find_channel(nick
)) != NULL
)
279 if(!duplicate_ptr(chptr
))
281 if(ntargets
>= ConfigFileEntry
.max_targets
)
283 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
284 me
.name
, source_p
->name
, nick
);
287 targets
[ntargets
].ptr
= (void *) chptr
;
288 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
292 /* non existant channel */
293 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
294 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
295 form_str(ERR_NOSUCHNICK
), nick
);
300 if(MyClient(source_p
))
301 target_p
= find_named_person(nick
);
303 target_p
= find_person(nick
);
305 /* look for a privmsg to another client */
308 if(!duplicate_ptr(target_p
))
310 if(ntargets
>= ConfigFileEntry
.max_targets
)
312 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
313 me
.name
, source_p
->name
, nick
);
316 targets
[ntargets
].ptr
= (void *) target_p
;
317 targets
[ntargets
].type
= ENTITY_CLIENT
;
318 targets
[ntargets
++].flags
= 0;
323 /* @#channel or +#channel message ? */
327 /* allow %+@ if someone wants to do that */
332 else if(*nick
== '+')
333 type
|= CHFL_CHANOP
| CHFL_VOICE
;
342 if(EmptyString(nick
))
344 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
345 me
.name
, source_p
->name
, cmdname
[msgtype
]);
349 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
350 * if the channel is found, fine, if not report an error
353 if((chptr
= find_channel(nick
)) != NULL
)
355 struct membership
*msptr
;
357 msptr
= find_channel_membership(chptr
, source_p
);
359 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
361 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
362 get_id(&me
, source_p
),
363 get_id(source_p
, source_p
),
368 if(!duplicate_ptr(chptr
))
370 if(ntargets
>= ConfigFileEntry
.max_targets
)
372 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
373 me
.name
, source_p
->name
, nick
);
376 targets
[ntargets
].ptr
= (void *) chptr
;
377 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
378 targets
[ntargets
++].flags
= type
;
381 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
383 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
384 form_str(ERR_NOSUCHNICK
), nick
);
390 if(IsServer(client_p
) && *nick
== '=' && nick
[1] == '#')
393 if((chptr
= find_channel(nick
)) != NULL
)
395 if(!duplicate_ptr(chptr
))
397 if(ntargets
>= ConfigFileEntry
.max_targets
)
399 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
400 me
.name
, source_p
->name
, nick
);
403 targets
[ntargets
].ptr
= (void *) chptr
;
404 targets
[ntargets
++].type
= ENTITY_CHANNEL_OPMOD
;
408 /* non existant channel */
409 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
410 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
411 form_str(ERR_NOSUCHNICK
), nick
);
416 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
418 handle_special(msgtype
, client_p
, source_p
, nick
, text
);
422 /* no matching anything found - error if not NOTICE */
423 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
425 /* dont give this numeric when source is local,
426 * because its misleading --anfl
428 if(!MyClient(source_p
) && IsDigit(*nick
))
429 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
430 "Failed to deliver: [%.20s]",
431 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
432 get_id(source_p
, source_p
), text
);
434 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
435 form_str(ERR_NOSUCHNICK
), nick
);
445 * inputs - pointer to check
446 * - pointer to table of entities
447 * - number of valid entities so far
448 * output - true if duplicate pointer in table, false if not.
449 * note, this does the canonize using pointers
450 * side effects - NONE
453 duplicate_ptr(void *ptr
)
456 for(i
= 0; i
< ntargets
; i
++)
457 if(targets
[i
].ptr
== ptr
)
465 * inputs - flag privmsg or notice
466 * - pointer to client_p
467 * - pointer to source_p
468 * - pointer to channel
470 * side effects - message given channel
472 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
475 msg_channel(enum message_type msgtype
,
476 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
480 hook_data_privmsg_channel hdata
;
482 if(MyClient(source_p
))
484 /* idle time shouldnt be reset by notices --fl */
485 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
486 source_p
->localClient
->last
= rb_current_time();
489 hdata
.msgtype
= msgtype
;
490 hdata
.source_p
= source_p
;
495 call_hook(h_privmsg_channel
, &hdata
);
497 /* memory buffer address may have changed, update pointer */
500 if (hdata
.approved
!= 0)
503 /* hook may have reduced the string to nothing. */
504 if (EmptyString(text
))
506 /* could be empty after colour stripping and
507 * that would cause problems later */
508 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
509 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
513 /* chanops and voiced can flood their own channel with impunity */
514 if((result
= can_send(chptr
, source_p
, NULL
)))
516 if(result
!= CAN_SEND_OPV
&& MyClient(source_p
) &&
518 !add_channel_target(source_p
, chptr
))
520 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
521 me
.name
, source_p
->name
, chptr
->chname
);
524 if(result
== CAN_SEND_OPV
||
525 !flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
527 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
528 "%s %s :%s", cmdname
[msgtype
], chptr
->chname
, text
);
531 else if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
532 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
533 IsMember(source_p
, chptr
)))
535 if(MyClient(source_p
) && !IsOper(source_p
) &&
536 !add_channel_target(source_p
, chptr
))
538 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
539 me
.name
, source_p
->name
, chptr
->chname
);
542 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
544 sendto_channel_opmod(client_p
, source_p
, chptr
,
545 cmdname
[msgtype
], text
);
550 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
551 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
552 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
558 * inputs - flag privmsg or notice
559 * - pointer to client_p
560 * - pointer to source_p
561 * - pointer to channel
563 * side effects - message given channel ops
565 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
568 msg_channel_opmod(enum message_type msgtype
,
569 struct Client
*client_p
, struct Client
*source_p
,
570 struct Channel
*chptr
, const char *text
)
572 hook_data_privmsg_channel hdata
;
574 hdata
.msgtype
= msgtype
;
575 hdata
.source_p
= source_p
;
580 call_hook(h_privmsg_channel
, &hdata
);
582 /* memory buffer address may have changed, update pointer */
585 if (hdata
.approved
!= 0)
588 /* hook may have reduced the string to nothing. */
589 if (EmptyString(text
))
591 /* could be empty after colour stripping and
592 * that would cause problems later */
593 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
594 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
598 if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
599 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
600 IsMember(source_p
, chptr
)))
602 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
604 sendto_channel_opmod(client_p
, source_p
, chptr
,
605 cmdname
[msgtype
], text
);
610 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
611 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
612 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
619 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
620 * say NOTICE must not auto reply
621 * - pointer to client_p
622 * - pointer to source_p
623 * - pointer to channel
625 * - pointer to text to send
627 * side effects - message given channel either chanop or voice
630 msg_channel_flags(enum message_type msgtype
, struct Client
*client_p
,
631 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
635 hook_data_privmsg_channel hdata
;
637 if(flags
& CHFL_VOICE
)
639 type
= ONLY_CHANOPSVOICED
;
648 if(MyClient(source_p
))
650 /* idletime shouldnt be reset by notice --fl */
651 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
652 source_p
->localClient
->last
= rb_current_time();
655 hdata
.msgtype
= msgtype
;
656 hdata
.source_p
= source_p
;
661 call_hook(h_privmsg_channel
, &hdata
);
663 /* memory buffer address may have changed, update pointer */
666 if (hdata
.approved
!= 0)
669 if (EmptyString(text
))
671 /* could be empty after colour stripping and
672 * that would cause problems later */
673 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
674 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
678 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
679 cmdname
[msgtype
], c
, chptr
->chname
, text
);
683 expire_tgchange(void *unused
)
686 rb_dlink_node
*ptr
, *next_ptr
;
688 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
692 if(target
->expiry
< rb_current_time())
694 rb_dlinkDelete(ptr
, &tgchange_list
);
695 rb_patricia_remove(tgchange_tree
, target
->pnode
);
705 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
706 * say NOTICE must not auto reply
707 * - pointer to source_p source (struct Client *)
708 * - pointer to target_p target (struct Client *)
711 * side effects - message given channel either chanop or voice
714 msg_client(enum message_type msgtype
,
715 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
717 int do_floodcount
= 0;
718 hook_data_privmsg_user hdata
;
720 if(MyClient(source_p
))
723 * XXX: Controversial? Allow target users to send replies
724 * through a +g. Rationale is that people can presently use +g
725 * as a way to taunt users, e.g. harass them and hide behind +g
726 * as a way of griefing. --nenolod
728 if(msgtype
!= MESSAGE_TYPE_NOTICE
&&
729 (IsSetCallerId(source_p
) ||
730 (IsSetRegOnlyMsg(source_p
) && !target_p
->user
->suser
[0])) &&
731 !accept_message(target_p
, source_p
) &&
734 if(rb_dlink_list_length(&source_p
->localClient
->allow_list
) <
735 (unsigned long)ConfigFileEntry
.max_accept
)
737 rb_dlinkAddAlloc(target_p
, &source_p
->localClient
->allow_list
);
738 rb_dlinkAddAlloc(source_p
, &target_p
->on_allow_list
);
742 sendto_one_numeric(source_p
, ERR_OWNMODE
,
743 form_str(ERR_OWNMODE
),
744 target_p
->name
, "+g");
749 /* reset idle time for message only if its not to self
750 * and its not a notice */
751 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
752 source_p
->localClient
->last
= rb_current_time();
754 /* auto cprivmsg/cnotice */
755 do_floodcount
= !IsOper(source_p
) &&
756 !find_allowing_channel(source_p
, target_p
);
758 /* target change stuff, dont limit ctcp replies as that
759 * would allow people to start filling up random users
760 * targets just by ctcping them
762 if((msgtype
!= MESSAGE_TYPE_NOTICE
|| *text
!= '\001') &&
763 ConfigFileEntry
.target_change
&& do_floodcount
)
765 if(!add_target(source_p
, target_p
))
767 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
768 me
.name
, source_p
->name
, target_p
->name
);
773 if (do_floodcount
&& msgtype
== MESSAGE_TYPE_NOTICE
&& *text
== '\001' &&
774 target_p
->large_ctcp_sent
+ LARGE_CTCP_TIME
>= rb_current_time())
778 flood_attack_client(msgtype
, source_p
, target_p
))
781 else if(source_p
->from
== target_p
->from
)
783 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
784 "Send message to %s[%s] dropped from %s(Fake Dir)",
785 target_p
->name
, target_p
->from
->name
, source_p
->name
);
789 if(MyConnect(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
) && target_p
->user
&& target_p
->user
->away
)
790 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
791 target_p
->name
, target_p
->user
->away
);
793 if(MyClient(target_p
))
795 hdata
.msgtype
= msgtype
;
796 hdata
.source_p
= source_p
;
797 hdata
.target_p
= target_p
;
801 call_hook(h_privmsg_user
, &hdata
);
803 /* buffer location may have changed. */
806 if (hdata
.approved
!= 0)
809 if (EmptyString(text
))
811 /* could be empty after colour stripping and
812 * that would cause problems later */
813 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
814 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
818 /* XXX Controversial? allow opers always to send through a +g */
819 if(!IsServer(source_p
) && (IsSetCallerId(target_p
) ||
820 (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])))
822 /* Here is the anti-flood bot/spambot code -db */
823 if(accept_message(source_p
, target_p
) || IsOper(source_p
))
825 add_reply_target(target_p
, source_p
);
826 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
829 source_p
->host
, cmdname
[msgtype
], target_p
->name
, text
);
831 else if (IsSetRegOnlyMsg(target_p
) && !source_p
->user
->suser
[0])
833 if (msgtype
!= MESSAGE_TYPE_NOTICE
)
834 sendto_one_numeric(source_p
, ERR_NONONREG
,
835 form_str(ERR_NONONREG
),
840 /* check for accept, flag recipient incoming message */
841 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
843 sendto_one_numeric(source_p
, ERR_TARGUMODEG
,
844 form_str(ERR_TARGUMODEG
),
848 if((target_p
->localClient
->last_caller_id_time
+
849 ConfigFileEntry
.caller_id_wait
) < rb_current_time())
851 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
852 sendto_one_numeric(source_p
, RPL_TARGNOTIFY
,
853 form_str(RPL_TARGNOTIFY
),
856 add_reply_target(target_p
, source_p
);
857 sendto_one(target_p
, form_str(RPL_UMODEGMSG
),
858 me
.name
, target_p
->name
, source_p
->name
,
859 source_p
->username
, source_p
->host
);
861 target_p
->localClient
->last_caller_id_time
= rb_current_time();
867 add_reply_target(target_p
, source_p
);
868 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
872 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
878 * flood_attack_client
879 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
880 * says NOTICE must not auto reply
881 * - pointer to source Client
882 * - pointer to target Client
883 * output - true if target is under flood attack
884 * side effects - check for flood attack on target target_p
887 flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
)
891 /* Services could get many messages legitimately and
892 * can be messaged without rate limiting via aliases
893 * and msg user@server.
896 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
))
898 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
900 delta
= rb_current_time() - target_p
->first_received_message_time
;
901 target_p
->received_number_of_privmsgs
-= delta
;
902 target_p
->first_received_message_time
= rb_current_time();
903 if(target_p
->received_number_of_privmsgs
<= 0)
905 target_p
->received_number_of_privmsgs
= 0;
906 target_p
->flood_noticed
= 0;
910 if((target_p
->received_number_of_privmsgs
>=
911 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
913 if(target_p
->flood_noticed
== 0)
915 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
916 "Possible Flooder %s[%s@%s] on %s target: %s",
917 source_p
->name
, source_p
->username
,
919 source_p
->servptr
->name
, target_p
->name
);
920 target_p
->flood_noticed
= 1;
921 /* add a bit of penalty */
922 target_p
->received_number_of_privmsgs
+= 2;
924 if(MyClient(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
))
926 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
927 me
.name
, source_p
->name
, target_p
->name
);
931 target_p
->received_number_of_privmsgs
++;
940 * inputs - server pointer
942 * - nick stuff to grok for opers
943 * - text to send if grok
945 * side effects - all the traditional oper type messages are parsed here.
946 * i.e. "/msg #some.host."
947 * However, syntax has been changed.
948 * previous syntax "/msg #some.host.mask"
949 * now becomes "/msg $#some.host.mask"
950 * previous syntax of: "/msg $some.server.mask" remains
951 * This disambiguates the syntax.
954 handle_special(enum message_type msgtype
, struct Client
*client_p
,
955 struct Client
*source_p
, const char *nick
, const char *text
)
957 struct Client
*target_p
;
961 /* user[%host]@server addressed?
962 * NOTE: users can send to user@server, but not user%host@server
965 if((server
= strchr(nick
, '@')) != NULL
)
967 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
969 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
970 form_str(ERR_NOSUCHSERVER
), server
+ 1);
974 if(!IsOper(source_p
))
976 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
978 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
979 form_str(ERR_NOSUCHNICK
), nick
);
984 /* somewhere else.. */
987 sendto_one(target_p
, ":%s %s %s :%s",
988 get_id(source_p
, target_p
), cmdname
[msgtype
], nick
, text
);
992 /* Check if someones msg'ing opers@our.server */
993 if(strncmp(nick
, "opers@", 6) == 0)
995 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
996 source_p
->name
, text
);
1000 /* This was not very useful except for bypassing certain
1001 * restrictions. Note that we still allow sending to
1002 * remote servers this way, for messaging pseudoservers
1003 * securely whether they have a service{} block or not.
1006 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
1007 form_str(ERR_NOSUCHNICK
), nick
);
1012 * the following two cases allow masks in NOTICEs
1015 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1017 if(IsOper(source_p
) && *nick
== '$')
1019 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
1021 else if(MyOper(source_p
))
1023 sendto_one(source_p
,
1024 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1025 me
.name
, source_p
->name
, cmdname
[msgtype
], nick
, nick
);
1029 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
1031 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
1032 me
.name
, source_p
->name
, "mass_notice");
1036 if((s
= strrchr(nick
, '.')) == NULL
)
1038 sendto_one_numeric(source_p
, ERR_NOTOPLEVEL
,
1039 form_str(ERR_NOTOPLEVEL
), nick
);
1043 if(*s
== '.' || *s
== '*' || *s
== '?')
1045 if(*s
== '*' || *s
== '?')
1047 sendto_one_numeric(source_p
, ERR_WILDTOPLEVEL
,
1048 form_str(ERR_WILDTOPLEVEL
), nick
);
1052 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1054 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1055 "%s $%s :%s", cmdname
[msgtype
], nick
, text
);
1056 if (msgtype
!= MESSAGE_TYPE_NOTICE
&& *text
== '\001')
1057 source_p
->large_ctcp_sent
= rb_current_time();