|
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 |
|