URI: 
       trfc822.c - mixmaster - mixmaster 3.0 patched for libressl
  HTML git clone git://parazyd.org/mixmaster.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       trfc822.c (13497B)
       ---
            1 /* Mixmaster version 3.0  --  (C) 1999 - 2006 Anonymizer Inc. and others.
            2 
            3    Mixmaster may be redistributed and modified under certain conditions.
            4    This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
            5    ANY KIND, either express or implied. See the file COPYRIGHT for
            6    details.
            7 
            8    Parse RFC 822 headers
            9    $Id: rfc822.c 934 2006-06-24 13:40:39Z rabbi $ */
           10 
           11 
           12 #include "mix3.h"
           13 
           14 static int is_specials(int c);
           15 static int is_qtext(char c);
           16 static int is_ctext(char c);
           17 static void wsc(BUFFER *in, BUFFER *xomment);
           18 static int word(BUFFER *in, BUFFER *word, BUFFER *x);
           19 static int atom(BUFFER *in, BUFFER *atom, BUFFER *x);
           20 static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x);
           21 static int comment(BUFFER *in, BUFFER *string);
           22 static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x);
           23 static int domain(BUFFER *in, BUFFER *domain, BUFFER *x);
           24 static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x);
           25 static int domain_ref(BUFFER *in, BUFFER *dom, BUFFER *x);
           26 static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x);
           27 static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x);
           28 static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x);
           29 static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x);
           30 static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x);
           31 static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x);
           32 
           33 static void backtrack(BUFFER *b, int len)
           34 {
           35   if (b) {
           36     b->length = len;
           37     b->data[b->length] = '\0';
           38   }
           39 }
           40 
           41 /* white space and comments */
           42 static void wsc(BUFFER *in, BUFFER *string)
           43 {
           44   int c;
           45 
           46   for (;;) {
           47     c = buf_getc(in);
           48     if (c == -1)
           49       break;
           50     else if (c == '\n') {
           51       c = buf_getc(in);
           52       if (c != ' ' && c != '\t') {
           53         if (c != -1)
           54           buf_ungetc(in), buf_ungetc(in);
           55         break;
           56       }
           57     } else {
           58       if (c != ' ' && c != '\t') {
           59         buf_ungetc(in);
           60         if (!comment(in, string))
           61           break;
           62       }
           63     }
           64   }
           65 }
           66 
           67 /*          specials    =  "(" / ")" / "<" / ">" / "@"  ; Must be in quoted-
           68  *                      /  "," / ";" / ":" / "\" / <">  ;  string, to use
           69  *                      /  "." / "[" / "]"              ;  within a word.
           70  */
           71 
           72 static int is_specials(int c)
           73 {
           74   return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
           75           c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
           76           c == '.' || c == '[' || c == ']');
           77 }
           78 
           79 /*           qtext       =  <any CHAR excepting <">,     ; => may be folded
           80  *                          "\" & CR, and including
           81  *                          linear-white-space>
           82  */
           83 static int is_qtext(char c)
           84 {
           85   return (c != '\"' && c != '\\' && c != '\n');
           86 }
           87 
           88 /*           ctext       =  <any CHAR excluding "(",     ; => may be folded
           89  *                          ")", "\" & CR, & including
           90  *                          linear-white-space>
           91  */
           92 static int is_ctext(char c)
           93 {
           94   return (c != '(' && c != ')' && c != '\\' && c != '\n');
           95 }
           96 
           97 /*           word        =  atom / quoted-string
           98  */
           99 static int word(BUFFER *in, BUFFER *word, BUFFER *x)
          100 {
          101   return (atom(in, word, x) || quoted_string(in, word, x));
          102 }
          103 
          104 /*          atom        =  1*<any CHAR except specials, SPACE and CTLs>
          105  */
          106 static int atom(BUFFER *in, BUFFER *atom, BUFFER *x)
          107 {
          108   int c;
          109 
          110   buf_clear(atom);
          111   wsc(in, x);
          112   for (;;) {
          113     c = buf_getc(in);
          114     if (c == -1)
          115       break;
          116     else if (is_specials(c) || c == ' ' || c < 32 || c == 127) {
          117       buf_ungetc(in);
          118       break;
          119     } else
          120       buf_appendc(atom, c);
          121   }
          122   if (atom->length)
          123     wsc(in, x);
          124   return (atom->length);
          125 }
          126 
          127 /*           quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
          128  *                                                       ;   quoted chars.
          129  */
          130 static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x)
          131 {
          132   int ptr, xlen;
          133   int c;
          134 
          135   ptr = in->ptr, xlen = x ? x->length : 0;
          136   buf_clear(string);
          137   wsc(in, NULL);
          138   c = buf_getc(in);
          139   if (c == '\"') {
          140 #if 0
          141     buf_appendc(string, c);
          142 #endif
          143     for (;;) {
          144       c = buf_getc(in);
          145       if (c == -1)              /* catch unterminated quoted string */
          146         break;
          147       if (is_qtext(c))
          148         buf_appendc(string, c);
          149       else if (c == '\n') {
          150         c = buf_getc(in);
          151         if (c != ' ' && c != '\n')
          152           break;
          153       } else if (c == '\\') {
          154         c = buf_getc(in);
          155         if (c == -1)
          156           break;
          157         else
          158           buf_appendc(string, c);
          159       } else if (c == '\"') {
          160 #if 0
          161         buf_appendc(string, c);
          162 #endif
          163         wsc(in, NULL);
          164         return (1);
          165       } else
          166         break;
          167     }
          168   }
          169   in->ptr = ptr, backtrack(x, xlen);
          170   return (0);
          171 }
          172 
          173 /*           comment     =  "(" *(ctext / quoted-pair / comment) ")"
          174  */
          175 static int comment(BUFFER *in, BUFFER *string)
          176 {
          177   int ptr, xlen;
          178   int separator = 0;
          179   int c;
          180 
          181   ptr = in->ptr;
          182   xlen = string ? string->length : 0;
          183   if (xlen)
          184     separator = 1;
          185   c = buf_getc(in);
          186   if (c == '(') {
          187     for (;;) {
          188       c = buf_getc(in);
          189       if (c == -1)
          190         return(1); /* unterminated comment, bail out */
          191       if (is_ctext(c)) {
          192         if (string != NULL) {
          193           if (separator)
          194             buf_appendc(string, ' '), separator = 0;
          195           buf_appendc(string, c);
          196         }
          197       } else if (c == '\n') {
          198         c = buf_getc(in);
          199         if (c != ' ' && c != '\n')
          200           break;
          201       } else if (c == '\\') {
          202         c = buf_getc(in);
          203         if (c != -1) {
          204           if (string != NULL) {
          205             if (separator)
          206               buf_appendc(string, ' '), separator = 0;
          207             buf_appendc(string, c);
          208           }
          209         }
          210       } else if (c == ')')
          211         return (1);
          212       else {
          213         BUFFER *s;
          214         int o;
          215 
          216         s = buf_new();
          217         buf_ungetc(in);
          218         o = comment(in, s);
          219         if (o && string != NULL) {
          220           if (separator)
          221             buf_appendc(string, ' '), separator = 0;
          222           buf_cat(string, s);
          223         }
          224         buf_free(s);
          225         if (!o)
          226           break;
          227       }
          228     }
          229   }
          230   in->ptr = ptr;
          231   backtrack(string, xlen);
          232   return (0);
          233 }
          234 
          235 /*          local-part  =  word *("." word)             ; uninterpreted
          236  *                                                      ; case-preserved
          237  */
          238 static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x)
          239 {
          240   BUFFER *w;
          241   int c;
          242 
          243   buf_clear(addr);
          244   if (!word(in, addr, x))
          245     return (0);
          246   w = buf_new();
          247   for (;;) {
          248     c = buf_getc(in);
          249     if (c == -1)
          250       break;
          251     if (c == '.' && (word(in, w, x)))
          252       buf_appendc(addr, '.'), buf_cat(addr, w);
          253     else {
          254       buf_ungetc(in);
          255       break;
          256     }
          257   }
          258   buf_free(w);
          259   return (addr->length);
          260 }
          261 
          262 /*           domain      =  sub-domain *("." sub-domain)
          263  */
          264 static int domain(BUFFER *in, BUFFER *domain, BUFFER *x)
          265 {
          266   BUFFER *sub;
          267   int c;
          268 
          269   if (!sub_domain(in, domain, x))
          270     return (0);
          271   sub = buf_new();
          272   for (;;) {
          273     c = buf_getc(in);
          274     if (c == -1)
          275       break;
          276     if (c == '.' && (sub_domain(in, sub, x)))
          277       buf_appendc(domain, '.'), buf_cat(domain, sub);
          278     else {
          279       buf_ungetc(in);
          280       break;
          281     }
          282   }
          283   buf_free(sub);
          284   return (domain->length);
          285 }
          286 
          287 /*             sub-domain  =  domain-ref / domain-literal
          288  */
          289 static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x)
          290 {
          291   return (domain_ref(in, sub, x) || domain_literal(in, sub, x));
          292 }
          293 
          294 /*           domain-ref  =  atom                         ; symbolic reference
          295  */
          296 static int domain_ref(BUFFER *in, BUFFER *d, BUFFER *x)
          297 {
          298   return (atom(in, d, x));
          299 }
          300 
          301 /*           addr-spec   =  local-part "@" domain        ; global address
          302  */
          303 static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x)
          304 {
          305   BUFFER *dom;
          306   int ptr, xlen;
          307 
          308   ptr = in->ptr, xlen = x ? x->length : 0;
          309   dom = buf_new();
          310   buf_clear(addr);
          311   if (local_part(in, addr, x) && buf_getc(in) == '@' && domain(in, dom, x))
          312     buf_appendc(addr, '@'), buf_cat(addr, dom);
          313   else
          314     buf_clear(addr), in->ptr = ptr, backtrack(x, xlen);
          315   buf_free(dom);
          316   return (addr->length);
          317 }
          318 
          319 /*           route-addr  =  "<" [route] addr-spec ">"
          320  */
          321 static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
          322 {
          323   int c;
          324   int ptr, xlen;
          325 
          326   ptr = in->ptr, xlen = x ? x->length : 0;
          327   c = buf_getc(in);
          328   if (c == -1)
          329     return (0);
          330   if (c != '<') {
          331     buf_ungetc(in);
          332     return (0);
          333   }
          334   if (addr_spec(in, addr, x) && buf_getc(in) == '>')
          335     return (1);
          336   in->ptr = ptr, backtrack(x, xlen);
          337   return (0);
          338 }
          339 
          340 /*           phrase      =  1*word                       ; Sequence of words
          341  */
          342 static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x)
          343 {
          344   BUFFER *w;
          345 
          346   buf_clear(phr);
          347   w = buf_new();
          348   while (word(in, w, x)) {
          349     if (phr->length)
          350       buf_appendc(phr, ' ');
          351     buf_cat(phr, w);
          352   }
          353   buf_free(w);
          354   return (phr->length);
          355 }
          356 
          357 /*          mailbox     =  addr-spec                    ; simple address
          358  *                      /  [phrase] route-addr          ; name & addr-spec
          359  *                                                        (RFC 1123)
          360  */
          361 static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x)
          362 {
          363   int ptr, xlen, ret;
          364 
          365   buf_clear(name);
          366   if (addr_spec(in, mailbox, x))
          367     return (1);
          368 
          369   ptr = in->ptr, xlen = x ? x->length : 0;
          370   ret = phrase(in, name, x) && route_addr(in, mailbox, x);
          371   if (!ret) {
          372     in->ptr = ptr, backtrack(x, xlen);
          373     ret = route_addr(in, mailbox, x);
          374   }
          375 
          376   return (ret);
          377 }
          378 
          379 /*          address     =  mailbox                      ; one addressee
          380  *                      /  group                        ; named list
          381  */
          382 static int address(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
          383 {
          384   return (mailbox(in, address, name, x) || group(in, address, name, x));
          385 }
          386 
          387 /*          group       =  phrase ":" [#mailbox] ";"
          388  */
          389 static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x)
          390 {
          391   BUFFER *addr, *tmp;
          392   int ptr, xlen, ret = 0;
          393 
          394   ptr = in->ptr, xlen = x ? x->length : 0;
          395   addr = buf_new();
          396   tmp = buf_new();
          397   buf_clear(group);
          398   if (phrase(in, name, x) && buf_getc(in) == ':') {
          399     while (mailbox(in, addr, tmp, x))
          400       buf_cat(group, addr), buf_nl(group);
          401     ret = buf_getc(in) == ';';
          402   }
          403   if (!ret)
          404     in->ptr = ptr, backtrack(x, xlen);
          405   buf_free(addr);
          406   buf_free(tmp);
          407   return (ret);
          408 }
          409 
          410 /*         domain-literal =  "[" *(dtext / quoted-pair) "]"
          411  */
          412 static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x)
          413 {
          414   return 0;                        /* XXX */
          415 }
          416 
          417 /* local address without `@' is not specified in RFC 822 */
          418 
          419 /* local_addr = "<" atom ">" */
          420 static int local_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
          421 {
          422   int c;
          423   int ptr, xlen;
          424 
          425   ptr = in->ptr, xlen = x ? x->length : 0;
          426   c = buf_getc(in);
          427   if (c == -1)
          428     return (0);
          429   if (c != '<') {
          430     buf_ungetc(in);
          431     return (0);
          432   }
          433   if (atom(in, addr, x) && buf_getc(in) == '>')
          434     return (1);
          435   in->ptr = ptr, backtrack(x, xlen);
          436   return (0);
          437 }
          438 
          439 static int localaddress(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
          440 {
          441   int ptr, xlen;
          442 
          443   buf_clear(name);
          444   if (local_addr(in, address, x))
          445     return (1);
          446   ptr = in->ptr, xlen = x ? x->length : 0;
          447   if (phrase(in, name, x) && local_addr(in, address, x))
          448     return (1);
          449   in->ptr = ptr, backtrack(x, xlen);
          450   buf_clear(name);
          451   return (atom(in, address, x));
          452 }
          453 
          454 void rfc822_addr(BUFFER *destination, BUFFER *list)
          455 {
          456   BUFFER *addr, *name;
          457 
          458   addr = buf_new();
          459   name = buf_new();
          460 
          461   for (;;) {
          462     if (!address(destination, addr, name, NULL) &&
          463         !localaddress(destination, addr, name, NULL))
          464       break;
          465     buf_cat(list, addr);
          466     buf_nl(list);
          467     if (buf_getc(destination) != ',')
          468       break;
          469   }
          470   buf_free(addr);
          471   buf_free(name);
          472 }
          473 
          474 void rfc822_name(BUFFER *line, BUFFER *name)
          475 {
          476   BUFFER *addr, *comment;
          477   int ret;
          478 
          479   addr = buf_new();
          480   comment = buf_new();
          481   ret = address(line, addr, name, comment);
          482   if (ret == 0)
          483     ret = localaddress(line, addr, name, comment);
          484   if (ret) {
          485     if (name->length == 0)
          486       buf_set(name, comment);
          487     if (name->length == 0)
          488       buf_set(name, addr);
          489   }
          490   if (ret == 0)
          491     buf_set(name, line);
          492   buf_free(addr);
          493   buf_free(comment);
          494 }
          495 
          496 /* MIME extensions. RFC 2045 */
          497 
          498 /*    tspecials :=  "(" / ")" / "<" / ">" / "@" /
          499  *                  "," / ";" / ":" / "\" / <">
          500  *                  "/" / "[" / "]" / "?" / "="
          501  */
          502 
          503 static int is_tspecials(int c)
          504 {
          505   return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
          506           c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
          507           c == '/' || c == '[' || c == ']' || c == '?' || c == '=');
          508 }
          509 
          510 /* token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
          511  *                or tspecials>
          512  */
          513 static int token(BUFFER *in, BUFFER *token, BUFFER *x)
          514 {
          515   int c;
          516 
          517   buf_clear(token);
          518   wsc(in, x);
          519   for (;;) {
          520     c = buf_getc(in);
          521     if (c == -1)
          522       break;
          523     else if (is_tspecials(c) || c == ' ' || c < 32 || c == 127) {
          524       buf_ungetc(in);
          525       break;
          526     } else
          527       buf_appendc(token, c);
          528   }
          529   if (token->length)
          530     wsc(in, x);
          531   return (token->length);
          532 }
          533 
          534 /*   value := token / quoted-string
          535  */
          536 
          537 static int value(BUFFER *in, BUFFER *value, BUFFER *x)
          538 {
          539   return (token(in, value, x) || quoted_string(in, value, x));
          540 }
          541 
          542 /*   parameter := attribute "=" value
          543  */
          544 
          545 static int parameter(BUFFER *in, BUFFER *attribute, BUFFER *val, BUFFER *x)
          546 {
          547   int ptr;
          548   ptr = in->ptr;
          549   token(in, attribute, x);
          550   if (buf_getc(in) != '=') {
          551     in->ptr = ptr;
          552     return(0);
          553   }
          554   return(value(in, val, x));
          555 }
          556 
          557 /* get type */
          558 int get_type(BUFFER *content, BUFFER *type, BUFFER *subtype)
          559 {
          560   token(content, type, NULL);
          561   if (buf_getc(content) == '/')
          562     return (token(content, subtype, NULL));
          563   buf_ungetc(content);
          564   buf_clear(type);
          565   return (0);
          566 }
          567 
          568 /* get parameter value */
          569 void get_parameter(BUFFER *content, char *attribute, BUFFER *value)
          570 {
          571   BUFFER *tok;
          572   tok = buf_new();
          573   buf_clear(value);
          574 
          575   get_type(content, tok, tok);
          576     for (;;) {
          577       if (buf_getc(content) != ';')
          578         break;
          579       if (parameter(content, tok, value, NULL) &&
          580           strieq(attribute, tok->data))
          581         break; /* found */
          582       buf_clear(value);
          583     }
          584   buf_free(tok);
          585 }