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