ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/send.c
Revision: 3103
Committed: Thu Mar 6 00:05:12 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 28867 byte(s)
Log Message:
- send.c: cleaned up sendto_channel_butone() as suggested by Adam

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

Properties

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