ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 3107
Committed: Thu Mar 6 12:09:42 2014 UTC (12 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 27804 byte(s)
Error occurred while calculating annotation data.
Log Message:
- Applied dbuf changes as provided by Adam:
  Refcount dbufs instead of copying the same message to many
  different buffers.

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

Properties

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