Back to index

courier  0.68.2
Defines | Functions
rfc822.c File Reference
#include "rfc822.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Defines

#define SPECIALS   "<>@,;:.[]()%!\"\\?=/"

Functions

static void tokenize (const char *p, struct rfc822token *tokp, int *toklen, void(*err_func)(const char *, int, void *), void *voidp)
static void parseaddr (struct rfc822token *tokens, int ntokens, struct rfc822addr *addrs, int *naddrs)
static void print_token (const struct rfc822token *token, void(*print_func)(char, void *), void *ptr)
void rfc822tok_print (const struct rfc822token *token, void(*print_func)(char, void *), void *ptr)
static void rfc822_prname_int (const struct rfc822addr *addrs, void(*print_func)(char, void *), void *ptr)
static void rfc822_print_common_nameaddr_cntlen (char c, void *p)
static void rfc822_print_common_nameaddr_saveaddr (char c, void *p)
static int rfc822_print_common_nameaddr (const struct rfc822addr *addrs, char *(*decode_func)(const char *, const char *, int), const char *chset, void(*print_func)(char, void *), void *ptr)
int rfc822_print (const struct rfc822a *rfcp, void(*print_func)(char, void *), void(*print_separator)(const char *s, void *), void *ptr)
int rfc822_print_common (const struct rfc822a *rfcp, char *(*decode_func)(const char *, const char *, int), const char *chset, void(*print_func)(char, void *), void(*print_separator)(const char *, void *), void *ptr)
void rfc822t_free (struct rfc822t *p)
void rfc822a_free (struct rfc822a *p)
void rfc822_deladdr (struct rfc822a *rfcp, int index)
struct rfc822trfc822t_alloc_new (const char *addr, void(*err_func)(const char *, int, void *), void *voidp)
struct rfc822arfc822a_alloc (struct rfc822t *t)

Define Documentation

#define SPECIALS   "<>@,;:.[]()%!\"\\?=/"

Function Documentation

static void parseaddr ( struct rfc822token tokens,
int  ntokens,
struct rfc822addr addrs,
int *  naddrs 
) [static]

Definition at line 247 of file rfc822.c.

{
int    flag, j, k;

       *naddrs=0;

       while (ntokens)
       {
       int    i;

              /* atoms (token=0) or quoted strings, followed by a : token
              is a list name. */

              for (i=0; i<ntokens; i++)
                     if (tokens[i].token && tokens[i].token != '"')
                            break;
              if (i < ntokens && tokens[i].token == ':')
              {
                     ++i;
                     if (addrs)
                     {
                            addrs->tokens=0;
                            addrs->name=i ? tokens:0;
                            for (j=1; j<i; j++)
                                   addrs->name[j-1].next=addrs->name+j;
                            if (i)
                                   addrs->name[i-1].next=0;
                            addrs++;
                     }
                     ++*naddrs;
                     tokens += i;
                     ntokens -= i;
                     continue;  /* Group=phrase ":" */
              }

              /* Spurious commas are skipped, ;s are recorded */

              if (tokens->token == ',' || tokens->token == ';')
              {
                     if (tokens->token == ';')
                     {
                            if (addrs)
                            {
                                   addrs->tokens=0;
                                   addrs->name=tokens;
                                   addrs->name->next=0;
                                   addrs++;
                            }
                            ++*naddrs;
                     }
                     ++tokens;
                     --ntokens;
                     continue;
              }

              /* If we can find a '<' before the next comma or semicolon,
              we have new style RFC path address */

              for (i=0; i<ntokens && tokens[i].token != ';' &&
                            tokens[i].token != ',' &&
                                   tokens[i].token != '<'; i++)
                     ;

              if (i < ntokens && tokens[i].token == '<')
              {
              int    j;

                     /* Ok -- what to do with the stuff before '>'???
                     If it consists exclusively of atoms, leave them alone.
                     Else, make them all a quoted string. */

                        for (j=0; j<i && (tokens[j].token == 0 ||
                                          tokens[j].token == '('); j++)
                                ;

                     if (j == i)
                     {
                            if (addrs)
                            {
                                   addrs->name= i ? tokens:0;
                                   for (k=1; k<i; k++)
                                          addrs->name[k-1].next=addrs->name+k;
                                   if (i)
                                          addrs->name[i-1].next=0;
                            }
                     }
                     else   /* Intentionally corrupt the original toks */
                     {
                            if (addrs)
                            {
                                   tokens->len= tokens[i-1].ptr
                                                 + tokens[i-1].len
                                                 - tokens->ptr;
                                   /* We know that all the ptrs point
                                   to parts of the same string. */
                                   tokens->token='"';
                                          /* Quoted string. */
                                   addrs->name=tokens;
                                   addrs->name->next=0;
                            }
                     }

              /* Any comments in the name part are changed to quotes */

                     if (addrs)
                     {
                     struct rfc822token *t;

                            for (t=addrs->name; t; t=t->next)
                                   if (t->token == '(')
                                          t->token='"';
                     }

                     /* Now that's done and over with, see what can
                     be done with the <...> part. */

                     ++i;
                     tokens += i;
                     ntokens -= i;
                     for (i=0; i<ntokens && tokens[i].token != '>'; i++)
                            ;
                     if (addrs)
                     {
                            addrs->tokens=i ? tokens:0;
                            for (k=1; k<i; k++)
                                   addrs->tokens[k-1].next=addrs->tokens+k;
                            if (i)
                                   addrs->tokens[i-1].next=0;
                            ++addrs;
                     }
                     ++*naddrs;
                     tokens += i;
                     ntokens -= i;
                     if (ntokens)  /* Skip the '>' token */
                     {
                            --ntokens;
                            ++tokens;
                     }
                     continue;
              }

              /* Ok - old style address.  Assume the worst */

              /* Try to figure out where the address ends.  It ends upon:
              a comma, semicolon, or two consecutive atoms. */

              flag=0;
              for (i=0; i<ntokens && tokens[i].token != ',' &&
                     tokens[i].token != ';'; i++)
              {
                     if (tokens[i].token == '(') continue;
                                   /* Ignore comments */
                     if (tokens[i].token == 0 || tokens[i].token == '"')
                                                        /* Atom */
                     {
                            if (flag)     break;
                            flag=1;
                     }
                     else   flag=0;
              }
              if (i == 0)   /* Must be spurious comma, or something */
              {
                     ++tokens;
                     --ntokens;
                     continue;
              }

              if (addrs)
              {
                     addrs->name=0;
              }

              /* Ok, now get rid of embedded comments in the address.
              Consider the last comment to be the real name */

              if (addrs)
              {
                     struct rfc822token   save_token;

                     memset(&save_token, 0, sizeof(save_token));

                     for (j=k=0; j<i; j++)
                     {
                            if (tokens[j].token == '(')
                            {
                                   save_token=tokens[j];
                                   continue;
                            }
                            tokens[k]=tokens[j];
                            k++;
                     }

                     if (save_token.ptr)
                     {
                            tokens[i-1]=save_token;
                            addrs->name=tokens+i-1;
                            addrs->name->next=0;
                     }
                     addrs->tokens=k ? tokens:NULL;
                     for (j=1; j<k; j++)
                            addrs->tokens[j-1].next=addrs->tokens+j;
                     if (k)
                            addrs->tokens[k-1].next=0;
                     ++addrs;
              }
              ++*naddrs;
              tokens += i;
              ntokens -= i;
       }
}

Here is the caller graph for this function:

static void print_token ( const struct rfc822token token,
void(*)(char, void *)  print_func,
void *  ptr 
) [static]

Definition at line 459 of file rfc822.c.

{
const char *p;
int    n;

       if (token->token == 0 || token->token == '(')
       {
              for (n=token->len, p=token->ptr; n; --n, ++p)
                     (*print_func)(*p, ptr);
              return;
       }

       if (token->token != '"')
       {
              (*print_func)(token->token, ptr);
              return;
       }

       (*print_func)('"', ptr);
       n=token->len;
       p=token->ptr;
       while (n)
       {
              if (*p == '"' || (*p == '\\' && n == 1)) (*print_func)('\\', ptr);
              if (*p == '\\' && n > 1)
              {
                     (*print_func)('\\', ptr);
                     ++p;
                     --n;
              }
              (*print_func)(*p++, ptr);
              --n;
       }
       (*print_func)('"', ptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc822_deladdr ( struct rfc822a rfcp,
int  index 
)

Definition at line 774 of file rfc822.c.

{
int    i;

       if (index < 0 || index >= rfcp->naddrs)   return;

       for (i=index+1; i<rfcp->naddrs; i++)
              rfcp->addrs[i-1]=rfcp->addrs[i];
       if (--rfcp->naddrs == 0)
       {
              free(rfcp->addrs);
              rfcp->addrs=0;
       }
}

Here is the caller graph for this function:

int rfc822_print ( const struct rfc822a rfcp,
void(*)(char, void *)  print_func,
void(*)(const char *s, void *)  print_separator,
void *  ptr 
)

Definition at line 655 of file rfc822.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int rfc822_print_common ( const struct rfc822a rfcp,
char *(*)(const char *, const char *, int)  decode_func,
const char *  chset,
void(*)(char, void *)  print_func,
void(*)(const char *, void *)  print_separator,
void *  ptr 
)

Definition at line 661 of file rfc822.c.

{
const struct rfc822addr *addrs=rfcp->addrs;
int naddrs=rfcp->naddrs;

       while (naddrs)
       {
              if (addrs->tokens == 0)
              {
                     rfc822tok_print(addrs->name, print_func, ptr);
                     ++addrs;
                     --naddrs;
                     if (addrs[-1].name && naddrs)
                     {
                     struct rfc822token *t;

                            for (t=addrs[-1].name; t && t->next; t=t->next)
                                   ;

                            if (t && (t->token == ':' || t->token == ';'))
                                   (*print_separator)(" ", ptr);
                     }
                     continue;
              }
              else if (addrs->name && addrs->name->token == '(')
              {      /* old style */

                     if (!decode_func)
                     {
                            rfc822tok_print(addrs->tokens, print_func, ptr);
                            (*print_func)(' ', ptr);
                            rfc822tok_print(addrs->name, print_func, ptr);
                     }
                     else
                     {
                            if (rfc822_print_common_nameaddr(addrs,
                                                         decode_func,
                                                         chset,
                                                         print_func,
                                                         ptr) < 0)
                                   return -1;
                     }
              }
              else
              {
                     if (!decode_func)
                     {
                            int    print_braces=0;

                            if (addrs->name)
                            {
                                   rfc822tok_print(addrs->name,
                                                 print_func, ptr);
                                   (*print_func)(' ', ptr);
                                   print_braces=1;
                            }
#if 1
                            else
                            {
                                   struct rfc822token *p;

                                   for (p=addrs->tokens; p && p->next; p=p->next)
                                          if (rfc822_is_atom(p->token) &&
                                              rfc822_is_atom(p->next->token))
                                                 print_braces=1;
                            }
#endif

                            if (print_braces)
                                   (*print_func)('<', ptr);

                            rfc822tok_print(addrs->tokens, print_func, ptr);

                            if (print_braces)
                                   (*print_func)('>', ptr);
                     }
                     else
                     {
                            if (rfc822_print_common_nameaddr(addrs,
                                                         decode_func,
                                                         chset,
                                                         print_func,
                                                         ptr) < 0)
                                   return -1;
                     }
              }
              ++addrs;
              --naddrs;
              if (naddrs)
                     if (addrs->tokens || (addrs->name &&
                            rfc822_is_atom(addrs->name->token)))
                            (*print_separator)(", ", ptr);
       }
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int rfc822_print_common_nameaddr ( const struct rfc822addr addrs,
char *(*)(const char *, const char *, int)  decode_func,
const char *  chset,
void(*)(char, void *)  print_func,
void *  ptr 
) [static]

Definition at line 564 of file rfc822.c.

{
       size_t n=1;
       char *addrbuf, *namebuf;
       char *p, *q;
       int print_braces=0;

       if (addrs->tokens)
              rfc822tok_print(addrs->tokens,
                            rfc822_print_common_nameaddr_cntlen, &n);


       p=addrbuf=malloc(n);

       if (!addrbuf)
              return -1;

       if (addrs->tokens)
              rfc822tok_print(addrs->tokens,
                            rfc822_print_common_nameaddr_saveaddr, &p);

       *p=0;

       n=1;

       rfc822_prname_int(addrs,
                       rfc822_print_common_nameaddr_cntlen, &n);

       p=namebuf=malloc(n);

       if (!p)
       {
              free(addrbuf);
              return -1;
       }

       rfc822_prname_int(addrs,
                       rfc822_print_common_nameaddr_saveaddr, &p);

       *p=0;

       p=(*decode_func)(namebuf, chset, 0);

       free(namebuf);
       if (!p)
       {
              free(addrbuf);
              return -1;
       }

       for (namebuf=p; *p; p++)
       {
              print_braces=1;
              (*print_func)(*p, ptr);
       }
       free(namebuf);

       p=(*decode_func)(addrbuf, chset, 1);
       free(addrbuf);

       if (!p)
              return -1;

       if (print_braces)
              (*print_func)(' ', ptr);

       for (q=p; *q; ++q)
              if (*q != '.' && *q != '@' && strchr(RFC822_SPECIALS, *q))
              {
                     print_braces=1;
                     break;
              }

       if (print_braces)
              (*print_func)('<', ptr);

       for (addrbuf=p; *p; p++)
              (*print_func)(*p, ptr);

       if (print_braces)
              (*print_func)('>', ptr);

       free(addrbuf);
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rfc822_print_common_nameaddr_cntlen ( char  c,
void *  p 
) [static]

Definition at line 552 of file rfc822.c.

{
       ++ *(size_t *)p;
}

Here is the caller graph for this function:

static void rfc822_print_common_nameaddr_saveaddr ( char  c,
void *  p 
) [static]

Definition at line 557 of file rfc822.c.

{
       char **cp=(char **)p;

       *(*cp)++=c;
}

Here is the caller graph for this function:

static void rfc822_prname_int ( const struct rfc822addr addrs,
void(*)(char, void *)  print_func,
void *  ptr 
) [static]

Definition at line 513 of file rfc822.c.

{
       struct rfc822token *i;
       int n;
       int    prev_isatom=0;
       int    isatom=0;

       for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
       {
              isatom=rfc822_is_atom(i->token);
              if (isatom && prev_isatom)
                     (*print_func)(' ', ptr);

              if (i->token == '"')
              {
                     for (n=0; n<i->len; n++)
                     {
                            if (i->ptr[n] == '\\' &&
                                n + 1 < i->len)
                                   ++n;
                            (*print_func)(i->ptr[n], ptr);
                     }
                     continue;
              }

              if (i->token != '(')
              {
                     print_token(i, print_func, ptr);
                     continue;
              }

              for (n=2; n<i->len; n++)
                     (*print_func)(i->ptr[n-1], ptr);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct rfc822a* rfc822a_alloc ( struct rfc822t t) [read]

Definition at line 809 of file rfc822.c.

{
struct rfc822a *p=(struct rfc822a *)malloc(sizeof(struct rfc822a));

       if (!p)       return (NULL);
       memset(p, 0, sizeof(*p));

       parseaddr(t->tokens, t->ntokens, NULL, &p->naddrs);
       p->addrs=p->naddrs ? (struct rfc822addr *)
                     calloc(p->naddrs, sizeof(struct rfc822addr)):0;
       if (p->naddrs && !p->addrs)
       {
              rfc822a_free(p);
              return (NULL);
       }
       parseaddr(t->tokens, t->ntokens, p->addrs, &p->naddrs);
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc822a_free ( struct rfc822a p)

Definition at line 768 of file rfc822.c.

{
       if (p->addrs) free(p->addrs);
       free(p);
}

Here is the caller graph for this function:

struct rfc822t* rfc822t_alloc_new ( const char *  addr,
void(*)(const char *, int, void *)  err_func,
void *  voidp 
) [read]

Definition at line 789 of file rfc822.c.

{
struct rfc822t *p=(struct rfc822t *)malloc(sizeof(struct rfc822t));

       if (!p)       return (NULL);
       memset(p, 0, sizeof(*p));

       tokenize(addr, NULL, &p->ntokens, err_func, voidp);
       p->tokens=p->ntokens ? (struct rfc822token *)
                     calloc(p->ntokens, sizeof(struct rfc822token)):0;
       if (p->ntokens && !p->tokens)
       {
              rfc822t_free(p);
              return (NULL);
       }
       tokenize(addr, p->tokens, &p->ntokens, NULL, NULL);
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void rfc822t_free ( struct rfc822t p)

Definition at line 762 of file rfc822.c.

{
       if (p->tokens)       free(p->tokens);
       free(p);
}

Here is the caller graph for this function:

void rfc822tok_print ( const struct rfc822token token,
void(*)(char, void *)  print_func,
void *  ptr 
)

Definition at line 496 of file rfc822.c.

{
int    prev_isatom=0;
int    isatom;

       while (token)
       {
              isatom=rfc822_is_atom(token->token);
              if (prev_isatom && isatom)
                     (*print_func)(' ', ptr);
              print_token(token, print_func, ptr);
              prev_isatom=isatom;
              token=token->next;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tokenize ( const char *  p,
struct rfc822token tokp,
int *  toklen,
void(*)(const char *, int, void *)  err_func,
void *  voidp 
) [static]

Definition at line 14 of file rfc822.c.

{
const char *addr=p;
int    i=0;
int    inbracket=0;

       *toklen=0;
       while (*p)
       {
              if (isspace((int)(unsigned char)*p))
              {
                     p++;
                     i++;
                     continue;
              }

#define SPECIALS "<>@,;:.[]()%!\"\\?=/"

              switch (*p)   {
              int    level;

              case '(':
                     if (tokp)
                     {
                            tokp->token='(';
                            tokp->ptr=p;
                            tokp->len=0;
                     }
                     level=0;
                     for (;;)
                     {
                            if (!*p)
                            {
                                   if (err_func) (*err_func)(addr, i,
                                                          voidp);
                                   if (tokp) tokp->token='"';
                                   ++*toklen;
                                   return;
                            }
                            if (*p == '(')
                                   ++level;
                            if (*p == ')' && --level == 0)
                            {
                                   p++;
                                   i++;
                                   if (tokp)     tokp->len++;
                                   break;
                            }
                            if (*p == '\\' && p[1])
                            {
                                   p++;
                                   i++;
                                   if (tokp)     tokp->len++;
                            }

                            i++;
                            if (tokp)     tokp->len++;
                            p++;
                     }
                     if (tokp)     ++tokp;
                     ++*toklen;
                     continue;

              case '"':
                     p++;
                     i++;

                     if (tokp)
                     {
                            tokp->token='"';
                            tokp->ptr=p;
                     }
                     while (*p != '"')
                     {
                            if (!*p)
                            {
                                   if (err_func) (*err_func)(addr, i,
                                                          voidp);
                                   ++*toklen;
                                   return;
                            }
                            if (*p == '\\' && p[1])
                            {
                                   if (tokp)     tokp->len++;
                                   p++;
                                   i++;
                            }
                            if (tokp)     tokp->len++;
                            p++;
                            i++;
                     }
                     ++*toklen;
                     if (tokp)     ++tokp;
                     p++;
                     i++;
                     continue;
              case '\\':
              case ')':
                     if (err_func) (*err_func)(addr, i, voidp);
                     ++p;
                     ++i;
                     continue;

              case '=':

                     if (p[1] == '?')
                     {
                            int j;

                     /* exception: =? ... ?= */

                            for (j=2; p[j]; j++)
                            {
                                   if (p[j] == '?' && p[j+1] == '=')
                                          break;

                                   if (p[j] == '?' || p[j] == '=')
                                          continue;

                                   if (strchr(RFC822_SPECIALS, p[j]) ||
                                       isspace(p[j]))
                                          break;
                            }

                            if (p[j] == '?' && p[j+1] == '=')
                            {
                                   j += 2;
                                   if (tokp)
                                   {
                                          tokp->token=0;
                                          tokp->ptr=p;
                                          tokp->len=j;
                                          ++tokp;
                                   }
                                   ++*toklen;

                                   p += j;
                                   i += j;
                                   continue;
                            }
                     }
                     /* FALLTHROUGH */

              case '<':
              case '>':
              case '@':
              case ',':
              case ';':
              case ':':
              case '.':
              case '[':
              case ']':
              case '%':
              case '!':
              case '?':
              case '/':

                     if ( (*p == '<' && inbracket) ||
                            (*p == '>' && !inbracket))
                     {
                            if (err_func) (*err_func)(addr, i, voidp);
                            ++p;
                            ++i;
                            continue;
                     }

                     if (*p == '<')
                            inbracket=1;

                     if (*p == '>')
                            inbracket=0;

                     if (tokp)
                     {
                            tokp->token= *p;
                            tokp->ptr=p;
                            tokp->len=1;
                            ++tokp;
                     }
                     ++*toklen;

                     if (*p == '<' && p[1] == '>')
                                   /* Fake a null address */
                     {
                            if (tokp)
                            {
                                   tokp->token=0;
                                   tokp->ptr="";
                                   tokp->len=0;
                                   ++tokp;
                            }
                            ++*toklen;
                     }
                     ++p;
                     ++i;
                     continue;
              default:

                     if (tokp)
                     {
                            tokp->token=0;
                            tokp->ptr=p;
                            tokp->len=0;
                     }
                     while (*p && !isspace((int)(unsigned char)*p) && strchr(
                            SPECIALS, *p) == 0)
                     {
                            if (tokp)     ++tokp->len;
                            ++p;
                            ++i;
                     }
                     if (i == 0)   /* Idiot check */
                     {
                            if (err_func) (*err_func)(addr, i, voidp);
                            if (tokp)
                            {
                                   tokp->token='"';
                                   tokp->ptr=p;
                                   tokp->len=1;
                                   ++tokp;
                            }
                            ++*toklen;
                            ++p;
                            ++i;
                            continue;
                     }
                     if (tokp)     ++tokp;
                     ++*toklen;
              }
       }
}

Here is the caller graph for this function: