Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / send.c
1 /*
2  * IRC - Internet Relay Chat, common/send.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
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 1, or (at your option)
9  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id$
21  */
22 #include "send.h"
23 #include "channel.h"
24 #include "class.h"
25 #include "client.h"
26 #include "ircd.h"
27 #include "ircd_string.h"
28 #include "list.h"
29 #include "match.h"
30 #include "msg.h"
31 #include "numnicks.h"
32 #include "s_bsd.h"
33 #include "s_debug.h"
34 #include "s_misc.h"
35 #include "s_user.h"
36 #include "sprintf_irc.h"
37 #include "struct.h"
38 #include "sys.h"
39
40 #include <assert.h>
41 #include <stdio.h>
42 #include <string.h>
43
44
45 char sendbuf[2048];
46 static int sentalong[MAXCONNECTIONS];
47 static int sentalong_marker;
48 struct SLink *opsarray[32];     /* don't use highest bit unless you change
49                                    atoi to strtoul in sendto_op_mask() */
50 #ifdef GODMODE
51 char sendbuf2[2048];
52 int sdbflag;
53 #endif /* GODMODE */
54
55 /*
56  * dead_link
57  *
58  * An error has been detected. The link *must* be closed,
59  * but *cannot* call ExitClient (m_bye) from here.
60  * Instead, mark it with FLAGS_DEADSOCKET. This should
61  * generate ExitClient from the main loop.
62  *
63  * If 'notice' is not NULL, it is assumed to be a format
64  * for a message to local opers. I can contain only one
65  * '%s', which will be replaced by the sockhost field of
66  * the failing link.
67  *
68  * Also, the notice is skipped for "uninteresting" cases,
69  * like Persons and yet unknown connections...
70  */
71
72 static void dead_link(struct Client *to, char *notice)
73 {
74   to->flags |= FLAGS_DEADSOCKET;
75   /*
76    * If because of BUFFERPOOL problem then clean dbuf's now so that
77    * notices don't hurt operators below.
78    */
79   DBufClear(&to->recvQ);
80   DBufClear(&to->sendQ);
81
82   /* Keep a copy of the last comment, for later use... */
83   ircd_strncpy(LastDeadComment(to), notice, sizeof(LastDeadComment(to) - 1));
84   LastDeadComment(to)[sizeof(LastDeadComment(to)) - 1] = '\0';
85
86   if (!IsUser(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
87     sendto_ops("%s for %s", LastDeadComment(to), to->name);
88   Debug((DEBUG_ERROR, LastDeadComment(to)));
89 }
90
91 static int can_send(struct Client* to)
92 {
93   assert(0 != to);
94   return (IsDead(to) || IsMe(to) || -1 == to->fd) ? 0 : 1;
95 }
96
97 /*
98  * flush_connections
99  *
100  * Used to empty all output buffers for all connections. Should only
101  * be called once per scan of connections. There should be a select in
102  * here perhaps but that means either forcing a timeout or doing a poll.
103  * When flushing, all we do is empty the obuffer array for each local
104  * client and try to send it. if we cant send it, it goes into the sendQ
105  * -avalon
106  */
107 void flush_connections(struct Client* cptr)
108 {
109   if (cptr) {
110     send_queued(cptr);
111   }
112   else {
113     int i;
114     for (i = HighestFd; i >= 0; i--) {
115       if ((cptr = LocalClientArray[i]))
116         send_queued(cptr);
117     }
118   }
119 }
120
121 /*
122  * flush_sendq_except - run through local client array and flush
123  * the sendq for each client, if the address of the client sendq
124  * is the same as the one specified, it is skipped. This is used
125  * by dbuf_put to try to get some more memory before bailing and
126  * causing the client to be disconnected.
127  */
128 void flush_sendq_except(const struct DBuf* one)
129 {
130   int i;
131   struct Client* cptr;
132   for (i = HighestFd; i >= 0; i--) {
133     if ( (cptr = LocalClientArray[i]) && one != &cptr->sendQ)
134       send_queued(cptr);
135   }
136 }
137
138 /*
139  * send_queued
140  *
141  * This function is called from the main select-loop (or whatever)
142  * when there is a chance that some output would be possible. This
143  * attempts to empty the send queue as far as possible...
144  */
145 void send_queued(struct Client *to)
146 {
147   assert(0 != to);
148   assert(0 != to->local);
149
150   if (IsBlocked(to) || !can_send(to))
151     return;                     /* Don't bother */
152
153   while (DBufLength(&to->sendQ) > 0) {
154     unsigned int len;
155     const char* msg = dbuf_map(&to->sendQ, &len);
156
157     if ((len = deliver_it(to, msg, len))) {
158       dbuf_delete(&to->sendQ, len);
159       to->lastsq = DBufLength(&to->sendQ) / 1024;
160       if (IsBlocked(to))
161         break;
162     }
163     else {
164       if (IsDead(to))
165         dead_link(to, "Write error, closing link");
166       break;
167     }
168   }
169 }
170
171 /*
172  *  send message to single client
173  */
174 void sendto_one(struct Client *to, const char* pattern, ...)
175 {
176   va_list vl;
177   va_start(vl, pattern);
178   vsendto_one(to, pattern, vl);
179   va_end(vl);
180 }
181
182
183 void vsendto_one(struct Client *to, const char* pattern, va_list vl)
184 {
185   vsprintf_irc(sendbuf, pattern, vl);
186   sendbufto_one(to);
187 }
188
189 #ifdef GODMODE
190 static void send_to_god(struct Client* to, const char* buf)
191 {
192   if (!sdbflag && !IsUser(to)) {
193     char sbuf2[BUFSIZE + 1];
194     unsigned int len = strlen(buf) - 2;   /* Remove "\r\n" */
195
196     sdbflag = 1;
197     len = IRCD_MIN(len, BUFSIZE);
198     ircd_strncpy(sbuf2, buf, len);
199     sbuf2[len] = '\0';
200
201     if (len > 402) {
202       char c = sbuf2[200];
203       sbuf2[200] = '\0';
204       sendto_ops("SND:%-8.8s(%.4d): \"%s...%s\"",
205                  to->name, len, sbuf2, &sbuf2[len - 200]);
206     }
207     else
208       sendto_ops("SND:%-8.8s(%.4d): \"%s\"", to->name, len, sbuf2);
209     sdbflag = 0;
210   }
211 }
212 #endif /* GODMODE */
213
214 void send_buffer(struct Client* to, char* buf)
215 {
216   unsigned int len;
217   assert(0 != to);
218   assert(0 != buf);
219
220   if (to->from)
221     to = to->from;
222
223   if (!can_send(to))
224     /*
225      * This socket has already been marked as dead
226      */
227     return;
228
229   if (DBufLength(&to->sendQ) > get_sendq(to)) {
230     if (IsServer(to))
231       sendto_ops("Max SendQ limit exceeded for %s: " SIZE_T_FMT " > " SIZE_T_FMT,
232                  to->name, DBufLength(&to->sendQ), get_sendq(to));
233     dead_link(to, "Max sendQ exceeded");
234     return;
235   }
236
237   Debug((DEBUG_SEND, "Sending [%s] to %s", buf, to->name));
238
239   len = strlen(buf);
240   if (buf[len - 1] != '\n') {
241     if (len > 510)
242       len = 510;
243     buf[len++] = '\r';
244     buf[len++] = '\n';
245     buf[len] = '\0';
246   }
247
248   if (0 == dbuf_put(&to->sendQ, buf, len)) {
249     dead_link(to, "Buffer allocation error");
250     return;
251   }
252
253 #ifdef GODMODE
254   send_to_god(to, buf);
255 #endif /* GODMODE */
256   /*
257    * Update statistics. The following is slightly incorrect
258    * because it counts messages even if queued, but bytes
259    * only really sent. Queued bytes get updated in SendQueued.
260    */
261   ++to->sendM;
262   ++me.sendM;
263   /*
264    * This little bit is to stop the sendQ from growing too large when
265    * there is no need for it to. Thus we call send_queued() every time
266    * 2k has been added to the queue since the last non-fatal write.
267    * Also stops us from deliberately building a large sendQ and then
268    * trying to flood that link with data (possible during the net
269    * relinking done by servers with a large load).
270    */
271   if (DBufLength(&to->sendQ) / 1024 > to->lastsq)
272     send_queued(to);
273 }
274
275 void sendbufto_one(struct Client* to)
276 {
277   send_buffer(to, sendbuf);
278 }
279
280 static void vsendto_prefix_one(struct Client *to, struct Client *from,
281     const char* pattern, va_list vl)
282 {
283   if (to && from && MyUser(to) && IsUser(from))
284   {
285     static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
286     char *par;
287     int flag = 0;
288     struct User *user = from->user;
289
290     par = va_arg(vl, char *);
291     strcpy(sender, from->name);
292     if (user)
293     {
294       if (*user->username)
295       {
296         strcat(sender, "!");
297         strcat(sender, user->username);
298       }
299       if (*user->host && !MyConnect(from))
300       {
301         strcat(sender, "@");
302         strcat(sender, user->host);
303         flag = 1;
304       }
305     }
306     /*
307      * Flag is used instead of strchr(sender, '@') for speed and
308      * also since username/nick may have had a '@' in them. -avalon
309      */
310     if (!flag && MyConnect(from) && *user->host)
311     {
312       strcat(sender, "@");
313       strcat(sender, from->sockhost);
314     }
315     *sendbuf = ':';
316     strcpy(&sendbuf[1], sender);
317     /* Assuming 'pattern' always starts with ":%s ..." */
318     vsprintf_irc(sendbuf + strlen(sendbuf), &pattern[3], vl);
319   }
320   else
321     vsprintf_irc(sendbuf, pattern, vl);
322   sendbufto_one(to);
323 }
324
325 void sendto_channel_butone(struct Client *one, struct Client *from, struct Channel *chptr,
326     const char* pattern, ...)
327 {
328   va_list vl;
329   struct Membership* member;
330   struct Client *acptr;
331   int i;
332
333   va_start(vl, pattern);
334
335   ++sentalong_marker;
336   for (member = chptr->members; member; member = member->next_member)
337   {
338     acptr = member->user;
339     /* ...was the one I should skip */
340     if (acptr->from == one || IsZombie(member) || IsDeaf(acptr))
341       continue;
342     if (MyConnect(acptr))       /* (It is always a client) */
343       vsendto_prefix_one(acptr, from, pattern, vl);
344     else if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
345     {
346       sentalong[i] = sentalong_marker;
347       /*
348        * Don't send channel messages to links that are still eating
349        * the net.burst: -- Run 2/1/1997
350        */
351       if (!IsBurstOrBurstAck(acptr->from))
352         vsendto_prefix_one(acptr, from, pattern, vl);
353     }
354   }
355   va_end(vl);
356 }
357
358
359 void sendmsgto_channel_butone(struct Client *one, struct Client *from,
360                               struct Channel *chptr, const char *sender,
361                               const char *cmd, const char *chname, const char *msg)
362 {
363  /*
364   * Sends a PRIVMSG/NOTICE to all members on a channel but 'one', translating
365   * TOKENS to full messages when sent to local clients. --Gte (12/12/99)
366   */
367   struct Membership* member;
368   struct Client *acptr;
369   char userbuf[2048];
370   char servbuf[2048];
371   int i;
372   int flag=-1;
373
374   /* 
375    * Precalculate the buffers we sent to the clients instead of doing an
376    * expensive sprintf() per member that we send to.  We still have to
377    * use strcpy() which is evil.
378    */
379   if (IsServer(from)) {
380     sprintf(userbuf,":%s %s %s :%s",
381         from->name, 
382         ((cmd[0] == 'P') ? MSG_PRIVATE : MSG_NOTICE),
383         chname, msg);
384     sprintf(servbuf,"%s " TOK_PRIVATE " %s :%s",
385         NumServ(from), chname, msg);
386   } else {
387     sprintf(userbuf,":%s!%s@%s %s %s :%s",
388       from->name, from->username, from->user->host,
389       ((cmd[0] == 'P') ? MSG_PRIVATE : MSG_NOTICE),
390       chname, msg);
391     sprintf(servbuf,"%s%s %s %s :%s",
392       NumNick(from), 
393        ((cmd[0] == 'P') ? TOK_PRIVATE : TOK_NOTICE),
394      chname, msg);
395   }
396
397   ++sentalong_marker;
398   for (member = chptr->members; member; member = member->next_member)
399   {
400     acptr = member->user;
401     /* ...was the one I should skip */
402     if (acptr->from == one || IsZombie(member) || IsDeaf(acptr))
403       continue;
404     if (MyConnect(acptr)) {      /* (It is always a client) */
405         if (flag!=0)
406           strcpy(sendbuf,userbuf);
407         flag=0;
408         sendbufto_one(acptr);
409     }
410     else if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
411     {
412       sentalong[i] = sentalong_marker;
413       if (!IsBurstOrBurstAck(acptr->from)) {
414         if (flag != 1)
415           strcpy(sendbuf,servbuf);
416         flag = 1;
417         sendbufto_one(acptr);
418   }
419     } /* of if MyConnect() */
420   } /* of for(members) */
421 }
422
423 void sendto_lchanops_butone(struct Client *one, struct Client *from, struct Channel *chptr,
424     const char* pattern, ...)
425 {
426   va_list vl;
427   struct Membership* member;
428   struct Client *acptr;
429
430   va_start(vl, pattern);
431
432   for (member = chptr->members; member; member = member->next_member)
433   {
434     acptr = member->user;
435     /* ...was the one I should skip */
436     if (acptr == one || !IsChanOp(member) || IsZombie(member) || IsDeaf(acptr))
437       continue;
438     if (MyConnect(acptr))       /* (It is always a client) */
439       vsendto_prefix_one(acptr, from, pattern, vl);
440   }
441   va_end(vl);
442   return;
443 }
444
445 void sendto_chanopsserv_butone(struct Client *one, struct Client *from, struct Channel *chptr,
446     const char* pattern, ...)
447 {
448   va_list vl;
449   struct Membership* member;
450   struct Client *acptr;
451   int i;
452 #ifndef NO_PROTOCOL9
453   char  target[128];
454   char* source;
455   char* tp;
456   char* msg;
457 #endif
458
459   va_start(vl, pattern);
460
461   ++sentalong_marker;
462   for (member = chptr->members; member; member = member->next_member)
463   {
464     acptr = member->user;
465     if (acptr->from == acptr || /* Skip local clients */
466 #ifndef NO_PROTOCOL9
467         Protocol(acptr->from) < 10 ||   /* Skip P09 links */
468 #endif
469         acptr->from == one ||   /* ...was the one I should skip */
470         !IsChanOp(member) ||   /* Skip non chanops */
471         IsZombie(member) || IsDeaf(acptr))
472       continue;
473     if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
474     {
475       sentalong[i] = sentalong_marker;
476       /* Don't send channel messages to links that are
477          still eating the net.burst: -- Run 2/1/1997 */
478       if (!IsBurstOrBurstAck(acptr->from))
479         vsendto_prefix_one(acptr, from, pattern, vl);
480     }
481   }
482
483 #ifndef NO_PROTOCOL9
484   /* Send message to all 2.9 servers */
485   /* This is a hack, because it assumes that we know how `vl' is build up */
486   source = va_arg(vl, char *);
487   tp = va_arg(vl, char *);      /* Channel */
488   msg = va_arg(vl, char *);
489   for (member = chptr->members; member; member = member->next_member)
490   {
491     acptr = member->user;
492     if (acptr->from == acptr || /* Skip local clients */
493         Protocol(acptr->from) > 9 ||    /* Skip P10 servers */
494         acptr->from == one ||   /* ...was the one I should skip */
495         !IsChanOp(member) ||   /* Skip non chanops */
496         IsZombie(member) || IsDeaf(acptr))
497       continue;
498     if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
499     {
500       sentalong[i] = sentalong_marker;
501       /* Don't send channel messages to links that are
502          still eating the net.burst: -- Run 2/1/1997 */
503       if (!IsBurstOrBurstAck(acptr->from))
504       {
505         struct Membership* other_member;
506         struct Client* acptr2;
507         tp = target;
508         *tp = 0;
509         /* Find all chanops in this direction: */
510         for (other_member = chptr->members; other_member; other_member = other_member->next_member)
511         {
512           acptr2 = other_member->user;
513           if (acptr2->from == acptr->from && acptr2->from != one &&
514               IsChanOp(other_member) && !IsZombie(other_member) &&
515               !IsDeaf(acptr2))
516           {
517             int len = strlen(acptr2->name);
518             if (tp + len + 2 > target + sizeof(target))
519             {
520               sendto_prefix_one(acptr, from,
521                   ":%s NOTICE %s :%s", source, target, msg);
522               tp = target;
523               *tp = 0;
524             }
525             if (*target)
526               strcpy(tp++, ",");
527             strcpy(tp, acptr2->name);
528             tp += len;
529           }
530         }
531         sendto_prefix_one(acptr, from,
532             ":%s NOTICE %s :%s", source, target, msg);
533       }
534     }
535   }
536 #endif
537
538   va_end(vl);
539   return;
540 }
541
542 /*
543  * sendto_server_butone
544  *
545  * Send a message to all connected servers except the client 'one'.
546  */
547 void sendto_serv_butone(struct Client *one, const char* pattern, ...)
548 {
549   va_list vl;
550   struct DLink *lp;
551
552   va_start(vl, pattern);
553   vsprintf_irc(sendbuf, pattern, vl);
554   va_end(vl);
555
556   for (lp = me.serv->down; lp; lp = lp->next)
557   {
558     if (one && lp->value.cptr == one->from)
559       continue;
560     sendbufto_one(lp->value.cptr);
561   }
562
563 }
564
565 /*
566  * sendbufto_serv_butone()
567  *
568  * Send prepared sendbuf to all connected servers except the client 'one'
569  *  -Ghostwolf 18-May-97
570  */
571 void sendbufto_serv_butone(struct Client *one)
572 {
573   struct DLink *lp;
574
575   for (lp = me.serv->down; lp; lp = lp->next)
576   {
577     if (one && lp->value.cptr == one->from)
578       continue;
579     sendbufto_one(lp->value.cptr);
580   }
581 }
582
583
584 /*
585  * sendto_common_channels()
586  *
587  * Sends a message to all people (inclusing `acptr') on local server
588  * who are in same channel with client `acptr'.
589  */
590 void sendto_common_channels(struct Client *acptr, const char* pattern, ...)
591 {
592   va_list vl;
593   struct Membership* chan;
594   struct Membership* member;
595
596   assert(0 != acptr);
597   assert(0 != acptr->from);
598   assert(0 != pattern);
599
600   va_start(vl, pattern);
601
602   ++sentalong_marker;
603   if (-1 < acptr->from->fd)
604     sentalong[acptr->from->fd] = sentalong_marker;
605   /*
606    * loop through acptr's channels, and the members on their channels
607    */
608   if (acptr->user) {
609     for (chan = acptr->user->channel; chan; chan = chan->next_channel) {
610       for (member = chan->channel->members; member; member = member->next_member) {
611         struct Client *cptr = member->user;
612         int    i;
613         if (MyConnect(cptr) && 
614             -1 < (i = cptr->fd) && sentalong[i] != sentalong_marker) {
615           sentalong[i] = sentalong_marker;
616           vsendto_prefix_one(cptr, acptr, pattern, vl);
617         }
618       }
619     }
620   }
621   if (MyConnect(acptr))
622     vsendto_prefix_one(acptr, acptr, pattern, vl);
623   va_end(vl);
624   return;
625 }
626
627 /*
628  * sendto_channel_butserv
629  *
630  * Send a message to all members of a channel that
631  * are connected to this server.
632  */
633 void sendto_channel_butserv(struct Channel *chptr, struct Client *from, const char* pattern, ...)
634 {
635   va_list vl;
636   struct Membership* member;
637   struct Client *acptr;
638   
639   va_start(vl, pattern);
640
641   for (member = chptr->members; member; member = member->next_member) {
642     acptr = member->user;
643     if (MyConnect(acptr) && !IsZombie(member))
644       vsendto_prefix_one(acptr, from, pattern, vl);
645   }
646   va_end(vl);
647   return;
648 }
649
650 /*
651  * Send a msg to all ppl on servers/hosts that match a specified mask
652  * (used for enhanced PRIVMSGs)
653  *
654  *  addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
655  */
656
657 static int match_it(struct Client *one, const char *mask, int what)
658 {
659   switch (what)
660   {
661     case MATCH_HOST:
662       return (match(mask, one->user->host) == 0);
663     case MATCH_SERVER:
664     default:
665       return (match(mask, one->user->server->name) == 0);
666   }
667 }
668
669 /*
670  * sendto_match_butone
671  *
672  * Send to all clients which match the mask in a way defined on 'what';
673  * either by user hostname or user servername.
674  */
675 void sendto_match_butone(struct Client *one, struct Client *from,
676     const char *mask, int what, const char* pattern, ...)
677 {
678   va_list vl;
679   int i;
680   struct Client *cptr, *acptr;
681
682   va_start(vl, pattern);
683   for (i = 0; i <= HighestFd; i++)
684   {
685     if (!(cptr = LocalClientArray[i]))
686       continue;                 /* that clients are not mine */
687     if (cptr == one)            /* must skip the origin !! */
688       continue;
689     if (IsServer(cptr))
690     {
691       for (acptr = GlobalClientList; acptr; acptr = acptr->next)
692         if (IsUser(acptr) && match_it(acptr, mask, what) && acptr->from == cptr)
693           break;
694       /* a person on that server matches the mask, so we
695        *  send *one* msg to that server ...
696        */
697       if (acptr == NULL)
698         continue;
699       /* ... but only if there *IS* a matching person */
700     }
701     /* my client, does he match ? */
702     else if (!(IsUser(cptr) && match_it(cptr, mask, what)))
703       continue;
704     vsendto_prefix_one(cptr, from, pattern, vl);
705   }
706   va_end(vl);
707
708   return;
709 }
710
711 /*
712  * sendto_lops_butone
713  *
714  * Send to *local* ops but one.
715  */
716 void sendto_lops_butone(struct Client* one, const char* pattern, ...)
717 {
718   va_list         vl;
719   struct Client*  cptr;
720   struct Client** clients = me.serv->client_list;
721   int             i;
722   char            nbuf[1024];
723
724   assert(0 != clients);
725
726   sprintf_irc(nbuf, ":%s NOTICE %%s :*** Notice -- ", me.name);
727   va_start(vl, pattern);
728   vsprintf_irc(nbuf + strlen(nbuf), pattern, vl);
729   va_end(vl);
730
731   for (i = 0; i <= me.serv->nn_mask; ++i) {
732     if ((cptr = clients[i]) && cptr != one && SendServNotice(cptr)) {
733       sprintf_irc(sendbuf, nbuf, cptr->name);
734       sendbufto_one(cptr);
735     }
736   }
737 }
738
739 /*
740  * sendto_op_mask
741  *
742  * Sends message to the list indicated by the bitmask field.
743  * Don't try to send to more than one list! That is not supported.
744  * Xorath 5/1/97
745  */
746 void vsendto_op_mask(unsigned int mask, const char *pattern, va_list vl)
747 {
748   static char fmt[1024];
749   char *fmt_target;
750   int i = 0;            /* so that 1 points to opsarray[0] */
751   struct SLink *opslist;
752
753   while ((mask >>= 1))
754     i++;
755   if (!(opslist = opsarray[i]))
756     return;
757
758   fmt_target = sprintf_irc(fmt, ":%s NOTICE ", me.name);
759   do
760   {
761     strcpy(fmt_target, opslist->value.cptr->name);
762     strcat(fmt_target, " :*** Notice -- ");
763     strcat(fmt_target, pattern);
764     vsendto_one(opslist->value.cptr, fmt, vl);
765     opslist = opslist->next;
766   }
767   while (opslist);
768 }
769
770 /*
771  * sendbufto_op_mask
772  *
773  * Send a prepared sendbuf to the list indicated by the bitmask field.
774  * Ghostwolf 16-May-97
775  */
776 void sendbufto_op_mask(unsigned int mask)
777 {
778   int i = 0;            /* so that 1 points to opsarray[0] */
779   struct SLink *opslist;
780   while ((mask >>= 1))
781     i++;
782   if (!(opslist = opsarray[i]))
783     return;
784   do
785   {
786     sendbufto_one(opslist->value.cptr);
787     opslist = opslist->next;
788   }
789   while (opslist);
790 }
791
792
793 /*
794  * sendto_ops
795  *
796  * Send to *local* ops only.
797  */
798 void vsendto_ops(const char *pattern, va_list vl)
799 {
800   struct Client *cptr;
801   int i;
802   char fmt[1024];
803   char *fmt_target;
804
805   fmt_target = sprintf_irc(fmt, ":%s NOTICE ", me.name);
806
807   for (i = 0; i <= HighestFd; i++)
808     if ((cptr = LocalClientArray[i]) && !IsServer(cptr) &&
809         SendServNotice(cptr))
810     {
811       strcpy(fmt_target, cptr->name);
812       strcat(fmt_target, " :*** Notice -- ");
813       strcat(fmt_target, pattern);
814       vsendto_one(cptr, fmt, vl);
815     }
816 }
817
818 void sendto_op_mask(unsigned int mask, const char *pattern, ...)
819 {
820   va_list vl;
821   va_start(vl, pattern);
822   vsendto_op_mask(mask, pattern, vl);
823   va_end(vl);
824 }
825
826 void sendto_ops(const char *pattern, ...)
827 {
828   va_list vl;
829   va_start(vl, pattern);
830   vsendto_op_mask(SNO_OLDSNO, pattern, vl);
831   va_end(vl);
832 }
833
834 /*
835  * sendto_ops_butone
836  *
837  * Send message to all operators.
838  * one - client not to send message to
839  * from- client which message is from *NEVER* NULL!!
840  */
841 void sendto_ops_butone(struct Client *one, struct Client *from, const char *pattern, ...)
842 {
843   va_list vl;
844   int i;
845   struct Client *cptr;
846
847   va_start(vl, pattern);
848   ++sentalong_marker;
849   for (cptr = GlobalClientList; cptr; cptr = cptr->next)
850   {
851     if (!SendWallops(cptr))
852       continue;
853     i = cptr->from->fd;         /* find connection oper is on */
854     if (i < 0 || sentalong[i] == sentalong_marker)       /* sent message along it already ? */
855       continue;
856     if (cptr->from == one)
857       continue;                 /* ...was the one I should skip */
858     sentalong[i] = sentalong_marker;
859     vsendto_prefix_one(cptr->from, from, pattern, vl);
860   }
861   va_end(vl);
862
863   return;
864 }
865
866 /*
867  * sendto_g_serv_butone
868  *
869  * Send message to all remote +g users (server links).
870  *
871  * one - server not to send message to.
872  */
873 void sendto_g_serv_butone(struct Client *one, const char *pattern, ...)
874 {
875   va_list vl;
876   struct Client *cptr;
877   int i;
878
879   va_start(vl, pattern);
880   ++sentalong_marker;
881   vsprintf_irc(sendbuf, pattern, vl);
882   for (cptr = GlobalClientList; cptr; cptr = cptr->next)
883   {
884     if (!SendDebug(cptr))
885       continue;
886     i = cptr->from->fd;         /* find connection user is on */
887     if (i < 0 || sentalong[i] == sentalong_marker)       /* sent message along it already ? */
888       continue;
889     if (MyConnect(cptr))
890       continue;
891     sentalong[i] = sentalong_marker;
892     if (cptr->from == one)
893       continue;
894     sendbufto_one(cptr);
895   }
896   va_end(vl);
897
898   return;
899 }
900
901 /*
902  * sendto_prefix_one
903  *
904  * to - destination client
905  * from - client which message is from
906  *
907  * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
908  * -avalon
909  */
910 void sendto_prefix_one(struct Client *to, struct Client *from, const char *pattern, ...)
911 {
912   va_list vl;
913   va_start(vl, pattern);
914   vsendto_prefix_one(to, from, pattern, vl);
915   va_end(vl);
916 }
917
918 /*
919  * sendto_realops
920  *
921  * Send to *local* ops only but NOT +s nonopers.
922  */
923 void sendto_realops(const char *pattern, ...)
924 {
925   va_list vl;
926
927   va_start(vl, pattern);
928   vsendto_op_mask(SNO_OLDREALOP, pattern, vl);
929
930   va_end(vl);
931   return;
932 }
933
934 /*
935  * Send message to all servers of protocol 'p' and lower.
936  */
937 void sendto_lowprot_butone(struct Client *cptr, int p, const char *pattern, ...)
938 {
939   va_list vl;
940   struct DLink *lp;
941   va_start(vl, pattern);
942   for (lp = me.serv->down; lp; lp = lp->next)
943     if (lp->value.cptr != cptr && Protocol(lp->value.cptr) <= p)
944       vsendto_one(lp->value.cptr, pattern, vl);
945   va_end(vl);
946 }
947
948 /*
949  * Send message to all servers of protocol 'p' and higher.
950  */
951 void sendto_highprot_butone(struct Client *cptr, int p, const char *pattern, ...)
952 {
953   va_list vl;
954   struct DLink *lp;
955   va_start(vl, pattern);
956   for (lp = me.serv->down; lp; lp = lp->next)
957     if (lp->value.cptr != cptr && Protocol(lp->value.cptr) >= p)
958       vsendto_one(lp->value.cptr, pattern, vl);
959   va_end(vl);
960 }