ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 4925
Committed: Tue Nov 25 16:22:09 2014 UTC (10 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 24527 byte(s)
Log Message:
- send.c: replaced remaining DLINK_FOREACH_SAFE with just DLINK_FOREACH

File Contents

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

Properties

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