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     size_t 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     size_t 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   size_t 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     if (MyConnect(acptr = member->user) && !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 }