diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /rfc822/encode.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'rfc822/encode.c')
| -rw-r--r-- | rfc822/encode.c | 255 | 
1 files changed, 255 insertions, 0 deletions
| diff --git a/rfc822/encode.c b/rfc822/encode.c new file mode 100644 index 0000000..a6f791b --- /dev/null +++ b/rfc822/encode.c @@ -0,0 +1,255 @@ +/* +** Copyright 2003-2004 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + +/* +*/ +#include	"encode.h" +#include	<string.h> +#include	<stdlib.h> + +static int quoted_printable(struct libmail_encode_info *, +			    const char *, size_t); +static int base64(struct libmail_encode_info *, +		  const char *, size_t); +static int eflush(struct libmail_encode_info *, +		 const char *, size_t); + +void libmail_encode_start(struct libmail_encode_info *info, +			  const char *transfer_encoding, +			  int (*callback_func)(const char *, size_t, void *), +			  void *callback_arg) +{ +	info->output_buf_cnt=0; +	info->input_buf_cnt=0; + +	switch (*transfer_encoding) { +	case 'q': +	case 'Q': +		info->encoding_func=quoted_printable; +		info->input_buffer[0]=0; /* Recycle for qp encoding */ +		break; +	case 'b': +	case 'B': +		info->encoding_func=base64; +		break; +	default: +		info->encoding_func=eflush; +		break; +	} +	info->callback_func=callback_func; +	info->callback_arg=callback_arg; +} + +int libmail_encode(struct libmail_encode_info *info, +		   const char *ptr, +		   size_t cnt) +{ +	return ((*info->encoding_func)(info, ptr, cnt)); +} + +int libmail_encode_end(struct libmail_encode_info *info) +{ +	int rc=(*info->encoding_func)(info, NULL, 0); + +	if (rc == 0 && info->output_buf_cnt > 0) +	{ +		rc= (*info->callback_func)(info->output_buffer, +					   info->output_buf_cnt, +					   info->callback_arg); +		info->output_buf_cnt=0; +	} + +	return rc; +} + +static int eflush(struct libmail_encode_info *info, const char *ptr, size_t n) +{ +	while (n > 0) +	{ +		size_t i; + +		if (info->output_buf_cnt == sizeof(info->output_buffer)) +		{ +			int rc= (*info->callback_func)(info->output_buffer, +						       info->output_buf_cnt, +						       info->callback_arg); + +			info->output_buf_cnt=0; +			if (rc) +				return rc; +		} + +		i=n; + +		if (i > sizeof(info->output_buffer) - info->output_buf_cnt) +			i=sizeof(info->output_buffer) - info->output_buf_cnt; + +		memcpy(info->output_buffer + info->output_buf_cnt, ptr, i); +		info->output_buf_cnt += i; +		ptr += i; +		n -= i; +	} +	return 0; +} + +static int base64_flush(struct libmail_encode_info *); + +static int base64(struct libmail_encode_info *info, +		  const char *buf, size_t n) +{ +	if (!buf) +	{ +		int rc=0; + +		if (info->input_buf_cnt > 0) +			rc=base64_flush(info); + +		return rc; +	} + +	while (n) +	{ +		size_t	i; + +		if (info->input_buf_cnt == sizeof(info->input_buffer)) +		{ +			int rc=base64_flush(info); + +			if (rc != 0) +				return rc; +		} + +		i=n; +		if (i > sizeof(info->input_buffer) - info->input_buf_cnt) +			i=sizeof(info->input_buffer) - info->input_buf_cnt; + +		memcpy(info->input_buffer + info->input_buf_cnt, +		       buf, i); +		info->input_buf_cnt += i; +		buf += i; +		n -= i; +	} +	return 0; +} + +static const char base64tab[]= +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int base64_flush(struct libmail_encode_info *info) +{ +	int	a=0,b=0,c=0; +	int	i, j; +	int	d, e, f, g; +	char	output_buf[ sizeof(info->input_buffer) / 3 * 4+1]; + +	for (j=i=0; i<info->input_buf_cnt; i += 3) +	{ +		a=(unsigned char)info->input_buffer[i]; +		b= i+1 < info->input_buf_cnt ? +			(unsigned char)info->input_buffer[i+1]:0; +		c= i+2 < info->input_buf_cnt ? +			(unsigned char)info->input_buffer[i+2]:0; + +		d=base64tab[ a >> 2 ]; +		e=base64tab[ ((a & 3 ) << 4) | (b >> 4)]; +		f=base64tab[ ((b & 15) << 2) | (c >> 6)]; +		g=base64tab[ c & 63 ]; +		if (i + 1 >= info->input_buf_cnt)	f='='; +		if (i + 2 >= info->input_buf_cnt) g='='; +		output_buf[j++]=d; +		output_buf[j++]=e; +		output_buf[j++]=f; +		output_buf[j++]=g; +	} + +	info->input_buf_cnt=0; + +	output_buf[j++]='\n'; +	return eflush(info, output_buf, j); +} + +static const char xdigit[]="0123456789ABCDEF"; + +static int quoted_printable(struct libmail_encode_info *info, +			    const char *p, size_t n) +{ +	char local_buf[256]; +	int local_buf_cnt=0; + +#define QPUT(c) do { if (local_buf_cnt == sizeof(local_buf)) \ +                     { int rc=eflush(info, local_buf, local_buf_cnt); \ +			local_buf_cnt=0; if (rc) return (rc); } \ +			local_buf[local_buf_cnt]=(c); ++local_buf_cnt; } while(0) + +	if (!p) +		return (0); + +	while (n) +	{ + + +		/* +		** Repurpose input_buffer[0] as a flag whether the previous +		** character was a space. +		** +		** A space before a newline gets escaped. +		*/ + +		if (info->input_buffer[0]) +		{ +			if (*p == '\n') +			{ +				QPUT('='); +				QPUT('2'); +				QPUT('0'); +			} +			else +			{ +				QPUT(' '); +			} +			++info->input_buf_cnt; +		} + +		info->input_buffer[0]=0; + +		if (*p == ' ') +		{ +			info->input_buffer[0]=1; +			p++; +			--n; +			continue; +		} + +		if (info->input_buf_cnt > 72 && *p != '\n') +		{ +			QPUT('='); +			QPUT('\n'); +			info->input_buf_cnt=0; +		} + +		if ( *p == '\n') +			info->input_buf_cnt=0; +		else if (*p < ' ' || *p == '=' || *p >= 0x7F) +		{ +			QPUT('='); +			QPUT(xdigit[ (*p >> 4) & 15]); +			QPUT(xdigit[ *p & 15 ]); +			info->input_buf_cnt += 3; +			p++; +			--n; +			continue; +		} +		else info->input_buf_cnt++; + +		QPUT( *p); +		p++; +		--n; +	} + +	if (local_buf_cnt > 0) +		return eflush(info, local_buf, local_buf_cnt); + +	return 0; +} | 
