ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/send.c
Revision: 8556
Committed: Sat Sep 22 21:45:27 2018 UTC (5 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 23349 byte(s)
Log Message:
- Minor style corrections

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 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$
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
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
83 send_message(struct Client *to, struct dbuf_block *buf)
84 {
85 assert(!IsMe(to));
86 assert(to != &me);
87 assert(MyConnect(to));
88
89 if (dbuf_length(&to->connection->buf_sendq) + buf->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) + buf->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, buf);
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
129 send_message_remote(struct Client *to, const struct Client *from, struct dbuf_block *buf)
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 {
138 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
139 "Send message to %s dropped from %s (Fake Dir)",
140 to->name, from->name);
141 return;
142 }
143
144 send_message(to, buf);
145 }
146
147 /*
148 ** sendq_unblocked
149 ** Called when a socket is ready for writing.
150 */
151 void
152 sendq_unblocked(fde_t *F, void *data)
153 {
154 struct Client *const client_p = data;
155
156 assert(client_p);
157 assert(client_p->connection);
158 assert(client_p->connection->fd);
159 assert(client_p->connection->fd == F);
160
161 DelFlag(client_p, FLAGS_BLOCKED);
162 send_queued_write(client_p);
163 }
164
165 /*
166 ** send_queued_write
167 ** This is called when there is a chance that some output would
168 ** be possible. This attempts to empty the send queue as far as
169 ** possible, and then if any data is left, a write is rescheduled.
170 */
171 void
172 send_queued_write(struct Client *to)
173 {
174 int retlen = 0;
175
176 /*
177 ** Once socket is marked dead, we cannot start writing to it,
178 ** even if the error is removed...
179 */
180 if (IsDead(to) || HasFlag(to, FLAGS_BLOCKED))
181 return; /* no use calling send() now */
182
183 /* Next, lets try to write some data */
184 if (dbuf_length(&to->connection->buf_sendq))
185 {
186 do
187 {
188 int want_read = 0;
189 const struct dbuf_block *first = to->connection->buf_sendq.blocks.head->data;
190
191 if (tls_isusing(&to->connection->fd->ssl))
192 {
193 retlen = tls_write(&to->connection->fd->ssl, first->data + to->connection->buf_sendq.pos,
194 first->size - to->connection->buf_sendq.pos, &want_read);
195
196 if (want_read)
197 return; /* Retry later, don't register for write events */
198 }
199 else
200 retlen = send(to->connection->fd->fd, first->data + to->connection->buf_sendq.pos,
201 first->size - to->connection->buf_sendq.pos, 0);
202
203 if (retlen <= 0)
204 break;
205
206 dbuf_delete(&to->connection->buf_sendq, retlen);
207
208 /* We have some data written .. update counters */
209 to->connection->send.bytes += retlen;
210 me.connection->send.bytes += retlen;
211 } while (dbuf_length(&to->connection->buf_sendq));
212
213 if (retlen < 0 && comm_ignore_errno(errno))
214 {
215 AddFlag(to, FLAGS_BLOCKED);
216
217 /* we have a non-fatal error, reschedule a write */
218 comm_setselect(to->connection->fd, COMM_SELECT_WRITE, sendq_unblocked, to, 0);
219 }
220 else if (retlen <= 0)
221 {
222 dead_link_on_write(to, errno);
223 return;
224 }
225 }
226 }
227
228 /* send_queued_all()
229 *
230 * input - NONE
231 * output - NONE
232 * side effects - try to flush sendq of each client
233 */
234 void
235 send_queued_all(void)
236 {
237 dlink_node *node;
238
239 /* Servers are processed first, mainly because this can generate
240 * a notice to opers, which is to be delivered by this function.
241 */
242 DLINK_FOREACH(node, local_server_list.head)
243 send_queued_write(node->data);
244
245 DLINK_FOREACH(node, unknown_list.head)
246 send_queued_write(node->data);
247
248 DLINK_FOREACH(node, local_client_list.head)
249 send_queued_write(node->data);
250
251 /* NOTE: This can still put clients on aborted_list; unfortunately,
252 * exit_aborted_clients takes precedence over send_queued_all,
253 * because exiting clients can generate server/oper traffic.
254 * The easiest approach is dealing with aborted clients in the next I/O lap.
255 * -adx
256 */
257 }
258
259 /* sendto_one()
260 *
261 * inputs - pointer to destination client
262 * - var args message
263 * output - NONE
264 * side effects - send message to single client
265 */
266 void
267 sendto_one(struct Client *to, const char *pattern, ...)
268 {
269 va_list args;
270
271 if (IsDead(to->from))
272 return; /* This socket has already been marked as dead */
273
274 va_start(args, pattern);
275
276 struct dbuf_block *buffer = dbuf_alloc();
277 send_format(buffer, pattern, args);
278
279 va_end(args);
280
281 send_message(to->from, buffer);
282
283 dbuf_ref_free(buffer);
284 }
285
286 void
287 sendto_one_numeric(struct Client *to, const struct Client *from, enum irc_numerics numeric, ...)
288 {
289 va_list args;
290 const char *numstr = NULL;
291
292 if (IsDead(to->from))
293 return;
294
295 const char *dest = ID_or_name(to, to);
296 if (EmptyString(dest))
297 dest = "*";
298
299 struct dbuf_block *buffer = dbuf_alloc();
300 dbuf_put_fmt(buffer, ":%s %03d %s ", ID_or_name(from, to), numeric & ~SND_EXPLICIT, dest);
301
302 va_start(args, numeric);
303
304 if (numeric & SND_EXPLICIT)
305 numstr = va_arg(args, const char *);
306 else
307 numstr = numeric_form(numeric);
308
309 send_format(buffer, numstr, args);
310 va_end(args);
311
312 send_message(to->from, buffer);
313
314 dbuf_ref_free(buffer);
315 }
316
317 void
318 sendto_one_notice(struct Client *to, const struct Client *from, const char *pattern, ...)
319 {
320 va_list args;
321
322 if (IsDead(to->from))
323 return;
324
325 const char *dest = ID_or_name(to, to);
326 if (EmptyString(dest))
327 dest = "*";
328
329 struct dbuf_block *buffer = dbuf_alloc();
330 dbuf_put_fmt(buffer, ":%s NOTICE %s ", ID_or_name(from, to), dest);
331
332 va_start(args, pattern);
333 send_format(buffer, pattern, args);
334 va_end(args);
335
336 send_message(to->from, buffer);
337
338 dbuf_ref_free(buffer);
339 }
340
341 /* sendto_channel_butone()
342 *
343 * inputs - pointer to client(server) to NOT send message to
344 * - pointer to client that is sending this message
345 * - pointer to channel being sent to
346 * - vargs message
347 * output - NONE
348 * side effects - message as given is sent to given channel members.
349 *
350 * WARNING - +D clients are ignored
351 */
352 void
353 sendto_channel_butone(struct Client *one, const struct Client *from,
354 struct Channel *chptr, unsigned int type,
355 const char *pattern, ...)
356 {
357 va_list alocal, aremote;
358 struct dbuf_block *local_buf, *remote_buf;
359 dlink_node *node;
360
361 local_buf = dbuf_alloc(), remote_buf = dbuf_alloc();
362
363 if (IsClient(from))
364 dbuf_put_fmt(local_buf, ":%s!%s@%s ", from->name, from->username, from->host);
365 else
366 dbuf_put_fmt(local_buf, ":%s ", from->name);
367
368 dbuf_put_fmt(remote_buf, ":%s ", from->id);
369
370 va_start(alocal, pattern);
371 va_start(aremote, pattern);
372 send_format(local_buf, pattern, alocal);
373 send_format(remote_buf, pattern, aremote);
374
375 va_end(aremote);
376 va_end(alocal);
377
378 ++current_serial;
379
380 DLINK_FOREACH(node, chptr->members.head)
381 {
382 struct Membership *member = node->data;
383 struct Client *target_p = member->client_p;
384
385 assert(IsClient(target_p));
386
387 if (IsDefunct(target_p->from))
388 continue;
389
390 if (one && (target_p->from == one->from))
391 continue;
392
393 if (type && (member->flags & type) == 0)
394 continue;
395
396 if (HasUMode(target_p, UMODE_DEAF))
397 continue;
398
399 if (MyConnect(target_p))
400 send_message(target_p, local_buf);
401 else if (target_p->from->connection->serial != current_serial)
402 send_message_remote(target_p->from, from, remote_buf);
403
404 target_p->from->connection->serial = current_serial;
405 }
406
407 dbuf_ref_free(local_buf);
408 dbuf_ref_free(remote_buf);
409 }
410
411 /* sendto_server()
412 *
413 * inputs - pointer to client to NOT send to
414 * - pointer to channel
415 * - caps or'd together which must ALL be present
416 * - caps or'd together which must ALL NOT be present
417 * - printf style format string
418 * - args to format string
419 * output - NONE
420 * side effects - Send a message to all connected servers, except the
421 * client 'one' (if non-NULL), as long as the servers
422 * support ALL capabs in 'caps', and NO capabs in 'nocaps'.
423 *
424 * This function was written in an attempt to merge together the other
425 * billion sendto_*serv*() functions, which sprung up with capabs,
426 * lazylinks, uids, etc.
427 * -davidt
428 */
429 void
430 sendto_server(const struct Client *one,
431 const unsigned int caps,
432 const unsigned int nocaps,
433 const char *format, ...)
434 {
435 va_list args;
436 dlink_node *node;
437
438 va_start(args, format);
439
440 struct dbuf_block *buffer = dbuf_alloc();
441 send_format(buffer, format, args);
442
443 va_end(args);
444
445 DLINK_FOREACH(node, local_server_list.head)
446 {
447 struct Client *client_p = node->data;
448
449 /* If dead already skip */
450 if (IsDead(client_p))
451 continue;
452
453 /* check against 'one' */
454 if (one && (client_p == one->from))
455 continue;
456
457 /* check we have required capabs */
458 if ((client_p->connection->caps & caps) != caps)
459 continue;
460
461 /* check we don't have any forbidden capabs */
462 if ((client_p->connection->caps & nocaps))
463 continue;
464
465 send_message(client_p, buffer);
466 }
467
468 dbuf_ref_free(buffer);
469 }
470
471 /* sendto_common_channels_local()
472 *
473 * inputs - pointer to client
474 * - pattern to send
475 * output - NONE
476 * side effects - Sends a message to all people on local server who are
477 * in same channel with user.
478 * used by m_nick.c and exit_one_client.
479 */
480 void
481 sendto_common_channels_local(struct Client *user, int touser, unsigned int poscap,
482 unsigned int negcap, const char *pattern, ...)
483 {
484 va_list args;
485 dlink_node *uptr;
486 dlink_node *cptr;
487 struct Channel *chptr;
488 struct Membership *member;
489 struct Client *target_p;
490 struct dbuf_block *buffer = dbuf_alloc();
491
492 va_start(args, pattern);
493 send_format(buffer, pattern, args);
494 va_end(args);
495
496 ++current_serial;
497
498 DLINK_FOREACH(cptr, user->channel.head)
499 {
500 chptr = ((struct Membership *)cptr->data)->chptr;
501
502 DLINK_FOREACH(uptr, chptr->locmembers.head)
503 {
504 member = uptr->data;
505 target_p = member->client_p;
506
507 if (target_p == user || IsDefunct(target_p) ||
508 target_p->connection->serial == current_serial)
509 continue;
510
511 if (poscap && HasCap(target_p, poscap) != poscap)
512 continue;
513
514 if (negcap && HasCap(target_p, negcap))
515 continue;
516
517 target_p->connection->serial = current_serial;
518 send_message(target_p, buffer);
519 }
520 }
521
522 if (touser && MyConnect(user) && !IsDead(user) &&
523 user->connection->serial != current_serial)
524 if (HasCap(user, poscap) == poscap)
525 send_message(user, buffer);
526
527 dbuf_ref_free(buffer);
528 }
529
530 /*! \brief Send a message to members of a channel that are locally connected to this server.
531 * \param one Client to skip; can be NULL
532 * \param chptr Destination channel
533 * \param status Channel member status flags clients must have
534 * \param poscap Positive client capabilities flags (CAP)
535 * \param negcap Negative client capabilities flags (CAP)
536 * \param pattern Format string for command arguments
537 */
538 void
539 sendto_channel_local(const struct Client *one, struct Channel *chptr, unsigned int status,
540 unsigned int poscap, unsigned int negcap, const char *pattern, ...)
541 {
542 va_list args;
543 dlink_node *node;
544 struct dbuf_block *buffer = dbuf_alloc();
545
546 va_start(args, pattern);
547 send_format(buffer, pattern, args);
548 va_end(args);
549
550 DLINK_FOREACH(node, chptr->locmembers.head)
551 {
552 struct Membership *member = node->data;
553 struct Client *target_p = member->client_p;
554
555 if (IsDefunct(target_p))
556 continue;
557
558 if (one && target_p == one->from)
559 continue;
560
561 if (status && (member->flags & status) == 0)
562 continue;
563
564 if (poscap && HasCap(target_p, poscap) != poscap)
565 continue;
566
567 if (negcap && HasCap(target_p, negcap))
568 continue;
569
570 send_message(target_p, buffer);
571 }
572
573 dbuf_ref_free(buffer);
574 }
575
576 /*
577 ** match_it() and sendto_match_butone() ARE only used
578 ** to send a msg to all ppl on servers/hosts that match a specified mask
579 ** (used for enhanced PRIVMSGs) for opers
580 **
581 ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
582 **
583 */
584
585 /* match_it()
586 *
587 * inputs - client pointer to match on
588 * - actual mask to match
589 * - what to match on, HOST or SERVER
590 * output - 1 or 0 if match or not
591 * side effects - NONE
592 */
593 static int
594 match_it(const struct Client *one, const char *mask, unsigned int what)
595 {
596 if (what == MATCH_HOST)
597 return match(mask, one->host) == 0;
598
599 return match(mask, one->servptr->name) == 0;
600 }
601
602 /* sendto_match_butone()
603 *
604 * Send to all clients which match the mask in a way defined on 'what';
605 * either by user hostname or user servername.
606 *
607 * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh.
608 */
609 void
610 sendto_match_butone(const struct Client *one, const struct Client *from,
611 const char *mask, int what, const char *pattern, ...)
612 {
613 va_list alocal, aremote;
614 dlink_node *node;
615 struct dbuf_block *local_buf, *remote_buf;
616
617 local_buf = dbuf_alloc(), remote_buf = dbuf_alloc();
618
619 dbuf_put_fmt(local_buf, ":%s!%s@%s ", from->name, from->username, from->host);
620 dbuf_put_fmt(remote_buf, ":%s ", from->id);
621
622 va_start(alocal, pattern);
623 va_start(aremote, pattern);
624 send_format(local_buf, pattern, alocal);
625 send_format(remote_buf, pattern, aremote);
626 va_end(aremote);
627 va_end(alocal);
628
629 /* scan the local clients */
630 DLINK_FOREACH(node, local_client_list.head)
631 {
632 struct Client *client_p = node->data;
633
634 if ((one == NULL || client_p != one->from) && !IsDefunct(client_p))
635 if (match_it(client_p, mask, what))
636 send_message(client_p, local_buf);
637 }
638
639 /* Now scan servers */
640 DLINK_FOREACH(node, local_server_list.head)
641 {
642 struct Client *client_p = node->data;
643
644 /*
645 * The old code looped through every client on the
646 * network for each server to check if the
647 * server (client_p) has at least 1 client matching
648 * the mask, using something like:
649 *
650 * for (target_p = GlobalClientList; target_p; target_p = target_p->next)
651 * if (IsRegisteredUser(target_p) &&
652 * match_it(target_p, mask, what) &&
653 * (target_p->from == client_p))
654 * vsendto_prefix_one(client_p, from, pattern, args);
655 *
656 * That way, we wouldn't send the message to
657 * a server who didn't have a matching client.
658 * However, on a network such as EFNet, that
659 * code would have looped through about 50
660 * servers, and in each loop, loop through
661 * about 50k clients as well, calling match()
662 * in each nested loop. That is a very bad
663 * thing cpu wise - just send the message
664 * to every connected server and let that
665 * server deal with it.
666 * -wnder
667 */
668 if ((one == NULL || client_p != one->from) && !IsDefunct(client_p))
669 send_message_remote(client_p, from, remote_buf);
670 }
671
672 dbuf_ref_free(local_buf);
673 dbuf_ref_free(remote_buf);
674 }
675
676 /* sendto_match_servs()
677 *
678 * inputs - source client
679 * - mask to send to
680 * - capab needed
681 * - data
682 * outputs - none
683 * side effects - data sent to servers matching with capab
684 */
685 void
686 sendto_match_servs(const struct Client *source_p, const char *mask, unsigned int cap,
687 const char *pattern, ...)
688 {
689 va_list args;
690 dlink_node *node;
691 struct dbuf_block *buffer = dbuf_alloc();
692
693 dbuf_put_fmt(buffer, ":%s ", source_p->id);
694 va_start(args, pattern);
695 send_format(buffer, pattern, args);
696 va_end(args);
697
698 ++current_serial;
699
700 DLINK_FOREACH(node, global_server_list.head)
701 {
702 struct Client *target_p = node->data;
703
704 /* Do not attempt to send to ourselves, or the source */
705 if (IsMe(target_p) || target_p->from == source_p->from)
706 continue;
707
708 if (target_p->from->connection->serial == current_serial)
709 continue;
710
711 if (match(mask, target_p->name))
712 continue;
713
714 if (cap && IsCapable(target_p->from, cap) != cap)
715 continue;
716
717 target_p->from->connection->serial = current_serial;
718 send_message_remote(target_p->from, source_p, buffer);
719 }
720
721 dbuf_ref_free(buffer);
722 }
723
724 /* sendto_anywhere()
725 *
726 * inputs - pointer to dest client
727 * - pointer to from client
728 * - varags
729 * output - NONE
730 * side effects - less efficient than sendto_remote and sendto_one
731 * but useful when one does not know where target "lives"
732 */
733 void
734 sendto_anywhere(struct Client *to, const struct Client *from,
735 const char *command,
736 const char *pattern, ...)
737 {
738 va_list args;
739
740 if (IsDead(to->from))
741 return;
742
743 struct dbuf_block *buffer = dbuf_alloc();
744 if (MyClient(to) && IsClient(from))
745 dbuf_put_fmt(buffer, ":%s!%s@%s %s %s ", from->name, from->username,
746 from->host, command, to->name);
747 else
748 dbuf_put_fmt(buffer, ":%s %s %s ", ID_or_name(from, to),
749 command, ID_or_name(to, to));
750
751 va_start(args, pattern);
752 send_format(buffer, pattern, args);
753 va_end(args);
754
755 if (MyConnect(to))
756 send_message(to, buffer);
757 else
758 send_message_remote(to->from, from, buffer);
759
760 dbuf_ref_free(buffer);
761 }
762
763 /* sendto_realops_flags()
764 *
765 * inputs - flag types of messages to show to real opers
766 * - flag indicating opers/admins
767 * - var args input message
768 * output - NONE
769 * side effects - Send to *local* ops only but NOT +s nonopers.
770 */
771 void
772 sendto_realops_flags(unsigned int flags, int level, int type, const char *pattern, ...)
773 {
774 const char *ntype = "???";
775 dlink_node *node;
776 va_list args;
777
778 switch (type)
779 {
780 case SEND_NOTICE:
781 ntype = "Notice";
782 break;
783 case SEND_GLOBAL:
784 ntype = "Global";
785 break;
786 case SEND_LOCOPS:
787 ntype = "LocOps";
788 break;
789 default:
790 assert(0);
791 }
792
793 struct dbuf_block *buffer = dbuf_alloc();
794 dbuf_put_fmt(buffer, ":%s NOTICE * :*** %s -- ", me.name, ntype);
795
796 va_start(args, pattern);
797 send_format(buffer, pattern, args);
798 va_end(args);
799
800 DLINK_FOREACH(node, oper_list.head)
801 {
802 struct Client *client_p = node->data;
803 assert(HasUMode(client_p, UMODE_OPER));
804
805 /*
806 * If we're sending it to opers and they're an admin, skip.
807 * If we're sending it to admins, and they're not, skip.
808 */
809 if (((level == L_ADMIN) && !HasUMode(client_p, UMODE_ADMIN)) ||
810 ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN)))
811 continue;
812
813 if (HasUMode(client_p, flags) && !IsDead(client_p))
814 send_message(client_p, buffer);
815 }
816
817 dbuf_ref_free(buffer);
818 }
819
820 /* ts_warn()
821 *
822 * inputs - var args message
823 * output - NONE
824 * side effects - Call sendto_realops_flags, with some flood checking
825 * (at most 5 warnings every 5 seconds)
826 */
827 void
828 sendto_realops_flags_ratelimited(uintmax_t *rate, const char *pattern, ...)
829 {
830 va_list args;
831 char buffer[IRCD_BUFSIZE] = "";
832
833 if ((CurrentTime - *rate) < 20)
834 return;
835
836 *rate = CurrentTime;
837
838 va_start(args, pattern);
839 vsnprintf(buffer, sizeof(buffer), pattern, args);
840 va_end(args);
841
842 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%s", buffer);
843 ilog(LOG_TYPE_IRCD, "%s", buffer);
844 }
845
846 /* sendto_wallops_flags()
847 *
848 * inputs - flag types of messages to show to real opers
849 * - client sending request
850 * - var args input message
851 * output - NONE
852 * side effects - Send a wallops to local opers
853 */
854 void
855 sendto_wallops_flags(unsigned int flags, const struct Client *source_p,
856 const char *pattern, ...)
857 {
858 dlink_node *node;
859 va_list args;
860 struct dbuf_block *buffer = dbuf_alloc();
861
862 if (IsClient(source_p))
863 dbuf_put_fmt(buffer, ":%s!%s@%s WALLOPS :", source_p->name, source_p->username, source_p->host);
864 else
865 dbuf_put_fmt(buffer, ":%s WALLOPS :", source_p->name);
866
867 va_start(args, pattern);
868 send_format(buffer, pattern, args);
869 va_end(args);
870
871 DLINK_FOREACH(node, oper_list.head)
872 {
873 struct Client *client_p = node->data;
874 assert(client_p->umodes & UMODE_OPER);
875
876 if (HasUMode(client_p, flags) && !IsDead(client_p))
877 send_message(client_p, buffer);
878 }
879
880 dbuf_ref_free(buffer);
881 }

Properties

Name Value
svn:eol-style native
svn:keywords Id