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