Back to index

courier  0.68.2
rfc822.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2009 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 /*
00007 */
00008 #include      "rfc822.h"
00009 #include      <stdio.h>
00010 #include      <ctype.h>
00011 #include      <stdlib.h>
00012 #include      <string.h>
00013 
00014 static void tokenize(const char *p, struct rfc822token *tokp, int *toklen,
00015        void (*err_func)(const char *, int, void *), void *voidp)
00016 {
00017 const char *addr=p;
00018 int    i=0;
00019 int    inbracket=0;
00020 
00021        *toklen=0;
00022        while (*p)
00023        {
00024               if (isspace((int)(unsigned char)*p))
00025               {
00026                      p++;
00027                      i++;
00028                      continue;
00029               }
00030 
00031 #define SPECIALS "<>@,;:.[]()%!\"\\?=/"
00032 
00033               switch (*p)   {
00034               int    level;
00035 
00036               case '(':
00037                      if (tokp)
00038                      {
00039                             tokp->token='(';
00040                             tokp->ptr=p;
00041                             tokp->len=0;
00042                      }
00043                      level=0;
00044                      for (;;)
00045                      {
00046                             if (!*p)
00047                             {
00048                                    if (err_func) (*err_func)(addr, i,
00049                                                           voidp);
00050                                    if (tokp) tokp->token='"';
00051                                    ++*toklen;
00052                                    return;
00053                             }
00054                             if (*p == '(')
00055                                    ++level;
00056                             if (*p == ')' && --level == 0)
00057                             {
00058                                    p++;
00059                                    i++;
00060                                    if (tokp)     tokp->len++;
00061                                    break;
00062                             }
00063                             if (*p == '\\' && p[1])
00064                             {
00065                                    p++;
00066                                    i++;
00067                                    if (tokp)     tokp->len++;
00068                             }
00069 
00070                             i++;
00071                             if (tokp)     tokp->len++;
00072                             p++;
00073                      }
00074                      if (tokp)     ++tokp;
00075                      ++*toklen;
00076                      continue;
00077 
00078               case '"':
00079                      p++;
00080                      i++;
00081 
00082                      if (tokp)
00083                      {
00084                             tokp->token='"';
00085                             tokp->ptr=p;
00086                      }
00087                      while (*p != '"')
00088                      {
00089                             if (!*p)
00090                             {
00091                                    if (err_func) (*err_func)(addr, i,
00092                                                           voidp);
00093                                    ++*toklen;
00094                                    return;
00095                             }
00096                             if (*p == '\\' && p[1])
00097                             {
00098                                    if (tokp)     tokp->len++;
00099                                    p++;
00100                                    i++;
00101                             }
00102                             if (tokp)     tokp->len++;
00103                             p++;
00104                             i++;
00105                      }
00106                      ++*toklen;
00107                      if (tokp)     ++tokp;
00108                      p++;
00109                      i++;
00110                      continue;
00111               case '\\':
00112               case ')':
00113                      if (err_func) (*err_func)(addr, i, voidp);
00114                      ++p;
00115                      ++i;
00116                      continue;
00117 
00118               case '=':
00119 
00120                      if (p[1] == '?')
00121                      {
00122                             int j;
00123 
00124                      /* exception: =? ... ?= */
00125 
00126                             for (j=2; p[j]; j++)
00127                             {
00128                                    if (p[j] == '?' && p[j+1] == '=')
00129                                           break;
00130 
00131                                    if (p[j] == '?' || p[j] == '=')
00132                                           continue;
00133 
00134                                    if (strchr(RFC822_SPECIALS, p[j]) ||
00135                                        isspace(p[j]))
00136                                           break;
00137                             }
00138 
00139                             if (p[j] == '?' && p[j+1] == '=')
00140                             {
00141                                    j += 2;
00142                                    if (tokp)
00143                                    {
00144                                           tokp->token=0;
00145                                           tokp->ptr=p;
00146                                           tokp->len=j;
00147                                           ++tokp;
00148                                    }
00149                                    ++*toklen;
00150 
00151                                    p += j;
00152                                    i += j;
00153                                    continue;
00154                             }
00155                      }
00156                      /* FALLTHROUGH */
00157 
00158               case '<':
00159               case '>':
00160               case '@':
00161               case ',':
00162               case ';':
00163               case ':':
00164               case '.':
00165               case '[':
00166               case ']':
00167               case '%':
00168               case '!':
00169               case '?':
00170               case '/':
00171 
00172                      if ( (*p == '<' && inbracket) ||
00173                             (*p == '>' && !inbracket))
00174                      {
00175                             if (err_func) (*err_func)(addr, i, voidp);
00176                             ++p;
00177                             ++i;
00178                             continue;
00179                      }
00180 
00181                      if (*p == '<')
00182                             inbracket=1;
00183 
00184                      if (*p == '>')
00185                             inbracket=0;
00186 
00187                      if (tokp)
00188                      {
00189                             tokp->token= *p;
00190                             tokp->ptr=p;
00191                             tokp->len=1;
00192                             ++tokp;
00193                      }
00194                      ++*toklen;
00195 
00196                      if (*p == '<' && p[1] == '>')
00197                                    /* Fake a null address */
00198                      {
00199                             if (tokp)
00200                             {
00201                                    tokp->token=0;
00202                                    tokp->ptr="";
00203                                    tokp->len=0;
00204                                    ++tokp;
00205                             }
00206                             ++*toklen;
00207                      }
00208                      ++p;
00209                      ++i;
00210                      continue;
00211               default:
00212 
00213                      if (tokp)
00214                      {
00215                             tokp->token=0;
00216                             tokp->ptr=p;
00217                             tokp->len=0;
00218                      }
00219                      while (*p && !isspace((int)(unsigned char)*p) && strchr(
00220                             SPECIALS, *p) == 0)
00221                      {
00222                             if (tokp)     ++tokp->len;
00223                             ++p;
00224                             ++i;
00225                      }
00226                      if (i == 0)   /* Idiot check */
00227                      {
00228                             if (err_func) (*err_func)(addr, i, voidp);
00229                             if (tokp)
00230                             {
00231                                    tokp->token='"';
00232                                    tokp->ptr=p;
00233                                    tokp->len=1;
00234                                    ++tokp;
00235                             }
00236                             ++*toklen;
00237                             ++p;
00238                             ++i;
00239                             continue;
00240                      }
00241                      if (tokp)     ++tokp;
00242                      ++*toklen;
00243               }
00244        }
00245 }
00246 
00247 static void parseaddr(struct rfc822token *tokens, int ntokens,
00248               struct rfc822addr *addrs, int *naddrs)
00249 {
00250 int    flag, j, k;
00251 
00252        *naddrs=0;
00253 
00254        while (ntokens)
00255        {
00256        int    i;
00257 
00258               /* atoms (token=0) or quoted strings, followed by a : token
00259               is a list name. */
00260 
00261               for (i=0; i<ntokens; i++)
00262                      if (tokens[i].token && tokens[i].token != '"')
00263                             break;
00264               if (i < ntokens && tokens[i].token == ':')
00265               {
00266                      ++i;
00267                      if (addrs)
00268                      {
00269                             addrs->tokens=0;
00270                             addrs->name=i ? tokens:0;
00271                             for (j=1; j<i; j++)
00272                                    addrs->name[j-1].next=addrs->name+j;
00273                             if (i)
00274                                    addrs->name[i-1].next=0;
00275                             addrs++;
00276                      }
00277                      ++*naddrs;
00278                      tokens += i;
00279                      ntokens -= i;
00280                      continue;  /* Group=phrase ":" */
00281               }
00282 
00283               /* Spurious commas are skipped, ;s are recorded */
00284 
00285               if (tokens->token == ',' || tokens->token == ';')
00286               {
00287                      if (tokens->token == ';')
00288                      {
00289                             if (addrs)
00290                             {
00291                                    addrs->tokens=0;
00292                                    addrs->name=tokens;
00293                                    addrs->name->next=0;
00294                                    addrs++;
00295                             }
00296                             ++*naddrs;
00297                      }
00298                      ++tokens;
00299                      --ntokens;
00300                      continue;
00301               }
00302 
00303               /* If we can find a '<' before the next comma or semicolon,
00304               we have new style RFC path address */
00305 
00306               for (i=0; i<ntokens && tokens[i].token != ';' &&
00307                             tokens[i].token != ',' &&
00308                                    tokens[i].token != '<'; i++)
00309                      ;
00310 
00311               if (i < ntokens && tokens[i].token == '<')
00312               {
00313               int    j;
00314 
00315                      /* Ok -- what to do with the stuff before '>'???
00316                      If it consists exclusively of atoms, leave them alone.
00317                      Else, make them all a quoted string. */
00318 
00319                         for (j=0; j<i && (tokens[j].token == 0 ||
00320                                           tokens[j].token == '('); j++)
00321                                 ;
00322 
00323                      if (j == i)
00324                      {
00325                             if (addrs)
00326                             {
00327                                    addrs->name= i ? tokens:0;
00328                                    for (k=1; k<i; k++)
00329                                           addrs->name[k-1].next=addrs->name+k;
00330                                    if (i)
00331                                           addrs->name[i-1].next=0;
00332                             }
00333                      }
00334                      else   /* Intentionally corrupt the original toks */
00335                      {
00336                             if (addrs)
00337                             {
00338                                    tokens->len= tokens[i-1].ptr
00339                                                  + tokens[i-1].len
00340                                                  - tokens->ptr;
00341                                    /* We know that all the ptrs point
00342                                    to parts of the same string. */
00343                                    tokens->token='"';
00344                                           /* Quoted string. */
00345                                    addrs->name=tokens;
00346                                    addrs->name->next=0;
00347                             }
00348                      }
00349 
00350               /* Any comments in the name part are changed to quotes */
00351 
00352                      if (addrs)
00353                      {
00354                      struct rfc822token *t;
00355 
00356                             for (t=addrs->name; t; t=t->next)
00357                                    if (t->token == '(')
00358                                           t->token='"';
00359                      }
00360 
00361                      /* Now that's done and over with, see what can
00362                      be done with the <...> part. */
00363 
00364                      ++i;
00365                      tokens += i;
00366                      ntokens -= i;
00367                      for (i=0; i<ntokens && tokens[i].token != '>'; i++)
00368                             ;
00369                      if (addrs)
00370                      {
00371                             addrs->tokens=i ? tokens:0;
00372                             for (k=1; k<i; k++)
00373                                    addrs->tokens[k-1].next=addrs->tokens+k;
00374                             if (i)
00375                                    addrs->tokens[i-1].next=0;
00376                             ++addrs;
00377                      }
00378                      ++*naddrs;
00379                      tokens += i;
00380                      ntokens -= i;
00381                      if (ntokens)  /* Skip the '>' token */
00382                      {
00383                             --ntokens;
00384                             ++tokens;
00385                      }
00386                      continue;
00387               }
00388 
00389               /* Ok - old style address.  Assume the worst */
00390 
00391               /* Try to figure out where the address ends.  It ends upon:
00392               a comma, semicolon, or two consecutive atoms. */
00393 
00394               flag=0;
00395               for (i=0; i<ntokens && tokens[i].token != ',' &&
00396                      tokens[i].token != ';'; i++)
00397               {
00398                      if (tokens[i].token == '(') continue;
00399                                    /* Ignore comments */
00400                      if (tokens[i].token == 0 || tokens[i].token == '"')
00401                                                         /* Atom */
00402                      {
00403                             if (flag)     break;
00404                             flag=1;
00405                      }
00406                      else   flag=0;
00407               }
00408               if (i == 0)   /* Must be spurious comma, or something */
00409               {
00410                      ++tokens;
00411                      --ntokens;
00412                      continue;
00413               }
00414 
00415               if (addrs)
00416               {
00417                      addrs->name=0;
00418               }
00419 
00420               /* Ok, now get rid of embedded comments in the address.
00421               Consider the last comment to be the real name */
00422 
00423               if (addrs)
00424               {
00425                      struct rfc822token   save_token;
00426 
00427                      memset(&save_token, 0, sizeof(save_token));
00428 
00429                      for (j=k=0; j<i; j++)
00430                      {
00431                             if (tokens[j].token == '(')
00432                             {
00433                                    save_token=tokens[j];
00434                                    continue;
00435                             }
00436                             tokens[k]=tokens[j];
00437                             k++;
00438                      }
00439 
00440                      if (save_token.ptr)
00441                      {
00442                             tokens[i-1]=save_token;
00443                             addrs->name=tokens+i-1;
00444                             addrs->name->next=0;
00445                      }
00446                      addrs->tokens=k ? tokens:NULL;
00447                      for (j=1; j<k; j++)
00448                             addrs->tokens[j-1].next=addrs->tokens+j;
00449                      if (k)
00450                             addrs->tokens[k-1].next=0;
00451                      ++addrs;
00452               }
00453               ++*naddrs;
00454               tokens += i;
00455               ntokens -= i;
00456        }
00457 }
00458 
00459 static void print_token(const struct rfc822token *token,
00460               void (*print_func)(char, void *), void *ptr)
00461 {
00462 const char *p;
00463 int    n;
00464 
00465        if (token->token == 0 || token->token == '(')
00466        {
00467               for (n=token->len, p=token->ptr; n; --n, ++p)
00468                      (*print_func)(*p, ptr);
00469               return;
00470        }
00471 
00472        if (token->token != '"')
00473        {
00474               (*print_func)(token->token, ptr);
00475               return;
00476        }
00477 
00478        (*print_func)('"', ptr);
00479        n=token->len;
00480        p=token->ptr;
00481        while (n)
00482        {
00483               if (*p == '"' || (*p == '\\' && n == 1)) (*print_func)('\\', ptr);
00484               if (*p == '\\' && n > 1)
00485               {
00486                      (*print_func)('\\', ptr);
00487                      ++p;
00488                      --n;
00489               }
00490               (*print_func)(*p++, ptr);
00491               --n;
00492        }
00493        (*print_func)('"', ptr);
00494 }
00495 
00496 void rfc822tok_print(const struct rfc822token *token,
00497               void (*print_func)(char, void *), void *ptr)
00498 {
00499 int    prev_isatom=0;
00500 int    isatom;
00501 
00502        while (token)
00503        {
00504               isatom=rfc822_is_atom(token->token);
00505               if (prev_isatom && isatom)
00506                      (*print_func)(' ', ptr);
00507               print_token(token, print_func, ptr);
00508               prev_isatom=isatom;
00509               token=token->next;
00510        }
00511 }
00512 
00513 static void rfc822_prname_int(const struct rfc822addr *addrs,
00514                            void (*print_func)(char, void *),
00515                            void *ptr)
00516 
00517 {
00518        struct rfc822token *i;
00519        int n;
00520        int    prev_isatom=0;
00521        int    isatom=0;
00522 
00523        for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
00524        {
00525               isatom=rfc822_is_atom(i->token);
00526               if (isatom && prev_isatom)
00527                      (*print_func)(' ', ptr);
00528 
00529               if (i->token == '"')
00530               {
00531                      for (n=0; n<i->len; n++)
00532                      {
00533                             if (i->ptr[n] == '\\' &&
00534                                 n + 1 < i->len)
00535                                    ++n;
00536                             (*print_func)(i->ptr[n], ptr);
00537                      }
00538                      continue;
00539               }
00540 
00541               if (i->token != '(')
00542               {
00543                      print_token(i, print_func, ptr);
00544                      continue;
00545               }
00546 
00547               for (n=2; n<i->len; n++)
00548                      (*print_func)(i->ptr[n-1], ptr);
00549        }
00550 }
00551 
00552 static void rfc822_print_common_nameaddr_cntlen(char c, void *p)
00553 {
00554        ++ *(size_t *)p;
00555 }
00556 
00557 static void rfc822_print_common_nameaddr_saveaddr(char c, void *p)
00558 {
00559        char **cp=(char **)p;
00560 
00561        *(*cp)++=c;
00562 }
00563 
00564 static int rfc822_print_common_nameaddr(const struct rfc822addr *addrs,
00565                                    char *(*decode_func)(const char *,
00566                                                       const char *, int),
00567                                    const char *chset,
00568                                    void (*print_func)(char, void *),
00569                                    void *ptr)
00570 {
00571        size_t n=1;
00572        char *addrbuf, *namebuf;
00573        char *p, *q;
00574        int print_braces=0;
00575 
00576        if (addrs->tokens)
00577               rfc822tok_print(addrs->tokens,
00578                             rfc822_print_common_nameaddr_cntlen, &n);
00579 
00580 
00581        p=addrbuf=malloc(n);
00582 
00583        if (!addrbuf)
00584               return -1;
00585 
00586        if (addrs->tokens)
00587               rfc822tok_print(addrs->tokens,
00588                             rfc822_print_common_nameaddr_saveaddr, &p);
00589 
00590        *p=0;
00591 
00592        n=1;
00593 
00594        rfc822_prname_int(addrs,
00595                        rfc822_print_common_nameaddr_cntlen, &n);
00596 
00597        p=namebuf=malloc(n);
00598 
00599        if (!p)
00600        {
00601               free(addrbuf);
00602               return -1;
00603        }
00604 
00605        rfc822_prname_int(addrs,
00606                        rfc822_print_common_nameaddr_saveaddr, &p);
00607 
00608        *p=0;
00609 
00610        p=(*decode_func)(namebuf, chset, 0);
00611 
00612        free(namebuf);
00613        if (!p)
00614        {
00615               free(addrbuf);
00616               return -1;
00617        }
00618 
00619        for (namebuf=p; *p; p++)
00620        {
00621               print_braces=1;
00622               (*print_func)(*p, ptr);
00623        }
00624        free(namebuf);
00625 
00626        p=(*decode_func)(addrbuf, chset, 1);
00627        free(addrbuf);
00628 
00629        if (!p)
00630               return -1;
00631 
00632        if (print_braces)
00633               (*print_func)(' ', ptr);
00634 
00635        for (q=p; *q; ++q)
00636               if (*q != '.' && *q != '@' && strchr(RFC822_SPECIALS, *q))
00637               {
00638                      print_braces=1;
00639                      break;
00640               }
00641 
00642        if (print_braces)
00643               (*print_func)('<', ptr);
00644 
00645        for (addrbuf=p; *p; p++)
00646               (*print_func)(*p, ptr);
00647 
00648        if (print_braces)
00649               (*print_func)('>', ptr);
00650 
00651        free(addrbuf);
00652        return (0);
00653 }
00654 
00655 int rfc822_print(const struct rfc822a *rfcp, void (*print_func)(char, void *),
00656        void (*print_separator)(const char *s, void *), void *ptr)
00657 {
00658        return rfc822_print_common(rfcp, 0, 0, print_func, print_separator, ptr);
00659 }
00660 
00661 int rfc822_print_common(const struct rfc822a *rfcp,
00662                      char *(*decode_func)(const char *, const char *, int),
00663                      const char *chset,
00664                      void (*print_func)(char, void *),
00665                      void (*print_separator)(const char *, void *),
00666                      void *ptr)
00667 {
00668 const struct rfc822addr *addrs=rfcp->addrs;
00669 int naddrs=rfcp->naddrs;
00670 
00671        while (naddrs)
00672        {
00673               if (addrs->tokens == 0)
00674               {
00675                      rfc822tok_print(addrs->name, print_func, ptr);
00676                      ++addrs;
00677                      --naddrs;
00678                      if (addrs[-1].name && naddrs)
00679                      {
00680                      struct rfc822token *t;
00681 
00682                             for (t=addrs[-1].name; t && t->next; t=t->next)
00683                                    ;
00684 
00685                             if (t && (t->token == ':' || t->token == ';'))
00686                                    (*print_separator)(" ", ptr);
00687                      }
00688                      continue;
00689               }
00690               else if (addrs->name && addrs->name->token == '(')
00691               {      /* old style */
00692 
00693                      if (!decode_func)
00694                      {
00695                             rfc822tok_print(addrs->tokens, print_func, ptr);
00696                             (*print_func)(' ', ptr);
00697                             rfc822tok_print(addrs->name, print_func, ptr);
00698                      }
00699                      else
00700                      {
00701                             if (rfc822_print_common_nameaddr(addrs,
00702                                                          decode_func,
00703                                                          chset,
00704                                                          print_func,
00705                                                          ptr) < 0)
00706                                    return -1;
00707                      }
00708               }
00709               else
00710               {
00711                      if (!decode_func)
00712                      {
00713                             int    print_braces=0;
00714 
00715                             if (addrs->name)
00716                             {
00717                                    rfc822tok_print(addrs->name,
00718                                                  print_func, ptr);
00719                                    (*print_func)(' ', ptr);
00720                                    print_braces=1;
00721                             }
00722 #if 1
00723                             else
00724                             {
00725                                    struct rfc822token *p;
00726 
00727                                    for (p=addrs->tokens; p && p->next; p=p->next)
00728                                           if (rfc822_is_atom(p->token) &&
00729                                               rfc822_is_atom(p->next->token))
00730                                                  print_braces=1;
00731                             }
00732 #endif
00733 
00734                             if (print_braces)
00735                                    (*print_func)('<', ptr);
00736 
00737                             rfc822tok_print(addrs->tokens, print_func, ptr);
00738 
00739                             if (print_braces)
00740                                    (*print_func)('>', ptr);
00741                      }
00742                      else
00743                      {
00744                             if (rfc822_print_common_nameaddr(addrs,
00745                                                          decode_func,
00746                                                          chset,
00747                                                          print_func,
00748                                                          ptr) < 0)
00749                                    return -1;
00750                      }
00751               }
00752               ++addrs;
00753               --naddrs;
00754               if (naddrs)
00755                      if (addrs->tokens || (addrs->name &&
00756                             rfc822_is_atom(addrs->name->token)))
00757                             (*print_separator)(", ", ptr);
00758        }
00759        return 0;
00760 }
00761 
00762 void rfc822t_free(struct rfc822t *p)
00763 {
00764        if (p->tokens)       free(p->tokens);
00765        free(p);
00766 }
00767 
00768 void rfc822a_free(struct rfc822a *p)
00769 {
00770        if (p->addrs) free(p->addrs);
00771        free(p);
00772 }
00773 
00774 void rfc822_deladdr(struct rfc822a *rfcp, int index)
00775 {
00776 int    i;
00777 
00778        if (index < 0 || index >= rfcp->naddrs)   return;
00779 
00780        for (i=index+1; i<rfcp->naddrs; i++)
00781               rfcp->addrs[i-1]=rfcp->addrs[i];
00782        if (--rfcp->naddrs == 0)
00783        {
00784               free(rfcp->addrs);
00785               rfcp->addrs=0;
00786        }
00787 }
00788 
00789 struct rfc822t *rfc822t_alloc_new(const char *addr,
00790        void (*err_func)(const char *, int, void *), void *voidp)
00791 {
00792 struct rfc822t *p=(struct rfc822t *)malloc(sizeof(struct rfc822t));
00793 
00794        if (!p)       return (NULL);
00795        memset(p, 0, sizeof(*p));
00796 
00797        tokenize(addr, NULL, &p->ntokens, err_func, voidp);
00798        p->tokens=p->ntokens ? (struct rfc822token *)
00799                      calloc(p->ntokens, sizeof(struct rfc822token)):0;
00800        if (p->ntokens && !p->tokens)
00801        {
00802               rfc822t_free(p);
00803               return (NULL);
00804        }
00805        tokenize(addr, p->tokens, &p->ntokens, NULL, NULL);
00806        return (p);
00807 }
00808 
00809 struct rfc822a *rfc822a_alloc(struct rfc822t *t)
00810 {
00811 struct rfc822a *p=(struct rfc822a *)malloc(sizeof(struct rfc822a));
00812 
00813        if (!p)       return (NULL);
00814        memset(p, 0, sizeof(*p));
00815 
00816        parseaddr(t->tokens, t->ntokens, NULL, &p->naddrs);
00817        p->addrs=p->naddrs ? (struct rfc822addr *)
00818                      calloc(p->naddrs, sizeof(struct rfc822addr)):0;
00819        if (p->naddrs && !p->addrs)
00820        {
00821               rfc822a_free(p);
00822               return (NULL);
00823        }
00824        parseaddr(t->tokens, t->ntokens, p->addrs, &p->naddrs);
00825        return (p);
00826 }