home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / token822.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-15  |  11.0 KB  |  512 lines

  1. #include "stralloc.h"
  2. #include "alloc.h"
  3. #include "str.h"
  4. #include "token822.h"
  5. #include "gen_allocdefs.h"
  6.  
  7. static struct token822 comma = { TOKEN822_COMMA };
  8.  
  9. void token822_reverse(ta)
  10. token822_alloc *ta;
  11. {
  12.  int i;
  13.  int n;
  14.  struct token822 temp;
  15.  
  16.  n = ta->len - 1;
  17.  for (i = 0;i + i < n;++i)
  18.   {
  19.    temp = ta->t[i];
  20.    ta->t[i] = ta->t[n - i];
  21.    ta->t[n - i] = temp;
  22.   }
  23. }
  24.  
  25. GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready)
  26. GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus)
  27. GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append)
  28.  
  29. static int needspace(t1,t2)
  30. int t1;
  31. int t2;
  32. {
  33.  if (!t1) return 0;
  34.  if (t1 == TOKEN822_COLON) return 1;
  35.  if (t1 == TOKEN822_COMMA) return 1;
  36.  if (t2 == TOKEN822_LEFT) return 1;
  37.  switch(t1)
  38.   {
  39.    case TOKEN822_ATOM: case TOKEN822_LITERAL:
  40.    case TOKEN822_QUOTE: case TOKEN822_COMMENT:
  41.      switch(t2)
  42.       {
  43.        case TOKEN822_ATOM: case TOKEN822_LITERAL:
  44.        case TOKEN822_QUOTE: case TOKEN822_COMMENT:
  45.          return 1;
  46.       }
  47.   }
  48.  return 0;
  49. }
  50.  
  51. static int atomok(ch)
  52. char ch;
  53. {
  54.  switch(ch)
  55.   {
  56.    case ' ': case '\t': case '\r': case '\n':
  57.    case '(': case '[': case '"':
  58.    case '<': case '>': case ';': case ':':
  59.    case '@': case ',': case '.':
  60.      return 0;
  61.   }
  62.  return 1;
  63. }
  64.  
  65. static void atomcheck(t)
  66. struct token822 *t;
  67. {
  68.  int i;
  69.  char ch;
  70.  for (i = 0;i < t->slen;++i)
  71.   {
  72.    ch = t->s[i];
  73.    if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\'))
  74.     {
  75.      t->type = TOKEN822_QUOTE;
  76.      return;
  77.     }
  78.   }
  79. }
  80.  
  81. int token822_unparse(sa,ta,linelen)
  82. stralloc *sa;
  83. token822_alloc *ta;
  84. unsigned int linelen;
  85. {
  86.  struct token822 *t;
  87.  int len;
  88.  int ch;
  89.  int i;
  90.  int j;
  91.  int lasttype;
  92.  int newtype;
  93.  char *s;
  94.  char *lineb;
  95.  char *linee;
  96.  
  97.  len = 0;
  98.  lasttype = 0;
  99.  for (i = 0;i < ta->len;++i)
  100.   {
  101.    t = ta->t + i;
  102.    newtype = t->type;
  103.    if (needspace(lasttype,newtype))
  104.      ++len;
  105.    lasttype = newtype;
  106.    switch(newtype)
  107.     {
  108.      case TOKEN822_COMMA:
  109.        len += 3; break;
  110.      case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: case TOKEN822_RIGHT:
  111.      case TOKEN822_SEMI: case TOKEN822_COLON:
  112.        ++len; break;
  113.      case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
  114.        if (t->type != TOKEN822_ATOM) len += 2;
  115.        for (j = 0;j < t->slen;++j)
  116.      switch(ch = t->s[j])
  117.       {
  118.        case '"': case '[': case ']': case '(': case ')':
  119.        case '\\': case '\r': case '\n': ++len;
  120.        default: ++len;
  121.       }
  122.        break;
  123.     }
  124.   }
  125.  len += 2;
  126.  
  127.  if (!stralloc_ready(sa,len))
  128.    return -1;
  129.  
  130.  s = sa->s;
  131.  lineb = s;
  132.  linee = 0;
  133.  
  134.  lasttype = 0;
  135.  for (i = 0;i < ta->len;++i)
  136.   {
  137.    t = ta->t + i;
  138.    newtype = t->type;
  139.    if (needspace(lasttype,newtype))
  140.      *s++ = ' ';
  141.    lasttype = newtype;
  142.    switch(newtype)
  143.     {
  144.      case TOKEN822_COMMA:
  145.        *s++ = ',';
  146. #define NSUW \
  147.  s[0] = '\n'; s[1] = ' '; \
  148.  if (linee && (!linelen || (s - lineb <= linelen))) \
  149.   { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \
  150.  else { if (linee) lineb = linee + 1; linee = s; s += 2; }
  151.        NSUW
  152.        break;
  153.      case TOKEN822_AT: *s++ = '@'; break;
  154.      case TOKEN822_DOT: *s++ = '.'; break;
  155.      case TOKEN822_LEFT: *s++ = '<'; break;
  156.      case TOKEN822_RIGHT: *s++ = '>'; break;
  157.      case TOKEN822_SEMI: *s++ = ';'; break;
  158.      case TOKEN822_COLON: *s++ = ':'; break;
  159.      case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
  160.        if (t->type == TOKEN822_QUOTE) *s++ = '"';
  161.        if (t->type == TOKEN822_LITERAL) *s++ = '[';
  162.        if (t->type == TOKEN822_COMMENT) *s++ = '(';
  163.        for (j = 0;j < t->slen;++j)
  164.      switch(ch = t->s[j])
  165.       {
  166.        case '"': case '[': case ']': case '(': case ')':
  167.        case '\\': case '\r': case '\n': *s++ = '\\';
  168.        default: *s++ = ch;
  169.       }
  170.        if (t->type == TOKEN822_QUOTE) *s++ = '"';
  171.        if (t->type == TOKEN822_LITERAL) *s++ = ']';
  172.        if (t->type == TOKEN822_COMMENT) *s++ = ')';
  173.        break;
  174.     }
  175.   }
  176.  NSUW
  177.  --s;
  178.  sa->len = s - sa->s;
  179.  return 1;
  180. }
  181.  
  182. int token822_unquote(sa,ta)
  183. stralloc *sa;
  184. token822_alloc *ta;
  185. {
  186.  struct token822 *t;
  187.  int len;
  188.  int i;
  189.  int j;
  190.  char *s;
  191.  
  192.  len = 0;
  193.  for (i = 0;i < ta->len;++i)
  194.   {
  195.    t = ta->t + i;
  196.    switch(t->type)
  197.     {
  198.      case TOKEN822_COMMA: case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: 
  199.      case TOKEN822_RIGHT: case TOKEN822_SEMI: case TOKEN822_COLON: 
  200.        ++len; break;
  201.      case TOKEN822_LITERAL:
  202.        len += 2;
  203.      case TOKEN822_ATOM: case TOKEN822_QUOTE:
  204.        len += t->slen;
  205.     }
  206.   }
  207.  
  208.  if (!stralloc_ready(sa,len))
  209.    return -1;
  210.  
  211.  s = sa->s;
  212.  
  213.  for (i = 0;i < ta->len;++i)
  214.   {
  215.    t = ta->t + i;
  216.    switch(t->type)
  217.     {
  218.      case TOKEN822_COMMA: *s++ = ','; break;
  219.      case TOKEN822_AT: *s++ = '@'; break;
  220.      case TOKEN822_DOT: *s++ = '.'; break;
  221.      case TOKEN822_LEFT: *s++ = '<'; break;
  222.      case TOKEN822_RIGHT: *s++ = '>'; break;
  223.      case TOKEN822_SEMI: *s++ = ';'; break;
  224.      case TOKEN822_COLON: *s++ = ':'; break;
  225.      case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
  226.        if (t->type == TOKEN822_LITERAL) *s++ = '[';
  227.        for (j = 0;j < t->slen;++j)
  228.      *s++ = t->s[j];
  229.        if (t->type == TOKEN822_LITERAL) *s++ = ']';
  230.        break;
  231.      case TOKEN822_COMMENT: break;
  232.     }
  233.   }
  234.  sa->len = s - sa->s;
  235.  return 1;
  236. }
  237.  
  238. int token822_parse(ta,sa,buf)
  239. token822_alloc *ta;
  240. stralloc *sa;
  241. stralloc *buf;
  242. {
  243.  int i;
  244.  int salen;
  245.  int level;
  246.  struct token822 *t;
  247.  int numtoks;
  248.  int numchars;
  249.  char *cbuf;
  250.  
  251.  salen = sa->len;
  252.  
  253.  numchars = 0;
  254.  numtoks = 0;
  255.  for (i = 0;i < salen;++i)
  256.    switch(sa->s[i])
  257.     {
  258.      case '.': case ',': case '@': case '<': case '>': case ':': case ';':
  259.        ++numtoks; break;
  260.      case ' ': case '\t': case '\r': case '\n': break;
  261.      case ')': case ']': return 0;
  262.      /* other control chars and non-ASCII chars are also bad, in theory */
  263.      case '(':
  264.        level = 1;
  265.        while (level)
  266.     {
  267.      if (++i >= salen) return 0;
  268.      switch(sa->s[i])
  269.       {
  270.        case '(': ++level; break;
  271.        case ')': --level; break;
  272.        case '\\': if (++i >= salen) return 0;
  273.        default: ++numchars;
  274.       }
  275.     }
  276.        ++numtoks;
  277.        break;
  278.      case '"':
  279.        level = 1;
  280.        while (level)
  281.     {
  282.      if (++i >= salen) return 0;
  283.      switch(sa->s[i])
  284.       {
  285.        case '"': --level; break;
  286.        case '\\': if (++i >= salen) return 0;
  287.        default: ++numchars;
  288.       }
  289.     }
  290.        ++numtoks;
  291.        break;
  292.      case '[':
  293.        level = 1;
  294.        while (level)
  295.     {
  296.      if (++i >= salen) return 0;
  297.      switch(sa->s[i])
  298.       {
  299.        case ']': --level; break;
  300.        case '\\': if (++i >= salen) return 0;
  301.        default: ++numchars;
  302.       }
  303.     }
  304.        ++numtoks;
  305.        break;
  306.      default:
  307.        do
  308.     {
  309.      ++numchars;
  310.      if (++i >= salen)
  311.        break;
  312.     }
  313.        while (atomok(sa->s[i]));
  314.        --i;
  315.        ++numtoks;
  316.     }
  317.  
  318.  if (!token822_ready(ta,numtoks))
  319.    return -1;
  320.  if (!stralloc_ready(buf,numchars))
  321.    return -1;
  322.  cbuf = buf->s;
  323.  ta->len = numtoks;
  324.  
  325.  t = ta->t;
  326.  for (i = 0;i < salen;++i)
  327.    switch(sa->s[i])
  328.     {
  329.      case '.': t->type = TOKEN822_DOT; ++t; break;
  330.      case ',': t->type = TOKEN822_COMMA; ++t; break;
  331.      case '@': t->type = TOKEN822_AT; ++t; break;
  332.      case '<': t->type = TOKEN822_LEFT; ++t; break;
  333.      case '>': t->type = TOKEN822_RIGHT; ++t; break;
  334.      case ':': t->type = TOKEN822_COLON; ++t; break;
  335.      case ';': t->type = TOKEN822_SEMI; ++t; break;
  336.      case ' ': case '\t': case '\r': case '\n': break;
  337.      case '(':
  338.        t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0;
  339.        level = 1;
  340.        while (level)
  341.     {
  342.      ++i; /* assert: < salen */
  343.      switch(sa->s[i])
  344.       {
  345.        case '(': ++level; break;
  346.        case ')': --level; break;
  347.        case '\\': ++i; /* assert: < salen */
  348.        default: *cbuf++ = sa->s[i]; ++t->slen;
  349.       }
  350.     }
  351.        ++t;
  352.        break;
  353.      case '"':
  354.        t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0;
  355.        level = 1;
  356.        while (level)
  357.     {
  358.      ++i; /* assert: < salen */
  359.      switch(sa->s[i])
  360.       {
  361.        case '"': --level; break;
  362.        case '\\': ++i; /* assert: < salen */
  363.        default: *cbuf++ = sa->s[i]; ++t->slen;
  364.       }
  365.     }
  366.        ++t;
  367.        break;
  368.      case '[':
  369.        t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0;
  370.        level = 1;
  371.        while (level)
  372.     {
  373.      ++i; /* assert: < salen */
  374.      switch(sa->s[i])
  375.       {
  376.        case ']': --level; break;
  377.        case '\\': ++i; /* assert: < salen */
  378.        default: *cbuf++ = sa->s[i]; ++t->slen;
  379.       }
  380.     }
  381.        ++t;
  382.        break;
  383.      default:
  384.        t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
  385.        do
  386.     {
  387.      *cbuf++ = sa->s[i]; ++t->slen;
  388.      if (++i >= salen)
  389.        break;
  390.     }
  391.        while (atomok(sa->s[i]));
  392.        atomcheck(t);
  393.        --i;
  394.        ++t;
  395.     }
  396.  return 1;
  397. }
  398.  
  399. static int gotaddr(taout,taaddr,callback)
  400. token822_alloc *taout;
  401. token822_alloc *taaddr;
  402. int (*callback)();
  403. {
  404.  int i;
  405.  
  406.  if (callback(taaddr) != 1)
  407.    return 0;
  408.  
  409.  if (!token822_readyplus(taout,taaddr->len))
  410.    return 0;
  411.  
  412.  for (i = 0;i < taaddr->len;++i)
  413.    taout->t[taout->len++] = taaddr->t[i];
  414.  
  415.  taaddr->len = 0;
  416.  return 1;
  417. }
  418.  
  419. int token822_addrlist(taout,taaddr,ta,callback)
  420. token822_alloc *taout;
  421. token822_alloc *taaddr;
  422. token822_alloc *ta;
  423. int (*callback)();
  424. {
  425.  struct token822 *t;
  426.  struct token822 *beginning;
  427.  int ingroup;
  428.  int wordok;
  429.  
  430.  taout->len = 0;
  431.  taaddr->len = 0;
  432.  
  433.  if (!token822_readyplus(taout,1)) return -1;
  434.  if (!token822_readyplus(taaddr,1)) return -1;
  435.  
  436.  ingroup = 0;
  437.  wordok = 1;
  438.  
  439.  beginning = ta->t + 2;
  440.  t = ta->t + ta->len - 1;
  441.  
  442.  /* rfc 822 address lists are easy to parse from right to left */
  443.  
  444. #define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1;
  445. #define FLUSHCOMMA if (taaddr->len) { \
  446. if (!gotaddr(taout,taaddr,callback)) return -1; \
  447. if (!token822_append(taout,&comma)) return -1; }
  448. #define ADDRLEFT if (!token822_append(taaddr,t--)) return -1;
  449. #define OUTLEFT if (!token822_append(taout,t--)) return -1;
  450.  
  451.  while (t >= beginning)
  452.   {
  453.    switch(t->type)
  454.     {
  455.      case TOKEN822_SEMI:
  456.        FLUSHCOMMA
  457.        if (ingroup) return 0;
  458.        ingroup = 1;
  459.        wordok = 1;
  460.        break;
  461.      case TOKEN822_COLON:
  462.        FLUSH
  463.        if (!ingroup) return 0;
  464.        ingroup = 0;
  465.        while ((t >= beginning) && (t->type != TOKEN822_COMMA))
  466.      OUTLEFT
  467.        if (t >= beginning)
  468.      OUTLEFT
  469.        wordok = 1;
  470.        continue;
  471.      case TOKEN822_RIGHT:
  472.        FLUSHCOMMA
  473.        OUTLEFT
  474.        while ((t >= beginning) && (t->type != TOKEN822_LEFT))
  475.      ADDRLEFT
  476.        /* important to use address here even if it's empty: <> */
  477.        if (!gotaddr(taout,taaddr,callback)) return -1;
  478.        if (t < beginning) return 0;
  479.        OUTLEFT
  480.        while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) || (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) || (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT)))
  481.      OUTLEFT
  482.        wordok = 0;
  483.        continue;
  484.      case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
  485.        if (!wordok)
  486.      FLUSHCOMMA
  487.        wordok = 0;
  488.        ADDRLEFT
  489.        continue;
  490.      case TOKEN822_COMMENT:
  491.        /* comment is lexically a space; shouldn't affect wordok */
  492.        break;
  493.      case TOKEN822_COMMA:
  494.        FLUSH
  495.        wordok = 1;
  496.        break;
  497.      default:
  498.        wordok = 1;
  499.        ADDRLEFT
  500.        continue;
  501.     }
  502.    OUTLEFT
  503.   }
  504.  FLUSH
  505.  ++t;
  506.  while (t > ta->t)
  507.    if (!token822_append(taout,--t)) return -1;
  508.  
  509.  token822_reverse(taout);
  510.  return 1;
  511. }
  512.