added basic ssl support to ircu
[ircu2.10.12-pk.git] / ircd / whocmds.c
index f1b2d50c50da31aedc43e3982b8efd83aa2f2808..0b166ba0bb0ebd7e8a0dbc94d4382a77efc952fc 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id$
  */
+/** @file
+ * @brief Support functions for /WHO-like commands.
+ * @version $Id$
+ */
+#include "config.h"
+
 #include "whocmds.h"
 #include "channel.h"
 #include "client.h"
 #include "hash.h"
 #include "ircd.h"
 #include "ircd_chattr.h"
+#include "ircd_features.h"
 #include "ircd_reply.h"
+#include "ircd_snprintf.h"
 #include "ircd_string.h"
 #include "list.h"
 #include "match.h"
 #include "s_misc.h"
 #include "s_user.h"
 #include "send.h"
-#include "sprintf_irc.h"
 #include "struct.h"
-#include "support.h"
 #include "sys.h"
 #include "userload.h"
 #include "version.h"
 #include "whowas.h"
 #include "msg.h"
 
-#include <arpa/inet.h>        /* inet_ntoa */
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
-/*
- * The function that actually prints out the WHO reply for a client found
+/** Send a WHO reply to a client who asked.
+ * @param[in] sptr Client who is searching for other users.
+ * @param[in] acptr Client who may be shown to \a sptr.
+ * @param[in] repchan Shared channel that provides visibility.
+ * @param[in] fields Bitmask of WHO_FIELD_* values, indicating what to show.
+ * @param[in] qrt Query type string (ignored unless \a fields & WHO_FIELD_QTY).
  */
 void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
             int fields, char* qrt)
 {
   char *p1;
-  struct Channel *chptr = repchan;
+  struct Membership *chan = 0;
 
   static char buf1[512];
   /* NOTE: with current fields list and sizes this _cannot_ overrun, 
@@ -78,14 +85,17 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
      unless the listing is for a channel service, we already know
      that there are no common channels, thus use PubChannel and not
      SeeChannel */
-  if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
-      !IsChannelService(acptr))
+  if (repchan)
+  {
+    chan = find_channel_member(acptr, repchan);
+  }
+  else if ((!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA)))
+           && !IsChannelService(acptr))
   {
-    struct Membership* chan;
-    for (chan = cli_user(acptr)->channel; chan && !chptr; chan = chan->next_channel)
+    for (chan = cli_user(acptr)->channel; chan; chan = chan->next_channel)
       if (PubChannel(chan->channel) &&
           (acptr == sptr || !IsZombie(chan)))
-        chptr = chan->channel;
+        break;
   }
 
   /* Place the fields one by one in the buffer and send it
@@ -104,7 +114,7 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
   {
     char *p2;
     *(p1++) = ' ';
-    if ((p2 = (chptr ? chptr->chname : NULL)))
+    if ((p2 = (chan ? chan->channel->chname : NULL)))
       while ((*p2) && (*(p1++) = *(p2++)));
     else
       *(p1++) = '*';
@@ -119,7 +129,9 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
 
   if (fields & WHO_FIELD_NIP)
   {
-    const char* p2 = ircd_ntoa((const char*) &(cli_ip(acptr)));
+    const char* p2 = HasHiddenHost(acptr) && !IsAnOper(sptr) ?
+      feature_str(FEAT_HIDDEN_IP) :
+      ircd_ntoa(&cli_ip(acptr));
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
@@ -133,7 +145,9 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
 
   if (!fields || (fields & WHO_FIELD_SER))
   {
-    char *p2 = cli_name(cli_user(acptr)->server);
+    const char *p2 = (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr)) ?
+                       feature_str(FEAT_HIS_SERVERNAME) :
+                       cli_name(cli_user(acptr)->server);
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
@@ -152,28 +166,34 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
       *(p1++) = 'G';
     else
       *(p1++) = 'H';
-    if (IsAnOper(acptr) &&
-       (HasPriv(acptr, PRIV_DISPLAY) || HasPriv(sptr, PRIV_SEE_OPERS)))
+    if SeeOper(sptr,acptr)
       *(p1++) = '*';
-    if (fields) {
+    if (!chan) {
+      /* No flags possible for the channel, so skip them all. */
+    }
+    else if (fields) {
       /* If you specified flags then we assume you know how to parse
        * multiple channel status flags, as this is currently the only
        * way to know if someone has @'s *and* is +'d.
        */
-      if (chptr && is_chan_op(acptr, chptr))
+      if (IsChanOp(chan))
         *(p1++) = '@';
-      if (chptr && has_voice(acptr, chptr))
+      if (HasVoice(chan))
         *(p1++) = '+';
-      if (chptr && is_zombie(acptr, chptr))
+      if (IsZombie(chan))
         *(p1++) = '!';
+      if (IsDelayedJoin(chan))
+        *(p1++) = '<';
     }
     else {
-      if (chptr && is_chan_op(acptr, chptr))
+      if (IsChanOp(chan))
         *(p1++) = '@';
-      else if (chptr && has_voice(acptr, chptr))
+      else if (HasVoice(chan))
         *(p1++) = '+';
-      else if (chptr && is_zombie(acptr, chptr))
+      else if (IsZombie(chan))
         *(p1++) = '!';
+      else if (IsDelayedJoin(chan))
+        *(p1++) = '<';
     }
     if (IsDeaf(acptr))
       *(p1++) = 'd';
@@ -186,6 +206,8 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
       if (SendDebug(acptr))
         *(p1++) = 'g';
     }
+    if (HasHiddenHost(acptr))
+      *(p1++) = 'x';
   }
 
   if (!fields || (fields & WHO_FIELD_DIS))
@@ -193,18 +215,50 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
     *p1++ = ' ';
     if (!fields)
       *p1++ = ':';              /* Place colon here for default reply */
-    p1 = sprintf_irc(p1, "%d", cli_hopcount(acptr));
+    if (feature_bool(FEAT_HIS_WHO_HOPCOUNT) && !IsAnOper(sptr))
+      *p1++ = (sptr == acptr) ? '0' : '3';
+    else
+      /* three digit hopcount maximum */
+      p1 += ircd_snprintf(0, p1, 3, "%d", cli_hopcount(acptr));
   }
 
   if (fields & WHO_FIELD_IDL)
   {
     *p1++ = ' ';
-    if (MyUser(acptr)) {
-           p1 = sprintf_irc(p1, "%d", CurrentTime - cli_user(acptr)->last);
-    }    
-    else {
-           *p1++ = '0';
-    }
+    if (MyUser(acptr) &&
+       (IsAnOper(sptr) || !feature_bool(FEAT_HIS_WHO_SERVERNAME) ||
+        acptr == sptr))
+      p1 += ircd_snprintf(0, p1, 11, "%d",
+                          CurrentTime - cli_user(acptr)->last);
+    else
+      *p1++ = '0';
+  }
+
+  if (fields & WHO_FIELD_ACC)
+  {
+    char *p2 = cli_user(acptr)->account;
+    *(p1++) = ' ';
+    if (*p2)
+      while ((*p2) && (*(p1++) = *(p2++)));
+    else
+      *(p1++) = '0';
+  }
+
+  if (fields & WHO_FIELD_OPL)
+  {
+      if (!chan || !IsChanOp(chan))
+      {
+        strcpy(p1, " n/a");
+        p1 += 4;
+      }
+      else
+      {
+        int vis_level = MAXOPLEVEL;
+        if ((IsGlobalChannel(chan->channel->chname) ? IsOper(sptr) : IsAnOper(sptr))
+            || is_chan_op(sptr, chan->channel))
+          vis_level = OpLevel(chan);
+        p1 += ircd_snprintf(0, p1, 5, " %d", vis_level);
+      }
   }
 
   if (!fields || (fields & WHO_FIELD_REN))
@@ -222,4 +276,3 @@ void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
   p1 = buf1;
   send_reply(sptr, fields ? RPL_WHOSPCRPL : RPL_WHOREPLY, ++p1);
 }
-