ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 4815
Committed: Sat Nov 1 15:28:42 2014 UTC (11 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 25495 byte(s)
Error occurred while calculating annotation data.
Log Message:
- Renamed variables

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

Properties

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