ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 4804
Committed: Tue Oct 28 15:27:43 2014 UTC (10 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 25449 byte(s)
Log Message:
- send.c:sendto_anywhere(): replaced MyClient() test with MyConnect()

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 *ptr;
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(ptr, local_server_list.head)
281 send_queued_write(ptr->data);
282
283 DLINK_FOREACH(ptr, unknown_list.head)
284 send_queued_write(ptr->data);
285
286 DLINK_FOREACH(ptr, local_client_list.head)
287 send_queued_write(ptr->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 *ptr = NULL, *ptr_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(ptr, ptr_next, chptr->members.head)
426 {
427 struct Membership *ms = ptr->data;
428 struct Client *target_p = ms->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 && (ms->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 *ptr = NULL;
476 struct dbuf_block *buffer;
477
478 buffer = dbuf_alloc();
479
480 va_start(args, format);
481 send_format(buffer, format, args);
482 va_end(args);
483
484 DLINK_FOREACH(ptr, local_server_list.head)
485 {
486 struct Client *client_p = ptr->data;
487
488 /* If dead already skip */
489 if (IsDead(client_p))
490 continue;
491 /* check against 'one' */
492 if (one && (client_p == one->from))
493 continue;
494 /* check we have required capabs */
495 if ((client_p->connection->caps & caps) != caps)
496 continue;
497 /* check we don't have any forbidden capabs */
498 if ((client_p->connection->caps & nocaps))
499 continue;
500
501 send_message(client_p, buffer);
502 }
503
504 dbuf_ref_free(buffer);
505 }
506
507 /* sendto_common_channels_local()
508 *
509 * inputs - pointer to client
510 * - pattern to send
511 * output - NONE
512 * side effects - Sends a message to all people on local server who are
513 * in same channel with user.
514 * used by m_nick.c and exit_one_client.
515 */
516 void
517 sendto_common_channels_local(struct Client *user, int touser, unsigned int cap,
518 const char *pattern, ...)
519 {
520 va_list args;
521 dlink_node *uptr;
522 dlink_node *cptr;
523 struct Channel *chptr;
524 struct Membership *ms;
525 struct Client *target_p;
526 struct dbuf_block *buffer;
527
528 buffer = dbuf_alloc();
529
530 va_start(args, pattern);
531 send_format(buffer, pattern, args);
532 va_end(args);
533
534 ++current_serial;
535
536 DLINK_FOREACH(cptr, user->channel.head)
537 {
538 chptr = ((struct Membership *)cptr->data)->chptr;
539
540 DLINK_FOREACH(uptr, chptr->locmembers.head)
541 {
542 ms = uptr->data;
543 target_p = ms->client_p;
544
545 if (target_p == user || IsDefunct(target_p) ||
546 target_p->connection->serial == current_serial)
547 continue;
548
549 if (HasCap(target_p, cap) != cap)
550 continue;
551
552 target_p->connection->serial = current_serial;
553 send_message(target_p, buffer);
554 }
555 }
556
557 if (touser && MyConnect(user) && !IsDead(user) &&
558 user->connection->serial != current_serial)
559 if (HasCap(user, cap) == cap)
560 send_message(user, buffer);
561
562 dbuf_ref_free(buffer);
563 }
564
565 /* sendto_channel_local()
566 *
567 * inputs - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
568 * - pointer to channel to send to
569 * - var args pattern
570 * output - NONE
571 * side effects - Send a message to all members of a channel that are
572 * locally connected to this server.
573 */
574 void
575 sendto_channel_local(unsigned int type, struct Channel *chptr,
576 const char *pattern, ...)
577 {
578 va_list args;
579 dlink_node *ptr = NULL;
580 struct dbuf_block *buffer;
581
582 buffer = dbuf_alloc();
583
584 va_start(args, pattern);
585 send_format(buffer, pattern, args);
586 va_end(args);
587
588 DLINK_FOREACH(ptr, chptr->locmembers.head)
589 {
590 struct Membership *ms = ptr->data;
591 struct Client *target_p = ms->client_p;
592
593 if (type && (ms->flags & type) == 0)
594 continue;
595
596 if (IsDefunct(target_p))
597 continue;
598
599 send_message(target_p, buffer);
600 }
601
602 dbuf_ref_free(buffer);
603 }
604
605 /* sendto_channel_local_butone()
606 *
607 * inputs - pointer to client to NOT send message to
608 * - member status mask, e.g. CHFL_CHANOP | CHFL_VOICE
609 * - pointer to channel to send to
610 * - var args pattern
611 * output - NONE
612 * side effects - Send a message to all members of a channel that are
613 * locally connected to this server except one.
614 *
615 * WARNING - +D clients are omitted
616 */
617 void
618 sendto_channel_local_butone(struct Client *one, unsigned int poscap, unsigned int negcap,
619 struct Channel *chptr, const char *pattern, ...)
620 {
621 va_list args;
622 dlink_node *ptr = NULL;
623 struct dbuf_block *buffer = dbuf_alloc();
624
625 va_start(args, pattern);
626 send_format(buffer, pattern, args);
627 va_end(args);
628
629 DLINK_FOREACH(ptr, chptr->locmembers.head)
630 {
631 struct Membership *ms = ptr->data;
632 struct Client *target_p = ms->client_p;
633
634 if (one && target_p == one->from)
635 continue;
636
637 if (IsDefunct(target_p))
638 continue;
639
640 if (poscap && HasCap(target_p, poscap) != poscap)
641 continue;
642
643 if (negcap && HasCap(target_p, negcap))
644 continue;
645
646 send_message(target_p, buffer);
647 }
648
649 dbuf_ref_free(buffer);
650 }
651
652 /*
653 ** match_it() and sendto_match_butone() ARE only used
654 ** to send a msg to all ppl on servers/hosts that match a specified mask
655 ** (used for enhanced PRIVMSGs) for opers
656 **
657 ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
658 **
659 */
660
661 /* match_it()
662 *
663 * inputs - client pointer to match on
664 * - actual mask to match
665 * - what to match on, HOST or SERVER
666 * output - 1 or 0 if match or not
667 * side effects - NONE
668 */
669 static int
670 match_it(const struct Client *one, const char *mask, unsigned int what)
671 {
672 if (what == MATCH_HOST)
673 return !match(mask, one->host);
674
675 return !match(mask, one->servptr->name);
676 }
677
678 /* sendto_match_butone()
679 *
680 * Send to all clients which match the mask in a way defined on 'what';
681 * either by user hostname or user servername.
682 *
683 * ugh. ONLY used by m_message.c to send an "oper magic" message. ugh.
684 */
685 void
686 sendto_match_butone(struct Client *one, struct Client *from, const char *mask,
687 int what, const char *pattern, ...)
688 {
689 va_list alocal, aremote;
690 dlink_node *ptr = NULL, *ptr_next = NULL;
691 struct dbuf_block *local_buf, *remote_buf;
692
693 local_buf = dbuf_alloc(), remote_buf = dbuf_alloc();
694
695 dbuf_put_fmt(local_buf, ":%s!%s@%s ", from->name, from->username, from->host);
696 dbuf_put_fmt(remote_buf, ":%s ", from->id);
697
698 va_start(alocal, pattern);
699 va_start(aremote, pattern);
700 send_format(local_buf, pattern, alocal);
701 send_format(remote_buf, pattern, aremote);
702 va_end(aremote);
703 va_end(alocal);
704
705 /* scan the local clients */
706 DLINK_FOREACH(ptr, local_client_list.head)
707 {
708 struct Client *client_p = ptr->data;
709
710 if ((!one || client_p != one->from) && !IsDefunct(client_p) &&
711 match_it(client_p, mask, what))
712 send_message(client_p, local_buf);
713 }
714
715 /* Now scan servers */
716 DLINK_FOREACH_SAFE(ptr, ptr_next, local_server_list.head)
717 {
718 struct Client *client_p = ptr->data;
719
720 /*
721 * The old code looped through every client on the
722 * network for each server to check if the
723 * server (client_p) has at least 1 client matching
724 * the mask, using something like:
725 *
726 * for (target_p = GlobalClientList; target_p; target_p = target_p->next)
727 * if (IsRegisteredUser(target_p) &&
728 * match_it(target_p, mask, what) &&
729 * (target_p->from == client_p))
730 * vsendto_prefix_one(client_p, from, pattern, args);
731 *
732 * That way, we wouldn't send the message to
733 * a server who didn't have a matching client.
734 * However, on a network such as EFNet, that
735 * code would have looped through about 50
736 * servers, and in each loop, loop through
737 * about 50k clients as well, calling match()
738 * in each nested loop. That is a very bad
739 * thing cpu wise - just send the message
740 * to every connected server and let that
741 * server deal with it.
742 * -wnder
743 */
744 if ((!one || client_p != one->from) && !IsDefunct(client_p))
745 send_message_remote(client_p, from, remote_buf);
746 }
747
748 dbuf_ref_free(local_buf);
749 dbuf_ref_free(remote_buf);
750 }
751
752 /* sendto_match_servs()
753 *
754 * inputs - source client
755 * - mask to send to
756 * - capab needed
757 * - data
758 * outputs - none
759 * side effects - data sent to servers matching with capab
760 */
761 void
762 sendto_match_servs(struct Client *source_p, const char *mask, unsigned int cap,
763 const char *pattern, ...)
764 {
765 va_list args;
766 dlink_node *ptr = NULL, *ptr_next = NULL;
767 struct dbuf_block *buffer = dbuf_alloc();
768
769 dbuf_put_fmt(buffer, ":%s ", source_p->id);
770 va_start(args, pattern);
771 send_format(buffer, pattern, args);
772 va_end(args);
773
774 ++current_serial;
775
776 DLINK_FOREACH_SAFE(ptr, ptr_next, global_server_list.head)
777 {
778 struct Client *target_p = ptr->data;
779
780 /* Do not attempt to send to ourselves, or the source */
781 if (IsMe(target_p) || target_p->from == source_p->from)
782 continue;
783
784 if (target_p->from->connection->serial == current_serial)
785 continue;
786
787 if (match(mask, target_p->name))
788 continue;
789
790 /*
791 * If we set the serial here, then we'll never do a
792 * match() again, if !IsCapable()
793 */
794 target_p->from->connection->serial = current_serial;
795
796 if (!IsCapable(target_p->from, cap))
797 continue;
798
799 send_message_remote(target_p->from, source_p, buffer);
800 }
801
802 dbuf_ref_free(buffer);
803 }
804
805 /* sendto_anywhere()
806 *
807 * inputs - pointer to dest client
808 * - pointer to from client
809 * - varags
810 * output - NONE
811 * side effects - less efficient than sendto_remote and sendto_one
812 * but useful when one does not know where target "lives"
813 */
814 void
815 sendto_anywhere(struct Client *to, struct Client *from,
816 const char *command,
817 const char *pattern, ...)
818 {
819 va_list args;
820 struct dbuf_block *buffer = NULL;
821
822 if (IsDead(to->from))
823 return;
824
825 buffer = dbuf_alloc();
826
827 if (MyClient(to) && IsClient(from))
828 dbuf_put_fmt(buffer, ":%s!%s@%s %s %s ", from->name, from->username,
829 from->host, command, to->name);
830 else
831 dbuf_put_fmt(buffer, ":%s %s %s ", ID_or_name(from, to),
832 command, ID_or_name(to, to));
833
834 va_start(args, pattern);
835 send_format(buffer, pattern, args);
836 va_end(args);
837
838 if (MyConnect(to))
839 send_message(to, buffer);
840 else
841 send_message_remote(to->from, from, buffer);
842
843 dbuf_ref_free(buffer);
844 }
845
846 /* sendto_realops_flags()
847 *
848 * inputs - flag types of messages to show to real opers
849 * - flag indicating opers/admins
850 * - var args input message
851 * output - NONE
852 * side effects - Send to *local* ops only but NOT +s nonopers.
853 */
854 void
855 sendto_realops_flags(unsigned int flags, int level, int type, const char *pattern, ...)
856 {
857 const char *ntype = NULL;
858 dlink_node *ptr = NULL;
859 char nbuf[IRCD_BUFSIZE] = "";
860 va_list args;
861
862 va_start(args, pattern);
863 vsnprintf(nbuf, sizeof(nbuf), pattern, args);
864 va_end(args);
865
866 switch (type)
867 {
868 case SEND_NOTICE:
869 ntype = "Notice";
870 break;
871 case SEND_GLOBAL:
872 ntype = "Global";
873 break;
874 case SEND_LOCOPS:
875 ntype = "LocOps";
876 break;
877 default:
878 assert(0);
879 }
880
881 DLINK_FOREACH(ptr, oper_list.head)
882 {
883 struct Client *client_p = ptr->data;
884 assert(HasUMode(client_p, UMODE_OPER));
885
886 /*
887 * If we're sending it to opers and they're an admin, skip.
888 * If we're sending it to admins, and they're not, skip.
889 */
890 if (((level == L_ADMIN) && !HasUMode(client_p, UMODE_ADMIN)) ||
891 ((level == L_OPER) && HasUMode(client_p, UMODE_ADMIN)))
892 continue;
893
894 if (HasUMode(client_p, flags))
895 sendto_one(client_p, ":%s NOTICE %s :*** %s -- %s",
896 me.name, client_p->name, ntype, nbuf);
897 }
898 }
899
900 /* ts_warn()
901 *
902 * inputs - var args message
903 * output - NONE
904 * side effects - Call sendto_realops_flags, with some flood checking
905 * (at most 5 warnings every 5 seconds)
906 */
907 void
908 sendto_realops_flags_ratelimited(time_t *rate, const char *pattern, ...)
909 {
910 va_list args;
911 char buffer[IRCD_BUFSIZE] = "";
912
913 if ((CurrentTime - *rate) < 20)
914 return;
915 *rate = CurrentTime;
916
917 va_start(args, pattern);
918 vsnprintf(buffer, sizeof(buffer), pattern, args);
919 va_end(args);
920
921 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s", buffer);
922 ilog(LOG_TYPE_IRCD, "%s", buffer);
923 }
924
925 /* sendto_wallops_flags()
926 *
927 * inputs - flag types of messages to show to real opers
928 * - client sending request
929 * - var args input message
930 * output - NONE
931 * side effects - Send a wallops to local opers
932 */
933 void
934 sendto_wallops_flags(unsigned int flags, struct Client *source_p,
935 const char *pattern, ...)
936 {
937 dlink_node *ptr = NULL;
938 va_list args;
939 struct dbuf_block *buffer;
940
941 buffer = dbuf_alloc();
942
943 if (IsClient(source_p))
944 dbuf_put_fmt(buffer, ":%s!%s@%s WALLOPS :", source_p->name, source_p->username, source_p->host);
945 else
946 dbuf_put_fmt(buffer, ":%s WALLOPS :", source_p->name);
947
948 va_start(args, pattern);
949 send_format(buffer, pattern, args);
950 va_end(args);
951
952 DLINK_FOREACH(ptr, oper_list.head)
953 {
954 struct Client *client_p = ptr->data;
955 assert(client_p->umodes & UMODE_OPER);
956
957 if (HasUMode(client_p, flags) && !IsDefunct(client_p))
958 send_message(client_p, buffer);
959 }
960
961 dbuf_ref_free(buffer);
962 }

Properties

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