| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Copyright (C) 2002 Nigel Horne <njh@bandsman.co.uk> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *  it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *  the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *  (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *  GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *  along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							| 
									
										
										
										
											2003-09-28 10:07:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Change History: | 
					
						
							|  |  |  |  * $Log: message.c,v $ | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  |  * Revision 1.48  2004/03/25 22:40:46  nigelhorne | 
					
						
							|  |  |  |  * Removed even more calls to realloc and some duplicated code | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-21 17:21:12 +00:00
										 |  |  |  * Revision 1.47  2004/03/21 17:19:49  nigelhorne | 
					
						
							|  |  |  |  * Handle bounce messages with no headers | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  |  * Revision 1.46  2004/03/21 09:41:27  nigelhorne | 
					
						
							|  |  |  |  * Faster scanning for non MIME messages | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-20 19:28:10 +00:00
										 |  |  |  * Revision 1.45  2004/03/20 19:26:48  nigelhorne | 
					
						
							|  |  |  |  * Second attempt to handle all bounces | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-20 17:41:14 +00:00
										 |  |  |  * Revision 1.44  2004/03/20 17:39:23  nigelhorne | 
					
						
							|  |  |  |  * First attempt to handle all bounces | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-20 13:24:43 +00:00
										 |  |  |  * Revision 1.43  2004/03/20 13:23:44  nigelhorne | 
					
						
							|  |  |  |  * More bounces handled | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-19 17:39:47 +00:00
										 |  |  |  * Revision 1.42  2004/03/19 17:38:11  nigelhorne | 
					
						
							|  |  |  |  * Handle binary encoding as though it had no encoding | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-19 08:08:38 +00:00
										 |  |  |  * Revision 1.41  2004/03/19 08:08:38  nigelhorne | 
					
						
							|  |  |  |  * Handle '8 bit' encoding as well as the RFC '8bit' | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-18 21:52:51 +00:00
										 |  |  |  * Revision 1.40  2004/03/18 21:51:41  nigelhorne | 
					
						
							|  |  |  |  * If a message only contains a single RFC822 message that has no encoding don't save for scanning | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-18 14:07:44 +00:00
										 |  |  |  * Revision 1.39  2004/03/18 14:05:25  nigelhorne | 
					
						
							|  |  |  |  * Added bounce and handle text/plain encoding messages | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-17 19:47:32 +00:00
										 |  |  |  * Revision 1.38  2004/03/17 19:47:32  nigelhorne | 
					
						
							|  |  |  |  * Handle spaces in disposition type | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-10 05:37:46 +00:00
										 |  |  |  * Revision 1.37  2004/03/10 05:35:03  nigelhorne | 
					
						
							|  |  |  |  * Implemented a couple of small speed improvements | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-07 15:11:48 +00:00
										 |  |  |  * Revision 1.36  2004/03/07 15:11:48  nigelhorne | 
					
						
							|  |  |  |  * Fixed minor typo in bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-03-07 12:32:01 +00:00
										 |  |  |  * Revision 1.35  2004/03/07 12:32:01  nigelhorne | 
					
						
							|  |  |  |  * Added new bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-20 17:04:43 +00:00
										 |  |  |  * Revision 1.34  2004/02/20 17:04:43  nigelhorne | 
					
						
							|  |  |  |  * Added new bounce delimeter | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-18 10:09:46 +00:00
										 |  |  |  * Revision 1.33  2004/02/18 10:07:40  nigelhorne | 
					
						
							|  |  |  |  * Find some Yaha | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-17 20:46:02 +00:00
										 |  |  |  * Revision 1.32  2004/02/17 20:43:50  nigelhorne | 
					
						
							|  |  |  |  * Added bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-17 09:55:12 +00:00
										 |  |  |  * Revision 1.31  2004/02/17 09:53:56  nigelhorne | 
					
						
							|  |  |  |  * Added bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-13 14:24:49 +00:00
										 |  |  |  * Revision 1.30  2004/02/13 14:23:56  nigelhorne | 
					
						
							|  |  |  |  * Add a new bounce delimeter | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-10 17:02:52 +00:00
										 |  |  |  * Revision 1.29  2004/02/10 17:01:30  nigelhorne | 
					
						
							|  |  |  |  * Recognise a new type of bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-07 23:13:55 +00:00
										 |  |  |  * Revision 1.28  2004/02/07 23:13:55  nigelhorne | 
					
						
							|  |  |  |  * Handle content-type: text/ | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-06 13:46:08 +00:00
										 |  |  |  * Revision 1.27  2004/02/06 13:46:08  kojm | 
					
						
							|  |  |  |  * Support for clamav-config.h | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-06 13:10:34 +00:00
										 |  |  |  * Revision 1.26  2004/02/06 13:10:34  nigelhorne | 
					
						
							|  |  |  |  * Now integrates with winzip | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  |  * Revision 1.25  2004/02/05 11:23:07  nigelhorne | 
					
						
							|  |  |  |  * Bounce messages are now table driven | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  |  * Revision 1.24  2004/02/04 13:29:16  nigelhorne | 
					
						
							|  |  |  |  * Handle blobAddData of more than 128K | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-03 23:04:09 +00:00
										 |  |  |  * Revision 1.23  2004/02/03 23:04:09  nigelhorne | 
					
						
							|  |  |  |  * Disabled binhex code | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-03 22:54:59 +00:00
										 |  |  |  * Revision 1.22  2004/02/03 22:54:59  nigelhorne | 
					
						
							|  |  |  |  * Catch another example of Worm.Dumaru.Y | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-03 14:38:03 +00:00
										 |  |  |  * Revision 1.21  2004/02/03 14:35:37  nigelhorne | 
					
						
							|  |  |  |  * Fixed an infinite loop on binhex | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-02 17:12:16 +00:00
										 |  |  |  * Revision 1.20  2004/02/02 17:10:04  nigelhorne | 
					
						
							|  |  |  |  * Scan a rare form of bounce message | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-02 15:52:09 +00:00
										 |  |  |  * Revision 1.19  2004/02/02 15:52:09  nigelhorne | 
					
						
							|  |  |  |  * Remove handling of 8bit binhex files for now | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-02 15:30:54 +00:00
										 |  |  |  * Revision 1.18  2004/02/02 15:30:54  nigelhorne | 
					
						
							|  |  |  |  * Remove handling of 8bit binhex files for now | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-02-02 14:02:54 +00:00
										 |  |  |  * Revision 1.17  2004/02/02 14:01:58  nigelhorne | 
					
						
							|  |  |  |  * Carefully crafted binhex messages could have caused a crash | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-01-28 10:16:51 +00:00
										 |  |  |  * Revision 1.16  2004/01/28 10:15:24  nigelhorne | 
					
						
							|  |  |  |  * Added support to scan some bounce messages | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-01-14 10:09:59 +00:00
										 |  |  |  * Revision 1.15  2004/01/14 10:08:45  nigelhorne | 
					
						
							|  |  |  |  * blobGetData now allows contents to be changed - tuttut | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-01-10 13:03:59 +00:00
										 |  |  |  * Revision 1.14  2004/01/10 13:01:19  nigelhorne | 
					
						
							|  |  |  |  * Added BinHex compression support | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  |  * Revision 1.13  2004/01/09 18:01:03  nigelhorne | 
					
						
							|  |  |  |  * Started BinHex work | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  |  * Revision 1.12  2003/12/05 09:34:00  nigelhorne | 
					
						
							|  |  |  |  * Use cli_tok instead of strtok - replaced now by cli_strtok | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  |  * Revision 1.11  2003/11/17 07:57:12  nigelhorne | 
					
						
							|  |  |  |  * Prevent buffer overflow in broken uuencoded files | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-11-05 07:05:59 +00:00
										 |  |  |  * Revision 1.10  2003/11/05 07:03:51  nigelhorne | 
					
						
							|  |  |  |  * Handle broken content-disposition | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-10-01 09:28:23 +00:00
										 |  |  |  * Revision 1.9  2003/10/01 09:28:23  nigelhorne | 
					
						
							|  |  |  |  * Handle content-type header going over to a new line | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-09-28 10:07:34 +00:00
										 |  |  |  * Revision 1.8  2003/09/28 10:07:08  nigelhorne | 
					
						
							|  |  |  |  * uuencodebegin() no longer static | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | static	char	const	rcsid[] = "$Id: message.c,v 1.48 2004/03/25 22:40:46 nigelhorne Exp $"; | 
					
						
							| 
									
										
										
										
											2004-02-06 13:46:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if HAVE_CONFIG_H
 | 
					
						
							|  |  |  | #include "clamav-config.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef	CL_DEBUG
 | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | /*#define	NDEBUG	/* map CLAMAV debug onto standard */ | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CL_THREAD_SAFE
 | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | #ifndef	_REENTRANT
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | #define	_REENTRANT	/* for Solaris 2.8 */
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if	C_DARWIN
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <strings.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include <ctype.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "mbox.h"
 | 
					
						
							|  |  |  | #include "blob.h"
 | 
					
						
							|  |  |  | #include "text.h"
 | 
					
						
							|  |  |  | #include "strrcpy.h"
 | 
					
						
							|  |  |  | #include "others.h"
 | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | #include "str.h"
 | 
					
						
							| 
									
										
										
										
											2004-03-20 17:41:14 +00:00
										 |  |  | #include "scanners.h"
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* required for AIX and Tru64 */ | 
					
						
							|  |  |  | #ifdef TRUE
 | 
					
						
							|  |  |  | #undef TRUE
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef FALSE
 | 
					
						
							|  |  |  | #undef FALSE
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | typedef enum { FALSE = 0, TRUE = 1 } bool; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | static	unsigned char	*decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | static unsigned char *decode(const char *in, unsigned char *out, unsigned char (*decoder)(char), bool isFast); | 
					
						
							|  |  |  | static	unsigned	char	hex(char c); | 
					
						
							|  |  |  | static	unsigned	char	base64(char c); | 
					
						
							|  |  |  | static	unsigned	char	uudecode(char c); | 
					
						
							|  |  |  | static	const	char	*messageGetArgument(const message *m, int arg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * These maps are ordered in decreasing likelyhood of their appearance | 
					
						
							|  |  |  |  * in an e-mail | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static	const	struct	encoding_map { | 
					
						
							|  |  |  | 	const	char	*string; | 
					
						
							|  |  |  | 	encoding_type	type; | 
					
						
							|  |  |  | } encoding_map[] = { | 
					
						
							|  |  |  | 	{	"7bit",			NOENCODING	}, | 
					
						
							| 
									
										
										
										
											2004-03-18 21:52:51 +00:00
										 |  |  | 	{	"text/plain",		NOENCODING	}, | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	{	"quoted-printable",	QUOTEDPRINTABLE	},	/* rfc1522 */ | 
					
						
							|  |  |  | 	{	"base64",		BASE64		}, | 
					
						
							|  |  |  | 	{	"8bit",			EIGHTBIT	}, | 
					
						
							| 
									
										
										
										
											2004-03-19 08:08:38 +00:00
										 |  |  | 	{	"8 bit",		EIGHTBIT	},	/* incorrect */ | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	{	"x-uuencode",		UUENCODE	}, | 
					
						
							|  |  |  | 	{	"binary",		BINARY		}, | 
					
						
							| 
									
										
										
										
											2004-03-07 12:32:01 +00:00
										 |  |  | 	{	NULL,			NOENCODING	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static	struct	mime_map { | 
					
						
							|  |  |  | 	const	char	*string; | 
					
						
							|  |  |  | 	mime_type	type; | 
					
						
							|  |  |  | } mime_map[] = { | 
					
						
							|  |  |  | 	{	"text",			TEXT		}, | 
					
						
							|  |  |  | 	{	"multipart",		MULTIPART	}, | 
					
						
							|  |  |  | 	{	"application",		APPLICATION	}, | 
					
						
							|  |  |  | 	{	"audio",		AUDIO		}, | 
					
						
							|  |  |  | 	{	"image",		IMAGE		}, | 
					
						
							|  |  |  | 	{	"message",		MESSAGE		}, | 
					
						
							|  |  |  | 	{	"video",		VIDEO		}, | 
					
						
							| 
									
										
										
										
											2004-03-07 12:32:01 +00:00
										 |  |  | 	{	NULL,			TEXT		} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | message * | 
					
						
							|  |  |  | messageCreate(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	message *m = (message *)cli_calloc(1, sizeof(message)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m->mimeType = NOMIME; | 
					
						
							| 
									
										
										
										
											2004-03-18 21:52:51 +00:00
										 |  |  | 	m->encodingType = NOENCODING; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return m; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageDestroy(message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	messageReset(m); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(m); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageReset(message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(m->mimeSubtype) | 
					
						
							|  |  |  | 		free(m->mimeSubtype); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(m->mimeDispositionType) | 
					
						
							|  |  |  | 		free(m->mimeDispositionType); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 	if(m->mimeArguments) { | 
					
						
							|  |  |  | 		for(i = 0; i < m->numberOfArguments; i++) | 
					
						
							|  |  |  | 			free(m->mimeArguments[i]); | 
					
						
							|  |  |  | 		free(m->mimeArguments); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(m->body_first) | 
					
						
							|  |  |  | 		textDestroy(m->body_first); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(m, '\0', sizeof(message)); | 
					
						
							|  |  |  | 	m->mimeType = NOMIME; | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | 	m->encodingType = NOENCODING; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageSetMimeType(message *mess, const char *type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct mime_map *m; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(mess != NULL); | 
					
						
							|  |  |  | 	assert(type != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mess->mimeType = NOMIME; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cli_dbgmsg("messageSetMimeType: '%s'\n", type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Ignore leading spaces */ | 
					
						
							|  |  |  | 	while(isspace(*type)) | 
					
						
							|  |  |  | 		if(*type++ == '\0') | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(m = mime_map; m->string; m++) | 
					
						
							|  |  |  | 		if(strcasecmp(type, m->string) == 0) { | 
					
						
							|  |  |  | 			mess->mimeType = m->type; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(mess->mimeType == NOMIME) { | 
					
						
							|  |  |  | 		if(strncasecmp(type, "x-", 2) == 0) | 
					
						
							|  |  |  | 			mess->mimeType = MEXTENSION; | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 		else { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Based on a suggestion by James Stevens | 
					
						
							|  |  |  | 			 *	<James@kyzo.com> | 
					
						
							|  |  |  | 			 * Force scanning of strange messages | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			cli_warnmsg("Unknown MIME type: `%s' - set to Application\n", type); | 
					
						
							|  |  |  | 			mess->mimeType = APPLICATION; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mime_type | 
					
						
							|  |  |  | messageGetMimeType(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return(m->mimeType); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageSetMimeSubtype(message *m, const char *subtype) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							| 
									
										
										
										
											2004-02-07 23:13:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(subtype == NULL) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Handle broken content-type lines, e.g. | 
					
						
							|  |  |  | 		 *	Content-Type: text/ | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		cli_dbgmsg("Empty content subtype\n"); | 
					
						
							|  |  |  | 		subtype = ""; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(m->mimeSubtype) | 
					
						
							|  |  |  | 		free(m->mimeSubtype); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m->mimeSubtype = strdup(subtype); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char * | 
					
						
							|  |  |  | messageGetMimeSubtype(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return((m->mimeSubtype) ? m->mimeSubtype : ""); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageSetDispositionType(message *m, const char *disptype) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-05 07:05:59 +00:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * It's broken for there to be an entry such as "Content-Disposition:" | 
					
						
							|  |  |  | 	 * However some spam and viruses are rather broken, it's a sign | 
					
						
							|  |  |  | 	 * that something is wrong if we get that - maybe we should force a | 
					
						
							|  |  |  | 	 * scan of this part | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2004-03-17 19:47:32 +00:00
										 |  |  | 	if(disptype) { | 
					
						
							|  |  |  | 		while(isspace((int)*disptype)) | 
					
						
							|  |  |  | 			disptype++; | 
					
						
							|  |  |  | 		if(*disptype) | 
					
						
							|  |  |  | 			m->mimeDispositionType = strdup(disptype); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char * | 
					
						
							|  |  |  | messageGetDispositionType(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return((m->mimeDispositionType) ? m->mimeDispositionType : ""); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * TODO: | 
					
						
							|  |  |  |  *	Arguments are held on a per message basis, they should be held on | 
					
						
							|  |  |  |  * a per section basis. Otherwise what happens if two sections have two | 
					
						
							|  |  |  |  * different values for charset? Probably doesn't matter for the use this | 
					
						
							|  |  |  |  * code will be given, but will need fixing if this code is used elsewhere | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageAddArgument(message *m, const char *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(arg == NULL) | 
					
						
							|  |  |  | 		return;	/* Note: this is not an error condition */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(isspace(*arg)) | 
					
						
							|  |  |  | 		arg++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(*arg == '\0') | 
					
						
							|  |  |  | 		/* Empty argument? Probably a broken mail client... */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-10 05:37:46 +00:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * These are the only arguments we're interested in. | 
					
						
							|  |  |  | 	 * Do 'fgrep messageFindArgument *.c' if you don't believe me! | 
					
						
							|  |  |  | 	 * It's probably not good doing this since each time a new | 
					
						
							|  |  |  | 	 * messageFindArgument is added I need to remember to look here, | 
					
						
							|  |  |  | 	 * but it can save a lot of memory... | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if((strncasecmp(arg, "name", 4) != 0) && | 
					
						
							|  |  |  | 	   (strncasecmp(arg, "filename", 8) != 0) && | 
					
						
							|  |  |  | 	   (strncasecmp(arg, "boundary", 8) != 0) && | 
					
						
							|  |  |  | 	   (strncasecmp(arg, "type", 4) != 0)) { | 
					
						
							| 
									
										
										
										
											2004-03-20 17:41:14 +00:00
										 |  |  | 		cli_dbgmsg("Discarding unwanted argument '%s'\n", arg); | 
					
						
							| 
									
										
										
										
											2004-03-10 05:37:46 +00:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	cli_dbgmsg("Add argument '%s'\n", arg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	for(offset = 0; offset < m->numberOfArguments; offset++) | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		if(m->mimeArguments[offset] == NULL) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		else if(strcasecmp(arg, m->mimeArguments[offset]) == 0) | 
					
						
							|  |  |  | 			return;	/* already in there */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	if(offset == m->numberOfArguments) { | 
					
						
							|  |  |  | 		m->numberOfArguments++; | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 		m->mimeArguments = (char **)cli_realloc(m->mimeArguments, m->numberOfArguments * sizeof(char *)); | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	m->mimeArguments[offset] = strdup(arg); | 
					
						
							| 
									
										
										
										
											2004-02-03 22:54:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This is terribly broken from an RFC point of view but is useful | 
					
						
							|  |  |  | 	 * for catching viruses which have a filename but no type of | 
					
						
							|  |  |  | 	 * mime. By pretending defaulting to an application rather than | 
					
						
							|  |  |  | 	 * to nomime we can ensure they're saved and scanned | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if((strncasecmp(arg, "filename=", 9) == 0) || (strncasecmp(arg, "name=", 5) == 0)) | 
					
						
							|  |  |  | 		if(messageGetMimeType(m) == NOMIME) { | 
					
						
							|  |  |  | 			cli_dbgmsg("Force mime encoding to application\n"); | 
					
						
							|  |  |  | 			messageSetMimeType(m, "application"); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Add in all the arguments. | 
					
						
							|  |  |  |  * Cope with: | 
					
						
							|  |  |  |  *	name="foo bar.doc" | 
					
						
							|  |  |  |  *	charset=foo name=bar | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageAddArguments(message *m, const char *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *string = s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cli_dbgmsg("Add arguments '%s'\n", string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(string != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(*string) { | 
					
						
							|  |  |  | 		const char *key, *cptr; | 
					
						
							|  |  |  | 		char *data, *field; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(isspace(*string) || (*string == ';')) { | 
					
						
							|  |  |  | 			string++; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		key = string; | 
					
						
							|  |  |  | 		data = strchr(string, '='); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Some spam breaks RFC1521 by using ':' instead of '=' | 
					
						
							|  |  |  | 		 * e.g.: | 
					
						
							|  |  |  | 		 *	Content-Type: text/html; charset:ISO-8859-1 | 
					
						
							|  |  |  | 		 * should be: | 
					
						
							|  |  |  | 		 *	Content-type: text/html; charset=ISO-8859-1 | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * We give up with lines that are completely broken because | 
					
						
							|  |  |  | 		 * we don't have ESP and don't know what was meant to be there. | 
					
						
							|  |  |  | 		 * It's unlikely to really be a problem. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if(data == NULL) | 
					
						
							|  |  |  | 			data = strchr(string, ':'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(data == NULL) { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Completely broken, give up | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			cli_warnmsg("Can't parse non RFC1521 header \"%s\"\n", | 
					
						
							|  |  |  | 				s); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		string = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		string++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Handle white space to the right of the equals sign | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		while(isspace(*string) && (*string != '\0')) | 
					
						
							|  |  |  | 			string++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		cptr = string++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(*cptr == '"') { | 
					
						
							|  |  |  | 			char *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * The field is in quotes, so look for the | 
					
						
							|  |  |  | 			 * closing quotes | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			key = strdup(key); | 
					
						
							|  |  |  | 			ptr = strchr(key, '='); | 
					
						
							|  |  |  | 			if(ptr == NULL) | 
					
						
							|  |  |  | 				ptr = strchr(key, ':'); | 
					
						
							|  |  |  | 			*ptr = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cptr++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			string = strchr(cptr, '"'); | 
					
						
							|  |  |  | 			if((string == NULL) || (strlen(key) == 0)) { | 
					
						
							|  |  |  | 				cli_warnmsg("Can't parse header \"%s\"\n", s); | 
					
						
							|  |  |  | 				free((char *)key); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			string++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			data = strdup(cptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr = strchr(data, '"'); | 
					
						
							|  |  |  | 			if(ptr == NULL) { | 
					
						
							|  |  |  | 				/*
 | 
					
						
							|  |  |  | 				 * Weird e-mail header such as: | 
					
						
							|  |  |  | 				 * Content-Type: application/octet-stream; name=" | 
					
						
							|  |  |  | 				 * " | 
					
						
							|  |  |  | 				 * Content-Transfer-Encoding: base64 | 
					
						
							|  |  |  | 				 * Content-Disposition: attachment; filename=" | 
					
						
							|  |  |  | 				 * " | 
					
						
							|  |  |  | 				 * | 
					
						
							|  |  |  | 				 * TODO: the file should still be saved and | 
					
						
							|  |  |  | 				 * virus checked | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				cli_warnmsg("Can't parse header \"%s\"\n", s); | 
					
						
							|  |  |  | 				free(data); | 
					
						
							|  |  |  | 				free((char *)key); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			*ptr = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			field = cli_malloc(strlen(key) + strlen(data) + 2); | 
					
						
							|  |  |  | 			sprintf(field, "%s=%s", key, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			free((char *)key); | 
					
						
							|  |  |  | 			free(data); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			size_t len; | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(*cptr == '\0') { | 
					
						
							|  |  |  | 				cli_warnmsg("Ignoring empty field in \"%s\"\n", s); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * The field is not in quotes, so look for the closing | 
					
						
							|  |  |  | 			 * white space | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			while((*string != '\0') && !isspace(*string)) | 
					
						
							|  |  |  | 				string++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			len = (size_t)string - (size_t)key + 1; | 
					
						
							|  |  |  | 			field = cli_malloc(len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			memcpy(field, key, len - 1); | 
					
						
							|  |  |  | 			field[len - 1] = '\0'; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		messageAddArgument(m, field); | 
					
						
							|  |  |  | 		free(field); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char * | 
					
						
							|  |  |  | messageGetArgument(const message *m, int arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	assert(arg >= 0); | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	assert(arg < m->numberOfArguments); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return((m->mimeArguments[arg]) ? m->mimeArguments[arg] : ""); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Find a MIME variable from the header and return a COPY to the value of that | 
					
						
							|  |  |  |  * variable. The caller must free the copy | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const char * | 
					
						
							|  |  |  | messageFindArgument(const message *m, const char *variable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	assert(variable != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	for(i = 0; i < m->numberOfArguments; i++) { | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		const char *ptr; | 
					
						
							|  |  |  | 		size_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ptr = messageGetArgument(m, i); | 
					
						
							|  |  |  | 		if((ptr == NULL) || (*ptr == '\0')) | 
					
						
							|  |  |  | 			return(NULL); | 
					
						
							|  |  |  | 		len = strlen(variable); | 
					
						
							|  |  |  | #ifdef	CL_DEBUG
 | 
					
						
							|  |  |  | 		cli_dbgmsg("messageFindArgument: compare %d bytes of %s with %s\n", | 
					
						
							|  |  |  | 			len, variable, ptr); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		if(strncasecmp(ptr, variable, len) == 0) { | 
					
						
							|  |  |  | 			ptr = &ptr[len]; | 
					
						
							|  |  |  | 			while(isspace(*ptr)) | 
					
						
							|  |  |  | 				ptr++; | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 			if(*ptr != '=') { | 
					
						
							|  |  |  | 				cli_warnmsg("messageFindArgument: no '=' sign found in MIME header\n"); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			if((*++ptr == '"') && (strchr(&ptr[1], '"') != NULL)) { | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 				/* Remove any quote characters */ | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 				char *ret = strdup(++ptr); | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 				char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ret[strlen(ret) - 1] = '\0'; | 
					
						
							|  |  |  | 				/*
 | 
					
						
							|  |  |  | 				 * Thomas Lamy <Thomas.Lamy@in-online.net>: | 
					
						
							|  |  |  | 				 * fix un-quoting of boundary strings from | 
					
						
							|  |  |  | 				 * header, occurs if boundary was given as | 
					
						
							|  |  |  | 				 *	'boundary="_Test_";' | 
					
						
							|  |  |  | 				 * | 
					
						
							|  |  |  | 				 * At least two quotes in string, assume | 
					
						
							|  |  |  | 				 * quoted argument | 
					
						
							|  |  |  | 				 * end string at next quote | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				if((p = strchr(ret, '"')) != NULL) | 
					
						
							|  |  |  | 					*p = '\0'; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 				return(ret); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return(strdup(ptr)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return(NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageSetEncoding(message *m, const char *enctype) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct encoding_map *e; | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	assert(enctype != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m->encodingType = EEXTENSION; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-01 09:28:23 +00:00
										 |  |  | 	while((*enctype == '\t') || (*enctype == ' ')) | 
					
						
							|  |  |  | 		enctype++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	for(e = encoding_map; e->string; e++) | 
					
						
							|  |  |  | 		if(strcasecmp(enctype, e->string) == 0) { | 
					
						
							|  |  |  | 			m->encodingType = e->type; | 
					
						
							| 
									
										
										
										
											2003-10-01 09:28:23 +00:00
										 |  |  | 			cli_dbgmsg("Encoding type is \"%s\"\n", enctype); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 	cli_warnmsg("Unknown encoding type \"%s\"\n", enctype); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | encoding_type | 
					
						
							|  |  |  | messageGetEncoding(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	return(m->encodingType); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2004-03-17 19:47:32 +00:00
										 |  |  |  * Add a copy of the given line to the end of the given message | 
					
						
							|  |  |  |  * The caller will need to free the copy | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  |  * Line should not be terminated by a \n | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageAddLine(message *m, const char *line) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | 	static const char encoding[] = "Content-Transfer-Encoding"; | 
					
						
							|  |  |  | 	static const char binhex[] = "(This file must be converted with BinHex 4.0)"; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(m->body_first == NULL) | 
					
						
							|  |  |  | 		m->body_last = m->body_first = (text *)cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		m->body_last->t_next = (text *)cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 		m->body_last = m->body_last->t_next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | 	if(m->body_last == NULL) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	m->body_last->t_next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m->body_last->t_text = strdup((line) ? line : ""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(m->body_last->t_text != NULL); | 
					
						
							|  |  |  | 	assert(m->body_first != NULL); | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * See if this line marks the start of a non MIME inclusion that | 
					
						
							|  |  |  | 	 * will need to be scanned | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if(line) { | 
					
						
							|  |  |  | 		if((m->encoding == NULL) && | 
					
						
							|  |  |  | 		   (strncasecmp(line, encoding, sizeof(encoding) - 1) == 0)) | 
					
						
							|  |  |  | 			m->encoding = m->body_last; | 
					
						
							|  |  |  | 		else if((m->bounce == NULL) && | 
					
						
							|  |  |  | 			(cli_filetype(line, strlen(line)) == CL_MAILFILE)) | 
					
						
							|  |  |  | 				m->bounce = m->body_last; | 
					
						
							|  |  |  | 		else if((m->binhex == NULL) && | 
					
						
							|  |  |  | 			(strncasecmp(line, binhex, sizeof(binhex) - 1) == 0)) | 
					
						
							|  |  |  | 				m->binhex = m->body_last; | 
					
						
							|  |  |  | 		else if((m->uuencode == NULL) && | 
					
						
							|  |  |  | 			((strncasecmp(line, "begin ", 6) == 0) && | 
					
						
							|  |  |  | 			(isdigit(line[6])) && | 
					
						
							|  |  |  | 			(isdigit(line[7])) && | 
					
						
							|  |  |  | 			(isdigit(line[8])) && | 
					
						
							|  |  |  | 			(line[9] == ' '))) | 
					
						
							|  |  |  | 				m->uuencode = m->body_last; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const text * | 
					
						
							|  |  |  | messageGetBody(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	return(m->body_first); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Clean up the message by removing trailing spaces and blank lines | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | messageClean(message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	text *newEnd = textClean(m->body_first); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(newEnd) | 
					
						
							|  |  |  | 		m->body_last = newEnd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Decode and transfer the contents of the message into a blob | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  |  * The caller must free the returned blob | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | blob * | 
					
						
							|  |  |  | messageToBlob(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	blob *b; | 
					
						
							|  |  |  | 	const text *t_line = NULL; | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 	char *filename; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b = blobCreate(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 	if(b == NULL) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Find the filename to decode | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if(messageGetEncoding(m) == UUENCODE) { | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 		t_line = uuencodeBegin(m); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(t_line == NULL) { | 
					
						
							|  |  |  | 			/*cli_warnmsg("UUENCODED attachment is missing begin statement\n");*/ | 
					
						
							|  |  |  | 			blobDestroy(b); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 		filename = cli_strtok(t_line->t_text, 2, " "); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(filename == NULL) { | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 			cli_dbgmsg("UUencoded attachment sent with no filename\n"); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			blobDestroy(b); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 		cli_chomp(filename); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cli_dbgmsg("Set uuencode filename to \"%s\"\n", filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blobSetFilename(b, filename); | 
					
						
							|  |  |  | 		t_line = t_line->t_next; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 	} else if((t_line = binhexBegin(m)) != NULL) { | 
					
						
							|  |  |  | 		unsigned char byte; | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		unsigned long len, l, newlen = 0L; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		char *filename; | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		unsigned char *ptr, *data; | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 		int bytenumber; | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		blob *tmp = blobCreate(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Table look up by Thomas Lamy <Thomas.Lamy@in-online.net> | 
					
						
							|  |  |  | 		 * HQX conversion table - illegal chars are 0xff | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		const unsigned char hqxtbl[] = { | 
					
						
							|  |  |  | 			     /*   00   01   02   03   04   05   06   07   08   09   0a   0b   0c   0d   0e   0f */ | 
					
						
							|  |  |  | 		/* 00-0f */	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | 
					
						
							|  |  |  | 		/* 10-1f */	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | 
					
						
							|  |  |  | 		/* 20-2f */	0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0xff,0xff, | 
					
						
							|  |  |  | 		/* 30-3f */	0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0xff,0x14,0x15,0xff,0xff,0xff,0xff,0xff,0xff, | 
					
						
							|  |  |  | 		/* 40-4f */	0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0xff, | 
					
						
							|  |  |  | 		/* 50-5f */	0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0xff,0x2c,0x2d,0x2e,0x2f,0xff,0xff,0xff,0xff, | 
					
						
							|  |  |  | 		/* 60-6f */	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0xff,0x37,0x38,0x39,0x3a,0x3b,0x3c,0xff,0xff, | 
					
						
							|  |  |  | 		/* 70-7f */	0x3d,0x3e,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Decode BinHex4. First create a temporary blob which contains | 
					
						
							|  |  |  | 		 * the encoded message. Then decode that blob to the target | 
					
						
							| 
									
										
										
										
											2004-02-03 22:54:59 +00:00
										 |  |  | 		 * blob, free the temporary blob and return the target one | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		 * | 
					
						
							|  |  |  | 		 * See RFC1741 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 		while((t_line = t_line->t_next) != NULL) | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 			blobAddData(tmp, (unsigned char *)t_line->t_text, strlen(t_line->t_text)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data = blobGetData(tmp); | 
					
						
							| 
									
										
										
										
											2004-02-02 14:02:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(data == NULL) { | 
					
						
							|  |  |  | 			cli_warnmsg("Couldn't locate the binhex message that was claimed to be there\n"); | 
					
						
							|  |  |  | 			blobDestroy(tmp); | 
					
						
							|  |  |  | 			blobDestroy(b); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		if(data[0] != ':') { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * TODO: Need an example of this before I can be | 
					
						
							|  |  |  | 			 * sure it works | 
					
						
							|  |  |  | 			 * Possibly data[0] = '#' | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			cli_warnmsg("8 bit binhex code is not yet supported\n"); | 
					
						
							|  |  |  | 			blobDestroy(tmp); | 
					
						
							|  |  |  | 			blobDestroy(b); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		len = blobGetDataSize(tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-01-14 10:09:59 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * FIXME: this is dirty code, modification of the contents | 
					
						
							|  |  |  | 		 * of a member of the blob object should be done through blob.c | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		 * | 
					
						
							|  |  |  | 		 * Convert 7 bit data into 8 bit | 
					
						
							| 
									
										
										
										
											2004-01-14 10:09:59 +00:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		cli_dbgmsg("decode HQX7 message (%lu bytes)\n", len); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		ptr = cli_malloc(len); | 
					
						
							|  |  |  | 		memcpy(ptr, data, len); | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 		bytenumber = 0; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * ptr now contains the encoded (7bit) data - len bytes long | 
					
						
							|  |  |  | 		 * data will contain the unencoded (8bit) data | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		for(l = 1; l < len; l++) { | 
					
						
							|  |  |  | 			unsigned char c = ptr[l]; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 			if(c == ':') | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 			if((c == '\n') || (c == '\r')) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 			if((c < 0x20) || (c > 0x7f) || (hqxtbl[c] == 0xff)) { | 
					
						
							|  |  |  | 				cli_warnmsg("Invalid HQX7 character '%c' (0x%02x)\n", c, c); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			c = hqxtbl[c]; | 
					
						
							|  |  |  | 			assert(c <= 63); | 
					
						
							| 
									
										
										
										
											2004-02-03 14:38:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * These masks probably aren't needed, but | 
					
						
							|  |  |  | 			 * they're here to verify the code is correct | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			switch(bytenumber) { | 
					
						
							|  |  |  | 				case 0: | 
					
						
							|  |  |  | 					data[newlen] = (c << 2) & 0xFC; | 
					
						
							|  |  |  | 					bytenumber = 1; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 				case 1: | 
					
						
							|  |  |  | 					data[newlen++] |= (c >> 4) & 0x3; | 
					
						
							|  |  |  | 					data[newlen] = (c << 4) & 0xF0; | 
					
						
							|  |  |  | 					bytenumber = 2; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case 2: | 
					
						
							|  |  |  | 					data[newlen++] |= (c >> 2) & 0xF; | 
					
						
							|  |  |  | 					data[newlen] = (c << 6) & 0xC0; | 
					
						
							|  |  |  | 					bytenumber = 3; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case 3: | 
					
						
							|  |  |  | 					data[newlen++] |= c & 0x3F; | 
					
						
							|  |  |  | 					bytenumber = 0; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		cli_dbgmsg("decoded HQX7 message (now %lu bytes)\n", newlen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Throw away the old encoded (7bit) data | 
					
						
							|  |  |  | 		 * data now points to the encoded (8bit) data - newlen bytes | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * The data array may contain repetitive characters | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		free(ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Uncompress repetitive characters | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if(memchr(data, 0x90, newlen)) { | 
					
						
							|  |  |  | 			blob *u = blobCreate();	/* uncompressed data */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Includes compression | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			for(l = 0L; l < newlen; l++) { | 
					
						
							|  |  |  | 				unsigned char c = data[l]; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				/*
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 				 * TODO: handle the case where the first byte | 
					
						
							|  |  |  | 				 * is 0x90 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 				blobAddData(u, &c, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if((l < (newlen - 1L)) && (data[l + 1] == 0x90)) { | 
					
						
							|  |  |  | 					int count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					l += 2; | 
					
						
							|  |  |  | 					count = data[l]; | 
					
						
							|  |  |  | #ifdef	CL_DEBUG
 | 
					
						
							|  |  |  | 					cli_dbgmsg("uncompress HQX7 at 0x%06x: %d repetitive bytes\n", l, count); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if(count == 0) { | 
					
						
							|  |  |  | 						c = 0x90; | 
					
						
							|  |  |  | 						blobAddData(u, &c, 1); | 
					
						
							|  |  |  | 					} else | 
					
						
							|  |  |  | 						while(--count > 0) | 
					
						
							|  |  |  | 							blobAddData(u, &c, 1); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2004-02-02 15:30:54 +00:00
										 |  |  | 			blobDestroy(tmp); | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 			tmp = u; | 
					
						
							|  |  |  | 			data = blobGetData(tmp); | 
					
						
							|  |  |  | 			len = blobGetDataSize(tmp); | 
					
						
							|  |  |  | 			cli_dbgmsg("Uncompressed %lu bytes to %lu\n", newlen, len); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			len = newlen; | 
					
						
							|  |  |  | 			cli_dbgmsg("HQX7 message (%lu bytes) is not compressed\n", | 
					
						
							|  |  |  | 				len); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		 * The blob tmp now contains the uncompressed data | 
					
						
							|  |  |  | 		 * of len bytes, i.e. the repetitive bytes have been removed | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Parse the header | 
					
						
							|  |  |  | 		 * | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		 * TODO: set filename argument in message as well | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		byte = data[0]; | 
					
						
							|  |  |  | 		filename = cli_malloc(byte + 1); | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		memcpy(filename, &data[1], byte); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		filename[byte] = '\0'; | 
					
						
							|  |  |  | 		blobSetFilename(b, filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * skip over length, filename, version, type, creator and flags | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		byte = 1 + byte + 1 + 4 + 4 + 2; | 
					
						
							| 
									
										
										
										
											2004-02-03 14:38:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Set len to be the data fork length | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		len = ((data[byte] << 24) & 0xFF000000) | | 
					
						
							|  |  |  | 		      ((data[byte + 1] << 16) & 0xFF0000) | | 
					
						
							|  |  |  | 		      ((data[byte + 2] << 8) & 0xFF00) | | 
					
						
							|  |  |  | 		      (data[byte + 3] & 0xFF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cli_dbgmsg("Filename = '%s', data fork length = %lu bytes\n", | 
					
						
							|  |  |  | 			filename, len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		free((char *)filename); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Skip over data fork length, resource fork length and CRC | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		byte += 10; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-02-04 13:29:16 +00:00
										 |  |  | 		blobAddData(b, &data[byte], len); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		blobDestroy(tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return b; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Discard attachments with no filename | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2004-01-14 10:09:59 +00:00
										 |  |  | 		filename = (char *)messageFindArgument(m, "filename"); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		if(filename == NULL) { | 
					
						
							| 
									
										
										
										
											2004-01-14 10:09:59 +00:00
										 |  |  | 			filename = (char *)messageFindArgument(m, "name"); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(filename == NULL) { | 
					
						
							| 
									
										
										
										
											2004-03-19 17:39:47 +00:00
										 |  |  | 				cli_warnmsg("Attachment sent with no filename\n"); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 				blobDestroy(b); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blobSetFilename(b, filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t_line = messageGetBody(m); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 	free((char *)filename); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * t_line should now point to the first (encoded) line of the message | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if(t_line == NULL) { | 
					
						
							|  |  |  | 		cli_warnmsg("Empty attachment not saved\n"); | 
					
						
							|  |  |  | 		blobDestroy(b); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(messageGetEncoding(m) == NOENCODING) | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Fast copy | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 		return textToBlob(t_line, b); | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 	do { | 
					
						
							|  |  |  | 		unsigned char data[1024]; | 
					
						
							|  |  |  | 		unsigned char *uptr; | 
					
						
							|  |  |  | 		const char *line = t_line->t_text; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 		if(messageGetEncoding(m) == UUENCODE) | 
					
						
							|  |  |  | 			if(strcasecmp(line, "end") == 0) | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 		uptr = decodeLine(m, line, data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-25 22:42:00 +00:00
										 |  |  | 		if(uptr == NULL) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert(uptr <= &data[sizeof(data)]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		blobAddData(b, data, (size_t)(uptr - data)); | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * According to RFC1521, '=' is used to pad out | 
					
						
							|  |  |  | 		 * the last byte and should be used as evidence | 
					
						
							|  |  |  | 		 * of the end of the data. Some mail clients | 
					
						
							|  |  |  | 		 * annoyingly then put plain text after the '=' | 
					
						
							|  |  |  | 		 * bytes. Sigh | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		/*if(messageGetEncoding(m) == BASE64)
 | 
					
						
							|  |  |  | 			if(strchr(line, '=')) | 
					
						
							|  |  |  | 				break;*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} while((t_line = t_line->t_next) != NULL); | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	return b; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Decode and transfer the contents of the message into a text area | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | text * | 
					
						
							|  |  |  | messageToText(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	text *first = NULL, *last = NULL; | 
					
						
							|  |  |  | 	const text *t_line; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(messageGetEncoding(m) == NOENCODING) | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * Fast copy | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		for(t_line = messageGetBody(m); t_line; t_line = t_line->t_next) { | 
					
						
							|  |  |  | 			if(first == NULL) | 
					
						
							|  |  |  | 				first = last = cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				last->t_next = cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 				last = last->t_next; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-20 13:24:43 +00:00
										 |  |  | 			if((last == NULL) || | 
					
						
							|  |  |  | 			   ((last->t_text = strdup(t_line->t_text)) == NULL)) { | 
					
						
							| 
									
										
										
										
											2004-03-10 05:37:46 +00:00
										 |  |  | 				textDestroy(first); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 	else { | 
					
						
							|  |  |  | 		if(messageGetEncoding(m) == UUENCODE) { | 
					
						
							|  |  |  | 			t_line = uuencodeBegin(m); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 			if(t_line == NULL) { | 
					
						
							|  |  |  | 				/*cli_warnmsg("UUENCODED attachment is missing begin statement\n");*/ | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			t_line = t_line->t_next; | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2004-02-02 14:02:54 +00:00
										 |  |  | 			if(binhexBegin(m)) | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 				cli_warnmsg("Binhex messages not supported yet (2).\n"); | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 			t_line = messageGetBody(m); | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 		for(; t_line; t_line = t_line->t_next) { | 
					
						
							|  |  |  | 			unsigned char data[1024]; | 
					
						
							|  |  |  | 			unsigned char *uptr; | 
					
						
							|  |  |  | 			const char *line = t_line->t_text; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(messageGetEncoding(m) == UUENCODE) | 
					
						
							|  |  |  | 				if(strcasecmp(line, "end") == 0) | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 			uptr = decodeLine(m, line, data, sizeof(data)); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 			if(uptr == NULL) | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 			assert(uptr <= &data[sizeof(data)]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(first == NULL) | 
					
						
							|  |  |  | 				first = last = cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				last->t_next = cli_malloc(sizeof(text)); | 
					
						
							|  |  |  | 				last = last->t_next; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 			last->t_text = strdup((char *)data); | 
					
						
							|  |  |  | 			assert(last->t_text != NULL); | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(messageGetEncoding(m) == BASE64) | 
					
						
							|  |  |  | 				if(strchr(line, '=')) | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(last) | 
					
						
							|  |  |  | 		last->t_next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Scan to find the UUENCODED message (if any) | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #if	0
 | 
					
						
							| 
									
										
										
										
											2003-09-28 10:07:34 +00:00
										 |  |  | const text * | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | uuencodeBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const text *t_line; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Fix based on an idea by Magnus Jonsson | 
					
						
							|  |  |  | 	 * <Magnus.Jonsson@umdac.umu.se>, to allow for blank | 
					
						
							|  |  |  | 	 * lines before the begin. Should not happen, but some | 
					
						
							|  |  |  | 	 * e-mail clients are rather broken... | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for(t_line = messageGetBody(m); t_line; t_line = t_line->t_next) { | 
					
						
							|  |  |  | 		const char *line = t_line->t_text; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if((strncasecmp(line, "begin ", 6) == 0) && | 
					
						
							|  |  |  | 		   (isdigit(line[6])) && | 
					
						
							|  |  |  | 		   (isdigit(line[7])) && | 
					
						
							|  |  |  | 		   (isdigit(line[8])) && | 
					
						
							|  |  |  | 		   (line[9] == ' ')) | 
					
						
							|  |  |  | 			return t_line; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | const text * | 
					
						
							|  |  |  | uuencodeBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return m->uuencode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Scan to find the BINHEX message (if any) | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #if	0
 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | const text * | 
					
						
							|  |  |  | binhexBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const text *t_line; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(t_line = messageGetBody(m); t_line; t_line = t_line->t_next) | 
					
						
							|  |  |  | 		if(strcasecmp(t_line->t_text, "(This file must be converted with BinHex 4.0)") == 0) | 
					
						
							|  |  |  | 			return t_line; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | const text * | 
					
						
							|  |  |  | binhexBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return m->binhex; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-01-09 18:02:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-01-28 10:16:51 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Scan to find a bounce message. There is no standard for these, not | 
					
						
							|  |  |  |  * even a convention, so don't expect this to be foolproof | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #if	0
 | 
					
						
							| 
									
										
										
										
											2004-01-28 10:16:51 +00:00
										 |  |  | const text * | 
					
						
							|  |  |  | bounceBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const text *t_line; | 
					
						
							| 
									
										
										
										
											2004-02-05 11:24:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-20 19:28:10 +00:00
										 |  |  | 	for(t_line = messageGetBody(m); t_line; t_line = t_line->t_next) | 
					
						
							|  |  |  | 		if(cli_filetype(t_line->t_text, strlen(t_line->t_text)) == CL_MAILFILE) | 
					
						
							|  |  |  | 			return t_line; | 
					
						
							| 
									
										
										
										
											2004-01-28 10:16:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | const text * | 
					
						
							|  |  |  | bounceBegin(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return m->bounce; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * If a message doesn't not contain another message which could be harmful | 
					
						
							|  |  |  |  * it is deemed to be safe. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * TODO: ensure nothing can get through this | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * TODO: check to see if we need to | 
					
						
							|  |  |  |  * find anything else, perhaps anything | 
					
						
							|  |  |  |  * from the RFC821 table? | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #if	0
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | messageIsAllText(const message *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const text *t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(t = messageGetBody(m); t; t = t->t_next) | 
					
						
							|  |  |  | 		if(strncasecmp(t->t_text, | 
					
						
							|  |  |  | 			"Content-Transfer-Encoding", | 
					
						
							|  |  |  | 			strlen("Content-Transfer-Encoding")) == 0) | 
					
						
							|  |  |  | 				return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2004-03-21 17:21:12 +00:00
										 |  |  | const text * | 
					
						
							|  |  |  | encodingLine(const message *m) | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2004-03-21 17:21:12 +00:00
										 |  |  | 	return m->encoding; | 
					
						
							| 
									
										
										
										
											2004-03-21 09:43:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-01-28 10:16:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Decode a line and add it to a buffer, return the end of the buffer | 
					
						
							| 
									
										
										
										
											2003-08-30 19:20:04 +00:00
										 |  |  |  * to help appending callers. There is no new line at the end of "line" | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * len is sizeof(ptr) | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | static unsigned char * | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2003-12-05 09:35:30 +00:00
										 |  |  | 	size_t len; | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 	bool softbreak; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 	char *p2; | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 	char *copy; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	assert(m != NULL); | 
					
						
							|  |  |  | 	assert(line != NULL); | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 	assert(buf != NULL); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch(messageGetEncoding(m)) { | 
					
						
							| 
									
										
										
										
											2004-03-19 17:39:47 +00:00
										 |  |  | 		case BINARY: | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * TODO: find out what this is, encoded as binary?? | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			/* fall through */ | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 		case NOENCODING: | 
					
						
							|  |  |  | 		case EIGHTBIT: | 
					
						
							| 
									
										
										
										
											2003-08-29 14:27:15 +00:00
										 |  |  | 		default:	/* unknown encoding type - try our best */ | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 			buf = (unsigned char *)strrcpy((char *)buf, line); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			/* Put the new line back in */ | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 			return (unsigned char *)strrcpy((char *)buf, "\n"); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case QUOTEDPRINTABLE: | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 			softbreak = FALSE; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			while(*line) { | 
					
						
							|  |  |  | 				if(*line == '=') { | 
					
						
							|  |  |  | 					unsigned char byte; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 					if((*++line == '\0') || (*line == '\n')) { | 
					
						
							|  |  |  | 						softbreak = TRUE; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 						/* soft line break */ | 
					
						
							|  |  |  | 						break; | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 					byte = hex(*line); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if((*++line == '\0') || (*line == '\n')) { | 
					
						
							|  |  |  | 						/*
 | 
					
						
							|  |  |  | 						 * broken e-mail, not | 
					
						
							|  |  |  | 						 * adhering to RFC1522 | 
					
						
							|  |  |  | 						 */ | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 						*buf++ = byte; | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 					byte <<= 4; | 
					
						
							|  |  |  | 					byte += hex(*line); | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 					*buf++ = byte; | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 				} else | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 					*buf++ = *line; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 				line++; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-09-14 19:00:00 +00:00
										 |  |  | 			if(!softbreak) | 
					
						
							|  |  |  | 				/* Put the new line back in */ | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 				*buf++ = '\n'; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case BASE64: | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * RFC1521 sets the maximum length to 76 bytes | 
					
						
							|  |  |  | 			 * but many e-mail clients ignore that | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			copy = strdup(line); | 
					
						
							|  |  |  | 			p2 = strchr(copy, '='); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			if(p2) | 
					
						
							|  |  |  | 				*p2 = '\0'; | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * Klez doesn't always put "=" on the last line | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 			/*buf = decode(line, buf, base64, p2 == NULL);*/ | 
					
						
							| 
									
										
										
										
											2004-03-07 12:32:01 +00:00
										 |  |  | 			buf = decode(copy, buf, base64, FALSE); | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			free(copy); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case UUENCODE: | 
					
						
							| 
									
										
										
										
											2003-09-28 10:07:34 +00:00
										 |  |  | 			if(*line == '\0')	/* empty line */ | 
					
						
							| 
									
										
										
										
											2003-09-24 09:38:21 +00:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			if(strncasecmp(line, "begin ", 6) == 0) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			if(strcasecmp(line, "end") == 0) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if((line[0] & 0x3F) == ' ') | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			len = *line++ - ' '; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 			if(len > buflen) | 
					
						
							|  |  |  | 				/*
 | 
					
						
							|  |  |  | 				 * In practice this should never occur since | 
					
						
							|  |  |  | 				 * the maximum length of a uuencoded line is | 
					
						
							|  |  |  | 				 * 62 characters | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				cli_warnmsg("uudecode: buffer overflow stopped, attempting to ignore but decoding may fail"); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				buf = decode(line, buf, uudecode, (len & 3) == 0); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-17 07:58:42 +00:00
										 |  |  | 	*buf = '\0'; | 
					
						
							|  |  |  | 	return buf; | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-03-07 12:32:01 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Returns one byte after the end of the decoded data in "out" | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | static unsigned char * | 
					
						
							|  |  |  | decode(const char *in, unsigned char *out, unsigned char (*decoder)(char), bool isFast) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char b1, b2, b3, b4; | 
					
						
							|  |  |  | 	int nbytes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(isFast) | 
					
						
							|  |  |  | 		/* Fast decoding if not last line */ | 
					
						
							|  |  |  | 		while(*in) { | 
					
						
							|  |  |  | 			b1 = (*decoder)(*in++); | 
					
						
							|  |  |  | 			b2 = (*decoder)(*in++); | 
					
						
							|  |  |  | 			b3 = (*decoder)(*in++); | 
					
						
							|  |  |  | 			b4 = (*decoder)(*in++); | 
					
						
							|  |  |  | 			*out++ = (b1 << 2) | ((b2 >> 4) & 0x3); | 
					
						
							|  |  |  | 			*out++ = (b2 << 4) | ((b3 >> 2) & 0xF); | 
					
						
							|  |  |  | 			*out++ = (b3 << 6) | (b4 & 0x3F); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		/* Slower decoding for last line */ | 
					
						
							|  |  |  | 		while(*in) { | 
					
						
							|  |  |  | 			b1 = (*decoder)(*in++); | 
					
						
							|  |  |  | 			if(*in == '\0') { | 
					
						
							|  |  |  | 				b2 = '\0'; | 
					
						
							|  |  |  | 				nbytes = 1; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				assert(*in != '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				b2 = (*decoder)(*in++); | 
					
						
							|  |  |  | 				if(*in == '\0') { | 
					
						
							|  |  |  | 					b3 = '\0'; | 
					
						
							|  |  |  | 					nbytes = 2; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					assert(*in != '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					b3 = (*decoder)(*in++); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if(*in == '\0') { | 
					
						
							|  |  |  | 						b4 = '\0'; | 
					
						
							|  |  |  | 						nbytes = 3; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						assert(*in != '\0'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						b4 = (*decoder)(*in++); | 
					
						
							|  |  |  | 						nbytes = 4; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			switch(nbytes) { | 
					
						
							|  |  |  | 				case 3: | 
					
						
							|  |  |  | 					b4 = '\0'; | 
					
						
							|  |  |  | 					/* fall through */ | 
					
						
							|  |  |  | 				case 4: | 
					
						
							|  |  |  | 					*out++ = (b1 << 2) | ((b2 >> 4) & 0x3); | 
					
						
							|  |  |  | 					*out++ = (b2 << 4) | ((b3 >> 2) & 0xF); | 
					
						
							|  |  |  | 					*out++ = (b3 << 6) | (b4 & 0x3F); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case 2: | 
					
						
							|  |  |  | 					*out++ = (b1 << 2) | ((b2 >> 4) & 0x3); | 
					
						
							|  |  |  | 					*out++ = b2 << 4; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				case 1: | 
					
						
							|  |  |  | 					*out++ = b1 << 2; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				default: | 
					
						
							|  |  |  | 					assert(0); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(nbytes != 4) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	return out; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char | 
					
						
							|  |  |  | hex(char c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(isdigit(c)) | 
					
						
							|  |  |  | 		return c - '0'; | 
					
						
							|  |  |  | 	if((c >= 'A') && (c <= 'F')) | 
					
						
							|  |  |  | 		return c - 'A' + 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Some mails (notably some spam) break RFC1522 by failing to encode | 
					
						
							|  |  |  | 	 * the '=' character | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	return '='; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char | 
					
						
							|  |  |  | base64(char c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if(isupper(c)) | 
					
						
							|  |  |  | 		return c - 'A'; | 
					
						
							|  |  |  | 	if(islower(c)) | 
					
						
							|  |  |  | 		return c - 'a' + 26; | 
					
						
							|  |  |  | 	if(isdigit(c)) | 
					
						
							|  |  |  | 		return c - '0' + 52; | 
					
						
							|  |  |  | 	if(c == '+') | 
					
						
							|  |  |  | 		return 62; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-04 18:49:43 +00:00
										 |  |  | 	if(c != '/') | 
					
						
							| 
									
										
										
										
											2004-03-21 17:21:12 +00:00
										 |  |  | 		cli_dbgmsg("Illegal character <%c> in base64 encoding\n", c); | 
					
						
							| 
									
										
										
										
											2003-07-29 15:48:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 63; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char | 
					
						
							|  |  |  | uudecode(char c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return(c - ' '); | 
					
						
							|  |  |  | } |