clib package
This commit is contained in:
471
packages/clib/maildrop/rfc2045/rfc2045rewrite.c
Normal file
471
packages/clib/maildrop/rfc2045/rfc2045rewrite.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
|
||||
** distribution information.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "rfc2045.h"
|
||||
#include "rfc2045charset.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#if HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
#define strcasecmp stricmp
|
||||
#define strncasecmp strnicmp
|
||||
#if (_MSC_VER < 1300)
|
||||
#define write _write
|
||||
#endif
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
static char *rw_boundary_root;
|
||||
static int rw_boundary_cnt;
|
||||
static const char *rw_appname;
|
||||
|
||||
static FILE *fdin;
|
||||
static int fdout;
|
||||
static int (*fdout_func)(const char *, int, void *);
|
||||
static void *fdout_arg;
|
||||
|
||||
static char fdout_buf[512];
|
||||
static char *fdout_ptr;
|
||||
static size_t fdout_left;
|
||||
|
||||
/* Quoted printable encoding */
|
||||
static void qpe_start();
|
||||
static int qpe_do(const char *, size_t, void *);
|
||||
static void qpe_end();
|
||||
static int conv_err;
|
||||
|
||||
static int fdout_flush()
|
||||
{
|
||||
int n=fdout_ptr-fdout_buf;
|
||||
int i=0;
|
||||
char *p=fdout_buf;
|
||||
|
||||
while (n)
|
||||
{
|
||||
i=fdout_func ? (*fdout_func)(p, n, fdout_arg):
|
||||
write(fdout, p, n);
|
||||
if (i <= 0) return (-1);
|
||||
p += i;
|
||||
n -= i;
|
||||
}
|
||||
fdout_ptr=fdout_buf;
|
||||
fdout_left=sizeof(fdout_buf);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fdout_add(const char *p, size_t cnt)
|
||||
{
|
||||
while (cnt)
|
||||
{
|
||||
if (cnt < fdout_left)
|
||||
{
|
||||
memcpy(fdout_ptr, p, cnt);
|
||||
fdout_ptr += cnt;
|
||||
fdout_left -= cnt;
|
||||
return (0);
|
||||
}
|
||||
if (fdout_left == 0)
|
||||
{
|
||||
if (fdout_flush()) return (-1);
|
||||
continue;
|
||||
}
|
||||
memcpy(fdout_ptr, p, fdout_left);
|
||||
p += fdout_left;
|
||||
cnt -= fdout_left;
|
||||
fdout_ptr += fdout_left;
|
||||
fdout_left=0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int do_8bit(const char *p, size_t cnt, void *ptr)
|
||||
{
|
||||
if (fdout_add(p, cnt))
|
||||
conv_err=1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fdout_autoconverted(const char *oldte, const char *newte)
|
||||
{
|
||||
if (fdout_add("X-Mime-Autoconverted: from ", 27) ||
|
||||
fdout_add(oldte, strlen(oldte)) ||
|
||||
fdout_add(" to ", 4) ||
|
||||
fdout_add(newte, strlen(newte)) ||
|
||||
(rw_appname && (fdout_add(" by ", 4) ||
|
||||
fdout_add(rw_appname, strlen(rw_appname)))) ||
|
||||
fdout_add("\n", 1)) return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fdout_value(const char *);
|
||||
|
||||
static int fdout_attr(const struct rfc2045attr *a)
|
||||
{
|
||||
if (fdout_add(a->name, strlen(a->name))) return (-1);
|
||||
if (a->value && (fdout_add("=", 1) || fdout_value(a->value)))
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int fdout_value(const char *v)
|
||||
{
|
||||
size_t i,j;
|
||||
|
||||
for (i=0; v[i]; i++)
|
||||
{
|
||||
if ( !isalnum((int)(unsigned char)v[i]) && v[i] != '-')
|
||||
{
|
||||
if (fdout_add("\"", 1)) return (-1);
|
||||
for (j=i=0; v[i]; i++)
|
||||
if (v[i] == '\\' || v[i] == '"')
|
||||
{
|
||||
if (fdout_add(v+j, i-j) ||
|
||||
fdout_add("\\", 1))
|
||||
return (-1);
|
||||
j=i;
|
||||
}
|
||||
if (fdout_add(v+j, i-j) || fdout_add("\"", 1))
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (fdout_add(v, i));
|
||||
}
|
||||
|
||||
#define TE(p) ((p)->rw_transfer_encoding ? \
|
||||
(p)->rw_transfer_encoding: (p)->content_transfer_encoding)
|
||||
|
||||
static int rwmime(struct rfc2045 *p)
|
||||
{
|
||||
static char mimever[]="Mime-Version: 1.0\n";
|
||||
const char *te;
|
||||
struct rfc2045attr *a;
|
||||
|
||||
if (!p->parent)
|
||||
if (fdout_add(mimever, sizeof(mimever)-1)) return (-1);
|
||||
|
||||
if (p->content_type)
|
||||
{
|
||||
if (fdout_add("Content-Type: ", 14) ||
|
||||
fdout_add(p->content_type, strlen(p->content_type)))
|
||||
return (-1);
|
||||
|
||||
for (a=p->content_type_attr; a; a=a->next)
|
||||
{
|
||||
if (!a->name || strcmp(a->name, "boundary") == 0)
|
||||
continue;
|
||||
if ( fdout_add("; ", 2) ||
|
||||
fdout_attr(a)) return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (p->firstpart
|
||||
&& p->firstpart->next /* ADDED 8/30/99, see below */)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
++rw_boundary_cnt;
|
||||
sprintf(buf, "-%d", rw_boundary_cnt);
|
||||
if ( fdout_add("; boundary=\"", 12) ||
|
||||
fdout_add(rw_boundary_root, strlen(rw_boundary_root)) ||
|
||||
fdout_add(buf, strlen(buf)) ||
|
||||
fdout_add("\"", 1)) return (-1);
|
||||
}
|
||||
if (fdout_add("\n", 1)) return (-1);
|
||||
|
||||
/* Show content transfer encoding for top section, or if it's
|
||||
** different than the parent.
|
||||
*/
|
||||
te=TE(p);
|
||||
if (te && (!p->parent || strcmp(te, TE(p->parent))))
|
||||
{
|
||||
if (fdout_add("Content-Transfer-Encoding: ", 27) ||
|
||||
fdout_add(te, strlen(te)) ||
|
||||
fdout_add("\n", 1)) return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int dorw(struct rfc2045 *p)
|
||||
{
|
||||
/* WTF STATIC??? */ int seen_mime=0;
|
||||
char buf[256];
|
||||
int c;
|
||||
int bcnt;
|
||||
|
||||
if (fseek(fdin, p->startpos, SEEK_SET) == -1) return (-1);
|
||||
if (p->parent)
|
||||
{
|
||||
seen_mime=1;
|
||||
if (rwmime(p)) return (-1);
|
||||
}
|
||||
while (fgets(buf, sizeof(buf), fdin))
|
||||
{
|
||||
if (buf[0] == '\n') break;
|
||||
|
||||
if (RFC2045_ISMIME1DEF(p->mime_version) &&
|
||||
strncasecmp(buf, "mime-version:", 13) == 0 &&
|
||||
!seen_mime)
|
||||
{
|
||||
seen_mime=1;
|
||||
rwmime(p);
|
||||
if (strchr(buf, '\n') == NULL)
|
||||
while ((c=getc(fdin)) >= 0 && c != '\n')
|
||||
;
|
||||
while ((c=getc(fdin)) >= 0 && c != '\n' && isspace(c))
|
||||
while ((c=getc(fdin)) >= 0 && c != '\n')
|
||||
;
|
||||
if (c >= 0) ungetc(c, fdin);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!RFC2045_ISMIME1DEF(p->mime_version) || (
|
||||
strncasecmp(buf, "mime-version:", 13) &&
|
||||
strncasecmp(buf, "content-type:", 13) &&
|
||||
strncasecmp(buf, "content-transfer-encoding:", 26))
|
||||
)
|
||||
{
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
if (fdout_add(buf, strlen(buf)))
|
||||
return (-1);
|
||||
} while (strchr(buf, '\n') == NULL &&
|
||||
fgets(buf, sizeof(buf), fdin));
|
||||
|
||||
c=getc(fdin);
|
||||
if (c >= 0) ungetc(c, fdin);
|
||||
} while (c >= 0 && c != '\n' && isspace(c) &&
|
||||
fgets(buf, sizeof(buf), fdin));
|
||||
}
|
||||
else
|
||||
while ( (c=getc(fdin)) >= 0 &&
|
||||
(ungetc(c, fdin), c) != '\n' && isspace(c))
|
||||
{
|
||||
while (fgets(buf, sizeof(buf), fdin) &&
|
||||
strchr(buf, '\n') == NULL)
|
||||
;
|
||||
}
|
||||
}
|
||||
if (RFC2045_ISMIME1DEF(p->mime_version))
|
||||
{
|
||||
if (!seen_mime)
|
||||
if (rwmime(p)) return (-1);
|
||||
|
||||
if (!p->firstpart && p->rw_transfer_encoding)
|
||||
if (fdout_autoconverted(p->content_transfer_encoding,
|
||||
p->rw_transfer_encoding)) return (-1);
|
||||
}
|
||||
|
||||
if (fdout_add("\n", 1)) return (-1);
|
||||
if (fseek(fdin, p->startbody, SEEK_SET) == -1) return (-1);
|
||||
|
||||
/* For non-multipart section, just print the body */
|
||||
|
||||
if (!p->firstpart)
|
||||
{
|
||||
off_t ps=p->startbody;
|
||||
int convmode=0;
|
||||
|
||||
if (p->rw_transfer_encoding)
|
||||
{
|
||||
if ( strcasecmp(p->rw_transfer_encoding,
|
||||
"quoted-printable") == 0)
|
||||
convmode=RFC2045_RW_7BIT;
|
||||
else
|
||||
convmode=RFC2045_RW_8BIT;
|
||||
}
|
||||
|
||||
conv_err=0;
|
||||
if (convmode == RFC2045_RW_7BIT)
|
||||
{
|
||||
qpe_start();
|
||||
rfc2045_cdecode_start(p, &qpe_do, 0);
|
||||
}
|
||||
|
||||
if (convmode == RFC2045_RW_8BIT)
|
||||
{
|
||||
rfc2045_cdecode_start(p, &do_8bit, 0);
|
||||
}
|
||||
|
||||
while (ps < p->endbody)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (p->endbody - ps > sizeof(buf))
|
||||
n=sizeof(buf);
|
||||
else n=p->endbody-ps;
|
||||
n=fread(buf, 1, n, fdin);
|
||||
if (n <= 0) return (-1);
|
||||
if (convmode)
|
||||
rfc2045_cdecode(p, buf, n);
|
||||
else if (fdout_add(buf, n)) conv_err=1;
|
||||
ps += n;
|
||||
if (conv_err) break;
|
||||
}
|
||||
if (convmode == RFC2045_RW_7BIT)
|
||||
{
|
||||
rfc2045_cdecode_end(p);
|
||||
qpe_end();
|
||||
}
|
||||
if (convmode == RFC2045_RW_8BIT)
|
||||
{
|
||||
rfc2045_cdecode_end(p);
|
||||
}
|
||||
if (conv_err) return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
bcnt=rw_boundary_cnt;
|
||||
|
||||
/* Sam 8/30/99 fix - handle message/rfc822:
|
||||
|
||||
--boundary
|
||||
Content-Type: message/rfc822
|
||||
|
||||
--><-- we're here, DON'T add RFC2045MIMEMSG and rest of crap here
|
||||
*/
|
||||
if (p->firstpart->next == 0)
|
||||
{
|
||||
int rc;
|
||||
|
||||
p->firstpart->parent=0;
|
||||
rc=dorw(p->firstpart);
|
||||
p->firstpart->parent=p;
|
||||
return (rc);
|
||||
}
|
||||
|
||||
if (fdout_add(RFC2045MIMEMSG, sizeof(RFC2045MIMEMSG)-1))
|
||||
return (-1);
|
||||
for (p=p->firstpart; p; p=p->next)
|
||||
{
|
||||
if (p->isdummy) continue;
|
||||
sprintf(buf, "\n--%s-%d\n", rw_boundary_root, bcnt);
|
||||
if (fdout_add(buf, strlen(buf))) return (-1);
|
||||
if (dorw(p) != 0) return(-1);
|
||||
}
|
||||
sprintf(buf, "\n--%s-%d--\n", rw_boundary_root, bcnt);
|
||||
if (fdout_add(buf, strlen(buf))) return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int rfc2045_rewrite_common(struct rfc2045 *, int, const char *);
|
||||
|
||||
int rfc2045_rewrite(struct rfc2045 *p, int fdin_arg, int fdout_arg,
|
||||
const char *appname)
|
||||
{
|
||||
fdout=fdout_arg;
|
||||
fdout_func=0;
|
||||
return (rfc2045_rewrite_common(p, fdin_arg, appname));
|
||||
}
|
||||
|
||||
int rfc2045_rewrite_func(struct rfc2045 *p, int fdin_arg,
|
||||
int (*funcarg)(const char *, int, void *), void *funcargarg,
|
||||
const char *appname)
|
||||
{
|
||||
fdout= -1;
|
||||
fdout_func=funcarg;
|
||||
fdout_arg=funcargarg;
|
||||
return (rfc2045_rewrite_common(p, fdin_arg, appname));
|
||||
}
|
||||
|
||||
static int rfc2045_rewrite_common(struct rfc2045 *p,
|
||||
int fdin_arg, const char *appname)
|
||||
{
|
||||
int rc;
|
||||
int fd=dup(fdin_arg);
|
||||
|
||||
if (fd < 0) return (-1);
|
||||
rw_appname=appname;
|
||||
fdin=fdopen(fd, "r");
|
||||
if (!fdin)
|
||||
{
|
||||
close(fd);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
fdout_ptr=fdout_buf;
|
||||
fdout_left=sizeof(fdout_buf);
|
||||
|
||||
rw_boundary_root=rfc2045_mk_boundary(p, fd);
|
||||
if (rw_boundary_root == 0)
|
||||
rc= -1;
|
||||
else
|
||||
{
|
||||
rw_boundary_cnt=1;
|
||||
rc=dorw(p);
|
||||
free(rw_boundary_root);
|
||||
}
|
||||
if (rc == 0 && fdout_ptr > fdout_buf)
|
||||
rc=fdout_flush();
|
||||
fclose(fdin);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int qpe_pos;
|
||||
|
||||
static void qpe_start()
|
||||
{
|
||||
qpe_pos=0;
|
||||
}
|
||||
|
||||
static int qpe_do(const char *p, size_t i, void *ptr)
|
||||
{
|
||||
size_t j,k;
|
||||
|
||||
if (conv_err) return (0);
|
||||
for (j=k=0; j<i; j++)
|
||||
{
|
||||
if (p[j] == '\n')
|
||||
{
|
||||
if (fdout_add(p+k, j+1-k)) conv_err=1;
|
||||
k=j+1;
|
||||
qpe_pos=0;
|
||||
continue;
|
||||
}
|
||||
if (qpe_pos >= 72)
|
||||
{
|
||||
if (fdout_add(p+k, j-k) ||
|
||||
fdout_add("=\n", 2)) conv_err=1;
|
||||
k=j;
|
||||
qpe_pos=0;
|
||||
}
|
||||
|
||||
if (p[j] < 32 || p[j] >= 127 || p[j] == '=')
|
||||
{
|
||||
char buf[3];
|
||||
static char xdigit[16]="0123456789ABCDEF";
|
||||
unsigned n= (unsigned char)p[j];
|
||||
|
||||
buf[0]='=';
|
||||
buf[1]=xdigit[ n / 16];
|
||||
buf[2]=xdigit[ n % 16];
|
||||
if (fdout_add(p+k, j-k) ||
|
||||
fdout_add(buf, 3)) conv_err=1;
|
||||
qpe_pos += 2;
|
||||
k=j+1;
|
||||
}
|
||||
++qpe_pos;
|
||||
}
|
||||
if (fdout_add(p+k, j-k)) conv_err=1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void qpe_end()
|
||||
{
|
||||
}
|
Reference in New Issue
Block a user