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
;
59 static unsigned int CAP_ECHO
;
64 expire_tgchange_event
= rb_event_addish("expire_tgchange", expire_tgchange
, NULL
, 300);
65 expire_tgchange(NULL
);
72 rb_event_delete(expire_tgchange_event
);
75 struct Message privmsg_msgtab
= {
76 "PRIVMSG", 0, 0, 0, 0,
77 {mg_unreg
, {m_privmsg
, 0}, {m_privmsg
, 0}, mg_ignore
, mg_ignore
, {m_privmsg
, 0}}
79 struct Message notice_msgtab
= {
81 {mg_unreg
, {m_notice
, 0}, {m_notice
, 0}, {m_notice
, 0}, mg_ignore
, {m_notice
, 0}}
83 struct Message echo_msgtab
= {
85 {mg_unreg
, mg_ignore
, {m_echo
, 3}, mg_ignore
, mg_ignore
, mg_ignore
}
88 mapi_clist_av1 message_clist
[] = { &privmsg_msgtab
, ¬ice_msgtab
, &echo_msgtab
, NULL
};
90 mapi_cap_list_av2 message_cap_list
[] = {
91 { MAPI_CAP_SERVER
, "ECHO", NULL
, &CAP_ECHO
},
92 { 0, NULL
, NULL
, NULL
}
95 DECLARE_MODULE_AV2(message
, modinit
, moddeinit
, message_clist
, NULL
, NULL
, message_cap_list
, NULL
, message_desc
);
104 static int build_target_list(enum message_type msgtype
,
105 struct Client
*client_p
,
106 struct Client
*source_p
, const char *nicks_channels
, const char *text
);
108 static bool flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
);
110 /* Fifteen seconds should be plenty for a client to reply a ctcp */
111 #define LARGE_CTCP_TIME 15
113 #define ENTITY_NONE 0
114 #define ENTITY_CHANNEL 1
115 #define ENTITY_CHANNEL_OPMOD 2
116 #define ENTITY_CHANOPS_ON_CHANNEL 3
117 #define ENTITY_CLIENT 4
119 static struct entity targets
[512];
120 static int ntargets
= 0;
122 static bool duplicate_ptr(void *);
124 static void msg_channel(enum message_type msgtype
,
125 struct Client
*client_p
,
126 struct Client
*source_p
, struct Channel
*chptr
, const char *text
);
128 static void msg_channel_opmod(enum message_type msgtype
,
129 struct Client
*client_p
,
130 struct Client
*source_p
, struct Channel
*chptr
,
133 static void msg_channel_flags(enum message_type msgtype
,
134 struct Client
*client_p
,
135 struct Client
*source_p
,
136 struct Channel
*chptr
, int flags
, const char *text
);
138 static void msg_client(enum message_type msgtype
,
139 struct Client
*source_p
, struct Client
*target_p
, const char *text
);
141 static void handle_special(enum message_type msgtype
,
142 struct Client
*client_p
, struct Client
*source_p
, const char *nick
,
151 ** Another massive cleanup Nov, 2000
152 ** (I don't think there is a single line left from 6/91. Maybe.)
153 ** m_privmsg and m_notice do basically the same thing.
154 ** in the original 2.8.2 code base, they were the same function
155 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
156 ** of ircu fame, we split m_privmsg.c and m_notice.c.
157 ** I don't see the point of that now. Its harder to maintain, its
158 ** easier to introduce bugs into one version and not the other etc.
159 ** Really, the penalty of an extra function call isn't that big a deal folks.
163 const char *cmdname
[MESSAGE_TYPE_COUNT
] = {
164 [MESSAGE_TYPE_PRIVMSG
] = "PRIVMSG",
165 [MESSAGE_TYPE_NOTICE
] = "NOTICE",
169 m_privmsg(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
171 m_message(MESSAGE_TYPE_PRIVMSG
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
175 m_notice(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
177 m_message(MESSAGE_TYPE_NOTICE
, msgbuf_p
, client_p
, source_p
, parc
, parv
);
181 * inputs - flag privmsg or notice
182 * - pointer to client_p
183 * - pointer to source_p
184 * - pointer to channel
187 m_message(enum message_type msgtype
, struct MsgBuf
*msgbuf_p
,
188 struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
192 if(parc
< 2 || EmptyString(parv
[1]))
194 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
195 sendto_one(source_p
, form_str(ERR_NORECIPIENT
), me
.name
,
196 source_p
->name
, cmdname
[msgtype
]);
200 if(parc
< 3 || EmptyString(parv
[2]))
202 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
203 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
207 /* Finish the flood grace period if theyre not messaging themselves
208 * as some clients (ircN) do this as a "lag check"
210 if(MyClient(source_p
) && !IsFloodDone(source_p
) && irccmp(source_p
->name
, parv
[1]))
211 flood_endgrace(source_p
);
213 if(build_target_list(msgtype
, client_p
, source_p
, parv
[1], parv
[2]) < 0)
218 for(i
= 0; i
< ntargets
; i
++)
220 switch (targets
[i
].type
)
223 msg_channel(msgtype
, client_p
, source_p
,
224 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
227 case ENTITY_CHANNEL_OPMOD
:
228 msg_channel_opmod(msgtype
, client_p
, source_p
,
229 (struct Channel
*) targets
[i
].ptr
, parv
[2]);
232 case ENTITY_CHANOPS_ON_CHANNEL
:
233 msg_channel_flags(msgtype
, client_p
, source_p
,
234 (struct Channel
*) targets
[i
].ptr
,
235 targets
[i
].flags
, parv
[2]);
239 msg_client(msgtype
, source_p
,
240 (struct Client
*) targets
[i
].ptr
, parv
[2]);
247 m_echo(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
248 int parc
, const char *parv
[])
250 struct Client
*target_p
= find_person(parv
[2]);
251 enum message_type msgtype
;
253 if (target_p
== NULL
)
258 case 'P': msgtype
= MESSAGE_TYPE_PRIVMSG
; break;
259 case 'N': msgtype
= MESSAGE_TYPE_NOTICE
; break;
263 echo_msg(source_p
, target_p
, msgtype
, parv
[3]);
269 * inputs - pointer to given client_p (server)
270 * - pointer to given source (oper/client etc.)
271 * - pointer to list of nicks/channels
272 * - pointer to table to place results
273 * - pointer to text (only used if source_p is an oper)
274 * output - number of valid entities
275 * side effects - target_table is modified to contain a list of
276 * pointers to channels or clients
277 * if source client is an oper
278 * all the classic old bizzare oper privmsg tricks
279 * are parsed and sent as is, if prefixed with $
284 build_target_list(enum message_type msgtype
, struct Client
*client_p
,
285 struct Client
*source_p
, const char *nicks_channels
, const char *text
)
288 char *p
, *nick
, *target_list
;
289 struct Channel
*chptr
= NULL
;
290 struct Client
*target_p
;
292 target_list
= LOCAL_COPY(nicks_channels
); /* skip strcpy for non-lazyleafs */
296 for(nick
= rb_strtok_r(target_list
, ",", &p
); nick
; nick
= rb_strtok_r(NULL
, ",", &p
))
300 * channels are privmsg'd a lot more than other clients, moved up
301 * here plain old channel msg?
304 if(IsChanPrefix(*nick
))
306 /* ignore send of local channel to a server (should not happen) */
307 if(IsServer(client_p
) && *nick
== '&')
310 if((chptr
= find_channel(nick
)) != NULL
)
312 if(!duplicate_ptr(chptr
))
314 if(ntargets
>= ConfigFileEntry
.max_targets
)
316 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
317 me
.name
, source_p
->name
, nick
);
320 targets
[ntargets
].ptr
= (void *) chptr
;
321 targets
[ntargets
++].type
= ENTITY_CHANNEL
;
325 /* non existant channel */
326 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
327 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
328 form_str(ERR_NOSUCHNICK
), nick
);
333 if(MyClient(source_p
))
334 target_p
= find_named_person(nick
);
336 target_p
= find_person(nick
);
338 /* look for a privmsg to another client */
341 if(!duplicate_ptr(target_p
))
343 if(ntargets
>= ConfigFileEntry
.max_targets
)
345 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
346 me
.name
, source_p
->name
, nick
);
349 targets
[ntargets
].ptr
= (void *) target_p
;
350 targets
[ntargets
].type
= ENTITY_CLIENT
;
351 targets
[ntargets
++].flags
= 0;
356 /* @#channel or +#channel message ? */
360 /* allow %+@ if someone wants to do that */
365 else if(*nick
== '+')
366 type
|= CHFL_CHANOP
| CHFL_VOICE
;
375 if(EmptyString(nick
))
377 sendto_one(source_p
, form_str(ERR_NORECIPIENT
),
378 me
.name
, source_p
->name
, cmdname
[msgtype
]);
382 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
383 * if the channel is found, fine, if not report an error
386 if((chptr
= find_channel(nick
)) != NULL
)
388 struct membership
*msptr
;
390 msptr
= find_channel_membership(chptr
, source_p
);
392 if(!IsServer(source_p
) && !IsService(source_p
) && !is_chanop_voiced(msptr
))
394 sendto_one(source_p
, form_str(ERR_CHANOPRIVSNEEDED
),
395 get_id(&me
, source_p
),
396 get_id(source_p
, source_p
),
401 if(!duplicate_ptr(chptr
))
403 if(ntargets
>= ConfigFileEntry
.max_targets
)
405 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
406 me
.name
, source_p
->name
, nick
);
409 targets
[ntargets
].ptr
= (void *) chptr
;
410 targets
[ntargets
].type
= ENTITY_CHANOPS_ON_CHANNEL
;
411 targets
[ntargets
++].flags
= type
;
414 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
416 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
417 form_str(ERR_NOSUCHNICK
), nick
);
423 if(IsServer(client_p
) && *nick
== '=' && nick
[1] == '#')
426 if((chptr
= find_channel(nick
)) != NULL
)
428 if(!duplicate_ptr(chptr
))
430 if(ntargets
>= ConfigFileEntry
.max_targets
)
432 sendto_one(source_p
, form_str(ERR_TOOMANYTARGETS
),
433 me
.name
, source_p
->name
, nick
);
436 targets
[ntargets
].ptr
= (void *) chptr
;
437 targets
[ntargets
++].type
= ENTITY_CHANNEL_OPMOD
;
441 /* non existant channel */
442 else if(msgtype
!= MESSAGE_TYPE_NOTICE
)
443 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
444 form_str(ERR_NOSUCHNICK
), nick
);
449 if(strchr(nick
, '@') || (IsOper(source_p
) && (*nick
== '$')))
451 handle_special(msgtype
, client_p
, source_p
, nick
, text
);
455 /* no matching anything found - error if not NOTICE */
456 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
458 /* dont give this numeric when source is local,
459 * because its misleading --anfl
461 if(!MyClient(source_p
) && IsDigit(*nick
))
462 sendto_one(source_p
, ":%s %d %s * :Target left IRC. "
463 "Failed to deliver: [%.20s]",
464 get_id(&me
, source_p
), ERR_NOSUCHNICK
,
465 get_id(source_p
, source_p
), text
);
467 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
468 form_str(ERR_NOSUCHNICK
), nick
);
478 * inputs - pointer to check
479 * - pointer to table of entities
480 * - number of valid entities so far
481 * output - true if duplicate pointer in table, false if not.
482 * note, this does the canonize using pointers
483 * side effects - NONE
486 duplicate_ptr(void *ptr
)
489 for(i
= 0; i
< ntargets
; i
++)
490 if(targets
[i
].ptr
== ptr
)
498 * inputs - flag privmsg or notice
499 * - pointer to client_p
500 * - pointer to source_p
501 * - pointer to channel
503 * side effects - message given channel
505 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
508 msg_channel(enum message_type msgtype
,
509 struct Client
*client_p
, struct Client
*source_p
, struct Channel
*chptr
,
513 hook_data_privmsg_channel hdata
;
515 if(MyClient(source_p
))
517 /* idle time shouldn't be reset by notices --fl */
518 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
519 source_p
->localClient
->last
= rb_current_time();
522 hdata
.msgtype
= msgtype
;
523 hdata
.source_p
= source_p
;
528 call_hook(h_privmsg_channel
, &hdata
);
530 /* memory buffer address may have changed, update pointer */
533 if (hdata
.approved
!= 0)
536 /* hook may have reduced the string to nothing. */
537 if (EmptyString(text
))
539 /* could be empty after colour stripping and
540 * that would cause problems later */
541 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
542 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
546 /* chanops and voiced can flood their own channel with impunity */
547 if((result
= can_send(chptr
, source_p
, NULL
)))
549 if(result
!= CAN_SEND_OPV
&& MyClient(source_p
) &&
550 !IsOperGeneral(source_p
) &&
551 !add_channel_target(source_p
, chptr
))
553 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
554 me
.name
, source_p
->name
, chptr
->chname
);
557 if(result
== CAN_SEND_OPV
||
558 !flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
560 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
561 "%s %s :%s", cmdname
[msgtype
], chptr
->chname
, text
);
564 else if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
565 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
566 IsMember(source_p
, chptr
)))
568 if(MyClient(source_p
) && !IsOperGeneral(source_p
) &&
569 !add_channel_target(source_p
, chptr
))
571 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
572 me
.name
, source_p
->name
, chptr
->chname
);
575 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
577 sendto_channel_opmod(client_p
, source_p
, chptr
,
578 cmdname
[msgtype
], text
);
583 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
584 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
585 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
591 * inputs - flag privmsg or notice
592 * - pointer to client_p
593 * - pointer to source_p
594 * - pointer to channel
596 * side effects - message given channel ops
598 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
601 msg_channel_opmod(enum message_type msgtype
,
602 struct Client
*client_p
, struct Client
*source_p
,
603 struct Channel
*chptr
, const char *text
)
605 hook_data_privmsg_channel hdata
;
607 hdata
.msgtype
= msgtype
;
608 hdata
.source_p
= source_p
;
613 call_hook(h_privmsg_channel
, &hdata
);
615 /* memory buffer address may have changed, update pointer */
618 if (hdata
.approved
!= 0)
621 /* hook may have reduced the string to nothing. */
622 if (EmptyString(text
))
624 /* could be empty after colour stripping and
625 * that would cause problems later */
626 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
627 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
631 if(chptr
->mode
.mode
& MODE_OPMODERATE
&&
632 (!(chptr
->mode
.mode
& MODE_NOPRIVMSGS
) ||
633 IsMember(source_p
, chptr
)))
635 if(!flood_attack_channel(msgtype
, source_p
, chptr
, chptr
->chname
))
637 sendto_channel_opmod(client_p
, source_p
, chptr
,
638 cmdname
[msgtype
], text
);
643 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
644 sendto_one_numeric(source_p
, ERR_CANNOTSENDTOCHAN
,
645 form_str(ERR_CANNOTSENDTOCHAN
), chptr
->chname
);
652 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
653 * say NOTICE must not auto reply
654 * - pointer to client_p
655 * - pointer to source_p
656 * - pointer to channel
658 * - pointer to text to send
660 * side effects - message given channel either chanop or voice
663 msg_channel_flags(enum message_type msgtype
, struct Client
*client_p
,
664 struct Client
*source_p
, struct Channel
*chptr
, int flags
, const char *text
)
668 hook_data_privmsg_channel hdata
;
670 if(flags
& CHFL_VOICE
)
672 type
= ONLY_CHANOPSVOICED
;
681 if(MyClient(source_p
))
683 /* idle time shouldn't be reset by notices --fl */
684 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
685 source_p
->localClient
->last
= rb_current_time();
688 hdata
.msgtype
= msgtype
;
689 hdata
.source_p
= source_p
;
694 call_hook(h_privmsg_channel
, &hdata
);
696 /* memory buffer address may have changed, update pointer */
699 if (hdata
.approved
!= 0)
702 if (EmptyString(text
))
704 /* could be empty after colour stripping and
705 * that would cause problems later */
706 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
707 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
711 sendto_channel_flags(client_p
, type
, source_p
, chptr
, "%s %c%s :%s",
712 cmdname
[msgtype
], c
, chptr
->chname
, text
);
716 expire_tgchange(void *unused
)
719 rb_dlink_node
*ptr
, *next_ptr
;
721 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, tgchange_list
.head
)
725 if(target
->expiry
< rb_current_time())
727 rb_dlinkDelete(ptr
, &tgchange_list
);
728 rb_patricia_remove(tgchange_tree
, target
->pnode
);
736 echo_msg(struct Client
*source_p
, struct Client
*target_p
,
737 enum message_type msgtype
, const char *text
)
739 if (MyClient(target_p
))
741 if (!IsCapable(target_p
, CLICAP_ECHO_MESSAGE
))
744 sendto_one(target_p
, ":%s!%s@%s %s %s :%s",
745 target_p
->name
, target_p
->username
, target_p
->host
,
752 if (!(target_p
->from
->serv
->caps
& CAP_ECHO
))
755 sendto_one(target_p
, ":%s ECHO %c %s :%s",
757 msgtype
== MESSAGE_TYPE_PRIVMSG
? 'P' : 'N',
765 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
766 * say NOTICE must not auto reply
767 * - pointer to source_p source (struct Client *)
768 * - pointer to target_p target (struct Client *)
771 * side effects - message given channel either chanop or voice
774 msg_client(enum message_type msgtype
,
775 struct Client
*source_p
, struct Client
*target_p
, const char *text
)
777 int do_floodcount
= 0;
778 hook_data_privmsg_user hdata
;
780 if(MyClient(source_p
))
782 /* idle time shouldn't be reset by notices --fl */
783 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
784 source_p
->localClient
->last
= rb_current_time();
786 /* auto cprivmsg/cnotice */
787 do_floodcount
= !IsOperGeneral(source_p
) &&
788 !find_allowing_channel(source_p
, target_p
);
790 /* target change stuff, dont limit ctcp replies as that
791 * would allow people to start filling up random users
792 * targets just by ctcping them
794 if((msgtype
!= MESSAGE_TYPE_NOTICE
|| *text
!= '\001') &&
795 ConfigFileEntry
.target_change
&& do_floodcount
)
797 if(!add_target(source_p
, target_p
))
799 sendto_one(source_p
, form_str(ERR_TARGCHANGE
),
800 me
.name
, source_p
->name
, target_p
->name
);
805 if (do_floodcount
&& msgtype
== MESSAGE_TYPE_NOTICE
&& *text
== '\001' &&
806 target_p
->large_ctcp_sent
+ LARGE_CTCP_TIME
>= rb_current_time())
810 flood_attack_client(msgtype
, source_p
, target_p
))
813 else if(source_p
->from
== target_p
->from
)
815 sendto_realops_snomask(SNO_DEBUG
, L_NETWIDE
,
816 "Send message to %s[%s] dropped from %s(Fake Dir)",
817 target_p
->name
, target_p
->from
->name
, source_p
->name
);
821 if(MyConnect(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
) && target_p
->user
&& target_p
->user
->away
)
822 sendto_one_numeric(source_p
, RPL_AWAY
, form_str(RPL_AWAY
),
823 target_p
->name
, target_p
->user
->away
);
825 hdata
.msgtype
= msgtype
;
826 hdata
.source_p
= source_p
;
827 hdata
.target_p
= target_p
;
831 call_hook(h_privmsg_user
, &hdata
);
833 /* buffer location may have changed. */
836 if (hdata
.approved
!= 0)
839 if(MyClient(target_p
))
841 if (EmptyString(text
))
843 /* could be empty after colour stripping and
844 * that would cause problems later */
845 if(msgtype
!= MESSAGE_TYPE_NOTICE
)
846 sendto_one(source_p
, form_str(ERR_NOTEXTTOSEND
), me
.name
, source_p
->name
);
850 add_reply_target(target_p
, source_p
);
851 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
852 echo_msg(target_p
, source_p
, msgtype
, text
);
855 sendto_anywhere(target_p
, source_p
, cmdname
[msgtype
], ":%s", text
);
861 * flood_attack_client
862 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
863 * says NOTICE must not auto reply
864 * - pointer to source Client
865 * - pointer to target Client
866 * output - true if target is under flood attack
867 * side effects - check for flood attack on target target_p
870 flood_attack_client(enum message_type msgtype
, struct Client
*source_p
, struct Client
*target_p
)
874 /* Services could get many messages legitimately and
875 * can be messaged without rate limiting via aliases
876 * and msg user@server.
879 if(GlobalSetOptions
.floodcount
&& IsClient(source_p
) && source_p
!= target_p
&& !IsService(target_p
) && !HasPrivilege(target_p
, "oper:free_target"))
881 if((target_p
->first_received_message_time
+ 1) < rb_current_time())
883 delta
= rb_current_time() - target_p
->first_received_message_time
;
884 target_p
->received_number_of_privmsgs
-= delta
;
885 target_p
->first_received_message_time
= rb_current_time();
886 if(target_p
->received_number_of_privmsgs
<= 0)
888 target_p
->received_number_of_privmsgs
= 0;
889 target_p
->flood_noticed
= 0;
893 if((target_p
->received_number_of_privmsgs
>=
894 GlobalSetOptions
.floodcount
) || target_p
->flood_noticed
)
896 if(target_p
->flood_noticed
== 0)
898 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
899 "Possible Flooder %s[%s@%s] on %s target: %s",
900 source_p
->name
, source_p
->username
,
902 source_p
->servptr
->name
, target_p
->name
);
903 target_p
->flood_noticed
= 1;
904 /* add a bit of penalty */
905 target_p
->received_number_of_privmsgs
+= 2;
907 if(MyClient(source_p
) && (msgtype
!= MESSAGE_TYPE_NOTICE
))
909 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
910 me
.name
, source_p
->name
, target_p
->name
);
914 target_p
->received_number_of_privmsgs
++;
923 * inputs - server pointer
925 * - nick stuff to grok for opers
926 * - text to send if grok
928 * side effects - all the traditional oper type messages are parsed here.
929 * i.e. "/msg #some.host."
930 * However, syntax has been changed.
931 * previous syntax "/msg #some.host.mask"
932 * now becomes "/msg $#some.host.mask"
933 * previous syntax of: "/msg $some.server.mask" remains
934 * This disambiguates the syntax.
937 handle_special(enum message_type msgtype
, struct Client
*client_p
,
938 struct Client
*source_p
, const char *nick
, const char *text
)
940 struct Client
*target_p
;
943 /* user[%host]@server addressed?
944 * NOTE: users can send to user@server, but not user%host@server
947 if((server
= strchr(nick
, '@')) != NULL
)
949 if((target_p
= find_server(source_p
, server
+ 1)) == NULL
)
951 sendto_one_numeric(source_p
, ERR_NOSUCHSERVER
,
952 form_str(ERR_NOSUCHSERVER
), server
+ 1);
956 if(!IsOper(source_p
))
958 if(strchr(nick
, '%') || (strncmp(nick
, "opers", 5) == 0))
960 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
961 form_str(ERR_NOSUCHNICK
), nick
);
966 /* somewhere else.. */
969 sendto_one(target_p
, ":%s %s %s :%s",
970 get_id(source_p
, target_p
), cmdname
[msgtype
], nick
, text
);
974 /* Check if someones msg'ing opers@our.server */
975 if(strncmp(nick
, "opers@", 6) == 0)
977 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "To opers: From: %s: %s",
978 source_p
->name
, text
);
982 /* This was not very useful except for bypassing certain
983 * restrictions. Note that we still allow sending to
984 * remote servers this way, for messaging pseudoservers
985 * securely whether they have a service{} block or not.
988 sendto_one_numeric(source_p
, ERR_NOSUCHNICK
,
989 form_str(ERR_NOSUCHNICK
), nick
);
994 * the following two cases allow masks in NOTICEs
997 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
999 if(IsOper(source_p
) && *nick
== '$')
1001 if((*(nick
+ 1) == '$' || *(nick
+ 1) == '#'))
1003 else if(MyOper(source_p
))
1005 sendto_one(source_p
,
1006 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1007 me
.name
, source_p
->name
, cmdname
[msgtype
], nick
, nick
);
1011 if(MyClient(source_p
) && !IsOperMassNotice(source_p
))
1013 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
1014 me
.name
, source_p
->name
, "mass_notice");
1018 if(MyClient(source_p
))
1020 sendto_realops_snomask(SNO_GENERAL
, L_ALL
| L_NETWIDE
, "%s sent mass-%s to %s: %s",
1021 get_oper_name(source_p
),
1022 msgtype
== MESSAGE_TYPE_PRIVMSG
? "privmsg" : "notice",
1026 sendto_match_butone(IsServer(client_p
) ? client_p
: NULL
, source_p
,
1028 (*nick
== '#') ? MATCH_HOST
: MATCH_SERVER
,
1029 "%s $%s :%s", cmdname
[msgtype
], nick
, text
);
1030 if (msgtype
!= MESSAGE_TYPE_NOTICE
&& *text
== '\001')
1031 source_p
->large_ctcp_sent
= rb_current_time();