View | Details | Raw Unified | Return to bug 333292
Collapse All | Expand All

(-)gmime-2.2.15/gmime/gmime-parser.c (-163 / +276 lines)
Lines 1-6 Link Here
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
/*  GMime
2
/*  GMime
3
 *  Copyright (C) 2000-2007 Jeffrey Stedfast
3
 *  Copyright (C) 2000-2008 Jeffrey Stedfast
4
 *
4
 *
5
 *  This library is free software; you can redistribute it and/or
5
 *  This library is free software; you can redistribute it and/or
6
 *  modify it under the terms of the GNU Lesser General Public License
6
 *  modify it under the terms of the GNU Lesser General Public License
Lines 30-35 Link Here
30
30
31
#include "gmime-parser.h"
31
#include "gmime-parser.h"
32
32
33
#include "gmime-table-private.h"
33
#include "gmime-stream-mem.h"
34
#include "gmime-stream-mem.h"
34
#include "gmime-message-part.h"
35
#include "gmime-message-part.h"
35
#include "gmime-multipart.h"
36
#include "gmime-multipart.h"
Lines 80-90 enum { Link Here
80
	GMIME_PARSER_STATE_HEADERS,
81
	GMIME_PARSER_STATE_HEADERS,
81
	GMIME_PARSER_STATE_HEADERS_END,
82
	GMIME_PARSER_STATE_HEADERS_END,
82
	GMIME_PARSER_STATE_CONTENT,
83
	GMIME_PARSER_STATE_CONTENT,
84
	GMIME_PARSER_STATE_COMPLETE,
83
};
85
};
84
86
85
struct _GMimeParserPrivate {
87
struct _GMimeParserPrivate {
86
	int state;
87
	
88
	GMimeStream *stream;
88
	GMimeStream *stream;
89
	
89
	
90
	off_t offset;
90
	off_t offset;
Lines 115-121 struct _GMimeParserPrivate { Link Here
115
	off_t headers_start;
115
	off_t headers_start;
116
	off_t header_start;
116
	off_t header_start;
117
	
117
	
118
	unsigned int unstep:26;
118
	int state:26;
119
	unsigned int midline:1;
119
	unsigned int midline:1;
120
	unsigned int seekable:1;
120
	unsigned int seekable:1;
121
	unsigned int scan_from:1;
121
	unsigned int scan_from:1;
Lines 326-332 parser_init (GMimeParser *parser, GMimeS Link Here
326
	priv->headers_start = -1;
326
	priv->headers_start = -1;
327
	priv->header_start = -1;
327
	priv->header_start = -1;
328
	
328
	
329
	priv->unstep = 0;
330
	priv->midline = FALSE;
329
	priv->midline = FALSE;
331
	priv->seekable = offset != -1;
330
	priv->seekable = offset != -1;
332
	
331
	
Lines 354-367 parser_close (GMimeParser *parser) Link Here
354
		parser_pop_boundary (parser);
353
		parser_pop_boundary (parser);
355
}
354
}
356
355
357
static void
358
parser_unstep (GMimeParser *parser)
359
{
360
	struct _GMimeParserPrivate *priv = parser->priv;
361
	
362
	priv->unstep++;
363
}
364
365
356
366
/**
357
/**
367
 * g_mime_parser_new:
358
 * g_mime_parser_new:
Lines 793-841 parser_step_from (GMimeParser *parser) Link Here
793
	priv->rawptr = priv->rawbuf;                                      \
784
	priv->rawptr = priv->rawbuf;                                      \
794
} G_STMT_END
785
} G_STMT_END
795
786
796
#define header_parse(parser, priv, hend) G_STMT_START {                   \
787
static void
797
	struct _header_raw *header;                                       \
788
header_parse (GMimeParser *parser, struct _header_raw **tail)
798
	register char *colon;                                             \
789
{
799
	size_t hlen;                                                      \
790
	struct _GMimeParserPrivate *priv = parser->priv;
800
	                                                                  \
791
	struct _header_raw *header;
801
	header = g_new (struct _header_raw, 1);                           \
792
	register char *inptr, *end;
802
	header->next = NULL;                                              \
793
	char *start;
803
	                                                                  \
794
	size_t hlen;
804
	*priv->headerptr = '\0';                                          \
795
	
805
	colon = priv->headerbuf;                                          \
796
	header = g_new (struct _header_raw, 1);
806
	while (*colon && *colon != ':')                                   \
797
	header->next = NULL;
807
		colon++;                                                  \
798
	
808
	                                                                  \
799
	*priv->headerptr = '\0';
809
	hlen = colon - priv->headerbuf;                                   \
800
	inptr = priv->headerbuf;
810
	                                                                  \
801
	while (*inptr && *inptr != ':' && !is_type (*inptr, IS_SPACE | IS_CTRL))
811
	header->name = g_strndup (priv->headerbuf, hlen);                 \
802
		inptr++;
812
	g_strstrip (header->name);                                        \
803
	
813
	if (*colon != ':') {                                              \
804
	if (*inptr != ':') {
814
		w(g_warning ("Invalid header: %s", header->name));        \
805
		/* ignore invalid headers */
815
		header->value = header->name;                             \
806
		w(g_warning ("Invalid header at %lld: '%s'",
816
		header->name = g_strdup ("X-Invalid-Header");             \
807
			     (long long) priv->header_start,
817
	} else {                                                          \
808
			     priv->headerbuf));
818
		header->value = g_strdup (colon + 1);                     \
809
		
819
		g_strstrip (header->value);                               \
810
		priv->headerleft += priv->headerptr - priv->headerbuf;
820
	}                                                                 \
811
		priv->headerptr = priv->headerbuf;
821
	header->offset = priv->header_start;                              \
812
		
822
	                                                                  \
813
		return;
823
	hend->next = header;                                              \
814
	}
824
	hend = header;                                                    \
815
	
825
	                                                                  \
816
	hlen = inptr - priv->headerbuf;
826
	priv->headerleft += priv->headerptr - priv->headerbuf;            \
817
	header->name = g_strndup (priv->headerbuf, hlen);
827
	priv->headerptr = priv->headerbuf;                                \
818
	
828
	                                                                  \
819
	/* skip over leading lwsp */
829
	if (priv->have_regex &&                                           \
820
	inptr++;
830
	    !regexec (&priv->header_regex, header->name, 0, NULL, 0))     \
821
	while (is_lwsp (*inptr))
831
		priv->header_cb (parser, header->name, header->value,     \
822
		inptr++;
832
				 header->offset, priv->user_data);        \
823
	
833
} G_STMT_END
824
	/* cut trailing lwsp */
825
	start = inptr++;
826
	end = inptr;
827
	
828
	while (*inptr) {
829
		if (!is_lwsp (*inptr++))
830
			end = inptr;
831
	}
832
	
833
	header->value = g_strndup (start, end - start);
834
	
835
	header->offset = priv->header_start;
836
	
837
	(*tail)->next = header;
838
	*tail = header;
839
	
840
	priv->headerleft += priv->headerptr - priv->headerbuf;
841
	priv->headerptr = priv->headerbuf;
842
	
843
	if (priv->have_regex &&
844
	    !regexec (&priv->header_regex, header->name, 0, NULL, 0))
845
		priv->header_cb (parser, header->name, header->value,
846
				 header->offset, priv->user_data);
847
}
834
848
835
static int
849
static int
836
parser_step_headers (GMimeParser *parser)
850
parser_step_headers (GMimeParser *parser)
837
{
851
{
838
	struct _GMimeParserPrivate *priv = parser->priv;
852
	struct _GMimeParserPrivate *priv = parser->priv;
853
	gboolean valid = TRUE, fieldname = TRUE;
839
	struct _header_raw *hend;
854
	struct _header_raw *hend;
840
	register char *inptr;
855
	register char *inptr;
841
	char *start, *inend;
856
	char *start, *inend;
Lines 843-848 parser_step_headers (GMimeParser *parser Link Here
843
	size_t len;
858
	size_t len;
844
	
859
	
845
	priv->midline = FALSE;
860
	priv->midline = FALSE;
861
	raw_header_reset (priv);
862
	header_raw_clear (&priv->headers);
846
	hend = (struct _header_raw *) &priv->headers;
863
	hend = (struct _header_raw *) &priv->headers;
847
	priv->headers_start = parser_offset (priv, NULL);
864
	priv->headers_start = parser_offset (priv, NULL);
848
	priv->header_start = parser_offset (priv, NULL);
865
	priv->header_start = parser_offset (priv, NULL);
Lines 864-869 parser_step_headers (GMimeParser *parser Link Here
864
		
881
		
865
		while (inptr < inend) {
882
		while (inptr < inend) {
866
			start = inptr;
883
			start = inptr;
884
			
885
			if (fieldname && *inptr != '\n') {
886
				/* scan and validate the field name */
887
				if (*inptr != ':') {
888
					*inend = ':';
889
					while (*inptr != ':') {
890
						if (is_type (*inptr, IS_SPACE | IS_CTRL)) {
891
							valid = FALSE;
892
							break;
893
						}
894
						
895
						inptr++;
896
					}
897
					
898
					if (inptr == inend) {
899
						/* don't have the full field name */
900
						left = inend - start;
901
						priv->inptr = start;
902
						goto refill;
903
					}
904
					
905
					*inend = '\n';
906
				} else if (*inptr == ':') {
907
					valid = FALSE;
908
				}
909
				
910
				if (!valid) {
911
					if (priv->scan_from && (inptr - start) == 4
912
					    && !strncmp (start, "From ", 5))
913
						goto next_message;
914
					
915
					if (priv->headers != NULL || *inptr == ':') {
916
						/* probably the start of the content,
917
						 * a broken mailer didn't terminate the
918
						 * headers with an empty line. *sigh* */
919
						goto content_start;
920
					}
921
				}
922
			}
923
			
924
			fieldname = FALSE;
925
			
867
			/* Note: see optimization comment [1] */
926
			/* Note: see optimization comment [1] */
868
			while (*inptr != '\n')
927
			while (*inptr != '\n')
869
				inptr++;
928
				inptr++;
Lines 897-905 parser_step_headers (GMimeParser *parser Link Here
897
			if (*inptr == ' ' || *inptr == '\t') {
956
			if (*inptr == ' ' || *inptr == '\t') {
898
				priv->midline = TRUE;
957
				priv->midline = TRUE;
899
			} else {
958
			} else {
900
				priv->midline = FALSE;
959
				header_parse (parser, &hend);
901
				header_parse (parser, priv, hend);
902
				priv->header_start = parser_offset (priv, inptr);
960
				priv->header_start = parser_offset (priv, inptr);
961
				priv->midline = FALSE;
962
				fieldname = TRUE;
963
				valid = TRUE;
903
			}
964
			}
904
		}
965
		}
905
		
966
		
Lines 917-931 parser_step_headers (GMimeParser *parser Link Here
917
 headers_end:
978
 headers_end:
918
	
979
	
919
	if (priv->headerptr > priv->headerbuf)
980
	if (priv->headerptr > priv->headerbuf)
920
		header_parse (parser, priv, hend);
981
		header_parse (parser, &hend);
921
	
982
	
983
	priv->state = GMIME_PARSER_STATE_HEADERS_END;
922
	*priv->rawptr = '\0';
984
	*priv->rawptr = '\0';
985
	priv->inptr = inptr;
923
	
986
	
924
	priv->state = GMIME_PARSER_STATE_HEADERS_END;
987
	return 0;
925
	
988
	
926
	g_assert (inptr <= priv->inend);
989
 next_message:
927
	
990
	
928
	priv->inptr = inptr;
991
	priv->state = GMIME_PARSER_STATE_COMPLETE;
992
	*priv->rawptr = '\0';
993
	priv->inptr = start;
994
	
995
	return 0;
996
	
997
 content_start:
998
	
999
	priv->state = GMIME_PARSER_STATE_CONTENT;
1000
	*priv->rawptr = '\0';
1001
	priv->inptr = start;
929
	
1002
	
930
	return 0;
1003
	return 0;
931
}
1004
}
Lines 943-996 parser_content_type (GMimeParser *parser Link Here
943
}
1016
}
944
1017
945
static int
1018
static int
946
parser_step (GMimeParser *parser)
947
{
948
	struct _GMimeParserPrivate *priv = parser->priv;
949
	
950
	if (!priv->unstep) {
951
	step:
952
		switch (priv->state) {
953
		case GMIME_PARSER_STATE_INIT:
954
			if (priv->scan_from)
955
				priv->state = GMIME_PARSER_STATE_FROM;
956
			else
957
				priv->state = GMIME_PARSER_STATE_HEADERS;
958
			goto step;
959
			break;
960
		case GMIME_PARSER_STATE_FROM:
961
			parser_step_from (parser);
962
			break;
963
		case GMIME_PARSER_STATE_HEADERS:
964
			parser_step_headers (parser);
965
			break;
966
		case GMIME_PARSER_STATE_ERROR:
967
			break;
968
		default:
969
			g_assert_not_reached ();
970
			break;
971
		}
972
	} else {
973
		priv->unstep--;
974
	}
975
	
976
	return priv->state;
977
}
978
979
static void
980
parser_skip_line (GMimeParser *parser)
1019
parser_skip_line (GMimeParser *parser)
981
{
1020
{
982
	struct _GMimeParserPrivate *priv = parser->priv;
1021
	struct _GMimeParserPrivate *priv = parser->priv;
983
	register char *inptr;
1022
	register char *inptr;
984
	char *inend;
1023
	char *inend;
985
	
1024
	int rv = 0;
986
	inptr = priv->inptr;
987
	
1025
	
988
	do {
1026
	do {
989
		if (parser_fill (parser) <= 0) {
990
			inptr = priv->inptr;
991
			break;
992
		}
993
		
994
		inptr = priv->inptr;
1027
		inptr = priv->inptr;
995
		inend = priv->inend;
1028
		inend = priv->inend;
996
		*inend = '\n';
1029
		*inend = '\n';
Lines 1002-1016 parser_skip_line (GMimeParser *parser) Link Here
1002
			break;
1035
			break;
1003
		
1036
		
1004
		priv->inptr = inptr;
1037
		priv->inptr = inptr;
1038
		
1039
		if (parser_fill (parser) <= 0) {
1040
			inptr = priv->inptr;
1041
			rv = -1;
1042
			break;
1043
		}
1005
	} while (1);
1044
	} while (1);
1006
	
1045
	
1007
	priv->midline = FALSE;
1046
	priv->midline = FALSE;
1008
	
1047
	
1009
	priv->inptr = MIN (inptr + 1, priv->inend);
1048
	priv->inptr = MIN (inptr + 1, priv->inend);
1049
	
1050
	return rv;
1051
}
1052
1053
static int
1054
parser_step (GMimeParser *parser)
1055
{
1056
	struct _GMimeParserPrivate *priv = parser->priv;
1057
	
1058
	switch (priv->state) {
1059
	case GMIME_PARSER_STATE_ERROR:
1060
		break;
1061
	case GMIME_PARSER_STATE_INIT:
1062
		if (priv->scan_from)
1063
			priv->state = GMIME_PARSER_STATE_FROM;
1064
		else
1065
			priv->state = GMIME_PARSER_STATE_HEADERS;
1066
		break;
1067
	case GMIME_PARSER_STATE_FROM:
1068
		parser_step_from (parser);
1069
		break;
1070
	case GMIME_PARSER_STATE_HEADERS:
1071
		parser_step_headers (parser);
1072
		break;
1073
	case GMIME_PARSER_STATE_HEADERS_END:
1074
		if (parser_skip_line (parser) == -1)
1075
			priv->state = GMIME_PARSER_STATE_ERROR;
1076
		else
1077
			priv->state = GMIME_PARSER_STATE_CONTENT;
1078
		break;
1079
	case GMIME_PARSER_STATE_CONTENT:
1080
		break;
1081
	case GMIME_PARSER_STATE_COMPLETE:
1082
		break;
1083
	default:
1084
		g_assert_not_reached ();
1085
		break;
1086
	}
1087
	
1088
	return priv->state;
1010
}
1089
}
1011
1090
1091
1012
enum {
1092
enum {
1013
	FOUND_EOS          = 1,
1093
	FOUND_NOTHING,
1094
	FOUND_EOS,
1014
	FOUND_BOUNDARY,
1095
	FOUND_BOUNDARY,
1015
	FOUND_END_BOUNDARY
1096
	FOUND_END_BOUNDARY
1016
};
1097
};
Lines 1076-1082 check_boundary (struct _GMimeParserPriva Link Here
1076
 **/
1157
 **/
1077
1158
1078
static int
1159
static int
1079
parser_scan_content (GMimeParser *parser, GByteArray *content, guint *crlf)
1160
parser_scan_content (GMimeParser *parser, GByteArray *content, int *crlf)
1080
{
1161
{
1081
	struct _GMimeParserPrivate *priv = parser->priv;
1162
	struct _GMimeParserPrivate *priv = parser->priv;
1082
	register char *inptr;
1163
	register char *inptr;
Lines 1137-1143 parser_scan_content (GMimeParser *parser Link Here
1137
					goto refill;
1218
					goto refill;
1138
				}
1219
				}
1139
				
1220
				
1140
				/* check for a boundary not ending in a \n */
1221
				/* check for a boundary not ending in a \n (EOF) */
1141
				if ((found = check_boundary (priv, start, len)))
1222
				if ((found = check_boundary (priv, start, len)))
1142
					goto boundary;
1223
					goto boundary;
1143
			}
1224
			}
Lines 1174-1180 parser_scan_mime_part_content (GMimePars Link Here
1174
	GMimeDataWrapper *wrapper;
1255
	GMimeDataWrapper *wrapper;
1175
	GMimeStream *stream;
1256
	GMimeStream *stream;
1176
	off_t start, end;
1257
	off_t start, end;
1177
	guint crlf;
1258
	int crlf;
1259
	
1260
	g_assert (priv->state >= GMIME_PARSER_STATE_HEADERS_END);
1178
	
1261
	
1179
	if (priv->persist_stream && priv->seekable)
1262
	if (priv->persist_stream && priv->seekable)
1180
		start = parser_offset (priv, NULL);
1263
		start = parser_offset (priv, NULL);
Lines 1194-1204 parser_scan_mime_part_content (GMimePars Link Here
1194
	
1277
	
1195
	encoding = g_mime_part_get_encoding (mime_part);
1278
	encoding = g_mime_part_get_encoding (mime_part);
1196
	
1279
	
1197
	if (priv->persist_stream && priv->seekable) {
1280
	if (priv->persist_stream && priv->seekable)
1198
		stream = g_mime_stream_substream (priv->stream, start, end);
1281
		stream = g_mime_stream_substream (priv->stream, start, end);
1199
	} else {
1282
	else
1200
		stream = g_mime_stream_mem_new_with_byte_array (content);
1283
		stream = g_mime_stream_mem_new_with_byte_array (content);
1201
	}
1202
	
1284
	
1203
	wrapper = g_mime_data_wrapper_new_with_stream (stream, encoding);
1285
	wrapper = g_mime_data_wrapper_new_with_stream (stream, encoding);
1204
	g_mime_part_set_content_object (mime_part, wrapper);
1286
	g_mime_part_set_content_object (mime_part, wrapper);
Lines 1215-1224 parser_scan_message_part (GMimeParser *p Link Here
1215
	GMimeMessage *message;
1297
	GMimeMessage *message;
1216
	GMimeObject *object;
1298
	GMimeObject *object;
1217
	
1299
	
1300
	g_assert (priv->state == GMIME_PARSER_STATE_CONTENT);
1301
	
1218
	/* get the headers */
1302
	/* get the headers */
1219
	parser->priv->state = GMIME_PARSER_STATE_HEADERS;
1303
	priv->state = GMIME_PARSER_STATE_HEADERS;
1220
	while (parser_step (parser) != GMIME_PARSER_STATE_HEADERS_END)
1304
	if (parser_step (parser) == -1) {
1221
		;
1305
		/* Note: currently cannot happen because
1306
		 * parser_step_headers() never returns error */
1307
		*found = FOUND_EOS;
1308
		return;
1309
	}
1222
	
1310
	
1223
	message = g_mime_message_new (FALSE);
1311
	message = g_mime_message_new (FALSE);
1224
	header = priv->headers;
1312
	header = priv->headers;
Lines 1230-1241 parser_scan_message_part (GMimeParser *p Link Here
1230
	if (!(content_type = parser_content_type (parser)))
1318
	if (!(content_type = parser_content_type (parser)))
1231
		content_type = g_mime_content_type_new ("text", "plain");
1319
		content_type = g_mime_content_type_new ("text", "plain");
1232
	
1320
	
1233
	parser_unstep (parser);
1321
	if (g_mime_content_type_is_type (content_type, "multipart", "*"))
1234
	if (g_mime_content_type_is_type (content_type, "multipart", "*")) {
1235
		object = parser_construct_multipart (parser, content_type, found);
1322
		object = parser_construct_multipart (parser, content_type, found);
1236
	} else {
1323
	else
1237
		object = parser_construct_leaf_part (parser, content_type, found);
1324
		object = parser_construct_leaf_part (parser, content_type, found);
1238
	}
1239
	
1325
	
1240
	message->mime_part = object;
1326
	message->mime_part = object;
1241
	
1327
	
Lines 1250-1260 parser_construct_leaf_part (GMimeParser Link Here
1250
	struct _header_raw *header;
1336
	struct _header_raw *header;
1251
	GMimeObject *object;
1337
	GMimeObject *object;
1252
	
1338
	
1253
	/* get the headers */
1339
	g_assert (priv->state >= GMIME_PARSER_STATE_HEADERS_END);
1254
	while (parser_step (parser) != GMIME_PARSER_STATE_HEADERS_END)
1255
		;
1256
	
1340
	
1257
	object = g_mime_object_new_type (content_type->type, content_type->subtype);
1341
	object = g_mime_object_new_type (content_type->type, content_type->subtype);
1342
	
1258
	header = priv->headers;
1343
	header = priv->headers;
1259
	while (header) {
1344
	while (header) {
1260
		g_mime_object_add_header (object, header->name, header->value);
1345
		g_mime_object_add_header (object, header->name, header->value);
Lines 1270-1283 parser_construct_leaf_part (GMimeParser Link Here
1270
	g_mime_header_set_raw (object->headers, priv->rawbuf);
1355
	g_mime_header_set_raw (object->headers, priv->rawbuf);
1271
	raw_header_reset (priv);
1356
	raw_header_reset (priv);
1272
	
1357
	
1273
	/* skip empty line after headers */
1358
	if (priv->state == GMIME_PARSER_STATE_HEADERS_END) {
1274
	parser_skip_line (parser);
1359
		/* skip empty line after headers */
1360
		if (parser_step (parser) == -1) {
1361
			*found = FOUND_EOS;
1362
			return object;
1363
		}
1364
	}
1275
	
1365
	
1276
	if (GMIME_IS_MESSAGE_PART (object)) {
1366
	if (GMIME_IS_MESSAGE_PART (object))
1277
		parser_scan_message_part (parser, (GMimeMessagePart *) object, found);
1367
		parser_scan_message_part (parser, (GMimeMessagePart *) object, found);
1278
	} else {
1368
	else
1279
		parser_scan_mime_part_content (parser, (GMimePart *) object, found);
1369
		parser_scan_mime_part_content (parser, (GMimePart *) object, found);
1280
	}
1281
	
1370
	
1282
	return object;
1371
	return object;
1283
}
1372
}
Lines 1311-1319 static int Link Here
1311
parser_scan_multipart_face (GMimeParser *parser, GMimeMultipart *multipart, gboolean preface)
1400
parser_scan_multipart_face (GMimeParser *parser, GMimeMultipart *multipart, gboolean preface)
1312
{
1401
{
1313
	GByteArray *buffer;
1402
	GByteArray *buffer;
1314
	guint crlf;
1403
	int found, crlf;
1315
	char *face;
1404
	char *face;
1316
	int found;
1317
	
1405
	
1318
	buffer = g_byte_array_new ();
1406
	buffer = g_byte_array_new ();
1319
	found = parser_scan_content (parser, buffer, &crlf);
1407
	found = parser_scan_content (parser, buffer, &crlf);
Lines 1339-1383 parser_scan_multipart_face (GMimeParser Link Here
1339
#define parser_scan_multipart_preface(parser, multipart) parser_scan_multipart_face (parser, multipart, TRUE)
1427
#define parser_scan_multipart_preface(parser, multipart) parser_scan_multipart_face (parser, multipart, TRUE)
1340
#define parser_scan_multipart_postface(parser, multipart) parser_scan_multipart_face (parser, multipart, FALSE)
1428
#define parser_scan_multipart_postface(parser, multipart) parser_scan_multipart_face (parser, multipart, FALSE)
1341
1429
1430
static gboolean
1431
found_immediate_boundary (struct _GMimeParserPrivate *priv, gboolean end)
1432
{
1433
	struct _boundary_stack *s = priv->bounds;
1434
	size_t len = end ? s->boundarylenfinal : s->boundarylen;
1435
	
1436
	return !strncmp (priv->inptr, s->boundary, len)
1437
		&& (priv->inptr[len] == '\n' || priv->inptr[len] == '\r');
1438
}
1439
1342
static int
1440
static int
1343
parser_scan_multipart_subparts (GMimeParser *parser, GMimeMultipart *multipart)
1441
parser_scan_multipart_subparts (GMimeParser *parser, GMimeMultipart *multipart)
1344
{
1442
{
1443
	struct _GMimeParserPrivate *priv = parser->priv;
1345
	GMimeContentType *content_type;
1444
	GMimeContentType *content_type;
1346
	GMimeObject *subpart;
1445
	GMimeObject *subpart;
1347
	int found;
1446
	int found;
1348
	
1447
	
1349
	do {
1448
	do {
1350
		/* skip over the boundary marker */
1449
		/* skip over the boundary marker */
1351
		parser_skip_line (parser);
1450
		if (parser_skip_line (parser) == -1) {
1451
			found = FOUND_EOS;
1452
			break;
1453
		}
1352
		
1454
		
1353
		/* get the headers */
1455
		/* get the headers */
1354
		parser_step_headers (parser);
1456
		priv->state = GMIME_PARSER_STATE_HEADERS;
1457
		if (parser_step (parser) == -1) {
1458
			found = FOUND_EOS;
1459
			break;
1460
		}
1461
		
1462
		if (priv->state == GMIME_PARSER_STATE_COMPLETE && priv->headers == NULL) {
1463
			found = FOUND_END_BOUNDARY;
1464
			break;
1465
		}
1355
		
1466
		
1356
		if (!(content_type = parser_content_type (parser)))
1467
		if (!(content_type = parser_content_type (parser)))
1357
			content_type = g_mime_content_type_new ("text", "plain");
1468
			content_type = g_mime_content_type_new ("text", "plain");
1358
		
1469
		
1359
		parser_unstep (parser);
1470
		if (g_mime_content_type_is_type (content_type, "multipart", "*"))
1360
		if (g_mime_content_type_is_type (content_type, "multipart", "*")) {
1361
			subpart = parser_construct_multipart (parser, content_type, &found);
1471
			subpart = parser_construct_multipart (parser, content_type, &found);
1362
		} else {
1472
		else
1363
			subpart = parser_construct_leaf_part (parser, content_type, &found);
1473
			subpart = parser_construct_leaf_part (parser, content_type, &found);
1364
		}
1365
		
1474
		
1366
		g_mime_multipart_add_part (multipart, subpart);
1475
		g_mime_multipart_add_part (multipart, subpart);
1367
		g_object_unref (subpart);
1476
		g_object_unref (subpart);
1368
	} while (found == FOUND_BOUNDARY);
1477
	} while (found == FOUND_BOUNDARY && found_immediate_boundary (priv, FALSE));
1369
	
1478
	
1370
	return found;
1479
	return found;
1371
}
1480
}
1372
1481
1373
static gboolean
1374
found_immediate_boundary (struct _GMimeParserPrivate *priv)
1375
{
1376
	struct _boundary_stack *s = priv->bounds;
1377
	
1378
	return !strncmp (s->boundary, priv->inptr, s->boundarylenfinal);
1379
}
1380
1381
static GMimeObject *
1482
static GMimeObject *
1382
parser_construct_multipart (GMimeParser *parser, GMimeContentType *content_type, int *found)
1483
parser_construct_multipart (GMimeParser *parser, GMimeContentType *content_type, int *found)
1383
{
1484
{
Lines 1387-1397 parser_construct_multipart (GMimeParser Link Here
1387
	const char *boundary;
1488
	const char *boundary;
1388
	GMimeObject *object;
1489
	GMimeObject *object;
1389
	
1490
	
1390
	/* get the headers */
1491
	g_assert (priv->state >= GMIME_PARSER_STATE_HEADERS_END);
1391
	while (parser_step (parser) != GMIME_PARSER_STATE_HEADERS_END)
1392
		;
1393
	
1492
	
1394
	object = g_mime_object_new_type (content_type->type, content_type->subtype);
1493
	object = g_mime_object_new_type (content_type->type, content_type->subtype);
1494
	
1395
	header = priv->headers;
1495
	header = priv->headers;
1396
	while (header) {
1496
	while (header) {
1397
		g_mime_object_add_header (object, header->name, header->value);
1497
		g_mime_object_add_header (object, header->name, header->value);
Lines 1409-1416 parser_construct_multipart (GMimeParser Link Here
1409
	
1509
	
1410
	multipart = (GMimeMultipart *) object;
1510
	multipart = (GMimeMultipart *) object;
1411
	
1511
	
1412
	/* skip empty line after headers */
1512
	if (priv->state == GMIME_PARSER_STATE_HEADERS_END) {
1413
	parser_skip_line (parser);
1513
		/* skip empty line after headers */
1514
		if (parser_step (parser) == -1) {
1515
			*found = FOUND_EOS;
1516
			return object;
1517
		}
1518
	}
1414
	
1519
	
1415
	boundary = g_mime_content_type_get_parameter (content_type, "boundary");
1520
	boundary = g_mime_content_type_get_parameter (content_type, "boundary");
1416
	if (boundary) {
1521
	if (boundary) {
Lines 1421-1427 parser_construct_multipart (GMimeParser Link Here
1421
		if (*found == FOUND_BOUNDARY)
1526
		if (*found == FOUND_BOUNDARY)
1422
			*found = parser_scan_multipart_subparts (parser, multipart);
1527
			*found = parser_scan_multipart_subparts (parser, multipart);
1423
		
1528
		
1424
		if (*found == FOUND_END_BOUNDARY && found_immediate_boundary (priv)) {
1529
		if (*found == FOUND_END_BOUNDARY && found_immediate_boundary (priv, TRUE)) {
1425
			/* eat end boundary */
1530
			/* eat end boundary */
1426
			parser_skip_line (parser);
1531
			parser_skip_line (parser);
1427
			parser_pop_boundary (parser);
1532
			parser_pop_boundary (parser);
Lines 1441-1463 parser_construct_multipart (GMimeParser Link Here
1441
static GMimeObject *
1546
static GMimeObject *
1442
parser_construct_part (GMimeParser *parser)
1547
parser_construct_part (GMimeParser *parser)
1443
{
1548
{
1549
	struct _GMimeParserPrivate *priv = parser->priv;
1444
	GMimeContentType *content_type;
1550
	GMimeContentType *content_type;
1445
	GMimeObject *object;
1551
	GMimeObject *object;
1446
	int found;
1552
	int found;
1447
	
1553
	
1448
	/* get the headers */
1554
	/* get the headers */
1449
	while (parser_step (parser) != GMIME_PARSER_STATE_HEADERS_END)
1555
	while (priv->state < GMIME_PARSER_STATE_HEADERS_END) {
1450
		;
1556
		if (parser_step (parser) == -1)
1557
			return NULL;
1558
	}
1451
	
1559
	
1452
	if (!(content_type = parser_content_type (parser)))
1560
	if (!(content_type = parser_content_type (parser)))
1453
		content_type = g_mime_content_type_new ("text", "plain");
1561
		content_type = g_mime_content_type_new ("text", "plain");
1454
	
1562
	
1455
	parser_unstep (parser);
1563
	if (g_mime_content_type_is_type (content_type, "multipart", "*"))
1456
	if (g_mime_content_type_is_type (content_type, "multipart", "*")) {
1457
		object = parser_construct_multipart (parser, content_type, &found);
1564
		object = parser_construct_multipart (parser, content_type, &found);
1458
	} else {
1565
	else
1459
		object = parser_construct_leaf_part (parser, content_type, &found);
1566
		object = parser_construct_leaf_part (parser, content_type, &found);
1460
	}
1461
	
1567
	
1462
	return object;
1568
	return object;
1463
}
1569
}
Lines 1484-1508 static GMimeMessage * Link Here
1484
parser_construct_message (GMimeParser *parser)
1590
parser_construct_message (GMimeParser *parser)
1485
{
1591
{
1486
	struct _GMimeParserPrivate *priv = parser->priv;
1592
	struct _GMimeParserPrivate *priv = parser->priv;
1593
	unsigned int content_length = ULONG_MAX;
1487
	GMimeContentType *content_type;
1594
	GMimeContentType *content_type;
1488
	struct _header_raw *header;
1595
	struct _header_raw *header;
1489
	int content_length = -1;
1490
	GMimeMessage *message;
1596
	GMimeMessage *message;
1491
	GMimeObject *object;
1597
	GMimeObject *object;
1492
	int state, found;
1598
	char *endptr;
1599
	int found;
1493
	
1600
	
1494
	/* get the headers (and, optionally, the from-line) */
1601
	/* scan the from-line if we are parsing an mbox */
1495
	while ((state = parser_step (parser)) != GMIME_PARSER_STATE_ERROR && state != GMIME_PARSER_STATE_HEADERS_END)
1602
	while (priv->state != GMIME_PARSER_STATE_HEADERS) {
1496
		;
1603
		if (parser_step (parser) == -1)
1604
			return NULL;
1605
	}
1497
	
1606
	
1498
	if (state == GMIME_PARSER_STATE_ERROR)
1607
	/* parse the headers */
1499
		return NULL;
1608
	while (priv->state < GMIME_PARSER_STATE_HEADERS_END) {
1609
		if (parser_step (parser) == -1)
1610
			return NULL;
1611
	}
1500
	
1612
	
1501
	message = g_mime_message_new (FALSE);
1613
	message = g_mime_message_new (FALSE);
1502
	header = priv->headers;
1614
	header = priv->headers;
1503
	while (header) {
1615
	while (header) {
1504
		if (priv->respect_content_length && !g_ascii_strcasecmp (header->name, "Content-Length"))
1616
		if (priv->respect_content_length && !g_ascii_strcasecmp (header->name, "Content-Length")) {
1505
			content_length = strtoul (header->value, NULL, 10);
1617
			content_length = strtoul (header->value, &endptr, 10);
1618
			if (endptr == header->value)
1619
				content_length = ULONG_MAX;
1620
		}
1506
		
1621
		
1507
		g_mime_object_add_header ((GMimeObject *) message, header->name, header->value);
1622
		g_mime_object_add_header ((GMimeObject *) message, header->name, header->value);
1508
		header = header->next;
1623
		header = header->next;
Lines 1510-1528 parser_construct_message (GMimeParser *p Link Here
1510
	
1625
	
1511
	if (priv->scan_from) {
1626
	if (priv->scan_from) {
1512
		parser_push_boundary (parser, "From ");
1627
		parser_push_boundary (parser, "From ");
1513
		if (priv->respect_content_length && content_length != -1)
1628
		if (priv->respect_content_length && content_length < ULONG_MAX)
1514
			priv->bounds->content_end = parser_offset (priv, NULL) + content_length;
1629
			priv->bounds->content_end = parser_offset (priv, NULL) + content_length;
1515
	}
1630
	}
1516
	
1631
	
1517
	if (!(content_type = parser_content_type (parser)))
1632
	if (!(content_type = parser_content_type (parser)))
1518
		content_type = g_mime_content_type_new ("text", "plain");
1633
		content_type = g_mime_content_type_new ("text", "plain");
1519
	
1634
	
1520
	parser_unstep (parser);
1635
	if (content_type && g_mime_content_type_is_type (content_type, "multipart", "*"))
1521
	if (content_type && g_mime_content_type_is_type (content_type, "multipart", "*")) {
1522
		object = parser_construct_multipart (parser, content_type, &found);
1636
		object = parser_construct_multipart (parser, content_type, &found);
1523
	} else {
1637
	else
1524
		object = parser_construct_leaf_part (parser, content_type, &found);
1638
		object = parser_construct_leaf_part (parser, content_type, &found);
1525
	}
1526
	
1639
	
1527
	message->mime_part = object;
1640
	message->mime_part = object;
1528
	
1641
	

Return to bug 333292