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