Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / send.c
index f5adb86d5cf8b35b6ab9390a4098979e5c3b80cc..c68773b07fba804d179df3838b30f15139f06ab1 100644 (file)
@@ -24,6 +24,7 @@
 #include "class.h"
 #include "client.h"
 #include "ircd.h"
+#include "ircd_snprintf.h"
 #include "ircd_string.h"
 #include "list.h"
 #include "match.h"
@@ -175,6 +176,7 @@ void send_queued(struct Client *to)
 /*
  *  send message to single client
  */
+/* See sendcmdto_one, below */
 void sendto_one(struct Client *to, const char* pattern, ...)
 {
   va_list vl;
@@ -183,7 +185,7 @@ void sendto_one(struct Client *to, const char* pattern, ...)
   va_end(vl);
 }
 
-
+/* See vsendcmdto_one, below */
 void vsendto_one(struct Client *to, const char* pattern, va_list vl)
 {
   vsprintf_irc(sendbuf, pattern, vl);
@@ -281,6 +283,7 @@ void sendbufto_one(struct Client* to)
   send_buffer(to, sendbuf);
 }
 
+/* See vsendcmdto_one, below */
 static void vsendto_prefix_one(struct Client *to, struct Client *from,
     const char* pattern, va_list vl)
 {
@@ -326,6 +329,7 @@ static void vsendto_prefix_one(struct Client *to, struct Client *from,
   sendbufto_one(to);
 }
 
+/* See sendcmdto_channel_butone, below */
 void sendto_channel_butone(struct Client *one, struct Client *from, struct Channel *chptr,
     const char* pattern, ...)
 {
@@ -359,7 +363,7 @@ void sendto_channel_butone(struct Client *one, struct Client *from, struct Chann
   va_end(vl);
 }
 
-
+/* See sendcmdto_channel_butone, below */
 void sendmsgto_channel_butone(struct Client *one, struct Client *from,
                               struct Channel *chptr, const char *sender,
                               const char *cmd, const char *chname, const char *msg)
@@ -388,7 +392,7 @@ void sendmsgto_channel_butone(struct Client *one, struct Client *from,
   }
   else {
     sprintf(userbuf,":%s!%s@%s %s %s :%s",
-            from->name, from->username, from->user->host,
+            from->name, from->user->username, from->user->host,
             ('P' == *cmd) ? MSG_PRIVATE : MSG_NOTICE, chname, msg);
     sprintf(servbuf,"%s%s %s %s :%s", NumNick(from), cmd, chname, msg);
   }
@@ -419,6 +423,7 @@ void sendmsgto_channel_butone(struct Client *one, struct Client *from,
   } /* of for(members) */
 }
 
+/* See sendcmdto_channel_butone, below */
 void sendto_lchanops_butone(struct Client *one, struct Client *from, struct Channel *chptr,
     const char* pattern, ...)
 {
@@ -441,6 +446,7 @@ void sendto_lchanops_butone(struct Client *one, struct Client *from, struct Chan
   return;
 }
 
+/* See sendcmdto_channel_butone, below */
 void sendto_chanopsserv_butone(struct Client *one, struct Client *from, struct Channel *chptr,
     const char* pattern, ...)
 {
@@ -543,6 +549,7 @@ void sendto_chanopsserv_butone(struct Client *one, struct Client *from, struct C
  *
  * Send a message to all connected servers except the client 'one'.
  */
+/* See sendcmdto_serv_butone, below */
 void sendto_serv_butone(struct Client *one, const char* pattern, ...)
 {
   va_list vl;
@@ -586,6 +593,7 @@ void sendbufto_serv_butone(struct Client *one)
  * Sends a message to all people (inclusing `acptr') on local server
  * who are in same channel with client `acptr'.
  */
+/* See sendcmdto_common_channels, below */
 void sendto_common_channels(struct Client *acptr, const char* pattern, ...)
 {
   va_list vl;
@@ -628,7 +636,14 @@ void sendto_common_channels(struct Client *acptr, const char* pattern, ...)
  *
  * Send a message to all members of a channel that
  * are connected to this server.
+ *
+ * This contains a subtle bug; after the first call to vsendto_prefix_one()
+ * below, vl is in an indeterminate state, according to ANSI; we'd have to
+ * move va_start() and va_end() into the loop to correct the problem.  It's
+ * easier, however, just to use sendcmdto_channel_butserv(), which builds a
+ * buffer and sends that prepared buffer to each channel member.
  */
+/* See sendcmdto_channel_butserv, below */
 void sendto_channel_butserv(struct Channel *chptr, struct Client *from, const char* pattern, ...)
 {
   va_list vl;
@@ -712,6 +727,7 @@ void sendto_match_butone(struct Client *one, struct Client *from,
  *
  * Send to *local* ops but one.
  */
+/* See sendto_opmask_butone, below */
 void sendto_lops_butone(struct Client* one, const char* pattern, ...)
 {
   va_list         vl;
@@ -742,6 +758,7 @@ void sendto_lops_butone(struct Client* one, const char* pattern, ...)
  * Don't try to send to more than one list! That is not supported.
  * Xorath 5/1/97
  */
+#ifdef OLD_VSENDTO_OP_MASK
 void vsendto_op_mask(unsigned int mask, const char *pattern, va_list vl)
 {
   static char fmt[1024];
@@ -765,6 +782,12 @@ void vsendto_op_mask(unsigned int mask, const char *pattern, va_list vl)
   }
   while (opslist);
 }
+#else /* !OLD_VSENDTO_OP_MASK */
+void vsendto_op_mask(unsigned int mask, const char *pattern, va_list vl)
+{
+  vsendto_opmask_butone(0, mask, pattern, vl);
+}
+#endif /* OLD_VSENDTO_OP_MASK */
 
 /*
  * sendbufto_op_mask
@@ -794,6 +817,7 @@ void sendbufto_op_mask(unsigned int mask)
  *
  * Send to *local* ops only.
  */
+/* See vsendto_opmask_butone, below */
 void vsendto_ops(const char *pattern, va_list vl)
 {
   struct Client *cptr;
@@ -814,6 +838,7 @@ void vsendto_ops(const char *pattern, va_list vl)
     }
 }
 
+/* See sendto_opmask_butone, below */
 void sendto_op_mask(unsigned int mask, const char *pattern, ...)
 {
   va_list vl;
@@ -822,6 +847,7 @@ void sendto_op_mask(unsigned int mask, const char *pattern, ...)
   va_end(vl);
 }
 
+/* See sendto_opmask_butone, below */
 void sendto_ops(const char *pattern, ...)
 {
   va_list vl;
@@ -906,6 +932,7 @@ void sendto_g_serv_butone(struct Client *one, const char *pattern, ...)
  * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
  * -avalon
  */
+/* See sendcmdto_one, below */
 void sendto_prefix_one(struct Client *to, struct Client *from, const char *pattern, ...)
 {
   va_list vl;
@@ -919,6 +946,7 @@ void sendto_prefix_one(struct Client *to, struct Client *from, const char *patte
  *
  * Send to *local* ops only but NOT +s nonopers.
  */
+/* See sendto_opmask_butone, below */
 void sendto_realops(const char *pattern, ...)
 {
   va_list vl;
@@ -933,6 +961,7 @@ void sendto_realops(const char *pattern, ...)
 /*
  * Send message to all servers of protocol 'p' and lower.
  */
+/* See sendcmdto_serv_butone, below */
 void sendto_lowprot_butone(struct Client *cptr, int p, const char *pattern, ...)
 {
   va_list vl;
@@ -947,6 +976,7 @@ void sendto_lowprot_butone(struct Client *cptr, int p, const char *pattern, ...)
 /*
  * Send message to all servers of protocol 'p' and higher.
  */
+/* See sendcmdto_serv_butone, below */
 void sendto_highprot_butone(struct Client *cptr, int p, const char *pattern, ...)
 {
   va_list vl;
@@ -957,3 +987,290 @@ void sendto_highprot_butone(struct Client *cptr, int p, const char *pattern, ...
       vsendto_one(lp->value.cptr, pattern, vl);
   va_end(vl);
 }
+
+/*
+ * Send a (prefixed) command to a single client; select which of <cmd>
+ * <tok> to use depending on if to is a server or not.  <from> is the
+ * originator of the command.
+ */
+void sendcmdto_one(struct Client *from, const char *cmd, const char *tok,
+                  struct Client *to, const char *pattern, ...)
+{
+  va_list vl;
+
+  va_start(vl, pattern);
+  vsendcmdto_one(from, cmd, tok, to, pattern, vl);
+  va_end(vl);
+}
+
+void vsendcmdto_one(struct Client *from, const char *cmd, const char *tok,
+                   struct Client *to, const char *pattern, va_list vl)
+{
+  struct VarData vd;
+  char sndbuf[IRC_BUFSIZE];
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  vd.vd_args = vl;
+
+  if (MyUser(to)) { /* :nick!user@host form; use cmd */
+    if (IsServer(from) || IsMe(from))
+      ircd_snprintf(to, sndbuf, sizeof(sndbuf) - 2, ":%s %s %v",
+                   from->name, cmd, &vd);
+    else
+      ircd_snprintf(to, sndbuf, sizeof(sndbuf) - 2, ":%s!%s@%s %s %v",
+                   from->name, from->user->username, from->user->host,
+                   cmd, &vd);
+  } else /* numeric form; use tok */
+    ircd_snprintf(to, sndbuf, sizeof(sndbuf) - 2, "%C %s %v", from, tok, &vd);
+
+  send_buffer(to, sndbuf);
+}
+
+/*
+ * Send a (prefixed) command to all servers but one, using tok; cmd
+ * is ignored in this particular function.
+ */
+void sendcmdto_serv_butone(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          const char *pattern, ...)
+{
+  struct VarData vd;
+  char sndbuf[IRC_BUFSIZE];
+  struct DLink *lp;
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  /* use token */
+  ircd_snprintf(&me, sndbuf, sizeof(sndbuf) - 2, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send it to our downlinks */
+  for (lp = me.serv->down; lp; lp = lp->next) {
+    if (one && lp->value.cptr == one->from)
+      continue;
+    send_buffer(lp->value.cptr, sndbuf);
+  }
+}
+
+/*
+ * Send a (prefix) command originating from <from> to all channels
+ * <from> is locally on.  <from> must be a user. <tok> is ignored in
+ * this function.
+ */
+void sendcmdto_common_channels(struct Client *from, const char *cmd,
+                              const char *tok, const char *pattern, ...)
+{
+  struct VarData vd;
+  char sndbuf[IRC_BUFSIZE];
+  struct Membership *chan;
+  struct Membership *member;
+
+  assert(0 != from);
+  assert(0 != from->from);
+  assert(0 != pattern);
+  assert(!IsServer(from) && !IsMe(from));
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+
+  va_start(vd.vd_args, pattern);
+
+  /* build the buffer */
+  ircd_snprintf(0, sndbuf, sizeof(sndbuf) - 2, ":%s!%s@%s %s %v", from->name,
+               from->user->username, from->user->host, cmd, &vd);
+  va_end(vd.vd_args);
+
+  sentalong_marker++;
+  if (-1 < from->from->fd)
+    sentalong[from->from->fd] = sentalong_marker;
+  /*
+   * loop through from's channels, and the members on their channels
+   */
+  for (chan = from->user->channel; chan; chan = chan->next_channel)
+    for (member = chan->channel->members; member;
+        member = member->next_member)
+      if (MyConnect(member->user) && -1 < from->fd &&
+         sentalong[member->user->from->fd] != sentalong_marker) {
+       sentalong[member->user->from->fd] = sentalong_marker;
+       send_buffer(member->user, sndbuf);
+      }
+
+  if (MyConnect(from))
+    send_buffer(from, sndbuf);
+}
+
+/*
+ * Send a (prefixed) command to all local users on the channel specified
+ * by <to>; <tok> is ignored by this function
+ */
+void sendcmdto_channel_butserv(struct Client *from, const char *cmd,
+                              const char *tok, struct Channel *to,
+                              const char *pattern, ...)
+{
+  struct VarData vd;
+  char sndbuf[IRC_BUFSIZE];
+  struct Membership *member;
+
+  vd.vd_format = pattern; /* set up the struct VarData for %v */
+  va_start(vd.vd_args, pattern);
+
+  /* build the buffer */
+  if (IsServer(from) || IsMe(from))
+    ircd_snprintf(0, sndbuf, sizeof(sndbuf) - 2, ":%s %s %v", from->name,
+                 cmd, &vd);
+  else
+    ircd_snprintf(0, sndbuf, sizeof(sndbuf) - 2, ":%s!%s@%s %s %v", from->name,
+                 from->user->username, from->user->host, cmd, &vd);
+  va_end(vd.vd_args);
+
+  /* send the buffer to each local channel member */
+  for (member = to->members; member; member = member->next_member) {
+    if (MyConnect(member->user) && !IsZombie(member))
+      send_buffer(member->user, sndbuf);
+  }
+}
+
+/*
+ * Send a (prefixed) command to all users on this channel, including
+ * remote users; users to skip may be specified by setting appropriate
+ * flags in the <skip> argument.  <one> will also be skipped.
+ */
+void sendcmdto_channel_butone(struct Client *from, const char *cmd,
+                             const char *tok, struct Channel *to,
+                             struct Client *one, unsigned int skip,
+                             const char *pattern, ...)
+{
+  struct Membership *member;
+  struct VarData vd;
+  char userbuf[IRC_BUFSIZE];
+  char servbuf[IRC_BUFSIZE];
+
+  vd.vd_format = pattern;
+
+  /* Build buffer to send to users */
+  va_start(vd.vd_args, pattern);
+  if (IsServer(from) || IsMe(from))
+    ircd_snprintf(0, userbuf, sizeof(userbuf) - 2, ":%s %s %v", from->name,
+                 cmd, &vd);
+  else
+    ircd_snprintf(0, userbuf, sizeof(userbuf) - 2, ":%s!%s@%s %s %v",
+                 from->name, from->user->username, from->user->host, cmd,
+                 &vd);
+  va_end(vd.vd_args);
+
+  /* Build buffer to send to servers */
+  va_start(vd.vd_args, pattern);
+  ircd_snprintf(&me, servbuf, sizeof(servbuf) - 2, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along! */
+  sentalong_marker++;
+  for (member = to->members; member; member = member->next_member) {
+    /* skip one, zombies, and deaf users... */
+    if (member->user->from == one || IsZombie(member) ||
+       (skip & SKIP_DEAF && IsDeaf(member->user)) ||
+       (skip & SKIP_NONOPS && !IsChanOp(member)))
+      continue;
+
+    if (MyConnect(member->user))
+      send_buffer(member->user, userbuf); /* send user buffer */
+    else if (-1 < member->user->from->fd &&
+            sentalong[member->user->from->fd] != sentalong_marker) {
+      sentalong[member->user->from->fd] = sentalong_marker;
+
+      if (skip & SKIP_BURST && IsBurstOrBurstAck(member->user->from))
+       continue; /* skip bursting servers */
+
+      send_buffer(member->user->from, servbuf); /* send server buffer */
+    }
+  }
+}
+
+/*
+ * Send a (prefixed) command to all users except <one> that have
+ * <flag> set.
+ */
+void sendcmdto_flag_butone(struct Client *from, const char *cmd,
+                          const char *tok, struct Client *one,
+                          unsigned int flag, const char *pattern, ...)
+{
+  struct VarData vd;
+  struct Client *cptr;
+  char userbuf[IRC_BUFSIZE];
+  char servbuf[IRC_BUFSIZE];
+
+  vd.vd_format = pattern;
+
+  /* Build buffer to send to users */
+  va_start(vd.vd_args, pattern);
+  if (IsServer(from) || IsMe(from))
+    ircd_snprintf(0, userbuf, sizeof(userbuf) - 2, ":%s %s %v", from->name,
+                 cmd, &vd);
+  else
+    ircd_snprintf(0, userbuf, sizeof(userbuf) - 2, ":%s!%s@%s %s %v",
+                 from->name, from->user->username, from->user->host, cmd,
+                 &vd);
+  va_end(vd.vd_args);
+
+  /* Build buffer to send to servers */
+  va_start(vd.vd_args, pattern);
+  ircd_snprintf(&me, servbuf, sizeof(servbuf) - 2, "%C %s %v", from, tok, &vd);
+  va_end(vd.vd_args);
+
+  /* send buffer along! */
+  sentalong_marker++;
+  for (cptr = GlobalClientList; cptr; cptr = cptr->next) {
+    if (cptr->from == one || !(cptr->flags & flag) || cptr->from->fd < 0 ||
+       sentalong[cptr->from->fd] == sentalong_marker)
+      continue; /* skip it */
+
+    if (IsServer(cptr)) /* send right buffer */
+      send_buffer(cptr, servbuf);
+    else
+      send_buffer(cptr, userbuf);
+  }
+}
+
+/*
+ * Send a server notice to all users subscribing to the indicated <mask>
+ * except for <one>
+ */
+void sendto_opmask_butone(struct Client *one, unsigned int mask,
+                         const char *pattern, ...)
+{
+  va_list vl;
+
+  va_start(vl, pattern);
+  vsendto_opmask_butone(one, mask, pattern, vl);
+  va_end(vl);
+}
+
+/*
+ * Same as above, except called with a variable argument list
+ */
+void vsendto_opmask_butone(struct Client *one, unsigned int mask,
+                          const char *pattern, va_list vl)
+{
+  struct VarData vd;
+  char sndbuf[IRC_BUFSIZE];
+  int i = 0; /* so that 1 points to opsarray[0] */
+  struct SLink *opslist;
+
+  while ((mask >>= 1))
+    i++;
+
+  if (!(opslist = opsarray[i]))
+    return;
+
+  /*
+   * build string; I don't want to bother with client nicknames, so I hope
+   * this is ok...
+   */
+  vd.vd_format = pattern;
+  vd.vd_args = vl;
+  ircd_snprintf(0, sndbuf, sizeof(sndbuf) - 2, ":%s " MSG_NOTICE
+               " * :*** Notice -- %v", me.name, &vd);
+
+  for (; opslist; opslist = opslist->next)
+    send_buffer(opslist->value.cptr, sndbuf);
+}