* 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 $
+ * $Id: match.c 3532 2007-07-14 13:32:18Z 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
}
}
-/** 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;
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++)
star_p = 1;
else if (*m == '?')
{
- if (!*n++)
+ /* changed for mask_match() */
+ if (*n == '*' || !*n)
goto backtrack;
+ n++;
}
else
break;
{
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;
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++;
}
}
+
+#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)
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;
*/
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;
if (cidrlen == 0)
return 0;
-#ifdef IPV6
+#ifdef RB_IPV6
if (strchr(mask, ':') && strchr(address, ':'))
{
aftype = AF_INET6;
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
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;
if (cidrlen == 0)
return 0;
-#ifdef IPV6
+#ifdef RB_IPV6
if (strchr(ip, ':') && strchr(ipmask, ':'))
{
aftype = AF_INET6;
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
/* 26 */ CNTRL_C | CHAN_C | NONEOS_C,
/* 27 */ CNTRL_C | CHAN_C | NONEOS_C,
/* 28 */ CNTRL_C | CHAN_C | NONEOS_C,
-/* 29 */ CNTRL_C | CHAN_C | NONEOS_C,
+/* 29 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
/* 30 */ CNTRL_C | CHAN_C | NONEOS_C,
/* 31 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
/* SP */ PRINT_C | SPACE_C,
/* ! */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C,
/* " */ PRINT_C | CHAN_C | NONEOS_C,
/* # */ PRINT_C | MWILD_C | CHANPFX_C | CHAN_C | NONEOS_C,
-/* $ */ PRINT_C | CHAN_C | NONEOS_C | USER_C,
+/* $ */ PRINT_C | CHAN_C | NONEOS_C,
/* % */ PRINT_C | CHAN_C | NONEOS_C,
/* & */ PRINT_C | CHANPFX_C | CHAN_C | NONEOS_C,
/* ' */ PRINT_C | CHAN_C | NONEOS_C,
/* , */ 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,