rfc822.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:13k
- /*
- ** Copyright 1998 - 1999 Double Precision, Inc.
- ** See COPYING for distribution information.
- */
- /*
- ** $Id: rfc822.c,v 1.12 2000/02/23 02:41:19 mrsam Exp $
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include "rfc822.h"
- static void tokenize(const char *p, struct rfc822token *tokp, int *toklen,
- void (*err_func)(const char *, int))
- {
- const char *addr=p;
- int i=0;
- int inbracket=0;
- *toklen=0;
- while (*p)
- {
- if (isspace((int)(unsigned char)*p))
- {
- p++;
- i++;
- continue;
- }
- 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);
- 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);
- ++*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);
- ++p;
- ++i;
- continue;
- case '<':
- 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);
- ++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(
- "<>@,;:.[]()%!"\?=/", *p) == 0)
- {
- if (tokp) ++tokp->len;
- ++p;
- ++i;
- }
- if (i == 0) /* Idiot check */
- {
- if (err_func) (*err_func)(addr, i);
- if (tokp)
- {
- tokp->token='"';
- tokp->ptr=p;
- tokp->len=1;
- ++tokp;
- }
- ++*toklen;
- ++p;
- ++i;
- continue;
- }
- if (tokp) ++tokp;
- ++*toklen;
- }
- }
- }
- static void parseaddr(struct rfc822token *tokens, int ntokens,
- struct rfc822addr *addrs, int *naddrs)
- {
- int flag, j, k;
- struct rfc822token save_token;
- *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)
- {
- save_token.ptr=0;
- save_token.len=0;
- 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;
- }
- }
- static void print_token(const struct rfc822token *token,
- void (*print_func)(char, void *), void *ptr)
- {
- 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);
- }
- void rfc822tok_print(const struct rfc822token *token,
- void (*print_func)(char, void *), void *ptr)
- {
- 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;
- }
- }
- void rfc822_print(const struct rfc822a *rfcp, void (*print_func)(char, void *),
- void (*print_separator)(const char *s, void *), void *ptr)
- {
- rfc822_print_common(rfcp, 0, 0, print_func, print_separator, ptr);
- }
- void rfc822_print_common(const struct rfc822a *rfcp,
- char *(*decode_func)(const char *, const char *), const char *chset,
- void (*print_func)(char, void *),
- void (*print_separator)(const char *, void *), void *ptr)
- {
- 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 */
- char *p;
- rfc822tok_print(addrs->tokens, print_func, ptr);
- (*print_func)(' ', ptr);
- if (decode_func && (p=rfc822_gettok(addrs->name))!=0)
- {
- char *q= (*decode_func)(p, chset);
- char *r;
- for (r=q; r && *r; r++)
- (*print_func)( (int)(unsigned char)*r,
- ptr);
- if (q) free(q);
- free(p);
- }
- else rfc822tok_print(addrs->name, print_func, ptr);
- }
- else
- {
- int print_braces=0;
- char *p;
- if (addrs->name)
- {
- if (decode_func &&
- (p=rfc822_gettok(addrs->name)) != 0)
- {
- char *q= (*decode_func)(p, chset);
- char *r;
- for (r=q; r && *r; r++)
- (*print_func)(
- (int)(unsigned char)*r,
- ptr);
- if (q) free(q);
- free(p);
- }
- else rfc822tok_print(addrs->name,
- print_func, ptr);
- (*print_func)(' ', ptr);
- print_braces=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;
- }
- if (print_braces)
- (*print_func)('<', ptr);
- rfc822tok_print(addrs->tokens, print_func, ptr);
- if (print_braces)
- {
- (*print_func)('>', ptr);
- }
- }
- ++addrs;
- --naddrs;
- if (naddrs)
- if (addrs->tokens || (addrs->name &&
- rfc822_is_atom(addrs->name->token)))
- (*print_separator)(", ", ptr);
- }
- }
- void rfc822t_free(struct rfc822t *p)
- {
- if (p->tokens) free(p->tokens);
- free(p);
- }
- void rfc822a_free(struct rfc822a *p)
- {
- if (p->addrs) free(p->addrs);
- free(p);
- }
- void rfc822_deladdr(struct rfc822a *rfcp, int index)
- {
- 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;
- }
- }
- struct rfc822t *rfc822t_alloc(const char *addr,
- void (*err_func)(const char *, int))
- {
- 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);
- 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);
- return (p);
- }
- struct rfc822a *rfc822a_alloc(struct rfc822t *t)
- {
- 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);
- }
- void rfc822_praddr(const struct rfc822a *rfcp, int index,
- void (*print_func)(char, void *), void *ptr)
- {
- const struct rfc822addr *addrs;
- if (index < 0 || index >= rfcp->naddrs) return;
- addrs=rfcp->addrs+index;
- if (addrs->tokens)
- {
- rfc822tok_print(addrs->tokens, print_func, ptr);
- (*print_func)('n', ptr);
- }
- }
- void rfc822_addrlist(const struct rfc822a *rfcp,
- void (*print_func)(char, void *), void *ptr)
- {
- int i;
- for (i=0; i<rfcp->naddrs; i++)
- rfc822_praddr(rfcp, i, print_func, ptr);
- }
- void rfc822_prname(const struct rfc822a *rfcp, int index,
- void (*print_func)(char, void *), void *ptr)
- {
- const struct rfc822addr *addrs;
- if (index < 0 || index >= rfcp->naddrs) return;
- addrs=rfcp->addrs+index;
- if (!addrs->tokens) return;
- if (addrs->name)
- {
- 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 != '(')
- {
- print_token(i, print_func, ptr);
- continue;
- }
- for (n=2; n<i->len; n++)
- (*print_func)(i->ptr[n-1], ptr);
- }
- } else
- rfc822tok_print(addrs->tokens, print_func, ptr);
- (*print_func)('n', ptr);
- }
- void rfc822_namelist(const struct rfc822a *rfcp,
- void (*print_func)(char, void *), void *ptr)
- {
- int i;
- for (i=0; i<rfcp->naddrs; i++)
- rfc822_prname(rfcp, i, print_func, ptr);
- }