/***************************************************************************** * * File ..................: rfcaddr.c * Purpose ...............: MBSE BBS Common Library * Last modification date : 23-Mar-2001 * ***************************************************************************** * Copyright (C) 1997-2001 * * 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, 675 Mass Ave, Cambridge, MA 02139, USA. *****************************************************************************/ #include "libs.h" #include "structs.h" #include "records.h" #include "clcomm.h" #include "common.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; // Syslog('M', "parserfcaddr() 1"); 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 */ // Syslog('M', "parserfcaddr() 1b strlen=%d", strlen(s)); inbrackets = calloc(strlen(s)+1, sizeof(char)); outbrackets = calloc(strlen(s)+1, sizeof(char)); brackets = quotes = escaped = anglecomplete = 0; // Syslog('M', "parserfcaddr() 2"); 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; } // Syslog('M', "parserfcaddr() 3"); *q = '\0'; *r = '\0'; if (brackets || quotes) addrerror |= ADDR_UNMATCHED; // Syslog('N', " inbrackets: \"%s\"",inbrackets); // Syslog('N', "outbrackets: \"%s\"",outbrackets); // Syslog('N', " addrerror: 0x%04x",addrerror); if (addrerror) goto leave1; cleanbuf = calloc(strlen(s)+1, sizeof(char)); combuf = calloc(strlen(s)+1, sizeof(char)); // Syslog('M', "parserfcaddr() 4"); 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; } // Syslog('N', " now parsing: \"%s\"",p); // Syslog('N', "current comment: \"%s\"",result.comment); /* 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 */ // Syslog('M', "parserfcaddr() 5"); 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; // Syslog('N', " now parsing: \"%s\"",inbrackets); // Syslog('N', "complete comment: \"%s\"",result.comment); // Syslog('N', " addrerror: 0x%04x",addrerror); // Syslog('M', "parserfcaddr() 6"); 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; } // Syslog('M', "parserfcaddr() 7"); if ((firstat == cleanbuf) && colon) { // Syslog('N', "@aaa,@bbb:xxx@yyy construct"); if (comma && (comma < colon)) { *comma = '\0'; r = comma + 1; // Syslog('M', "parserfcaddr() 9"); } else { *colon = '\0'; r = colon + 1; // Syslog('M', "parserfcaddr() 10"); } t = firstat + 1; // Syslog('M', "parserfcaddr() 11"); } else if (lastat) { // Syslog('N', "anything@somewhere construct"); *lastat = '\0'; r = cleanbuf; t = lastat + 1; // Syslog('M', "parserfcaddr() 12"); } else if (exclam) { // Syslog('N', "domain!something construct (without @'s)"); *exclam = '\0'; r = exclam + 1; t = cleanbuf; // Syslog('M', "parserfcaddr() 13"); } else if (percent) { // Syslog('N', "anything%%somewhere construct (without !'s and @'s)"); *percent = '\0'; r = cleanbuf; t = percent + 1; // Syslog('M', "parserfcaddr() 14"); } else { // Syslog('N', "remainder only present"); /* unquote it if necessary */ if ((*cleanbuf == '\"') && (*(p = (cleanbuf+strlen(cleanbuf)-1)) == '\"')) { *p = '\0'; r = cleanbuf + 1; } else r = cleanbuf; t = NULL; // Syslog('M', "parserfcaddr() 15"); } // Syslog('M', "parserfcaddr() 16"); if (t && (*t != '\0')) result.target = xstrcpy(t); // Syslog('M', "parserfcaddr() 17"); if (r && (*r != '\0')) result.remainder = xstrcpy(r); // Syslog('M', "parserfcaddr() 18"); if (*combuf != '\0') result.comment = xstrcpy(combuf); // Syslog('M', "parserfcaddr() 19"); leave1: /* this is also normal exit */ // Syslog('M', "parserfcaddr() leave1"); free(cleanbuf); free(combuf); free(inbrackets); free(outbrackets); // Syslog('M', "going"); return result; leave2: /* if error found on second stage, free */ // Syslog('M', "parserfcaddr() leave2"); free(cleanbuf); free(combuf); // Syslog('M', "going"); return result; }