Logo Search packages:      
Sourcecode: zmailer version File versions  Download package

rfc822walk.c

/*
 *    Copyright 1990 by Rayan S. Zachariassen, all rights reserved.
 *    This will be free software, but only when it is finished.
 *
 *      Copyright Matti Aarnio <mea@nic.funet.fi> 1992-2000
 */

#include "hostenv.h"
#include "mailer.h"
#include "prototypes.h"

#undef STATIC
#define STATIC    static
#undef ATHACK     /* 'user at host' == 'user@host' */

#include "rfc822.sst.h"
STATIC            /* This will apply to the array in the .sst file */
#include "rfc822.sst.c"

extern void EmitToken __((token822 *t, ComponentClass ac, struct address *ap));
STATIC const char * Input822TokenName __((int));

/* private semantics mechanism variables: */
STATIC ComponentClass currentTokenType;
STATIC token822 *ptrNextInputToken, *ptrAcceptedToken;
STATIC token822 *headPending, **pending;
STATIC token822 *headDeferred, **deferred;

/* Table Walker State */
STATIC int  processing;       /* are we running the table walker? */
STATIC int  inAddress;        /* are we collecting an address? */
STATIC int  sslPointer;       /* index into S/SL table */
STATIC TableOperation   operation;  /* the current operation */

/* convenience */
STATIC struct address nullAddr = { NULL, NULL, newAddress, 0, NULL, NULL };
#ifdef ATHACK
STATIC token822 atsigntoken = { "@", 1, Special, NULL };
#endif

/* Tracing Control */
STATIC FILE *tracefp;         /* if non-null, trace output here */

/* Abort flag */
STATIC int  aborted;

/*
 * The Rule Call Stack implements Syntax/Semantic Language rule call and return.
 * Each time an oCall operation is executed, the table return address is pushed
 * onto the Rule Call Stack.  When an oReturn is executed, the return address
 * is popped from the stack.  An oReturn executed when the Rule Call Stack is
 * empty terminates table execution.
 */

STATIC int  sslStack[127];          /* The S/SL Rule Call Stack */
#define     sslStackSize      (sizeof sslStack/sizeof sslStack[0])
STATIC int  sslTop;

/*
 * Set by the Choice Handler to indicate whether a match was made or the
 * otherwise path was taken.  Set to true if a match was made and false
 * otherwise.  This flag is used in input choices to indicate whether the
 * choice input token should be accepted or not.
 */

STATIC int  choiceTagMatched; /* Choice Match Flag */

/*
 * These are used to hold the decoded parameter value to a parameterized
 * semantic operation and the result value returned by a choice semantic
 * operation or rule respectively.                           
 */

STATIC int  parameterValue;         /* Parameter for Semantic Operation */
STATIC int  resultValue;            /* Result from Semantic Operation */

/* S/SL System Failure Codes */

typedef enum {
      fSemanticChoiceFailed,              /* 0 */
      fChoiceRuleFailed             /* 1 */
} FailureCodes;                     /* S/SL System Failure Code Type */


#define     maxErrors   20
STATIC int  noErrors;         /* Error Counter */
STATIC ErrorCodes firstFatalErrorCode = eSslStackOverflow;  /* fix */

/* Input Interface */
STATIC InputTokens      nextInputToken = tNewLine;
STATIC InputTokens      acceptedToken;

struct receivedtag {
      const char  *name;
      int          len;
      InputTokens  value;
};

STATIC struct receivedtag rt[] = {
      {     "from",           4,    tFrom       },
      {     "by",       2,    tBy         },
      {     "id",       2,    tId         },
      {     "with",           4,    tWith       },
      {     "via",            3,    tVia        },
      {     "for",            3,    tFor        },
      {     "convert",  7,    tConvert    },
      {     0,          0,    tSyntaxError      }
};

/* Variables Used in Syntax Error Recovery */
STATIC InputTokens      savedInputToken;
STATIC int        RunningSslRecovery = 0;

STATIC struct {
      ErrorCodes ec;
      const char *msg;
} ear[] = {
{ eSyntaxError,               "Syntax error"                      },
{ ePrematureEndOfFile,        "Unexpected end of file"            },
{ eExtraneousProgramText,     "Extraneous program text"           },
{ eSslStackOverflow,          "Nesting too deep"                  },
{ eExtraneousTokensInAddress, "extraneous tokens in address"            },
{ eExtraneousTokensInMailbox, "extraneous tokens in mailbox"            },
{ eMissingSemicolonToEndGroup,      "missing semicolon to end mail group"     },
{ eMissingSemicolonInReceived,      "missing semicolon before timestamp"      },
{ eMissingEndOfAddress,       "missing end of address"            },
{ eMissingEndOfMailbox,       "missing end of mailbox"            },
{ eIllegalWordInPhrase,       "illegal word in phrase"            },
{ eIllegalSpecialInPhrase,    "illegal special character in phrase"     },
{ eIllegalPeriodInPhrase,     "illegal period in phrase"          },
{ eIllegalPhraseMustBeQuoted, "phrases containing '.' must be quoted"   },
{ eIllegalSubdomainInDomain,  "illegal subdomain in domain, probably extra '.' at the end of the address"   },
{ eIllegalTokenInRoute,       "illegal token in route"            },
{ eIllegalWordInLocalPart,    "illegal word in localpart, probably extra '.' at the end of the address"     },
{ eIllegalStartOfMessageId,   "illegal start of message identification"},
{ eIllegalEndOfMessageId,     "illegal end of message identification"   },
{ eIllegalEncryptionIdentifier,     "illegal encryption Identifier"           },
{ eIllegalAddressSeparator,   "illegal address separator"         },
{ eIllegalMailboxSeparator,   "illegal mailbox separator"         },
{ eIllegalMessageIDSeparator, "illegal message-id separator"            },
{ eExpectedWord,        "expected word"                     },
{ eIllegalStartOfRouteAddress,      "illegal start of route address"    },
{ eIllegalEndOfRouteAddress,  "illegal end of route address"            },
{ eIllegalSpecialInValue,     "illegal special in value"          },
{ eIllegalReferencesSeparator,      "illegal reference separator"       },
};

/* This procedure emits the error message associated with errCode */

STATIC void SslError __((ErrorCodes, struct address *));
STATIC void
SslError(errCode, ap)
      ErrorCodes errCode;
      struct address *ap;
{
      token822 *t;
      int i;

      if (errCode == eNoError)
        abort();

      for (t = NULL, i = 0; i < (sizeof ear/sizeof ear[0]); ++i) {
        if (ear[i].ec == errCode) {
          t = makeToken(ear[i].msg, strlen(ear[i].msg));
          break;
        }
      }
      if (t == NULL)
        t = makeToken("Unknown", sizeof("Unknown")-1);
      t->t_type = Error;
      EmitToken(t, cError, ap);

      ++noErrors;

      if ((int)(errCode) >= (int)(firstFatalErrorCode)
          || noErrors == maxErrors) {
        aborted = 1;
        processing = 0;
      }
}

/*
 * This procedure provides the interface to the previous pass.
 * It is reponsible for handling all input including line number
 * indicators and the values and text associated with input tokens.  
 */

STATIC void AcceptInputToken __((token822 **, struct address *));
STATIC void
AcceptInputToken(tlistp, ap)
      token822 **tlistp;
      struct address *ap;
{

      if (acceptedToken == tEndOfHeader && nextInputToken == tEndOfHeader)
        abort();

      if (nextInputToken == tSyntaxError) {
        acceptedToken = tSyntaxError;
        /* ptrAcceptedToken = NULL; */
        nextInputToken = savedInputToken;
        goto ok;
      } else {
        /* Accept Token */
        acceptedToken = nextInputToken;
        ptrAcceptedToken = ptrNextInputToken;
      }

      /* Read Next Input Token */
      do {
      next:
        if (*tlistp == NULL) {
          nextInputToken = tEndOfHeader;
          ptrNextInputToken = NULL;
        } else {
          ptrNextInputToken = *tlistp;
          switch ((*tlistp)->t_type) {
          case Error:
          case Comment:
            if (ptrAcceptedToken == NULL && ap != NULL) {
            EmitToken(*tlistp,
                    (*tlistp)->t_type == Error ?
                    cError : cComment, ap);
            } else {
            (*pending) = copyToken(*tlistp);
            pending = &((*pending)->t_next);
            }
            (*tlistp) = (*tlistp)->t_next;
            goto next;
          case Space:
#if 0
# if 0
            if (RunningSslRecovery) {
            /* Copy it only during SslRecovery */
            if (ptrAcceptedToken == NULL && ap != NULL) {
              EmitToken(*tlistp, cSpace, ap);
            } else {
              (*pending) = copyToken(*tlistp);
              pending = &((*pending)->t_next);
            }
            }
# else
            nextInputToken = tSpace;
            (*tlistp) = (*tlistp)->t_next;
            break;
# endif
#endif
            /* fall through */
          case Fold:
            (*tlistp) = (*tlistp)->t_next;
            goto next;
          case Special:
            switch ((*tlistp)->t_pname[0]) {
            case ';':
            nextInputToken = tSemicolon;
            break;
            case ',':
            nextInputToken = tComma;
            break;
            case '.':
            nextInputToken = tPeriod;
            break;
            case ':':
            if ((*tlistp)->t_pname[1] == ':')
              nextInputToken = tDoubleColon;
            else
              nextInputToken = tColon;
            break;
            case '<':
            nextInputToken = tLeftAngle;
            break;
            case '>':
            nextInputToken = tRightAngle;
            break;
            case '@':
            nextInputToken = tAtSign;
            break;
            default:
            nextInputToken = tOtherSpecial;
            break;
            }
            *tlistp = (*tlistp)->t_next;
            break;
          case String:
            nextInputToken = tQuotedString;
            *tlistp = (*tlistp)->t_next;
            break;
          case Atom:
            nextInputToken = tAtom;
            *tlistp = (*tlistp)->t_next;
            break;
          case DomainLiteral:
            nextInputToken = tDomainLiteral;
            *tlistp = (*tlistp)->t_next;
            break;
          case Word:
          case Empty:
            abort();
          default:
            break;
          }
        }
      } while (nextInputToken == tNewLine);

ok:
      /* Trace Input */
      if (tracefp)
        printf("Input token accepted %s (%d)  Next input token %s (%d)\n",
             Input822TokenName((int)acceptedToken), acceptedToken,
             Input822TokenName((int)nextInputToken), nextInputToken);
}

/*
 * The constants, variables, types, modules and procedures used in
 * implementing the Semantic Mechanisms of the pass go here.  These
 * implement the facilities used in the semantic operations.
 */

/* Syntax Error Handling */

/*
 * This procedure handles syntax errors in the input to the Parser pass,
 *
 * Syntax error recovery:
 * When a mismatch occurs between the the next input token and the syntax
 * table, the following recovery is employed.
 *
 * If the expected token is tEndOfHeader then if there has been no previous
 * syntax error on the line, ignore the error.  (A missing logical end of
 * header is not a real error.)
 *
 * If the expected token is tComma or tSemicolon or tEndOfHeader and a syntax
 * error has already been detected in the current logical address (flagged
 * by nextInputToken == tSyntaxError), then flush the input and exit when
 * any of these tokens are found.
 *
 * Otherwise, if this is the first syntax error detected on the line
 * (flagged by nextInputToken != tSyntaxError), then if the input token is
 * tEndOfHeader then emit the ePrematureEndOfFile error code and terminate
 * execution.  Otherwise, emit the eSyntaxError error code and set the
 * nextInputToken to tSyntaxError to prevent further input, and exit when the
 * expected ( ?? ) input is tSemicolon or tNewLine.
 *
 * If the expected token is not tSemicolon nor tNewLine and a syntax error
 * has already been detected on the current line (flagged by nextInputToken ==
 * tSyntaxError), then do nothing and continue as if the expected token had
 * been matched.
 */

STATIC void SslSyntaxError __((token822 **, struct address *));
STATIC void
SslSyntaxError(tlistp, ap)
      token822 **tlistp;
      struct address *ap;
{
      if (operation != oInput && operation != oInputAny)
            abort();

      if (nextInputToken == tSyntaxError) {
        /* Currently recovering from syntax error */
        /* Complete recovery by synchronizing input to a new address */
        nextInputToken = savedInputToken;
        RunningSslRecovery = 1;
        while (nextInputToken != tSemicolon
             && nextInputToken != tComma
             && nextInputToken != tEndOfHeader) {
          AcceptInputToken(tlistp, ap);
          EmitToken(ptrAcceptedToken, cResync, ap);
        }
        RunningSslRecovery = 0;
        if (sslTop == 0)
          /* Return from main S/SL procedure */
          processing = 0;
        else
          sslPointer = sslStack[sslTop--];
      } else {
        /* First syntax error on the line */
        if (sslTable[sslPointer] == (int)(tEndOfHeader)) {
          /* Ignore missing logical newlines */
        } else {
          /* mark syntax error, gobble tokens, jump to resync */
          savedInputToken = nextInputToken;
          nextInputToken = tSyntaxError;
        }
      }
}

STATIC const char *
Input822TokenName(in)
      int in;
{
      switch ((InputTokens)in) {
      case tSyntaxError:      return "tSyntaxError";
      case tIdent:            return "tIdent";
      case tString:           return "tString";
      case tInteger:          return "tInteger";
      case tSemicolon:  return "tSemicolon";
      case tComma:            return "tComma";
      case tPeriod:           return "tPeriod";
      case tDoubleColon:      return "tDoubleColon";
      case tColon:            return "tColon";
      case tLeftAngle:  return "tLeftAngle";
      case tRightAngle: return "tRightAngle";
      case tAtSign:           return "tAtSign";
      case tOtherSpecial:     return "tOtherSpecial";
      case tAtom:       return "tAtom";
      case tBy:         return "tBy";
      case tDomainLiteral:    return "tDomainLiteral";
      case tFor:        return "tFor";
      case tFrom:       return "tFrom";
      case tId:         return "tId";
      case tQuotedString:     return "tQuotedString";
      case tVia:        return "tVia";
      case tWith:       return "tWith";
      case tNewLine:          return "tNewLine";
      case tEndOfHeader:      return "tEndOfHeader";
      default: break;
      }
      return "unknown input token";
}

STATIC const char * TableOperationName __((TableOperation));
STATIC const char *
TableOperationName(op)
      TableOperation    op;
{
      switch (op) {
      case oCall:       return "oCall";
      case oReturn:           return "oReturn";
      case oRuleEnd:          return "oRuleEnd";
      case oJump:       return "oJump";
      case oInput:            return "oInput";
      case oInputAny:         return "oInputAny";
      case oInputChoice:      return "oInputChoice";
      case oEmit:       return "oEmit";
      case oError:            return "oError";
      case oChoice:           return "oChoice";
      case oChoiceEnd:  return "oChoiceEnd";
      case oSetParameter:     return "oSetParameter";
      case oSetResult:  return "oSetResult";
      case oSetResultFromInput:     return "oSetResultFromInput";
      case oSetComponentType: return "oSetComponentType";
      case oEmitToken:  return "oEmitToken";
      case oEmitTokenCurType: return "oEmitTokenCurType";
      case oOpenAddress:      return "oOpenAddress";
      case oAppendAddress:    return "oAppendAddress";
      case oCloseAddress:     return "oCloseAddress";
      case oDateTime:         return "oDateTime";
      case oEnterReceived:    return "oEnterReceived";
      case oExitReceived:     return "oExitReceived";
      case oSetReturnType:    return "oSetReturnType";
      case oRewind:           return "oRewind";
      default: break;
      }
      return "unknown operation";
}

STATIC void SslTrace __((void));
STATIC void
SslTrace()
{
      printf("Table index %d  Operation %d (%s) Argument %d\n",
             sslPointer-1, operation, TableOperationName(operation),
             sslTable[sslPointer]);
}

STATIC void SslFailure __((FailureCodes));
STATIC void
SslFailure(failCode)
      FailureCodes failCode;
{
      printf("### S/SL program failure:  ");

      switch (failCode) {
      case fSemanticChoiceFailed:
            printf("Semantic choice failed\n");
            break;
      case fChoiceRuleFailed:
            printf("Choice rule returned without a value\n");
            break;
      }

      SslTrace();
      abort();
}


/*
 * This procedure performs both input and semantic choices.  It sequentially
 * tests each alternative value against the tag value, and when a match is
 * found, performs a branch to the corresponding alternative path.  If none
 * of the alternative values matches the tag value, sslTable interpretation
 * proceeds to the operation immediately following the list of alternatives
 * (normally the otherwise path).  The flag choiceTagMatched is set to true
 * if a match is found and false otherwise.
 */

STATIC void SslChoice __((int));
STATIC void
SslChoice(choiceTag)
      int choiceTag;
{
      int   numberOfChoices, choicePointer;

      choicePointer = sslTable[sslPointer];
      choiceTagMatched = 0;

      for (numberOfChoices = sslTable[choicePointer++];
           numberOfChoices > 0;
           choicePointer += 2, --numberOfChoices) {
        if (tracefp)
          printf("Matching %s (%d) with %s (%d)\n",
               Input822TokenName(choiceTag), choiceTag,
               Input822TokenName(sslTable[choicePointer]),
               sslTable[choicePointer]);
        if (sslTable[choicePointer] == choiceTag
#ifdef      ATHACK
            || (choiceTag == (int)tAtom
              && sslTable[choicePointer] == (int)tAtSign
              && ptrNextInputToken != NULL
              && ptrNextInputToken->t_len == 2
              && (ptrNextInputToken->t_pname[0] == 'a'
                  || ptrNextInputToken->t_pname[0] == 'A')
              && (ptrNextInputToken->t_pname[1] == 't'
                  || ptrNextInputToken->t_pname[1] == 'T')
              && (ptrNextInputToken = &atsigntoken))
#endif      /* ATHACK */
            ) {
          sslPointer = sslTable[choicePointer+1];
          choiceTagMatched = 1;
          if (tracefp)
            printf("Matched!\n");
          return;
        }
      }
      if (tracefp)
        printf("No match!\n");
      sslPointer = choicePointer;
}

void
EmitToken(t, ac, ap)
      token822 *t;
      ComponentClass ac;
      struct address *ap;
{
      token822 *nt, **ptp;
      struct addr *na;
      AddrComponent type;

      if (deferred != NULL) {
        if (ac == cError)  {  /* prepend errors to deferred tokens */
          nt = copyToken(t);
          ptp = &headDeferred;
          for(t = headDeferred; t ; ptp = &t->t_next, t = *ptp)
            if (t->t_type != Error)
            break;
          nt->t_next = *ptp;
          *ptp = nt;
          if (deferred == &headDeferred)
            deferred = &nt->t_next;
        } else {
          (*deferred) = copyToken(t);
          deferred = &((*deferred)->t_next);
        }
        if (headPending) {
          /* printf("append pending\n"); */
          (*deferred) = headPending;
          deferred = pending;
          (*pending) = NULL;
          pending = &headPending;
          headPending = 0;
        }
        return;
      }
      switch (ac) {
      case cPhrase:     type = aPhrase; break;
      case cComment:    type = aComment; break;
      case cSpecial:    type = aSpecial; break;
      case cGroup:      type = aGroup; break;
      case cAddress:    type = anAddress; break;
      case cDomain:     type = aDomain; break;
      case cWord: type = aWord; break;
#if 0
      case cSpace:      type = aSpace; break;
#endif
      case cResync:     type = reSync; ap->a_stamp = BadAddress; break;
      case cError:
      default:    type = anError; ap->a_stamp = BadAddress; break;
      }
      /*
       * For efficiency, we just keep prepending tokens. The
       * reverseComponent() function will eventually do the reversal.
       */
      if (ap->a_tokens != NULL && ap->a_tokens->p_type == type) {
        /* prepend now -- reverse later */
        nt = copyToken(t);
        nt->t_next = ap->a_tokens->p_tokens;
        ap->a_tokens->p_tokens = nt;
      } else {
        na = (struct addr *)tmalloc(sizeof (struct addr));
        /* prepend now -- reverse later */
        nt = copyToken(t);
        nt->t_next = NULL;
        na->p_tokens = nt;
        na->p_next = ap->a_tokens;
        na->p_type = type;
        ap->a_tokens = na;
      }
      if (headPending) {
        (*pending) = NULL;
        for (t = headPending, headPending = NULL;
             t != NULL; t = t->t_next)
          EmitToken(t, t->t_type==Error ? cError : cComment, ap);
        pending = &headPending;
      }
}

struct address *
revaddress(ap)
      struct address *ap;
{
      register token822 *rprev, *rnext, *r;
      register struct addr    *pprev, *pnext, *p;

      /* reverse order of address components and tokens */
      if (ap == NULL)
        return NULL;
      /* reverse the various linked lists */
      pprev = NULL;
      for (p = ap->a_tokens; p != NULL; p = pnext) {
        pnext = p->p_next;
        p->p_next = pprev;
        pprev = p;
        rprev = NULL;
        for (r = p->p_tokens; r != NULL; r = rnext) {
          rnext = r->t_next;
          r->t_next = rprev;
          rprev = r;
        }
        p->p_tokens = rprev;
      }
      ap->a_tokens = pprev;
      return ap;
}

STATIC void revappend __((token822 **, struct address *));
STATIC void
revappend(tprev,ap)
token822 **tprev;
struct address *ap;
{
      struct addr *p;
      token822 *t;

      ap = revaddress(ap);
      /* append all the tokens together */
      if (ap == NULL || ap->a_tokens == NULL
          || ap->a_stamp == BadAddress)
        return;
      for (p = ap->a_tokens; p ; p = p->p_next) {
        *tprev = p->p_tokens;
        for (t = p->p_tokens; t ; t = t->t_next)
          tprev = &(t->t_next);
      }
      *tprev = NULL;
}

/*
 * The Parser.
 *
 * entry    - where in the S/SL table to start executing.
 * tlistp   - pointer to raw token list as returned by the scanner.
 * tfp            - trace file pointer (for debugging output)
 *
 * The parser can return any of the union misc type values, however the
 * usual case is when trying to recognize an address or mailbox of some kind.
 * In this case, the parser can return a list of address structures, each
 * of which describes an address or mailbox as appropriate. This description
 * consists of a categorization of which scanner tokens correspond to which
 * RFC822 tokens. Certain non-terminals in the RFC822 grammar can correspond
 * to simple word lists, for example phrases or comments. These appear as
 * token classes (the AddrComponent enum type) alongside Atoms and Specials
 * in what the parser returns.
 */

union misc
parse822(entry, tlistp, ltmp, tfp)
      HeaderSemantics   entry;
      token822 **tlistp;
      struct tm *ltmp;
      FILE *tfp;
{
      int         inReceived, i;
      token822    *t, *torig;
      struct address    *ap, *na, *pap;
      struct received   rcvd;
      union misc  retval;
      ReturnValue returnType;

      tracefp = tfp;
      torig = *tlistp;
      pending = &headPending;
      deferred = NULL;
      inReceived = 0;
      inAddress = 0;
      ap = NULL;
      processing = 1;
      aborted = 0;
      sslTop = 0;
      noErrors = 0;
      nextInputToken = tNewLine;
      acceptedToken = tNewLine;
      returnType = rAddress;
      currentTokenType = cAddress;

      if (tracefp) {
        sslPointer = ((int)entry) + 1;
        operation = (TableOperation)-1; /* Invalid value! */
        SslTrace();
      }

      /* Initialize Input/Output */
      AcceptInputToken(tlistp, ap);
      if (nextInputToken == tEndOfHeader) {
        retval.a = NULL;
        return retval;
      }

      /* Walk the S/SL Table */

      sslPointer = (int)entry;
      while (processing || inAddress) {
        if (processing)
          operation = (TableOperation)(sslTable[sslPointer++]);
        else
          operation = oCloseAddress;

        /* Trace Execution */
        if (tracefp)
          SslTrace();

        switch (operation) {
        case oCall:
          if (sslTop < sslStackSize) {
            sslStack[++sslTop] = sslPointer + 1;
            sslPointer = sslTable[sslPointer];
          } else {
            if (ap == NULL) {
            ap = (struct address *)
              tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
            }
            SslError(eSslStackOverflow, ap);
            processing = 0;
          }
          break;
        case oReturn:
          if (sslTop == 0)
            /* Return from main S/SL procedure */
            processing = 0;
          else
            sslPointer = sslStack[sslTop--];
          break;
        case oRuleEnd:
          SslFailure(fChoiceRuleFailed);
          break;
        case oJump:
          sslPointer = sslTable[sslPointer];
          break;
        case oInput:
          if (sslTable[sslPointer] == (int)(nextInputToken)
#ifdef      ATHACK
            || (nextInputToken == tAtom
                && sslTable[sslPointer] == (int)tAtSign
                && ptrNextInputToken != NULL
                && ptrNextInputToken->t_len == 2
                && (ptrNextInputToken->t_pname[0] == 'a'
                  || ptrNextInputToken->t_pname[0] == 'A')
                && (ptrNextInputToken->t_pname[1] == 't'
                  || ptrNextInputToken->t_pname[1] == 'T')
                && (ptrNextInputToken = &atsigntoken))
#endif      /* ATHACK */
            ) {
            AcceptInputToken(tlistp, ap);
            ++sslPointer;
          } else {
            ++sslPointer;
            /* Syntax error in input */
            if (ap == NULL) {
            ap = (struct address *)
              tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
            }
            SslSyntaxError(tlistp, ap);
          }
          break;
        case oInputAny:
          if (nextInputToken != tEndOfHeader)
            AcceptInputToken(tlistp, ap);
          else {
            /* Premature end of file */
            if (ap == NULL) {
            ap = (struct address *)
              tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
            }
            SslSyntaxError(tlistp, ap);
          }
          break;
        case oInputChoice:
          if (inReceived && nextInputToken == tAtom) {
            t = ptrNextInputToken;
            for (i = 0; rt[i].name != NULL; ++i) {
            if (TOKENLEN(t) == strlen(rt[i].name)
                && CISTREQN(t->t_pname,
                        rt[i].name, rt[i].len)) {
              nextInputToken = rt[i].value;
              break;
            }
            }
          }
          SslChoice((int)nextInputToken);

          if (choiceTagMatched)
            AcceptInputToken(tlistp, ap);
          break;
        case oEmit:
          ++sslPointer;
          break;
        case oError:
          ++sslPointer;
          if (ap == NULL) {
            ap = (struct address *)
            tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
          }
          SslError((ErrorCodes)sslTable[sslPointer-1], ap);
          break;
        case oChoice:
          if (inReceived && resultValue == (int)tAtom) {
            t = ptrNextInputToken;
            for (i = 0; rt[i].name != NULL; ++i) {
            if (TOKENLEN(t) == strlen(rt[i].name)
                && CISTREQN(t->t_pname,
                        rt[i].name, rt[i].len)) {
              resultValue = (int)rt[i].value;
              break;
            }
            }
          }
          SslChoice(resultValue);
          break;
        case oChoiceEnd:
          SslFailure(fSemanticChoiceFailed);
          break;
        case oSetParameter:
          parameterValue = sslTable[sslPointer++];
          break;
        case oSetResult:
          resultValue = sslTable[sslPointer++];
          break;
        case oSetResultFromInput:
          resultValue = (int)nextInputToken;
          break;

          /* The Following Are Pass Dependent Semantic Mechanisms */

        case oSetComponentType:
          currentTokenType = (ComponentClass)parameterValue;
          break;
        case oEmitTokenCurType:
          parameterValue = (int)currentTokenType;
          /* fall through */
        case oEmitToken:
          if (ap == NULL) {
            ap = (struct address *)
            tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
          }
          EmitToken(ptrAcceptedToken,
                  (ComponentClass)parameterValue, ap);
          break;
        case oDeferEmitToken:
          if (deferred != NULL)
            abort();
          deferred = &headDeferred;
          if (headPending) {
            if (ap == NULL) {
            ap = (struct address *)
              tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
            }
            (*pending) = NULL;
            for (t = headPending, headPending = NULL;
               t != NULL; t = t->t_next)
            EmitToken(t, t->t_type == Error ?
                    cError : cComment, ap);
            pending = &headPending;
          }
          break;
        case oReleaseEmitToken:     /* comments... */
          if (ap == NULL) {
            ap = (struct address *)
            tmalloc(sizeof (struct address));
            *ap = nullAddr;
            inAddress = 1;
          }
          t = headDeferred;
          headDeferred = NULL;
          (*deferred) = NULL;
          deferred = NULL;
          for (; t != NULL; t = t->t_next)
            if (t->t_type == Comment)
            EmitToken(t, cComment, ap);
            else if (t->t_type == Error)
            EmitToken(t, cError, ap);
            else
            EmitToken(t,
                    (ComponentClass)parameterValue,
                    ap);
          break;
        case oOpenAddress:
          if (inAddress)
            break;
          na = (struct address *)tmalloc(sizeof (struct address));
          *na = nullAddr;
          na->a_next = ap;
          ap = na;
          inAddress = 1;
          break;
        case oAppendAddress:
          if (inAddress)
            break;
          ap = revaddress(ap);
          inAddress = 1;
          break;
        case oCloseAddress:
          if (!inAddress)
            break;
          ap = revaddress(ap);
          inAddress = 0;
          break;
        case oDateTime:
          if (ptrNextInputToken != NULL) {
            retval.d = dateParse(ltmp, ptrNextInputToken);
          } else
            retval.d = 0;
          break;
        case oEnterReceived:
          inReceived = 1;
          rcvd.r_from = rcvd.r_by = rcvd.r_id = rcvd.r_for = NULL;
          rcvd.r_via = rcvd.r_with = rcvd.r_convert = NULL;
          rcvd.r_time = 0L;
          break;
        case oExitReceived:
          inReceived = 0;
          break;
        case oSaveReceivedComponent:
          switch ((ReceivedComponent)parameterValue) {
          case rcFrom:
            rcvd.r_from = revaddress(ap);
            break;
          case rcBy:
            rcvd.r_by = revaddress(ap);
            break;
          case rcVia:
            /* grab a single token */
            if (ap != NULL
              && ap->a_stamp != BadAddress
              && ap->a_tokens != NULL
              && ap->a_tokens->p_tokens != NULL) {
            rcvd.r_via = ap->a_tokens->p_tokens;
            rcvd.r_via->t_next = NULL; /* in case */
            }
            break;
          case rcWith:
            revappend(&rcvd.r_with,ap);
            break;
          case rcConvert:
            revappend(&rcvd.r_convert,ap);
            break;
          case rcId:
            rcvd.r_id = revaddress(ap);
            break;
          case rcFor:
            rcvd.r_for = revaddress(ap);
            break;
          case rcDate:
            rcvd.r_time = retval.d;
            break;
          default:
            break;
          }
          ap = NULL;
          break;
        case oSetReturnType:
          returnType = (ReturnValue)parameterValue;
          break;
        case oRewind:
          if (ap == NULL
            || (ap->a_tokens == NULL && ap->a_next == NULL)) {
            *tlistp = torig;
            pending = &headPending;
            deferred = NULL;
            nextInputToken = tNewLine;
            acceptedToken = tNewLine;
            AcceptInputToken(tlistp, ap);
            resultValue = (int)Success;
          } else
            resultValue = (int)Failure;
          break;
                
        default:
          printf("Unknown operation %d\n", (int)operation);
          abort();
        }
      }

      if (returnType == rAddress) {
        if (nextInputToken != tEndOfHeader && !aborted && ap != NULL)
          SslError(eExtraneousProgramText, ap);
        /* reverse order of addresses */
        for (na = NULL; ap != NULL; na = ap, ap = pap) {
          pap = ap->a_next;
          ap->a_next = na;
        }
        retval.a = na;
      } else if (returnType == rReceived) {
        retval.r = (struct received *)tmalloc(sizeof (struct received));
        *(retval.r) = rcvd;
      }
      return retval;
}

Generated by  Doxygen 1.6.0   Back to index