]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/match.c
Move cmode +N to cmode +d, so that extensions/m_roleplay can retain cmode +N and...
[irc/rqf/shadowircd.git] / src / match.c
index ee77aeb8361a06d5e6c8c98271c778a16d0c89f1..7ebc0c2062b60b143e7d1380a444be8ae780bc42 100644 (file)
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: match.c 3175 2007-02-01 00:02:35Z jilles $
  *
  */
 #include "stdinc.h"
 #include "config.h"
 #include "client.h"
 #include "ircd.h"
-#include "irc_string.h"
+#include "match.h"
 
 /*
  * Compare if a given string (name) matches the given
@@ -105,20 +104,18 @@ int match(const char *mask, const char *name)
        }
 }
 
-/** Check a string against a mask.
+/** Check a mask against a mask.
  * This test checks using traditional IRC wildcards only: '*' means
  * match zero or more characters of any type; '?' means match exactly
- * one character of any type; '#' means match exactly one character
- * that is a number.
- *
- * This function supports escaping, so that a wildcard may be matched 
- * exactly.
+ * one character of any type.
+ * The difference between mask_match() and match() is that in mask_match()
+ * a '?' in mask does not match a '*' in name.
  *
- * @param[in] mask Wildcard-containing mask.
- * @param[in] name String to check against \a mask.
- * @return Zero if \a mask matches \a name, non-zero if no match.
+ * @param[in] mask Existing wildcard-containing mask.
+ * @param[in] name New wildcard-containing mask.
+ * @return 1 if \a name is equal to or more specific than \a mask, 0 otherwise.
  */
-int match_esc(const char *mask, const char *name)
+int mask_match(const char *mask, const char *name)
 {
        const char *m = mask, *n = name;
        const char *m_tmp = mask, *n_tmp = name;
@@ -140,12 +137,6 @@ int match_esc(const char *mask, const char *name)
                          m = m_tmp;
                          n = ++n_tmp;
                          break;
-                 case '\\':
-                         m++;
-                         /* allow escaping to force capitalization */
-                         if (*m++ != *n++)
-                                 goto backtrack;
-                         break;
                  case '*':
                  case '?':
                          for (star_p = 0;; m++)
@@ -154,8 +145,10 @@ int match_esc(const char *mask, const char *name)
                                          star_p = 1;
                                  else if (*m == '?')
                                  {
-                                         if (!*n++)
+                                         /* changed for mask_match() */
+                                         if (*n == '*' || !*n)
                                                  goto backtrack;
+                                         n++;
                                  }
                                  else
                                          break;
@@ -164,23 +157,6 @@ int match_esc(const char *mask, const char *name)
                          {
                                  if (!*m)
                                          return 1;
-                                 else if (*m == '\\')
-                                 {
-                                         m_tmp = ++m;
-                                         if (!*m)
-                                                 return 0;
-                                         for (n_tmp = n; *n && *n != *m; n++);
-                                 }
-                                 else if (*m == '#')
-                                 {
-                                         m_tmp = m;
-                                         for (n_tmp = n; *n && !IsDigit(*n); n++);
-                                 }
-                                 else if (*m == '@')
-                                 {
-                                         m_tmp = m;
-                                         for (n_tmp = n; *n && !IsLetter(*n); n++);
-                                 }
                                  else
                                  {
                                          m_tmp = m;
@@ -191,17 +167,7 @@ int match_esc(const char *mask, const char *name)
                  default:
                          if (!*n)
                                  return (*m != '\0' ? 0 : 1);
-                         if (*m == '#')
-                         {
-                                 if (!IsDigit(*n))
-                                       goto backtrack;
-                         }
-                         else if (*m == '@')
-                         {
-                                 if (!IsLetter(*n))
-                                       goto backtrack;
-                         }
-                         else if (ToLower(*m) != ToLower(*n))
+                         if (ToLower(*m) != ToLower(*n))
                                  goto backtrack;
                          m++;
                          n++;
@@ -210,6 +176,137 @@ int match_esc(const char *mask, const char *name)
        }
 }
 
+
+#define MATCH_MAX_CALLS 512    /* ACK! This dies when it's less that this
+                                  and we have long lines to parse */
+/** Check a string against a mask.
+ * This test checks using extended wildcards: '*' means match zero
+ * or more characters of any type; '?' means match exactly one
+ * character of any type; '#' means match exactly one character that
+ * is a number; '@' means match exactly one character that is a
+ * letter; '\s' means match a space.
+ *
+ * This function supports escaping, so that a wildcard may be matched 
+ * exactly.
+ *
+ * @param[in] mask Wildcard-containing mask.
+ * @param[in] name String to check against \a mask.
+ * @return Zero if \a mask matches \a name, non-zero if no match.
+ */
+int
+match_esc(const char *mask, const char *name)
+{
+       const unsigned char *m = (const unsigned char *)mask;
+       const unsigned char *n = (const unsigned char *)name;
+       const unsigned char *ma = (const unsigned char *)mask;
+       const unsigned char *na = (const unsigned char *)name;
+       int wild = 0;
+       int calls = 0;
+       int quote = 0;
+       int match1 = 0;
+
+       s_assert(mask != NULL);
+       s_assert(name != NULL);
+
+       if(!mask || !name)
+               return 0;
+
+       /* if the mask is "*", it matches everything */
+       if((*m == '*') && (*(m + 1) == '\0'))
+               return 1;
+
+       while(calls++ < MATCH_MAX_CALLS)
+       {
+               if(quote)
+                       quote++;
+               if(quote == 3)
+                       quote = 0;
+               if(*m == '\\' && !quote)
+               {
+                       m++;
+                       quote = 1;
+                       continue;
+               }
+               if(!quote && *m == '*')
+               {
+                       /*
+                        * XXX - shouldn't need to spin here, the mask should have been
+                        * collapsed before match is called
+                        */
+                       while(*m == '*')
+                               m++;
+
+                       wild = 1;
+                       ma = m;
+                       na = n;
+
+                       if(*m == '\\')
+                       {
+                               m++;
+                               /* This means it is an invalid mask -A1kmm. */
+                               if(!*m)
+                                       return 0;
+                               quote++;
+                               continue;
+                       }
+               }
+
+               if(!*m)
+               {
+                       if(!*n)
+                               return 1;
+                       if(quote)
+                               return 0;
+                       for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--);;
+
+                       if(*m == '*' && (m > (const unsigned char *)mask))
+                               return 1;
+                       if(!wild)
+                               return 0;
+                       m = ma;
+                       n = ++na;
+               }
+               else if(!*n)
+               {
+                       /*
+                        * XXX - shouldn't need to spin here, the mask should have been
+                        * collapsed before match is called
+                        */
+                       if(quote)
+                               return 0;
+                       while(*m == '*')
+                               m++;
+                       return (*m == 0);
+               }
+
+               if(quote)
+                       match1 = *m == 's' ? *n == ' ' : ToLower(*m) == ToLower(*n);
+               else if(*m == '?')
+                       match1 = 1;
+               else if(*m == '@')
+                       match1 = IsLetter(*n);
+               else if(*m == '#')
+                       match1 = IsDigit(*n);
+               else
+                       match1 = ToLower(*m) == ToLower(*n);
+               if(match1)
+               {
+                       if(*m)
+                               m++;
+                       if(*n)
+                               n++;
+               }
+               else
+               {
+                       if(!wild)
+                               return 0;
+                       m = ma;
+                       n = ++na;
+               }
+       }
+       return 0;
+}
+
 int comp_with_mask(void *addr, void *dest, u_int mask)
 {
        if (memcmp(addr, dest, mask / 8) == 0)
@@ -234,7 +331,7 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask
                iaddr = &((struct sockaddr_in *)addr)->sin_addr;
                idest = &((struct sockaddr_in *)dest)->sin_addr;
        }
-#ifdef IPV6
+#ifdef RB_IPV6
        else
        {
                iaddr = &((struct sockaddr_in6 *)addr)->sin6_addr;
@@ -253,7 +350,7 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask
  */
 int match_ips(const char *s1, const char *s2)
 {
-       struct irc_sockaddr_storage ipaddr, maskaddr;
+       struct rb_sockaddr_storage ipaddr, maskaddr;
        char mask[BUFSIZE];
        char address[HOSTLEN + 1];
        char *len;
@@ -273,7 +370,7 @@ int match_ips(const char *s1, const char *s2)
        if (cidrlen == 0)
                return 0;
 
-#ifdef IPV6
+#ifdef RB_IPV6
        if (strchr(mask, ':') && strchr(address, ':'))
        {
                aftype = AF_INET6;
@@ -291,8 +388,8 @@ int match_ips(const char *s1, const char *s2)
        else
                return 0;
 
-       inetpton(aftype, address, ipptr);
-       inetpton(aftype, mask, maskptr);
+       rb_inet_pton(aftype, address, ipptr);
+       rb_inet_pton(aftype, mask, maskptr);
        if (comp_with_mask(ipptr, maskptr, cidrlen))
                return 1;
        else
@@ -307,7 +404,7 @@ int match_ips(const char *s1, const char *s2)
 
 int match_cidr(const char *s1, const char *s2)
 {
-       struct irc_sockaddr_storage ipaddr, maskaddr;
+       struct rb_sockaddr_storage ipaddr, maskaddr;
        char mask[BUFSIZE];
        char address[NICKLEN + USERLEN + HOSTLEN + 6];
        char *ipmask;
@@ -341,7 +438,7 @@ int match_cidr(const char *s1, const char *s2)
        if (cidrlen == 0)
                return 0;
 
-#ifdef IPV6
+#ifdef RB_IPV6
        if (strchr(ip, ':') && strchr(ipmask, ':'))
        {
                aftype = AF_INET6;
@@ -359,8 +456,8 @@ int match_cidr(const char *s1, const char *s2)
        else
                return 0;
 
-       inetpton(aftype, ip, ipptr);
-       inetpton(aftype, ipmask, maskptr);
+       rb_inet_pton(aftype, ip, ipptr);
+       rb_inet_pton(aftype, ipmask, maskptr);
        if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address))
                return 1;
        else
@@ -604,7 +701,7 @@ const unsigned int CharAttrs[] = {
 /* , */ PRINT_C | NONEOS_C,
 /* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
 /* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C,
-/* / */ PRINT_C | CHAN_C | NONEOS_C,
+/* / */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
 /* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
 /* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
 /* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,