This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/lib/rfcaddr.c

286 lines
6.3 KiB
C
Raw Normal View History

/*****************************************************************************
*
* $Id: rfcaddr.c,v 1.7 2004/02/21 14:24:04 mbroek Exp $
* Purpose ...............: MBSE BBS Common Library - RFC address functions
*
*****************************************************************************
* Copyright (C) 1997-2004
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*****************************************************************************/
#include "../config.h"
#include "mbselib.h"
extern int addrerror;
static char *errname[] = {
(char *)"nested <>",
(char *)"multiple <>",
(char *)"unmatched <>""()",
(char *)"badtoken",
(char *)"badstructure",
};
char *addrerrstr(int err)
{
int i;
static char buf[128];
buf[0] = '\0';
for (i = 0; i < ADDR_ERRMAX; i++)
if (err & (1 << i)) {
if (buf[0])
strcat(buf,",");
strcat(buf, errname[i]);
}
if (buf[0] == '\0')
strcpy(buf,"none");
return buf;
}
void tidyrfcaddr(parsedaddr addr)
{
if (addr.target)
free(addr.target);
if (addr.remainder)
free(addr.remainder);
if (addr.comment)
free(addr.comment);
}
parsedaddr parserfcaddr(char *s)
{
parsedaddr result;
char *inbrackets = NULL, *outbrackets = NULL, *cleanbuf = NULL, *combuf = NULL;
char *t, *r, *c, *p, *q, **x;
int quotes, brackets, escaped, anglecomplete;
char *firstat, *lastat, *percent, *colon, *comma, *exclam;
result.target = NULL;
result.remainder = NULL;
result.comment = NULL;
addrerror = 0;
if ((s == NULL) || (*s == '\0'))
return result;
/*
* First check if there is an "angled" portion
*/
inbrackets = calloc(strlen(s)+1, sizeof(char));
outbrackets = calloc(strlen(s)+1, sizeof(char));
brackets = quotes = escaped = anglecomplete = 0;
for (p = s,q = inbrackets, r = outbrackets, x = &r; *p; p++) {
if (escaped)
escaped = FALSE;
else /* process all special chars */
switch (*p) {
case '\\': escaped = TRUE; break;
case '\"': quotes = !quotes; break;
case '<': if (quotes)
break;
if (brackets)
addrerror |= ADDR_NESTED;
if (anglecomplete)
addrerror |= ADDR_MULTIPLE;
brackets++;
x = &q;
break;
case '>': if (quotes)
break;
if (brackets)
brackets--;
else
addrerror |= ADDR_UNMATCHED;
if (!brackets)
anglecomplete = 1;
break;
}
*((*x)++) = *p;
if (!brackets)
x = &r;
}
*q = '\0';
*r = '\0';
if (brackets || quotes)
addrerror |= ADDR_UNMATCHED;
if (addrerror)
goto leave1;
cleanbuf = calloc(strlen(s)+1, sizeof(char));
combuf = calloc(strlen(s)+1, sizeof(char));
if (*inbrackets) { /* there actually is an angled portion */
strcpy(combuf, outbrackets);
c = combuf + strlen(combuf);
p = inbrackets + 1;
*(p+strlen(p)-1) = '\0';
} else {
c = combuf;
p = outbrackets;
}
/* OK, now we have result.comment filled with wat was outside
angle brackets, c pointing past the end of it,
p pointing to what is supposed to be address, with angle
brackets already removed */
quotes = brackets = escaped = 0;
for (r = cleanbuf, x = &r; *p; p++) {
if (escaped) {
escaped=0;
*((*x)++)=*p;
} else /* process all special chars */
if (isspace(*p)) {
if ((quotes) || (brackets))
*((*x)++) = *p;
} else
switch (*p) {
case '\\': escaped=1;
/* pass backslash itself only inside quotes
and comments, or for the special cases
\" and \\ otherwise eat it away */
if ((quotes) || (brackets))
*((*x)++) = *p;
else if ((*(p+1)=='"') || (*(p+1)=='\\'))
*((*x)++) = *p;
break;
case '\"': quotes = !quotes;
*((*x)++) = *p;
break;
case '(':
brackets++;
x = &c;
break;
case ')':
if (brackets)
brackets--;
else
addrerror |= ADDR_UNMATCHED;
if (!brackets)
x = &r;
break;
default:
*((*x)++) = *p;
break;
}
}
*r = '\0';
*c = '\0';
if (brackets || quotes)
addrerror |= ADDR_UNMATCHED;
if (addrerror)
goto leave2;
/* OK, now we have inangles buffer filled with the 'clean' address,
all comments removed, and result.comment is ready filled */
/* seach for special chars that are outside quotes */
firstat = lastat = percent = colon = comma = exclam = NULL;
quotes = 0; escaped = 0;
for (p = cleanbuf; *p; p++)
if (*p == '\\')
p++;
else if (*p == '\"')
quotes = !quotes;
else if (!quotes)
switch (*p) {
case '@':
if (!firstat)
firstat = p;
lastat = p;
break;
case '%':
percent = p;
break;
case ':':
colon = p;
break;
case ',':
comma = p;
break;
case '!':
if (!exclam)
exclam = p;
break;
}
if ((firstat == cleanbuf) && colon) {
if (comma && (comma < colon)) {
*comma = '\0';
r = comma + 1;
} else {
*colon = '\0';
r = colon + 1;
}
t = firstat + 1;
} else if (lastat) {
*lastat = '\0';
r = cleanbuf;
t = lastat + 1;
} else if (exclam) {
*exclam = '\0';
r = exclam + 1;
t = cleanbuf;
} else if (percent) {
*percent = '\0';
r = cleanbuf;
t = percent + 1;
} else {
/* unquote it if necessary */
if ((*cleanbuf == '\"') && (*(p = (cleanbuf+strlen(cleanbuf)-1)) == '\"')) {
*p = '\0';
r = cleanbuf + 1;
} else
r = cleanbuf;
t = NULL;
}
if (t && (*t != '\0'))
result.target = xstrcpy(t);
if (r && (*r != '\0'))
result.remainder = xstrcpy(r);
if (*combuf != '\0')
result.comment = xstrcpy(combuf);
leave1: /* this is also normal exit */
free(cleanbuf);
free(combuf);
free(inbrackets);
free(outbrackets);
return result;
leave2: /* if error found on second stage, free */
free(cleanbuf);
free(combuf);
return result;
}