rfc2047.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:10k
- /*
- ** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
- ** distribution information.
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include "rfc822.h"
- #include "rfc2047.h"
- static const char rcsid[]="$Id: rfc2047.c,v 1.1 2000/02/23 02:41:19 mrsam Exp $";
- static const char xdigit[]="0123456789ABCDEF";
- static char *rfc2047_search_quote(const char **ptr)
- {
- const char *p= *ptr;
- char *s;
- while (**ptr && **ptr != '?')
- ++ *ptr;
- if ((s=malloc( *ptr - p + 1)) == 0)
- return (0);
- memcpy(s, p, *ptr-p);
- s[*ptr - p]=0;
- return (s);
- }
- static int nyb(int c)
- {
- const char *p;
- c=toupper( (int)(unsigned char)c );
- p=strchr(xdigit, c);
- return (p ? p-xdigit:0);
- }
- static unsigned char decode64tab[256];
- static int decode64tab_init=0;
- static size_t decodebase64(char *ptr, size_t cnt)
- {
- size_t i, j;
- char a,b,c;
- size_t k;
- if (!decode64tab_init)
- {
- for (i=0; i<256; i++) decode64tab[i]=0;
- for (i=0; i<64; i++)
- decode64tab[ (int)
- ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i])]=i;
- decode64tab[ (int)'=' ] = 99;
- }
- i=cnt / 4;
- i=i*4;
- k=0;
- for (j=0; j<i; j += 4)
- {
- int w=decode64tab[(int)(unsigned char)ptr[j]];
- int x=decode64tab[(int)(unsigned char)ptr[j+1]];
- int y=decode64tab[(int)(unsigned char)ptr[j+2]];
- int z=decode64tab[(int)(unsigned char)ptr[j+3]];
- a= (w << 2) | (x >> 4);
- b= (x << 4) | (y >> 2);
- c= (y << 6) | z;
- ptr[k++]=a;
- if ( ptr[j+2] != '=')
- ptr[k++]=b;
- if ( ptr[j+3] != '=')
- ptr[k++]=c;
- }
- return (k);
- }
- /*
- ** This is the main rfc2047 decoding function. It receives rfc2047-encoded
- ** text, and a callback function. The callback function is repeatedly
- ** called, each time receiving a piece of decoded text. The decoded
- ** info includes a text fragment - string, string length arg - followed
- ** by the character set, followed by a context pointer that is received
- ** from the caller. If the callback function returns non-zero, rfc2047
- ** decoding terminates, returning the result code. Otherwise,
- ** rfc2047_decode returns 0 after a successfull decoding (-1 if malloc
- ** failed).
- */
- int rfc2047_decode(const char *text, int (*func)(const char *, int,
- const char *, void *),
- void *arg)
- {
- int rc;
- int had_last_word=0;
- const char *p;
- char *chset;
- char *encoding;
- char *enctext;
- while (text && *text)
- {
- if (text[0] != '=' || text[1] != '?')
- {
- p=text;
- while (*text)
- {
- if (text[0] == '=' && text[1] == '?')
- break;
- if (!isspace((int)(unsigned char)*text))
- had_last_word=0;
- ++text;
- }
- if (text > p && !had_last_word)
- {
- rc=(*func)(p, text-p, 0, arg);
- if (rc) return (rc);
- }
- continue;
- }
- text += 2;
- if ((chset=rfc2047_search_quote( &text )) == 0)
- return (-1);
- if (*text) ++text;
- if ((encoding=rfc2047_search_quote( &text )) == 0)
- {
- free(chset);
- return (-1);
- }
- if (*text) ++text;
- if ((enctext=rfc2047_search_quote( &text )) == 0)
- {
- free(encoding);
- free(chset);
- return (-1);
- }
- if (*text == '?' && text[1] == '=')
- text += 2;
- if (strcmp(encoding, "Q") == 0 || strcmp(encoding, "q") == 0)
- {
- char *q, *r;
- for (q=r=enctext; *q; )
- {
- if (*q == '=' && q[1] && q[2])
- {
- *r++ = (char)(
- nyb(q[1])*16+nyb(q[2]));
- q += 3;
- continue;
- }
- *r++ = *q++ ;
- }
- *r=0;
- }
- else if (strcmp(encoding, "B") == 0 || strcmp(encoding, "b")==0)
- {
- enctext[decodebase64(enctext, strlen(enctext))]=0;
- }
- rc=(*func)(enctext, strlen(enctext), chset, arg);
- free(enctext);
- free(chset);
- free(encoding);
- if (rc) return (rc);
- had_last_word=1; /* Ignore blanks between enc words */
- }
- return (0);
- }
- /*
- ** rfc2047_decode_simple just strips out the rfc2047 decoding, throwing away
- ** the character set. This is done by calling rfc2047_decode twice, once
- ** to count the number of characters in the decoded text, the second time to
- ** actually do it.
- */
- struct simple_info {
- char *string;
- int index;
- const char *mychset;
- } ;
- static int count_simple(const char *txt, int len, const char *chset,
- void *arg)
- {
- struct simple_info *iarg= (struct simple_info *)arg;
- iarg->index += len;
- return (0);
- }
- static int save_simple(const char *txt, int len, const char *chset,
- void *arg)
- {
- struct simple_info *iarg= (struct simple_info *)arg;
- memcpy(iarg->string+iarg->index, txt, len);
- iarg->index += len;
- return (0);
- }
- char *rfc2047_decode_simple(const char *text)
- {
- struct simple_info info;
- info.index=1;
- if (rfc2047_decode(text, &count_simple, &info))
- return (0);
- if ((info.string=malloc(info.index)) == 0) return (0);
- info.index=0;
- if (rfc2047_decode(text, &save_simple, &info))
- {
- free(info.string);
- return (0);
- }
- info.string[info.index]=0;
- return (info.string);
- }
- /*
- ** rfc2047_decode_enhanced is like simply, but prefixes the character set
- ** name before the text, in brackets.
- */
- static int do_enhanced(const char *txt, int len, const char *chset,
- void *arg,
- int (*func)(const char *, int, const char *, void *)
- )
- {
- int rc=0;
- struct simple_info *info=(struct simple_info *)arg;
- if (chset && info->mychset && strcmp(chset, info->mychset) == 0)
- chset=0;
- if (chset)
- {
- rc= (*func)(" [", 2, 0, arg);
- if (rc == 0)
- rc= (*func)(chset, strlen(chset), 0, arg);
- if (rc == 0)
- rc= (*func)("] ", 2, 0, arg);
- }
- if (rc == 0)
- rc= (*func)(txt, len, 0, arg);
- return (rc);
- }
- static int count_enhanced(const char *txt, int len, const char *chset,
- void *arg)
- {
- return (do_enhanced(txt, len, chset, arg, &count_simple));
- }
- static int save_enhanced(const char *txt, int len, const char *chset,
- void *arg)
- {
- return (do_enhanced(txt, len, chset, arg, &save_simple));
- }
- char *rfc2047_decode_enhanced(const char *text, const char *mychset)
- {
- struct simple_info info;
- info.mychset=mychset;
- info.index=1;
- if (rfc2047_decode(text, &count_enhanced, &info))
- return (0);
- if ((info.string=malloc(info.index)) == 0) return (0);
- info.index=0;
- if (rfc2047_decode(text, &save_enhanced, &info))
- {
- free(info.string);
- return (0);
- }
- info.string[info.index]=0;
- return (info.string);
- }
- void rfc2047_print(const struct rfc822a *a,
- const char *charset,
- void (*print_func)(char, void *),
- void (*print_separator)(const char *, void *), void *ptr)
- {
- rfc822_print_common(a, &rfc2047_decode_enhanced, charset,
- print_func, print_separator, ptr);
- }
- static char *a_rfc2047_encode_str(const char *str, const char *charset);
- static void rfc2047_encode_header_do(const struct rfc822a *a,
- const char *charset,
- void (*print_func)(char, void *),
- void (*print_separator)(const char *, void *), void *ptr)
- {
- rfc822_print_common(a, &a_rfc2047_encode_str, charset,
- print_func, print_separator, ptr);
- }
- /*
- ** When MIMEifying names from an RFC822 list of addresses, strip quotes
- ** before MIMEifying them, and add them afterwards.
- */
- static char *a_rfc2047_encode_str(const char *str, const char *charset)
- {
- size_t l=strlen(str);
- char *p, *s;
- if (*str != '"' || str[l-1] != '"')
- return (rfc2047_encode_str(str, charset));
- p=malloc(l);
- if (!p) return (0);
- memcpy(p, str+1, l-2);
- p[l-2]=0;
- s=rfc2047_encode_str(p, charset);
- free(p);
- if (!s) return (0);
- p=malloc(strlen(s)+3);
- if (!p)
- {
- free(s);
- return (0);
- }
- p[0]='"';
- strcpy(p+1, s);
- strcat(p, """);
- free(s);
- return (p);
- }
- static void count(char c, void *p);
- static void counts(const char *c, void *p);
- static void save(char c, void *p);
- static void saves(const char *c, void *p);
- char *rfc2047_encode_header(const struct rfc822a *a,
- const char *charset)
- {
- size_t l;
- char *s, *p;
- l=1;
- rfc2047_encode_header_do(a, charset, &count, &counts, &l);
- if ((s=malloc(l)) == 0) return (0);
- p=s;
- rfc2047_encode_header_do(a, charset, &save, &saves, &p);
- *p=0;
- return (s);
- }
- static void count(char c, void *p)
- {
- ++*(size_t *)p;
- }
- static void counts(const char *c, void *p)
- {
- while (*c) count(*c++, p);
- }
- static void save(char c, void *p)
- {
- **(char **)p=c;
- ++*(char **)p;
- }
- static void saves(const char *c, void *p)
- {
- while (*c) save(*c++, p);
- }
- int rfc2047_encode_callback(const char *str, const char *charset,
- int (*func)(const char *, size_t, void *), void *arg)
- {
- int rc;
- while (*str)
- {
- size_t i, c;
- for (i=0; str[i]; i++)
- if ((str[i] & 0x80) || str[i] == '"')
- break;
- if (str[i] == 0)
- return ( i ? (*func)(str, i, arg):0);
- /* Find start of word */
- while (i)
- {
- --i;
- if (isspace((int)(unsigned char)str[i]))
- {
- ++i;
- break;
- }
- }
- if (i)
- {
- rc= (*func)(str, i, arg);
- if (rc) return (rc);
- str += i;
- }
- for (i=0; str[i]; i++)
- if (isspace((int)(unsigned char)str[i]))
- break;
- /* Output mimeified text, insert spaces at 70+ character
- ** boundaries for line wrapping.
- */
- c=0;
- while (i)
- {
- if (c == 0)
- {
- if ( (rc=(*func)("=?", 2, arg)) != 0 ||
- (rc=(*func)(charset, strlen(charset),
- arg)) != 0 ||
- (rc=(*func)("?Q?", 3, arg)) != 0)
- return (rc);
- c += strlen(charset)+5;
- }
- if ((*str & 0x80) || *str == '"')
- {
- char buf[3];
- buf[0]='=';
- buf[1]=xdigit[ ( *str >> 4) & 0x0F ];
- buf[2]=xdigit[ *str & 0x0F ];
- if ( (rc=(*func)(buf, 3, arg)) != 0)
- return (rc);
- c += 3;
- ++str;
- --i;
- }
- else
- {
- size_t j;
- for (j=0; j < i && !(str[j] & 0x80) &&
- str[j] != '"'; j++)
- if (j + c >= 70)
- break;
- if ( (rc=(*func)(str, j, arg)) != 0)
- return (rc);
- c += j;
- str += j;
- i -= j;
- }
- if (i == 0 || c >= 70)
- {
- if ( (rc=(*func)("?= ", i ? 3:2, arg)) != 0)
- return (rc);
-
- c=0;
- }
- }
- }
- return (0);
- }
- static int count_char(const char *c, size_t l, void *p)
- {
- size_t *i=(size_t *)p;
- *i += l;
- return (0);
- }
- static int save_char(const char *c, size_t l, void *p)
- {
- char **s=(char **)p;
- memcpy(*s, c, l);
- *s += l;
- return (0);
- }
- char *rfc2047_encode_str(const char *str, const char *charset)
- {
- size_t i=1;
- char *s, *p;
- (void)rfc2047_encode_callback(str, charset, &count_char, &i);
- if ((s=malloc(i)) == 0) return (0);
- p=s;
- (void)rfc2047_encode_callback(str, charset, &save_char, &p);
- *p=0;
- return (s);
- }