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
41 #include "s_newconf.h"
44 #include "inline/stringops.h"
46 static const char message_desc
[] =
47 "Provides the PRIVMSG and NOTICE commands to send messages to users and channels";
49 static void m_message(enum message_type
, struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
50 static void m_privmsg(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
51 static void m_notice(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
52 static void m_echo(struct MsgBuf
*, struct Client
*, struct Client
*, int, const char **);
54 static void echo_msg(struct Client
*, struct Client
*, enum message_type
, const char *);
56 static void expire_tgchange(void *unused
);
57 static struct ev_entry
*expire_tgchange_event
;
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, 0,
75 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
77 struct Message notice_msgtab
= {
79 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
81 struct Message echo_msgtab
= {
83 {mg_unreg
, mg_ignore
, {m_echo
, 3}, mg_ignore
, mg_ignore
, mg_ignore
}
86 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, &echo_msgtab
, NULL
};
88 DECLARE_MODULE_AV2(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, NULL
, NULL
, message_desc
);
97 static int build_target_list(enum message_type msgtype
,
98 struct Client
*client_p
,
99 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
101 static bool flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
);
103 /* Fifteen seconds should be plenty for a client to reply a ctcp */
104 #define LARGE_CTCP_TIME 15
106 #define ENTITY_NONE 0
107 #define ENTITY_CHANNEL 1
108 #define ENTITY_CHANNEL_OPMOD 2
109 #define ENTITY_CHANOPS_ON_CHANNEL 3
110 #define ENTITY_CLIENT 4
112 static struct entity targets
[512];
113 static int ntargets
= 0;
115 static bool duplicate_ptr(void *);
117 static void msg_channel(enum message_type msgtype
,
118 struct Client
*client_p
,
119 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
121 static void msg_channel_opmod(enum message_type msgtype
,
122 struct Client
*client_p
,
123 struct Client
*source_p
, struct Channel
*chptr
,
126 static void msg_channel_flags(enum message_type msgtype
,
127 struct Client
*client_p
,
128 struct Client
*source_p
,
129 struct Channel
*chptr
, int flags
, const char *text
);
131 static void msg_client(enum message_type msgtype
,
132 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
134 static void handle_special(enum message_type msgtype
,
135 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
144 ** Another massive cleanup Nov, 2000
145 ** (I don't think there is a single line left from 6/91. Maybe.)
146 ** m_privmsg and m_notice do basically the same thing.
147 ** in the original 2.8.2 code base, they were the same function
148 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
149 ** of ircu fame, we split m_privmsg.c and m_notice.c.
150 ** I don't see the point of that now. Its harder to maintain, its
151 ** easier to introduce bugs into one version and not the other etc.
152 ** Really, the penalty of an extra function call isn't that big a deal folks.
156 const char *cmdname
[MESSAGE_TYPE_COUNT
] = {
157 [MESSAGE_TYPE_PRIVMSG
] = "PRIVMSG",
158 [MESSAGE_TYPE_NOTICE
] = "NOTICE",
162 m_privmsg(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
164 m_message(MESSAGE_TYPE_PRIVMSG
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
168 m_notice(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
170 m_message(MESSAGE_TYPE_NOTICE
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
174 * inputs - flag privmsg or notice
175 * - pointer to client_p
176 * - pointer to source_p
177 * - pointer to channel
180 m_message(enum message_type msgtype
, struct MsgBuf
*msgbuf_p
,
181 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
185 if(parc
< 2 || EmptyString(parv
[1]))
187 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
188 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
189 source_p
->name
, cmdname
[msgtype
]);
193 if(parc
< 3 || EmptyString(parv
[2]))
195 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
196 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
200 /* Finish the flood grace period if theyre not messaging themselves
201 * as some clients (ircN) do this as a "lag check"
203 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
204 flood_endgrace(source_p
);
206 if(build_target_list(msgtype
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
211 for(i
= 0; i
< ntargets
; i
++)
213 switch (targets
[i
].type
)
216 msg_channel(msgtype
, client_p
, source_p
,
217 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
220 case ENTITY_CHANNEL_OPMOD
:
221 msg_channel_opmod(msgtype
, client_p
, source_p
,
222 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
225 case ENTITY_CHANOPS_ON_CHANNEL
:
226 msg_channel_flags(msgtype
, client_p
, source_p
,
227 (struct Channel
*) targets
[i
].ptr
,
228 targets
[i
].flags
, parv
[2]);
232 msg_client(msgtype
, source_p
,
233 (struct Client
*) targets
[i
].ptr
, parv
[2]);
240 m_echo(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
241 int parc
, const char *parv
[])
243 struct Client
*target_p
= find_person(parv
[2]);
244 enum message_type msgtype
;
246 if (target_p
== NULL
)
251 case 'P': msgtype
= MESSAGE_TYPE_PRIVMSG
; break;
252 case 'N': msgtype
= MESSAGE_TYPE_NOTICE
; break;
256 echo_msg(source_p
, target_p
, msgtype
, parv
[3]);
262 * inputs - pointer to given client_p (server)
263 * - pointer to given source (oper/client etc.)
264 * - pointer to list of nicks/channels
265 * - pointer to table to place results
266 * - pointer to text (only used if source_p is an oper)
267 * output - number of valid entities
268 * side effects - target_table is modified to contain a list of
269 * pointers to channels or clients
270 * if source client is an oper
271 * all the classic old bizzare oper privmsg tricks
272 * are parsed and sent as is, if prefixed with $
277 build_target_list(enum message_type msgtype
, struct Client
*client_p
,
278 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
281 char *p
, *nick
, *target_list
;
282 struct Channel
*chptr
= NULL
;
283 struct Client
*target_p
;
285 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
289 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
293 * channels are privmsg'd a lot more than other clients, moved up
294 * here plain old channel msg?
297 if(IsChanPrefix(*nick
))
299 /* ignore send of local channel to a server (should not happen) */
300 if(IsServer(client_p
) && *nick
== '&')
303 if((chptr
= find_channel(nick
)) != NULL
)
305 if(!duplicate_ptr(chptr
))
307 if(ntargets
>= ConfigFileEntry
.max_targets
)
309 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
310 me
.name
, source_p
->name
, nick
);
313 targets
[ntargets
].ptr
= (void *) chptr
;
314 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
318 /* non existant channel */
319 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
320 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
321 form_str(ERR_NOSUCHNICK
), nick
);
326 if(MyClient(source_p
))
327 target_p
= find_named_person(nick
);
329 target_p
= find_person(nick
);
331 /* look for a privmsg to another client */
334 if(!duplicate_ptr(target_p
))
336 if(ntargets
>= ConfigFileEntry
.max_targets
)
338 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
339 me
.name
, source_p
->name
, nick
);
342 targets
[ntargets
].ptr
= (void *) target_p
;
343 targets
[ntargets
].type
= ENTITY_CLIENT
;
344 targets
[ntargets
++].flags
= 0;
349 /* @#channel or +#channel message ? */
353 /* allow %+@ if someone wants to do that */
358 else if(*nick
== '+')
359 type
|= CHFL_CHANOP
| CHFL_VOICE
;
368 if(EmptyString(nick
))
370 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
371 me
.name
, source_p
->name
, cmdname
[msgtype
]);
375 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
376 * if the channel is found, fine, if not report an error
379 if((chptr
= find_channel(nick
)) != NULL
)
381 struct membership
*msptr
;
383 msptr
= find_channel_membership(chptr
, source_p
);
385 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
387 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
388 get_id(&me
, source_p
),
389 get_id(source_p
, source_p
),
394 if(!duplicate_ptr(chptr
))
396 if(ntargets
>= ConfigFileEntry
.max_targets
)
398 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
399 me
.name
, source_p
->name
, nick
);
402 targets
[ntargets
].ptr
= (void *) chptr
;
403 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
404 targets
[ntargets
++].flags
= type
;
407 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
409 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
410 form_str(ERR_NOSUCHNICK
), nick
);
416 if(IsServer(client_p
) && *nick
== '=' && nick
[1] == '#')
419 if((chptr
= find_channel(nick
)) != NULL
)
421 if(!duplicate_ptr(chptr
))
423 if(ntargets
>= ConfigFileEntry
.max_targets
)
425 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
426 me
.name
, source_p
->name
, nick
);
429 targets
[ntargets
].ptr
= (void *) chptr
;
430 targets
[ntargets
++].type
= ENTITY_CHANNEL_OPMOD
;
434 /* non existant channel */
435 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
436 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
437 form_str(ERR_NOSUCHNICK
), nick
);
442 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
444 handle_special(msgtype
, client_p
, source_p
, nick
, text
);
448 /* no matching anything found - error if not NOTICE */
449 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
451 /* dont give this numeric when source is local,
452 * because its misleading --anfl
454 if(!MyClient(source_p
) && IsDigit(*nick
))
455 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
456 "Failed to deliver: [%.20s]",
457 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
458 get_id(source_p
, source_p
), text
);
460 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
461 form_str(ERR_NOSUCHNICK
), nick
);
471 * inputs - pointer to check
472 * - pointer to table of entities
473 * - number of valid entities so far
474 * output - true if duplicate pointer in table, false if not.
475 * note, this does the canonize using pointers
476 * side effects - NONE
479 duplicate_ptr(void *ptr
)
482 for(i
= 0; i
< ntargets
; i
++)
483 if(targets
[i
].ptr
== ptr
)
491 * inputs - flag privmsg or notice
492 * - pointer to client_p
493 * - pointer to source_p
494 * - pointer to channel
496 * side effects - message given channel
498 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
501 msg_channel(enum message_type msgtype
,
502 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
506 hook_data_privmsg_channel hdata
;
508 if(MyClient(source_p
))
510 /* idle time shouldnt be reset by notices --fl */
511 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
512 source_p
->localClient
->last
= rb_current_time();
515 hdata
.msgtype
= msgtype
;
516 hdata
.source_p
= source_p
;
521 call_hook(h_privmsg_channel
, &hdata
);
523 /* memory buffer address may have changed, update pointer */
526 if (hdata
.approved
!= 0)
529 /* hook may have reduced the string to nothing. */
530 if (EmptyString(text
))
532 /* could be empty after colour stripping and
533 * that would cause problems later */
534 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
535 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
539 /* chanops and voiced can flood their own channel with impunity */
540 if((result
= can_send(chptr
, source_p
, NULL
)))
542 if(result
!= CAN_SEND_OPV
&& MyClient(source_p
) &&
543 !IsOperGeneral(source_p
) &&
544 !add_channel_target(source_p
, chptr
))
546 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
547 me
.name
, source_p
->name
, chptr
->chname
);
550 if(result
== CAN_SEND_OPV
||
551 !flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
553 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
554 "%s %s :%s", cmdname
[msgtype
], chptr
->chname
, text
);
557 else if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
558 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
559 IsMember(source_p
, chptr
)))
561 if(MyClient(source_p
) && !IsOperGeneral(source_p
) &&
562 !add_channel_target(source_p
, chptr
))
564 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
565 me
.name
, source_p
->name
, chptr
->chname
);
568 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
570 sendto_channel_opmod(client_p
, source_p
, chptr
,
571 cmdname
[msgtype
], text
);
576 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
577 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
578 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
584 * inputs - flag privmsg or notice
585 * - pointer to client_p
586 * - pointer to source_p
587 * - pointer to channel
589 * side effects - message given channel ops
591 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
594 msg_channel_opmod(enum message_type msgtype
,
595 struct Client
*client_p
, struct Client
*source_p
,
596 struct Channel
*chptr
, const char *text
)
598 hook_data_privmsg_channel hdata
;
600 hdata
.msgtype
= msgtype
;
601 hdata
.source_p
= source_p
;
606 call_hook(h_privmsg_channel
, &hdata
);
608 /* memory buffer address may have changed, update pointer */
611 if (hdata
.approved
!= 0)
614 /* hook may have reduced the string to nothing. */
615 if (EmptyString(text
))
617 /* could be empty after colour stripping and
618 * that would cause problems later */
619 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
620 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
624 if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
625 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
626 IsMember(source_p
, chptr
)))
628 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
630 sendto_channel_opmod(client_p
, source_p
, chptr
,
631 cmdname
[msgtype
], text
);
636 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
637 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
638 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
645 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
646 * say NOTICE must not auto reply
647 * - pointer to client_p
648 * - pointer to source_p
649 * - pointer to channel
651 * - pointer to text to send
653 * side effects - message given channel either chanop or voice
656 msg_channel_flags(enum message_type msgtype
, struct Client
*client_p
,
657 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
661 hook_data_privmsg_channel hdata
;
663 if(flags
& CHFL_VOICE
)
665 type
= ONLY_CHANOPSVOICED
;
674 if(MyClient(source_p
))
676 /* idletime shouldnt be reset by notice --fl */
677 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
678 source_p
->localClient
->last
= rb_current_time();
681 hdata
.msgtype
= msgtype
;
682 hdata
.source_p
= source_p
;
687 call_hook(h_privmsg_channel
, &hdata
);
689 /* memory buffer address may have changed, update pointer */
692 if (hdata
.approved
!= 0)
695 if (EmptyString(text
))
697 /* could be empty after colour stripping and
698 * that would cause problems later */
699 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
700 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
704 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
705 cmdname
[msgtype
], c
, chptr
->chname
, text
);
709 expire_tgchange(void *unused
)
712 rb_dlink_node
*ptr
, *next_ptr
;
714 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
718 if(target
->expiry
< rb_current_time())
720 rb_dlinkDelete(ptr
, &tgchange_list
);
721 rb_patricia_remove(tgchange_tree
, target
->pnode
);
729 echo_msg(struct Client
*source_p
, struct Client
*target_p
,
730 enum message_type msgtype
, const char *text
)
732 if (MyClient(target_p
))
734 if (!IsCapable(target_p
, CLICAP_ECHO_MESSAGE
))
737 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
738 target_p
->name
, target_p
->username
, target_p
->host
,
745 sendto_one(target_p
, ":%s ECHO %c %s :%s",
747 msgtype
== MESSAGE_TYPE_PRIVMSG
? 'P' : 'N',
755 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
756 * say NOTICE must not auto reply
757 * - pointer to source_p source (struct Client *)
758 * - pointer to target_p target (struct Client *)
761 * side effects - message given channel either chanop or voice
764 msg_client(enum message_type msgtype
,
765 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
767 int do_floodcount
= 0;
768 hook_data_privmsg_user hdata
;
770 if(MyClient(source_p
))
772 /* reset idle time for message only if its not to self
773 * and its not a notice */
774 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
775 source_p
->localClient
->last
= rb_current_time();
777 /* auto cprivmsg/cnotice */
778 do_floodcount
= !IsOperGeneral(source_p
) &&
779 !find_allowing_channel(source_p
, target_p
);
781 /* target change stuff, dont limit ctcp replies as that
782 * would allow people to start filling up random users
783 * targets just by ctcping them
785 if((msgtype
!= MESSAGE_TYPE_NOTICE
|| *text
!= '\001') &&
786 ConfigFileEntry
.target_change
&& do_floodcount
)
788 if(!add_target(source_p
, target_p
))
790 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
791 me
.name
, source_p
->name
, target_p
->name
);
796 if (do_floodcount
&& msgtype
== MESSAGE_TYPE_NOTICE
&& *text
== '\001' &&
797 target_p
->large_ctcp_sent
+ LARGE_CTCP_TIME
>= rb_current_time())
801 flood_attack_client(msgtype
, source_p
, target_p
))
804 else if(source_p
->from
== target_p
->from
)
806 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
807 "Send message to %s[%s] dropped from %s(Fake Dir)",
808 target_p
->name
, target_p
->from
->name
, source_p
->name
);
812 if(MyConnect(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
) && target_p
->user
&& target_p
->user
->away
)
813 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
814 target_p
->name
, target_p
->user
->away
);
816 hdata
.msgtype
= msgtype
;
817 hdata
.source_p
= source_p
;
818 hdata
.target_p
= target_p
;
822 call_hook(h_privmsg_user
, &hdata
);
824 /* buffer location may have changed. */
827 if (hdata
.approved
!= 0)
830 if(MyClient(target_p
))
832 if (EmptyString(text
))
834 /* could be empty after colour stripping and
835 * that would cause problems later */
836 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
837 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
841 add_reply_target(target_p
, source_p
);
842 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
843 echo_msg(target_p
, source_p
, msgtype
, text
);
846 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
852 * flood_attack_client
853 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
854 * says NOTICE must not auto reply
855 * - pointer to source Client
856 * - pointer to target Client
857 * output - true if target is under flood attack
858 * side effects - check for flood attack on target target_p
861 flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
)
865 /* Services could get many messages legitimately and
866 * can be messaged without rate limiting via aliases
867 * and msg user@server.
870 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
))
872 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
874 delta
= rb_current_time() - target_p
->first_received_message_time
;
875 target_p
->received_number_of_privmsgs
-= delta
;
876 target_p
->first_received_message_time
= rb_current_time();
877 if(target_p
->received_number_of_privmsgs
<= 0)
879 target_p
->received_number_of_privmsgs
= 0;
880 target_p
->flood_noticed
= 0;
884 if((target_p
->received_number_of_privmsgs
>=
885 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
887 if(target_p
->flood_noticed
== 0)
889 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
890 "Possible Flooder %s[%s@%s] on %s target: %s",
891 source_p
->name
, source_p
->username
,
893 source_p
->servptr
->name
, target_p
->name
);
894 target_p
->flood_noticed
= 1;
895 /* add a bit of penalty */
896 target_p
->received_number_of_privmsgs
+= 2;
898 if(MyClient(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
))
900 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
901 me
.name
, source_p
->name
, target_p
->name
);
905 target_p
->received_number_of_privmsgs
++;
914 * inputs - server pointer
916 * - nick stuff to grok for opers
917 * - text to send if grok
919 * side effects - all the traditional oper type messages are parsed here.
920 * i.e. "/msg #some.host."
921 * However, syntax has been changed.
922 * previous syntax "/msg #some.host.mask"
923 * now becomes "/msg $#some.host.mask"
924 * previous syntax of: "/msg $some.server.mask" remains
925 * This disambiguates the syntax.
928 handle_special(enum message_type msgtype
, struct Client
*client_p
,
929 struct Client
*source_p
, const char *nick
, const char *text
)
931 struct Client
*target_p
;
934 /* user[%host]@server addressed?
935 * NOTE: users can send to user@server, but not user%host@server
938 if((server
= strchr(nick
, '@')) != NULL
)
940 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
942 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
943 form_str(ERR_NOSUCHSERVER
), server
+ 1);
947 if(!IsOper(source_p
))
949 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
951 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
952 form_str(ERR_NOSUCHNICK
), nick
);
957 /* somewhere else.. */
960 sendto_one(target_p
, ":%s %s %s :%s",
961 get_id(source_p
, target_p
), cmdname
[msgtype
], nick
, text
);
965 /* Check if someones msg'ing opers@our.server */
966 if(strncmp(nick
, "opers@", 6) == 0)
968 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
969 source_p
->name
, text
);
973 /* This was not very useful except for bypassing certain
974 * restrictions. Note that we still allow sending to
975 * remote servers this way, for messaging pseudoservers
976 * securely whether they have a service{} block or not.
979 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
980 form_str(ERR_NOSUCHNICK
), nick
);
985 * the following two cases allow masks in NOTICEs
988 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
990 if(IsOper(source_p
) && *nick
== '$')
992 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
994 else if(MyOper(source_p
))
997 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
998 me
.name
, source_p
->name
, cmdname
[msgtype
], nick
, nick
);
1002 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
1004 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
1005 me
.name
, source_p
->name
, "mass_notice");
1009 if(MyClient(source_p
))
1011 sendto_realops_snomask(SNO_GENERAL
, L_ALL
| L_NETWIDE
, "%s sent mass-%s to %s: %s",
1012 get_oper_name(source_p
),
1013 msgtype
== MESSAGE_TYPE_PRIVMSG
? "privmsg" : "notice",
1017 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1019 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1020 "%s $%s :%s", cmdname
[msgtype
], nick
, text
);
1021 if (msgtype
!= MESSAGE_TYPE_NOTICE
&& *text
== '\001')
1022 source_p
->large_ctcp_sent
= rb_current_time();