1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2021 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file send.c
23 * \brief Functions for sending messages.
24 * \version $Id: send.c 9858 2021-01-01 04:43:42Z michael $
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "send.h"
30 #include "channel.h"
31 #include "client.h"
32 #include "dbuf.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "s_bsd.h"
36 #include "server_capab.h"
37 #include "conf_class.h"
38 #include "log.h"
39
40
41 static uintmax_t current_serial;
42
43
44 /* send_format()
45 *
46 * inputs
47 * - buffer
48 * - format pattern to use
49 * - var args
50 * output - number of bytes formatted output
51 * side effects - modifies sendbuf
52 */
53 static void
send_format(struct dbuf_block * buffer,const char * pattern,va_list args)54 send_format(struct dbuf_block *buffer, const char *pattern, va_list args)
55 {
56 /*
57 * from rfc1459
58 *
59 * IRC messages are always lines of characters terminated with a CR-LF
60 * (Carriage Return - Line Feed) pair, and these messages shall not
61 * exceed 512 characters in length, counting all characters
62 * including the trailing CR-LF.
63 * Thus, there are 510 characters maximum allowed
64 * for the command and its parameters. There is no provision for
65 * continuation message lines. See section 7 for more details about
66 * current implementations.
67 */
68 dbuf_put_args(buffer, pattern, args);
69
70 if (buffer->size > IRCD_BUFSIZE - 2)
71 buffer->size = IRCD_BUFSIZE - 2;
72
73 buffer->data[buffer->size++] = '\r';
74 buffer->data[buffer->size++] = '\n';
75 }
76
77 /*
78 ** send_message
79 ** Internal utility which appends given buffer to the sockets
80 ** sendq.
81 */
82 static void
send_message(struct Client * to,struct dbuf_block * buffer)83 send_message(struct Client *to, struct dbuf_block *buffer)
84 {
85 assert(!IsMe(to));
86 assert(to != &me);
87 assert(MyConnect(to));
88
89 if (dbuf_length(&to->connection->buf_sendq) + buffer->size > get_sendq(&to->connection->confs))
90 {
91 if (IsServer(to))
92 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
93 "Max SendQ limit exceeded for %s: %zu > %u",
94 client_get_name(to, HIDE_IP),
95 (dbuf_length(&to->connection->buf_sendq) + buffer->size),
96 get_sendq(&to->connection->confs));
97
98 if (IsClient(to))
99 AddFlag(to, FLAGS_SENDQEX);
100
101 dead_link_on_write(to, 0);
102 return;
103 }
104
105 dbuf_add(&to->connection->buf_sendq, buffer);
106
107 /*
108 * Update statistics. The following is slightly incorrect because
109 * it counts messages even if queued, but bytes only really sent.
110 * Queued bytes get updated in send_queued_write().
111 */
112 ++to->connection->send.messages;
113 ++me.connection->send.messages;
114
115 send_queued_write(to);
116 }
117
118 /* send_message_remote()
119 *
120 * inputs - pointer to client from message is being sent
121 * - pointer to client to send to
122 * - pointer to buffer
123 * output - none
124 * side effects - Despite the function name, this only sends to directly
125 * connected clients.
126 *
127 */
128 static void
send_message_remote(struct Client * to,const struct Client * from,struct dbuf_block * buffer)129 send_message_remote(struct Client *to, const struct Client *from, struct dbuf_block *buffer)
130 {
131 assert(MyConnect(to));
132 assert(IsServer(to));
133 assert(!IsMe(to));
134 assert(to->from == to);
135
136 if (to == from->from)
137 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "Send message to %s dropped from %s (Fake Dir)",
138 to->name, from->name);
139 else
140 send_message(to, buffer);
141 }
142
143 /*
144 ** sendq_unblocked
145 ** Called when a socket is ready for writing.
146 */
147 void
sendq_unblocked(fde_t * F,void * data)148 sendq_unblocked(fde_t *F, void *data)
149 {
150 struct Client *const client = data;
151
152 assert(client);
153 assert(client->connection);
154 assert(client->connection->fd);
155 assert(client->connection->fd == F);
156
157 DelFlag(client, FLAGS_BLOCKED);
158 send_queued_write(client);
159 }
160
161 /*
162 ** send_queued_write
163 ** This is called when there is a chance that some output would
164 ** be possible. This attempts to empty the send queue as far as
165 ** possible, and then if any data is left, a write is rescheduled.
166 */
167 void
send_queued_write(struct Client * to)168 send_queued_write(struct Client *to)
169 {
170 ssize_t retlen;
171
172 /*
173 * Once socket is marked dead, we cannot start writing to it,
174 * even if the error is removed...
175 */
176 if (IsDead(to) || HasFlag(to, FLAGS_BLOCKED))
177 return; /* no use calling send() now */
178
179 /* Next, lets try to write some data */
180 while (dbuf_length(&to->connection->buf_sendq))
181 {
182 bool want_read = false;
183 const struct dbuf_block *first = to->connection->buf_sendq.blocks.head->data;
184
185 if (tls_isusing(&to->connection->fd->tls))
186 {
187 retlen = tls_write(&to->connection->fd->tls, first->data + to->connection->buf_sendq.pos,
188 first->size - to->connection->buf_sendq.pos, &want_read);
189
190 if (want_read == true)
191 return; /* Retry later, don't register for write events */
192 }
193 else
194 retlen = send(to->connection->fd->fd, first->data + to->connection->buf_sendq.pos,
195 first->size - to->connection->buf_sendq.pos, 0);
196
197 if (retlen <= 0)
198 {
199 if (retlen < 0 && comm_ignore_errno(errno) == true)
200 {
201 AddFlag(to, FLAGS_BLOCKED);
202 /* We have a non-fatal error, reschedule a write */
203 comm_setselect(to->connection->fd, COMM_SELECT_WRITE, sendq_unblocked, to, 0);
204 }
205 else
206 dead_link_on_write(to, errno);
207 return;
208 }
209
210 dbuf_delete(&to->connection->buf_sendq, retlen);
211
212 /* We have some data written .. update counters */
213 to->connection->send.bytes += retlen;
214 me.connection->send.bytes += retlen;
215 }
216 }
217
218 /* sendto_one()
219 *
220 * inputs - pointer to destination client
221 * - var args message
222 * output - NONE
223 * side effects - send message to single client
224 */
225 void
sendto_one(struct Client * to,const char * pattern,...)226 sendto_one(struct Client *to, const char *pattern, ...)
227 {
228 va_list args;
229
230 if (IsDead(to->from))
231 return; /* This socket has already been marked as dead */
232
233 va_start(args, pattern);
234
235 struct dbuf_block *buffer = dbuf_alloc();
236 send_format(buffer, pattern, args);
237
238 va_end(args);
239
240 send_message(to->from, buffer);
241
242 dbuf_ref_free(buffer);
243 }
244
245 void
sendto_one_numeric(struct Client * to,const struct Client * from,enum irc_numerics numeric,...)246 sendto_one_numeric(struct Client *to, const struct Client *from, enum irc_numerics numeric, ...)
247 {
248 va_list args;
249
250 if (IsDead(to->from))
251 return; /* This socket has already been marked as dead */
252
253 const char *dest = ID_or_name(to, to);
254 if (EmptyString(dest))
255 dest = "*";
256
257 struct dbuf_block *buffer = dbuf_alloc();
258 dbuf_put_fmt(buffer, ":%s %03d %s ", ID_or_name(from, to), numeric & ~SND_EXPLICIT, dest);
259
260 va_start(args, numeric);
261
262 const char *numstr;
263 if (numeric & SND_EXPLICIT)
264 numstr = va_arg(args, const char *);
265 else
266 numstr = numeric_form(numeric);
267
268 send_format(buffer, numstr, args);
269 va_end(args);
270
271 send_message(to->from, buffer);
272
273 dbuf_ref_free(buffer);
274 }
275
276 void
sendto_one_notice(struct Client * to,const struct Client * from,const char * pattern,...)277 sendto_one_notice(struct Client *to, const struct Client *from, const char *pattern, ...)
278 {
279 va_list args;
280
281 if (IsDead(to->from))
282 return; /* This socket has already been marked as dead */
283
284 const char *dest = ID_or_name(to, to);
285 if (EmptyString(dest))
286 dest = "*";
287
288 struct dbuf_block *buffer = dbuf_alloc();
289 dbuf_put_fmt(buffer, ":%s NOTICE %s ", ID_or_name(from, to), dest);
290
291 va_start(args, pattern);
292 send_format(buffer, pattern, args);
293 va_end(args);
294
295 send_message(to->from, buffer);
296
297 dbuf_ref_free(buffer);
298 }
299
300 /* sendto_channel_butone()
301 *
302 * inputs - pointer to client(server) to NOT send message to
303 * - pointer to client that is sending this message
304 * - pointer to channel being sent to
305 * - vargs message
306 * output - NONE
307 * side effects - message as given is sent to given channel members.
308 *
309 * WARNING - +D clients are ignored
310 */
311 void
sendto_channel_butone(struct Client * one,const struct Client * from,struct Channel * channel,unsigned int type,const char * pattern,...)312 sendto_channel_butone(struct Client *one, const struct Client *from,
313 struct Channel *channel, unsigned int type,
314 const char *pattern, ...)
315 {
316 va_list args_l, args_r;
317 dlink_node *node;
318 struct dbuf_block *buffer_l = dbuf_alloc();
319 struct dbuf_block *buffer_r = dbuf_alloc();
320
321 if (IsClient(from))
322 dbuf_put_fmt(buffer_l, ":%s!%s@%s ", from->name, from->username, from->host);
323 else
324 dbuf_put_fmt(buffer_l, ":%s ", from->name);
325
326 dbuf_put_fmt(buffer_r, ":%s ", from->id);
327
328 va_start(args_l, pattern);
329 va_start(args_r, pattern);
330 send_format(buffer_l, pattern, args_l);
331 send_format(buffer_r, pattern, args_r);
332 va_end(args_l);
333 va_end(args_r);
334
335 ++current_serial;
336
337 DLINK_FOREACH(node, channel->members.head)
338 {
339 struct ChannelMember *member = node->data;
340 struct Client *target = member->client;
341
342 assert(IsClient(target));
343
344 if (IsDead(target->from))
345 continue;
346
347 if (one && (target->from == one->from))
348 continue;
349
350 if (type && (member->flags & type) == 0)
351 continue;
352
353 if (HasUMode(target, UMODE_DEAF))
354 continue;
355
356 if (MyConnect(target))
357 send_message(target, buffer_l);
358 else if (target->from->connection->serial != current_serial)
359 send_message_remote(target->from, from, buffer_r);
360
361 target->from->connection->serial = current_serial;
362 }
363
364 dbuf_ref_free(buffer_l);
365 dbuf_ref_free(buffer_r);
366 }
367
368 /* sendto_server()
369 *
370 * inputs - pointer to client to NOT send to
371 * - pointer to channel
372 * - capabs or'd together which must ALL be present
373 * - capabs or'd together which must ALL NOT be present
374 * - printf style format string
375 * - args to format string
376 * output - NONE
377 * side effects - Send a message to all connected servers, except the
378 * client 'one' (if non-NULL), as long as the servers
379 * support ALL capabs in 'capab', and NO capabs in 'nocapab'.
380 *
381 * This function was written in an attempt to merge together the other
382 * billion sendto_*serv*() functions, which sprung up with capabs,
383 * lazylinks, uids, etc.
384 * -davidt
385 */
386 void
sendto_server(const struct Client * one,const unsigned int capab,const unsigned int nocapab,const char * format,...)387 sendto_server(const struct Client *one,
388 const unsigned int capab,
389 const unsigned int nocapab,
390 const char *format, ...)
391 {
392 va_list args;
393 dlink_node *node;
394 struct dbuf_block *buffer = dbuf_alloc();
395
396 va_start(args, format);
397 send_format(buffer, format, args);
398 va_end(args);
399
400 DLINK_FOREACH(node, local_server_list.head)
401 {
402 struct Client *client = node->data;
403
404 /* If dead already skip */
405 if (IsDead(client))
406 continue;
407
408 /* check against 'one' */
409 if (one && (client == one->from))
410 continue;
411
412 /* check we have required capabs */
413 if (IsCapable(client, capab) != capab)
414 continue;
415
416 /* check we don't have any forbidden capabs */
417 if (IsCapable(client, nocapab))
418 continue;
419
420 send_message(client, buffer);
421 }
422
423 dbuf_ref_free(buffer);
424 }
425
426 /* sendto_common_channels_local()
427 *
428 * inputs - pointer to client
429 * - pattern to send
430 * output - NONE
431 * side effects - Sends a message to all people on local server who are
432 * in same channel with user.
433 * used by m_nick.c and exit_one_client.
434 */
435 void
sendto_common_channels_local(struct Client * user,bool touser,unsigned int poscap,unsigned int negcap,const char * pattern,...)436 sendto_common_channels_local(struct Client *user, bool touser, unsigned int poscap,
437 unsigned int negcap, const char *pattern, ...)
438 {
439 va_list args;
440 dlink_node *node, *node2;
441 struct dbuf_block *buffer = dbuf_alloc();
442
443 va_start(args, pattern);
444 send_format(buffer, pattern, args);
445 va_end(args);
446
447 ++current_serial;
448
449 DLINK_FOREACH(node, user->channel.head)
450 {
451 struct ChannelMember *member = node->data;
452 struct Channel *channel = member->channel;
453
454 DLINK_FOREACH(node2, channel->members_local.head)
455 {
456 struct ChannelMember *member2 = node2->data;
457 struct Client *target = member2->client;
458
459 if (IsDead(target))
460 continue;
461
462 if (target == user)
463 continue;
464
465 if (target->connection->serial == current_serial)
466 continue;
467
468 if (poscap && HasCap(target, poscap) != poscap)
469 continue;
470
471 if (negcap && HasCap(target, negcap))
472 continue;
473
474 target->connection->serial = current_serial;
475 send_message(target, buffer);
476 }
477 }
478
479 if (touser == true && MyConnect(user) && !IsDead(user))
480 if (HasCap(user, poscap) == poscap)
481 send_message(user, buffer);
482
483 dbuf_ref_free(buffer);
484 }
485
486 /*! \brief Send a message to members of a channel that are locally connected to this server.
487 * \param one Client to skip; can be NULL
488 * \param channel Destination channel
489 * \param status Channel member status flags clients must have
490 * \param poscap Positive client capabilities flags (CAP)
491 * \param negcap Negative client capabilities flags (CAP)
492 * \param pattern Format string for command arguments
493 */
494 void
sendto_channel_local(const struct Client * one,struct Channel * channel,unsigned int status,unsigned int poscap,unsigned int negcap,const char * pattern,...)495 sendto_channel_local(const struct Client *one, struct Channel *channel, unsigned int status,
496 unsigned int poscap, unsigned int negcap, const char *pattern, ...)
497 {
498 va_list args;
499 dlink_node *node;
500 struct dbuf_block *buffer = dbuf_alloc();
501
502 va_start(args, pattern);
503 send_format(buffer, pattern, args);
504 va_end(args);
505
506 DLINK_FOREACH(node, channel->members_local.head)
507 {
508 struct ChannelMember *member = node->data;
509 struct Client *target = member->client;
510
511 if (IsDead(target))
512 continue;
513
514 if (one && (target == one->from))
515 continue;
516
517 if (status && (member->flags & status) == 0)
518 continue;
519
520 if (poscap && HasCap(target, poscap) != poscap)
521 continue;
522
523 if (negcap && HasCap(target, negcap))
524 continue;
525
526 send_message(target, buffer);
527 }
528
529 dbuf_ref_free(buffer);
530 }
531
532 /*
533 ** match_it() and sendto_match_butone() ARE only used
534 ** to send a msg to all ppl on servers/hosts that match a specified mask
535 ** (used for enhanced PRIVMSGs) for opers
536 **
537 ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
538 **
539 */
540
541 /* match_it()
542 *
543 * inputs - client pointer to match on
544 * - actual mask to match
545 * - what to match on, HOST or SERVER
546 * output - 1 or 0 if match or not
547 * side effects - NONE
548 */
549 static bool
match_it(const struct Client * one,const char * mask,unsigned int what)550 match_it(const struct Client *one, const char *mask, unsigned int what)
551 {
552 if (what == MATCH_HOST)
553 return match(mask, one->host) == 0;
554
555 return match(mask, one->servptr->name) == 0;
556 }
557
558 /* sendto_match_butone()
559 *
560 * Send to all clients which match the mask in a way defined on 'what';
561 * either by user hostname or user servername.
562 *
563 * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh.
564 */
565 void
sendto_match_butone(const struct Client * one,const struct Client * from,const char * mask,int what,const char * pattern,...)566 sendto_match_butone(const struct Client *one, const struct Client *from,
567 const char *mask, int what, const char *pattern, ...)
568 {
569 va_list args_l, args_r;
570 dlink_node *node;
571 struct dbuf_block *buffer_l = dbuf_alloc();
572 struct dbuf_block *buffer_r = dbuf_alloc();
573
574 dbuf_put_fmt(buffer_l, ":%s!%s@%s ", from->name, from->username, from->host);
575 dbuf_put_fmt(buffer_r, ":%s ", from->id);
576
577 va_start(args_l, pattern);
578 va_start(args_r, pattern);
579 send_format(buffer_l, pattern, args_l);
580 send_format(buffer_r, pattern, args_r);
581 va_end(args_l);
582 va_end(args_r);
583
584 /* Scan the local clients */
585 DLINK_FOREACH(node, local_client_list.head)
586 {
587 struct Client *client = node->data;
588
589 if (IsDead(client))
590 continue;
591
592 if (one && (client == one->from))
593 continue;
594
595 if (match_it(client, mask, what) == false)
596 continue;
597
598 send_message(client, buffer_l);
599 }
600
601 /* Now scan servers */
602 DLINK_FOREACH(node, local_server_list.head)
603 {
604 struct Client *client = node->data;
605
606 /*
607 * The old code looped through every client on the network for each
608 * server to check if the server (client) has at least 1 client
609 * matching the mask, using something like:
610 *
611 * for (target = GlobalClientList; target; target = target->next)
612 * if (IsRegisteredUser(target) &&
613 * match_it(target, mask, what) &&
614 * (target->from == client))
615 * vsendto_prefix_one(client, from, pattern, args);
616 *
617 * That way, we wouldn't send the message to a server who didn't have
618 * a matching client. However, on a network such as EFNet, that code
619 * would have looped through about 50 servers, and in each loop, loop
620 * through about 50k clients as well, calling match() in each nested
621 * loop. That is a very bad thing cpu wise - just send the message to
622 * every connected server and let that server deal with it.
623 * -wnder
624 */
625 if (IsDead(client))
626 continue;
627
628 if (one && (client == one->from))
629 continue;
630
631 send_message_remote(client, from, buffer_r);
632 }
633
634 dbuf_ref_free(buffer_l);
635 dbuf_ref_free(buffer_r);
636 }
637
638 /* sendto_match_servs()
639 *
640 * inputs - source client
641 * - mask to send to
642 * - capab needed
643 * - data
644 * outputs - none
645 * side effects - data sent to servers matching with capab
646 */
647 void
sendto_match_servs(const struct Client * source_p,const char * mask,unsigned int capab,const char * pattern,...)648 sendto_match_servs(const struct Client *source_p, const char *mask, unsigned int capab,
649 const char *pattern, ...)
650 {
651 va_list args;
652 dlink_node *node;
653 struct dbuf_block *buffer = dbuf_alloc();
654
655 dbuf_put_fmt(buffer, ":%s ", source_p->id);
656
657 va_start(args, pattern);
658 send_format(buffer, pattern, args);
659 va_end(args);
660
661 ++current_serial;
662
663 DLINK_FOREACH(node, global_server_list.head)
664 {
665 struct Client *target = node->data;
666
667 if (IsDead(target->from))
668 continue;
669
670 /* Do not attempt to send to ourselves ... */
671 if (IsMe(target))
672 continue;
673
674 /* ... or the source */
675 if (target->from == source_p->from)
676 continue;
677
678 if (target->from->connection->serial == current_serial)
679 continue;
680
681 if (IsCapable(target->from, capab) != capab)
682 continue;
683
684 if (match(mask, target->name))
685 continue;
686
687 target->from->connection->serial = current_serial;
688 send_message_remote(target->from, source_p, buffer);
689 }
690
691 dbuf_ref_free(buffer);
692 }
693
694 /* sendto_anywhere()
695 *
696 * inputs - pointer to dest client
697 * - pointer to from client
698 * - varags
699 * output - NONE
700 * side effects - less efficient than sendto_remote and sendto_one
701 * but useful when one does not know where target "lives"
702 */
703 void
sendto_anywhere(struct Client * to,const struct Client * from,const char * command,const char * pattern,...)704 sendto_anywhere(struct Client *to, const struct Client *from,
705 const char *command,
706 const char *pattern, ...)
707 {
708 va_list args;
709
710 if (IsDead(to->from))
711 return;
712
713 struct dbuf_block *buffer = dbuf_alloc();
714 if (MyClient(to) && IsClient(from))
715 dbuf_put_fmt(buffer, ":%s!%s@%s %s %s ", from->name, from->username,
716 from->host, command, to->name);
717 else
718 dbuf_put_fmt(buffer, ":%s %s %s ", ID_or_name(from, to),
719 command, ID_or_name(to, to));
720
721 va_start(args, pattern);
722 send_format(buffer, pattern, args);
723 va_end(args);
724
725 if (MyConnect(to))
726 send_message(to, buffer);
727 else
728 send_message_remote(to->from, from, buffer);
729
730 dbuf_ref_free(buffer);
731 }
732
733 /* sendto_realops_flags()
734 *
735 * inputs - flag types of messages to show to real opers
736 * - flag indicating opers/admins
737 * - var args input message
738 * output - NONE
739 * side effects - Send to *local* ops only but NOT +s nonopers.
740 */
741 void
sendto_realops_flags(unsigned int flags,int level,int type,const char * pattern,...)742 sendto_realops_flags(unsigned int flags, int level, int type, const char *pattern, ...)
743 {
744 va_list args;
745 dlink_node *node;
746 const char *ntype = "???";
747
748 switch (type)
749 {
750 case SEND_NOTICE:
751 ntype = "Notice";
752 break;
753 case SEND_GLOBAL:
754 ntype = "Global";
755 break;
756 case SEND_LOCOPS:
757 ntype = "LocOps";
758 break;
759 default:
760 assert(0);
761 }
762
763 struct dbuf_block *buffer = dbuf_alloc();
764 dbuf_put_fmt(buffer, ":%s NOTICE * :*** %s -- ", me.name, ntype);
765
766 va_start(args, pattern);
767 send_format(buffer, pattern, args);
768 va_end(args);
769
770 DLINK_FOREACH(node, oper_list.head)
771 {
772 struct Client *client = node->data;
773 assert(HasUMode(client, UMODE_OPER));
774
775 if (IsDead(client))
776 continue;
777
778 /*
779 * If we're sending it to opers and they're an admin, skip.
780 * If we're sending it to admins, and they're not, skip.
781 */
782 if (((level == L_ADMIN) && !HasUMode(client, UMODE_ADMIN)) ||
783 ((level == L_OPER) && HasUMode(client, UMODE_ADMIN)))
784 continue;
785
786 if (!HasUMode(client, flags))
787 continue;
788
789 send_message(client, buffer);
790 }
791
792 dbuf_ref_free(buffer);
793 }
794
795 /* ts_warn()
796 *
797 * inputs - var args message
798 * output - NONE
799 * side effects - Call sendto_realops_flags, with some flood checking
800 * (at most 5 warnings every 5 seconds)
801 */
802 void
sendto_realops_flags_ratelimited(uintmax_t * rate,const char * pattern,...)803 sendto_realops_flags_ratelimited(uintmax_t *rate, const char *pattern, ...)
804 {
805 va_list args;
806 char buffer[IRCD_BUFSIZE];
807
808 if ((event_base->time.sec_monotonic - *rate) < 20)
809 return;
810
811 *rate = event_base->time.sec_monotonic;
812
813 va_start(args, pattern);
814 vsnprintf(buffer, sizeof(buffer), pattern, args);
815 va_end(args);
816
817 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%s", buffer);
818 ilog(LOG_TYPE_IRCD, "%s", buffer);
819 }
820
821 /* sendto_wallops_flags()
822 *
823 * inputs - flag types of messages to show to real opers
824 * - client sending request
825 * - var args input message
826 * output - NONE
827 * side effects - Send a wallops to local opers
828 */
829 void
sendto_wallops_flags(unsigned int flags,const struct Client * source_p,const char * pattern,...)830 sendto_wallops_flags(unsigned int flags, const struct Client *source_p,
831 const char *pattern, ...)
832 {
833 va_list args;
834 dlink_node *node;
835 struct dbuf_block *buffer = dbuf_alloc();
836
837 if (IsClient(source_p))
838 dbuf_put_fmt(buffer, ":%s!%s@%s WALLOPS :", source_p->name, source_p->username, source_p->host);
839 else
840 dbuf_put_fmt(buffer, ":%s WALLOPS :", source_p->name);
841
842 va_start(args, pattern);
843 send_format(buffer, pattern, args);
844 va_end(args);
845
846 DLINK_FOREACH(node, oper_list.head)
847 {
848 struct Client *client = node->data;
849 assert(client->umodes & UMODE_OPER);
850
851 if (IsDead(client))
852 continue;
853
854 if (!HasUMode(client, flags))
855 continue;
856
857 send_message(client, buffer);
858 }
859
860 dbuf_ref_free(buffer);
861 }
862