1
/*-----------------------------------------------------------------------
6
** Written by Paul L Daniels, originally for the Xamime project
7
** (http://www.xamime.com) but since spawned off to the ripMIME/alterMIME
8
** family of email parsing tools.
10
** Copyright PLD, 1999,2000,2001,2002,2003
12
** For more information on the licence and copyrights of this code, please
13
** email copyright@pldaniels.com
16
** 2003-Jun-24: PLD: Added subject parsing
28
#include <sys/types.h>
35
#include "libmime-decoders.h"
38
#include "boundary-stack.h"
39
#include "filename-filters.h"
40
#include "MIME_headers.h"
44
#define FL __FILE__, __LINE__
48
#define MIMEH_DPEDANTIC ((glb.debug >= _MIMEH_DEBUG_PEDANTIC))
49
#define MIMEH_DNORMAL ((glb.debug >= _MIMEH_DEBUG_NORMAL ))
51
#define DMIMEH if ((glb.debug >= _MIMEH_DEBUG_NORMAL))
54
char *MIMEH_defect_description_array[_MIMEH_DEFECT_ARRAY_SIZE];
58
struct MIMEH_globals {
62
char doubleCRname[_MIMEH_STRLEN_MAX +1];
64
char appledouble_filename[_MIMEH_STRLEN_MAX +1];
66
char subject[_MIMEH_STRLEN_MAX +1];
69
char *headerline_original; // Holds the original header-form without decoding.
71
int save_headers_original;
78
int verbose_contenttype;
80
int header_longsearch; // keep searching until valid headers are found - this is used to filter out qmail bounced emails - breaks RFC's but people are wanting it :-(
81
int longsearch_limit; // how many segments do we attempt to look ahead...
83
char output_dir[_MIMEH_STRLEN_MAX +1];
87
FILE *original_header_file;
88
int original_header_save_to_file;
91
static struct MIMEH_globals glb;
95
/*-----------------------------------------------------------------\
96
Function Name : MIMEH_version
103
--------------------------------------------------------------------
106
--------------------------------------------------------------------
109
\------------------------------------------------------------------*/
110
int MIMEH_version(void)
112
fprintf(stdout,"mimeheaders: %s\n", MIMEH_VERSION);
117
/*-----------------------------------------------------------------\
118
Function Name : MIMEH_init
125
--------------------------------------------------------------------
128
--------------------------------------------------------------------
131
\------------------------------------------------------------------*/
132
int MIMEH_init( void )
136
glb.headerline = NULL;
137
glb.headerline_original = NULL;
138
glb.header_file = NULL;
139
glb.original_header_file = NULL;
140
glb.original_header_save_to_file = 0;
142
glb.save_headers = 0;
143
glb.save_headers_original = 0;
144
glb.test_mailbox = 0;
147
glb.doubleCR_count = 0;
148
glb.doubleCR_save = 1;
151
glb.verbose_contenttype = 0;
152
glb.output_dir[0]='\0';
153
glb.doubleCRname[0]='\0';
154
glb.appledouble_filename[0]='\0';
155
glb.header_longsearch=0;
156
glb.longsearch_limit=1;
161
/*-----------------------------------------------------------------\
162
Function Name : MIMEH_get_doubleCR
169
--------------------------------------------------------------------
172
--------------------------------------------------------------------
175
\------------------------------------------------------------------*/
176
int MIMEH_get_doubleCR( void )
181
/*-----------------------------------------------------------------\
182
Function Name : MIMEH_set_doubleCR
189
--------------------------------------------------------------------
192
--------------------------------------------------------------------
195
\------------------------------------------------------------------*/
196
int MIMEH_set_doubleCR( int level )
198
glb.doubleCR = level;
204
/*-----------------------------------------------------------------\
205
Function Name : MIMEH_set_headerfix
212
--------------------------------------------------------------------
215
--------------------------------------------------------------------
218
\------------------------------------------------------------------*/
219
int MIMEH_set_headerfix( int level )
221
glb.header_fix = level;
222
return glb.header_fix;
225
/*-----------------------------------------------------------------\
226
Function Name : MIMEH_set_doubleCR_save
233
--------------------------------------------------------------------
236
--------------------------------------------------------------------
239
\------------------------------------------------------------------*/
240
int MIMEH_set_doubleCR_save( int level )
242
glb.doubleCR_save = level;
244
return glb.doubleCR_save;
247
/*-----------------------------------------------------------------\
248
Function Name : MIMEH_get_doubleCR_save
255
--------------------------------------------------------------------
258
--------------------------------------------------------------------
261
\------------------------------------------------------------------*/
262
int MIMEH_get_doubleCR_save( void )
264
return glb.doubleCR_save;
268
/*-----------------------------------------------------------------\
269
Function Name : *MIMEH_get_doubleCR_name
276
--------------------------------------------------------------------
279
--------------------------------------------------------------------
282
\------------------------------------------------------------------*/
283
char *MIMEH_get_doubleCR_name( void )
285
return glb.doubleCRname;
289
/*-----------------------------------------------------------------\
290
Function Name : MIMEH_set_debug
297
--------------------------------------------------------------------
300
--------------------------------------------------------------------
303
\------------------------------------------------------------------*/
304
int MIMEH_set_debug( int level )
310
/*-----------------------------------------------------------------\
311
Function Name : MIMEH_set_outputdir
318
--------------------------------------------------------------------
321
--------------------------------------------------------------------
324
\------------------------------------------------------------------*/
325
int MIMEH_set_outputdir( char *dir )
327
if (dir) snprintf(glb.output_dir,_MIMEH_STRLEN_MAX,"%s",dir);
331
/*-----------------------------------------------------------------\
332
Function Name : MIMEH_set_webform
339
--------------------------------------------------------------------
342
--------------------------------------------------------------------
345
\------------------------------------------------------------------*/
346
int MIMEH_set_webform( int level )
353
/*-----------------------------------------------------------------\
354
Function Name : MIMEH_set_mailbox
361
--------------------------------------------------------------------
364
--------------------------------------------------------------------
367
\------------------------------------------------------------------*/
368
int MIMEH_set_mailbox( int level )
370
glb.test_mailbox = level;
374
/*-----------------------------------------------------------------\
375
Function Name : MIMEH_set_verbosity
382
--------------------------------------------------------------------
385
--------------------------------------------------------------------
388
\------------------------------------------------------------------*/
389
int MIMEH_set_verbosity( int level )
395
/*-----------------------------------------------------------------\
396
Function Name : MIMEH_set_verbosity_contenttype
403
--------------------------------------------------------------------
406
--------------------------------------------------------------------
409
\------------------------------------------------------------------*/
410
int MIMEH_set_verbosity_contenttype( int level )
412
glb.verbose_contenttype = level;
416
/*-----------------------------------------------------------------\
417
Function Name : MIMEH_get_verbosity_contenttype
424
--------------------------------------------------------------------
427
--------------------------------------------------------------------
430
\------------------------------------------------------------------*/
431
int MIMEH_get_verbosity_contenttype( void )
433
return glb.verbose_contenttype;
438
/*------------------------------------------------------------------------
439
Procedure: MIMEH_set_headers_save ID:1
440
Purpose: Sets MIMEH's headers save file (where MIMEH will save the
441
headers it reads in from the mailpack)
445
------------------------------------------------------------------------*/
446
int MIMEH_set_headers_save( FILE *f )
449
glb.save_headers = 1;
454
/*-----------------------------------------------------------------\
455
Function Name : MIMEH_set_headers_original_save_to_file
462
--------------------------------------------------------------------
465
--------------------------------------------------------------------
468
\------------------------------------------------------------------*/
469
int MIMEH_set_headers_original_save_to_file( FILE *f )
471
if (f == NULL) glb.original_header_save_to_file = 0;
472
else glb.original_header_save_to_file = 1;
473
glb.original_header_file = f;
475
return glb.original_header_save_to_file;
478
/*-----------------------------------------------------------------\
479
Function Name : MIMEH_set_headers_nosave
486
--------------------------------------------------------------------
489
--------------------------------------------------------------------
492
\------------------------------------------------------------------*/
493
int MIMEH_set_headers_nosave( void )
495
glb.header_file = NULL;
496
glb.save_headers = 0;
500
/*-----------------------------------------------------------------\
501
Function Name : MIMEH_get_headers_save
508
--------------------------------------------------------------------
511
--------------------------------------------------------------------
514
\------------------------------------------------------------------*/
515
int MIMEH_get_headers_save( void )
517
return glb.save_headers;
521
/*-----------------------------------------------------------------\
522
Function Name : MIMEH_set_headers_save_original
529
--------------------------------------------------------------------
532
--------------------------------------------------------------------
535
\------------------------------------------------------------------*/
536
int MIMEH_set_headers_save_original( int level )
538
glb.save_headers_original = level;
540
return glb.save_headers_original;
544
/*-----------------------------------------------------------------\
545
Function Name : MIMEH_get_headers_ptr
552
--------------------------------------------------------------------
555
--------------------------------------------------------------------
558
\------------------------------------------------------------------*/
559
char *MIMEH_get_headers_ptr( void )
561
return glb.headerline;
565
/*-----------------------------------------------------------------\
566
Function Name : *MIMEH_get_headers_original_ptr
573
--------------------------------------------------------------------
576
--------------------------------------------------------------------
579
\------------------------------------------------------------------*/
580
char *MIMEH_get_headers_original_ptr( void )
582
return glb.headerline_original;
586
/*-----------------------------------------------------------------\
587
Function Name : MIMEH_set_header_longsearch
594
--------------------------------------------------------------------
596
The header long-search is a facility switch that will make the
597
header searching to continue on until it either reaches the end of
598
the file or it finds valid (??) headers to work on.
601
--------------------------------------------------------------------
604
\------------------------------------------------------------------*/
605
int MIMEH_set_header_longsearch( int level )
607
glb.header_longsearch = level;
609
return glb.header_longsearch;
612
/*-----------------------------------------------------------------\
613
Function Name : MIMEH_set_defect
616
1. struct MIMEH_header_info *hinfo,
617
2. int defect , The defect code to set
621
--------------------------------------------------------------------
624
--------------------------------------------------------------------
627
\------------------------------------------------------------------*/
628
int MIMEH_set_defect( struct MIMEH_header_info *hinfo, int defect )
630
if ((defect >= 0)&&(defect < _MIMEH_DEFECT_ARRAY_SIZE))
632
hinfo->defects[defect]++;
633
hinfo->header_defect_count++;
634
DMIMEH LOGGER_log("%s:%d:MIMEH_set_defect:DEBUG: Setting defect index '%d' to '%d'",FL, defect, hinfo->defects[defect]);
639
/*-----------------------------------------------------------------\
640
Function Name : MIMEH_is_contenttype
644
2. int content_type ,
648
--------------------------------------------------------------------
651
--------------------------------------------------------------------
654
\------------------------------------------------------------------*/
655
int MIMEH_is_contenttype( int range_type, int content_type )
659
diff = content_type -range_type;
661
if ((diff < _CTYPE_RANGE)&&(diff > 0)) return 1;
666
/*-----------------------------------------------------------------\
667
Function Name : MIMEH_is_binary
670
1. struct FFGET_FILE *f ,
672
Exit Codes : 1 = yes, it's binary, 0 = no.
674
--------------------------------------------------------------------
677
--------------------------------------------------------------------
680
\------------------------------------------------------------------*/
681
int MIMEH_is_binary( char *fname )
687
f = fopen(fname,"r");
689
read_count = fread(buffer, 1, 1024, f);
695
if (buffer[read_count] == 0) return 1;
701
/*-----------------------------------------------------------------\
702
Function Name : MIMEH_are_headers_RFC822
709
--------------------------------------------------------------------
712
--------------------------------------------------------------------
715
\------------------------------------------------------------------*/
716
int MIMEH_are_headers_RFC822( char *headers )
718
char conditions[7][16] = { "received", "from", "subject", "date", "content", "boundary" };
721
char *lc_headers = NULL;
725
DMIMEH LOGGER_log("%s:%d:MIMEH_are_headers_RFC822:DEBUG: Headers are NULL");
729
DMIMEH LOGGER_log("%s:%d:MIMEH_are_headers_RFC822:DEBUG:----\n%s\n----",FL,headers);
731
lc_headers = strdup(headers);
732
if (lc_headers == NULL) return 0;
734
//PLD_strlower((unsigned char *)lc_headers);
735
PLD_strlower(lc_headers);
737
DMIMEH LOGGER_log("%s:%d:MIMEH_are_headers_RFC822:DEBUG:----(lowercase)----\n%s\n----",FL,lc_headers);
739
for (condition_item=0; condition_item < 6; condition_item++)
743
DMIMEH LOGGER_log("%s:%d:MIMEH_are_headers_RFC822:DEBUG: Condition test item[%d] = '%s'",FL,condition_item,conditions[condition_item]);
744
p = strstr(lc_headers, conditions[condition_item]);
749
if ((*(p-1) == '\n')||(*(p-1) == '\r'))
751
} else if (p == lc_headers) hitcount++;
755
if (lc_headers != NULL) free(lc_headers);
761
/*-----------------------------------------------------------------\
762
Function Name : MIMEH_save_doubleCR
769
--------------------------------------------------------------------
772
--------------------------------------------------------------------
775
\------------------------------------------------------------------*/
776
int MIMEH_save_doubleCR( FFGET_FILE *f )
784
// Determine a file name we can use.
787
glb.doubleCR_count++;
788
snprintf(glb.doubleCRname,_MIMEH_STRLEN_MAX,"%s/doubleCR.%d",glb.output_dir,glb.doubleCR_count);
790
while (stat(glb.doubleCRname, &st) == 0);
793
fo = fopen(glb.doubleCRname,"w");
796
LOGGER_log("%s:%d:MIMEH_save_doubleCR:ERROR: unable to open '%s' to write (%s)", FL,glb.doubleCRname,strerror(errno));
800
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_save_doubleCR:DEBUG: Saving DoubleCR header: %s\n", FL,glb.doubleCRname);
807
if ((c == EOF)||(c == '\n'))
819
/*-----------------------------------------------------------------\
823
1. MIMEH_absorb_whitespace( char *p ,
827
--------------------------------------------------------------------
830
--------------------------------------------------------------------
833
\------------------------------------------------------------------*/
834
char * MIMEH_absorb_whitespace( char *p )
838
while ((*p != '\0')&&((*p == ' ')||(*p == '\t'))) p++;
844
/*-----------------------------------------------------------------\
845
Function Name : MIMEH_strip_comments
852
--------------------------------------------------------------------
854
Removes comments from RFC[2]822 headers
856
--------------------------------------------------------------------
859
\------------------------------------------------------------------*/
860
int MIMEH_strip_comments( char *input )
865
if (input == NULL) return 0;
872
// Locate (if any) the first occurance of the (
873
while ((p_org != NULL)&&((*p_org != '(')||(in_quote==1)))
894
if ((p != NULL)&&(in_quote == 0))
896
int stop_searching = 0;
898
DMIMEH LOGGER_log("%s:%d:MIMEH_strip_comments:DEBUG: Located open ( at %s",FL,p);
899
// If we did locate an opening parenthesis, look for the closing one
900
// NOTE - we cannot have a breaking \n or \r inbetween
901
// q = strpbrk(p, ")\n\r");
903
while ( (q != NULL) && (stop_searching == 0) )
922
DMIMEH LOGGER_log("%s:%d:MIMEH_strip_comments:DEBUG: Located closing ) at %s",FL,q);
923
if (in_quote == 0) stop_searching = 1;
926
if ((q != NULL)&&(stop_searching == 0)) q++;
929
// If we've got both opening and closing, then we need to remove
930
// the contents of the comment, including the parenthesis
935
// if we found a \n or \r between the two (), then jump out
936
// and move p to the next position.
941
// Move q to the first char after the closing parenthesis
944
DMIMEH LOGGER_log("%s:%d:MIMEH_strip_comments:DEBUG: located closing ) at %s ",FL, q);
945
// While there's more chars in string, copy them to where
946
// the opening parenthesis is
953
DMIMEH LOGGER_log("%s:%d:MIMEH_strip_comments:DEBUG: char copy done",FL);
955
// Terminate the string
959
} else break; // if q == NULL
963
} while ((p != NULL)&&(p_org != NULL)); // do-while more comments to remove
965
DMIMEH LOGGER_log("%s:%d:MIMEH_strip_comments:DEBUG: Final string = '%s'",FL,input);
971
/*-----------------------------------------------------------------\
972
Function Name : MIMEH_fix_header_mistakes
979
--------------------------------------------------------------------
982
Some headers are broken in their wrapping, ie, they fail to
983
put a leading space at the start of the next wrapped data line; ie
985
Content-Transfer-Encoding: quoted-printable
986
Content-Disposition: attachment;
987
filename="yxnjjhyk.xml"
989
Which causes normal header processing to not locate the filename.
991
This function will see if there are any lines with a trailing ; that
992
do not have a leading space on the next line and subsequently replace
993
the \r\n chars after the ; with blanks, effectively pulling the line up
995
--------------------------------------------------------------------
998
\------------------------------------------------------------------*/
999
int MIMEH_fix_header_mistakes( char *data )
1004
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Checking and fixing headers in '%s'",FL,data);
1006
if (glb.header_fix == 0) return result;
1010
int nonblank_detected = 0;
1014
if (p == NULL) break;
1019
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Located ';' at offset %d '%20s",FL, p -data, p);
1021
if ((*q == '\n')||(*q == '\r')) {
1022
nonblank_detected = 0;
1024
/** If the ; isn't immediately followed by a \n or \r, then search till
1025
** the end of the line to see if all the chars are blank **/
1027
while ((*q != '\0')||(*q != '\r')||(*q != '\n')) {
1033
nonblank_detected = 0;
1036
nonblank_detected = 1;
1039
if (nonblank_detected == 1) break;
1042
} /** while looking for the end of the line **/
1043
} /** ELSE - if *q wasn't a line break char **/
1045
if (nonblank_detected == 1) {
1046
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Line was normal/safe, continue...",FL);
1049
} /** if nonblank_detected == 1 **/
1051
/** if we had nothing but blanks till the end of the
1052
** line, then we need to pull up the next line **/
1054
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Line needs fixing",FL);
1057
if ((*q == '\n')||(*q == '\r')) *q = ' ';
1058
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Line fixed",FL);
1060
} /** If q wasn't the end of data **/
1062
} /** while looking for more ';' chars **/
1064
DMIMEH LOGGER_log("%s:%d:MIMEH_fix_header_mistakes:DEBUG: Done",FL);
1069
/*------------------------------------------------------------------------
1070
Procedure: MIMEH_read_headers ID:1
1071
Purpose: Reads from the stream F until it detects a From line, or a blank line
1076
------------------------------------------------------------------------*/
1077
int MIMEH_read_headers( struct MIMEH_header_info *hinfo, FFGET_FILE *f )
1079
char buffer[_MIMEH_STRLEN_MAX+1];
1082
int totalsize_original=0;
1088
char *fget_result = NULL;
1089
char *headerline_end;
1094
int is_RFC822_headers=0; // 20040208-1335:PLD: Added to give an indication if the headers are RFC822 like; used in conjunction with the header_longsearch for pulling apart qmail bouncebacks.
1097
Lets start the ugly big fat DO loop here so that we can, if needed
1098
search until we find headers which are actually valid. Personally
1099
I hate this - but people want it in order to detect malformed
1100
(deliberate or otherwise) emails. It'd be nice if for once in the
1101
software world someone actually enforced standards rather than trying
1102
to be overly intelligent about interpreting data.
1105
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: File position = %ld [0x%0X]"
1114
glb.headerline = NULL;
1115
glb.headerline_original = NULL;
1116
tmp_original = NULL;
1119
while ((fget_result=FFGET_fgets(buffer,_MIMEH_STRLEN_MAX, f)))
1123
linesize = strlen(linestart);
1124
lineend = linestart +linesize;
1126
if (strstr(linestart,"\r\n")) hinfo->crlf_count++;
1127
else if (strstr(linestart,"\r\r")) hinfo->crcr_count++;
1128
else if (strchr(linestart,'\n')) hinfo->lf_count++;
1130
if (MIMEH_DNORMAL)LOGGER_log("%s:%d:MIMEH_read_headers: Data In=[sz=%d:tb=%d:mem=%p]'%s'",FL, linesize, f->trueblank, glb.headerline, buffer);
1132
// If we are being told to copy the input data to an output file
1133
// then do so here (this is for the originals)
1134
if ((glb.original_header_save_to_file > 0)&&(glb.original_header_file != NULL))
1136
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: saving to file...",FL);
1137
fprintf(glb.original_header_file,"%s",linestart);
1140
// if we are being told to keep a copy of the original data
1141
// as it comes in from ffget, then do the storage here
1142
if (glb.save_headers_original > 0)
1144
if (MIMEH_DNORMAL) LOGGER_log("MIMEH_read_headers:DEBUG:Data-In:[%d:%d] '%s'", strlen(linestart), linesize, linestart);
1145
tmp_original = realloc(glb.headerline_original, totalsize_original+linesize+1);
1146
if (tmp_original == NULL)
1148
LOGGER_log("%s:%d:MIMEH_read_headers:ERROR: Cannot allocate %d bytes to contain new headers_original ", FL,totalsize_original +linesize +1);
1149
if (glb.headerline_original != NULL) free(glb.headerline_original);
1150
glb.headerline_original = NULL;
1154
if (glb.headerline_original == NULL)
1156
glb.headerline_original = tmp_original;
1157
totalsize_original = linesize +1;
1158
PLD_strncpy( glb.headerline_original, linestart, (linesize+1));
1159
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: '%s'", FL, glb.headerline_original);
1161
glb.headerline_original = tmp_original;
1162
PLD_strncpy( (glb.headerline_original +totalsize_original -1), linestart, (linesize +1));
1163
totalsize_original += linesize;
1164
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: HO = '%s'", FL, glb.headerline_original);
1166
//LOGGER_log("DEBUG:linesize=%d data='%s'",linesize, linestart);
1170
/** Normal processing of the headers now starts. **/
1171
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: realloc'ing dataspace",FL);
1172
tmp = realloc(glb.headerline, totalsize+linesize+1);
1175
LOGGER_log("%s:%d:MIMEH_read_headers:ERROR: Cannot allocate %d bytes to contain new headers ", FL,totalsize +linesize +1);
1176
if (glb.headerline != NULL) free(glb.headerline);
1177
glb.headerline = NULL;
1181
if (glb.headerline == NULL)
1183
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: Initial appending of head to dataspace headerline = NULL realloc block = %p linestart = %p linesize = %d",FL, tmp, linestart, linesize);
1184
glb.headerline = tmp;
1185
totalsize = linesize;
1186
PLD_strncpy(glb.headerline, linestart, (linesize +1));
1187
headerline_end = glb.headerline +totalsize;
1188
} // If the global headerline is currently NULL
1191
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: Appending of new data to existing header existing-headerline = %p new realloc block = %p linestart = %p linesize = %d",FL, glb.headerline, tmp, linestart, linesize);
1193
// Perform header unfolding by removing any CRLF's
1194
// of the last line if the first characters of the
1195
// newline are blank/space
1197
glb.headerline = tmp;
1199
if ((linestart < lineend)&&((*linestart == '\t')||(*linestart == ' ')))
1202
// Here we start at the last character of the previous line
1203
// and check to see if it's a 'space' type charcter, if it is
1204
// we will then reduce the total size of the headers thus far and
1205
// move the pointer where we're going to append this new line back
1206
// one more character - Ultimately what we wish to achieve is that
1207
// the new line will tacked on [sans leading spaces] to the end of
1208
// the previous line.
1210
// 'p' holds the location at the -end- of the current headers where
1211
// we are going to append the newly read line
1214
p = glb.headerline +totalsize -1;
1215
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: unwrapping headers headers=%p, p = %p",FL,glb.headerline, p);
1216
while ((p >= glb.headerline)&&(( *p == '\n' )||( *p == '\r' )))
1218
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: Removing trailing space p=[%p]%c",FL, p, *p);
1225
p = glb.headerline +totalsize -1;
1230
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: Memcopying line, source = %p, dest = %p, size = %d", FL, linestart, glb.headerline +totalsize, linesize);
1231
memcpy((glb.headerline +totalsize), linestart, (linesize));
1232
totalsize += linesize;
1233
*(glb.headerline +totalsize) = '\0';
1236
} // If the glb.headerline already is allocated and we're appending to it.
1241
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Trueblank line detected in header reading",FL);
1242
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Headers /before/ decoding\n-------\n%s\n-------------------",FL, glb.headerline);
1244
MIMEH_fix_header_mistakes( glb.headerline );
1245
MDECODE_decode_ISO( glb.headerline, totalsize );
1247
if ((glb.save_headers)&&(glb.headerline))
1249
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Saving header line.",FL);
1250
fprintf(glb.header_file,"%s",glb.headerline);
1252
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Final Headers\n------------------\n%s---------------", FL,glb.headerline);
1256
} // If the last line was in fact a true blank line
1259
// If there was a doubleCR at the end of the line,
1260
// then we need to save the next set of data until there
1265
if (glb.doubleCR_save != 0)
1267
MIMEH_save_doubleCR(f);
1272
} // FFGET_doubleCR test
1275
} // While reading more headers from the source file.
1278
// If FFGET ran out of data whilst processing the headers, then acknowledge this
1279
// by returning a -1.
1281
// NOTE - This does not mean we do not have any data!
1282
// it just means that our input ran out.
1286
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:ERROR: FFGET module ran out of input while reading headers",FL);
1287
/** If we're meant to be saving the headers, we better do that now, even though we couldn't
1288
** read everything we wanted to **/
1289
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: save_headers=%d totalsize=%d headerline=%s", FL, glb.save_headers, totalsize, glb.headerline);
1291
if ((glb.save_headers)&&(glb.headerline))
1293
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Saving header line.",FL);
1294
MIMEH_fix_header_mistakes( glb.headerline );
1295
MDECODE_decode_ISO( glb.headerline, totalsize );
1296
fprintf(glb.header_file,"%s",glb.headerline);
1302
if (glb.header_longsearch > 0) {
1303
/** Test the headers for RFC compliance... **/
1304
is_RFC822_headers = MIMEH_are_headers_RFC822(glb.headerline);
1305
if (is_RFC822_headers == 0)
1307
/** If not RFC822 headers, then clean up everything we allocated in here **/
1308
DMIMEH LOGGER_log("%s:%d:MIME_read_headers:DEBUG: No RFC822 headers detected, cleanup.");
1309
MIMEH_headers_cleanup();
1313
} while ((is_RFC822_headers==0)&&(glb.header_longsearch>0)&&(result==0)&&(search_count<glb.longsearch_limit));
1315
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_read_headers:DEBUG: Finished.",FL);
1321
/*------------------------------------------------------------------------
1322
Procedure: MIMEH_display_info ID:1
1323
Purpose: DEBUGGING - Displays the values of the hinfo structure to
1328
------------------------------------------------------------------------*/
1329
int MIMEH_display_info( struct MIMEH_header_info *hinfo )
1333
LOGGER_log("%s:%d:MIMEH_display_info:\
1334
Content Type = %d\n\
1342
,hinfo->content_type\
1346
,hinfo->content_transfer_encoding\
1347
,hinfo->content_disposition);
1354
/*-----------------------------------------------------------------\
1355
Function Name : MIMEH_decode_multivalue_language_string
1362
--------------------------------------------------------------------
1365
--------------------------------------------------------------------
1368
\------------------------------------------------------------------*/
1369
int MIMEH_decode_multivalue_language_string( char *input )
1372
int language_set = 0;
1375
DMIMEH LOGGER_log("%s:%d:MIMEH_decode_multivalue_language_string:DEBUG: Decoding '%s'",FL,input);
1376
// Count the single-quotes
1377
while ((*q != '\0')&&(sq_count != 2)) if (*q++ == '\'') sq_count++;
1380
// LOGGER_log("%s:%d:MIMEH_decode_multivalue_language_string:WARNING: Insufficient single quotes for valid language-charset string",FL);
1386
// q will be pointing at the 2nd single-quote, which is the end of
1387
// the language encoding set, so we just jump over that and start
1388
// reading off the data and decoding it.
1389
MDECODE_decode_multipart( q );
1391
// If the language was set, we need to move down our decoded data to the
1392
// start of the input buffer
1393
if (language_set == 1)
1395
while (*q != '\0') { *input = *q; input++; q++; }
1399
DMIMEH LOGGER_log("%s:%d:MIMEH_decode_multivalue_language_string:DEBUG: Output = '%s'",FL,q);
1406
/*-----------------------------------------------------------------\
1407
Function Name : MIMEH_recompose_multivalue
1410
1. struct MIMEH_header_info *hinfo, Global header information, can be NULL
1411
2. char *header_name_prefix, Prefix we're looking for (ie, filename)
1412
3. char *header_value, String which the prefix should exist in
1413
4. char *buffer, Output buffer
1414
5. size_t buffer_size , Output buffer size
1418
--------------------------------------------------------------------
1420
Multivalue strings are ones which appear like:
1422
filename*0*=us-ascii'en-us'attachment%2E%65
1425
which should duly be recoded as:
1427
filename=attachment.exe
1429
Another example: (extracted from the RFC2231 document)
1431
Content-Type: application/x-stuff
1432
title*0*=us-ascii'en'This%20is%20even%20more%20
1433
title*1*=%2A%2A%2Afun%2A%2A%2A%20
1436
--------------------------------------------------------------------
1439
\------------------------------------------------------------------*/
1440
int MIMEH_recompose_multivalue( struct MIMEH_header_info *hinfo, char *header_name_prefix, char *header_value, char *buffer, size_t buffer_size, char **data_end_point )
1443
char *start_position = header_value;
1446
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: seeking for %s in %s and appending to '%s'. Buffer size=%d", FL, header_name_prefix, header_value,buffer, buffer_size );
1449
// Locate the first part of the multipart string
1450
start_position = strstr(header_value, header_name_prefix);
1451
if (start_position != NULL)
1456
// Setup our buffer insertion point for what ever new data we extract
1457
buffer_start = buffer +strlen(buffer);
1458
buffer_size -= strlen(buffer);
1462
// If the string we're looking for exists, then continue...
1466
char end_point_char='\0';
1470
p = strstr(q, header_name_prefix);
1471
if (p == NULL) break;
1473
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: prefix = %s", FL, p);
1476
if (q == NULL) break;
1478
// Test to see if we have to look for a language encoding specification *sigh*
1484
// Move the pointer past the '=' separator
1487
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: data = %s", FL, q);
1489
// Find where this multipart string ends
1490
end_point = strpbrk(q, ";\t\n\r ");
1491
if (end_point != NULL)
1494
end_point_char = *end_point;
1495
*data_end_point = end_point; // Set this so we know where to start decoding the next time we call this fn
1499
// If strpbrk comes up with nothing, then we set the data_end_point to the end of the string
1501
while (*ep != '\0') ep++;
1502
*data_end_point = ep;
1510
// LOGGER_log("%s:%d:DEBUG: Trimming '%s'", FL, q);
1513
if (*(q +bl -1) == '"') *(q +bl -1) = '\0';
1514
//LOGGER_log("%s:%d:DEBUG: Trim done, '%s'", FL, q);
1517
if (decode_data == 1)
1519
MIMEH_decode_multivalue_language_string(q);
1522
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: segment value = '%s', appending to '%s'", FL, q, buffer);
1523
snprintf(buffer_start,buffer_size,"%s",q);
1525
buffer_size -= q_len;
1526
buffer_start += q_len;
1527
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: Buffer[remaining=%d]= '%s'", FL, buffer_size,buffer);
1529
if (end_point != NULL)
1531
*end_point = end_point_char;
1536
} while ((q != NULL)&&(buffer_size > 0));
1540
DMIMEH LOGGER_log("%s:%d:MIMEH_recompose_multivalue:DEBUG: End point set to: [%d] '%s'",FL, (*data_end_point -header_value), *data_end_point);
1545
/*-----------------------------------------------------------------\
1546
Function Name : MIMEH_parse_header_parameter
1551
3. char *output_value,
1552
4. int output_value_size ,
1553
5. char *data_end_point, used to keep track of the last point of
1554
successful data decoding is.
1557
0 = Success, found the required parameter
1558
1 = No luck, didn't find the required parameter
1561
--------------------------------------------------------------------
1564
--------------------------------------------------------------------
1566
11-Aug-2004: Added new variable, data_end_point. This variable
1567
was required because without it, there was no way of telling
1568
where to continue on the search for more valid data, this is
1569
due to having to no longer rely on fixed atom separators like
1570
: and ; in the MIME text (thankyou MUA's which incorrectly
1571
interpreted the RFC's *sigh*)
1573
\------------------------------------------------------------------*/
1574
int MIMEH_parse_header_parameter( struct MIMEH_header_info *hinfo, char *data, char *searchstr, char *output_value, int output_value_size, char **data_end_point )
1576
int return_value = 0;
1580
// Set the data end point to be the beginning of the data, as we
1581
// have not yet searched through any of the header data
1582
*data_end_point = data;
1584
// Duplicate and convert to lowercase the header data
1585
// that we have been provided with.
1587
//PLD_strlower((unsigned char *)hl);
1590
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Seeking '%s' in '%s'", FL, searchstr, hl);
1592
// Look for the search string we're after (ie, filename, name, location etc)
1593
if (strncmp(hl,searchstr,strlen(searchstr))==0) p = hl; else p = NULL;
1594
// p = strstr (hl, searchstr); //TESTING
1597
char *string = NULL;
1599
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: found %s in %s", FL, searchstr, p);
1601
// Work out where in the -original- string the located parameter is.
1602
// We need to work from the original string because we need to
1603
// preserve case and our searching string is in _lower-case_.
1605
// After we've located it, we offset the pointer past the string we
1606
// searched for. At this position, we should see a separator of
1607
// some type in the set [*;:=\t ].
1609
string = p -hl +data +strlen(searchstr);
1612
** After searching for our parameter, if we've got a
1613
** basic match via strstr, we should then proceed to
1614
** check that the characters either side of it are
1615
** relevant to a typical parameter specification
1617
** the characters *, =, <space> and tab can succeed a
1626
** Permitted characters were found after the parameter name
1627
** so continue on...
1632
** Something other than the permitted characters was found,
1633
** this implies (assumed) that the string match was actually
1634
** just a bit of good luck, return to caller
1641
** Don't forget to also test the character _BEFORE_ the search string
1645
char *before_string;
1647
before_string = string -1 -strlen(searchstr);
1648
if (before_string >= data)
1651
** The characters, <space>, <tab>, ;, : may preceed a parameter name
1653
switch (*(before_string)) {
1659
** Permitted characters were found after the parameter name
1660
** so continue on...
1665
** Something other than the permitted characters was found,
1666
** this implies (assumed) that the string match was actually
1667
** just a bit of good luck, return to caller
1671
} /** Switch before_string **/
1672
} /** if before_string > data **/
1676
// If the char is a '*', this means we've got a multivalue parameter
1677
// which needs to be decoded (ie, name*1*=foo name*2*=bar )
1680
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Found a '*' after the name, so attempting multipart value decode",FL);
1682
// PLD:DEV:11/08/2004-18H30
1683
// Issue: RFC2231 handling
1684
return_value = MIMEH_recompose_multivalue( hinfo, searchstr, data, output_value, output_value_size, data_end_point);
1690
while (isspace((int) *string )) string++;
1692
//if ( *string != '=' )
1693
if ( *string == '\0' )
1695
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: In '%s' parsing, was expecting a '=' in the start of '%s'\n", FL, searchstr, string );
1701
// Eliminate multiple = separators.
1702
// Reference: c030804-006a
1703
// PLD:DEV: 11/08/2004-15H15
1704
while ((*(string +1) == '=')&&(*(string+1) != '\0')) { string++; MIMEH_set_defect(hinfo,MIMEH_DEFECT_MULTIPLE_EQUALS_SEPARATORS); }
1707
// Get the end of our string
1708
endchar = string +strlen(string) -1;
1709
*data_end_point = endchar;
1711
// Strip off trailing whitespace
1712
while ((endchar > string)&&(isspace((int)*endchar)))
1718
// we are at the '=' in the header, so skip it
1719
if (*string == '=') string++;
1721
MIMEH_set_defect(hinfo,MIMEH_DEFECT_MISSING_SEPARATORS);
1724
// skip any spaces... again
1725
while ( isspace((int) *string ) ) string++;
1727
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Extracting value out of '%s'",FL,string);
1729
// Because of all the potential exploits and bad behaviour
1730
// we have to be really careful about how we determine
1731
// what the enclosed string is for our parameter.
1733
// Previously we could _assume_ that we just get the last
1734
// quote (") on the line and copy out what was between,
1735
// unfortunately that doesn't work anymore. Instead now
1736
// we have to step along the data stream one char at a
1737
// time and make decisions along the way.
1742
// If our first char is a quote, then we'll then try and find
1743
// the second quote which closes the string, alas, this is
1744
// not always present in the header data, either due to a
1745
// broken MUA or due to an exploit attempt.
1748
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Using quoted-string tests",FL);
1750
// Remove multiple-sequential quotes
1752
while ((*string != '\0')&&(*string == '\"')){ string++; MIMEH_set_defect(hinfo,MIMEH_DEFECT_MULTIPLE_QUOTES); }
1754
if (*string == '\0') break; // 20071030-0958: Added by Claudio Jeker - prevents overflow.
1756
// Find the next quote which isn't sequential to the above
1757
// quotes that we just skipped over
1758
string_end = strchr(string+1, '\"');
1759
if (string_end != NULL)
1761
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: End of value found",FL);
1763
*data_end_point = string_end +1;
1765
// If string_end == NULL
1767
// If we didn't find any more quotes, that
1768
// means we've probably got an unbalanced string (oh joy)
1769
// so then we convert to looking for other items such as
1770
// ;\n\r\t and space.
1772
if (hinfo) MIMEH_set_defect(hinfo,MIMEH_DEFECT_UNBALANCED_QUOTES);
1773
string_end = strpbrk(string,"; \n\r\t");
1774
if (string_end != NULL)
1777
*data_end_point = string_end +1;
1779
// There is no termination to the string, instead the
1780
// end of the string is \0.
1790
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Using NON-quoted-string tests",FL);
1791
string_end = strpbrk(string,"; \n\r\t");
1792
if (string_end != NULL)
1795
*data_end_point = string_end +1;
1797
// There is no termination to the string, instead the
1798
// end of the string is \0.
1802
} /** end of switch **/
1804
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Extracting value out of '%s'",FL,string);
1805
// Trim up and leading/trailing quotes
1806
if (((*string == '\"')&&(*(string +strlen(string)-1) == '\"'))
1807
|| ((*string == '\'')&&(*(string +strlen(string)-1) == '\'')) )
1809
int slen = strlen(string) -2;
1811
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse-header_parameter:DEBUG: Stripping quotes from '%s'",FL,string);
1822
// Now that our string is all cleaned up, save it to our output value
1823
snprintf( output_value, output_value_size, "%s", string );
1824
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Final value = '%s'",FL, output_value);
1825
} // If the first non-whitespace char wasn't a '='
1826
} // If the first char after the search-string wasn't a '*'
1833
if (hl != NULL) free(hl);
1835
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: [return=%d] Done seeking for '%s' data_end_point=%p (from %p)",FL, return_value, searchstr, *data_end_point, data);
1837
return return_value;
1847
/*-----------------------------------------------------------------\
1848
Function Name : MIMEH_is_valid_header_prefix
1852
2. char *prefix_name ,
1858
--------------------------------------------------------------------
1861
--------------------------------------------------------------------
1864
\------------------------------------------------------------------*/
1866
int MIMEH_is_valid_header_prefix( char *data, char *prefix_name )
1868
int plen = strlen(prefix_name);
1870
/** If our string doesn't start with content-type, then exit **/
1871
if (strncasecmp(data, prefix_name, plen)!=0)
1877
/** Test to see that the terminating char after the content-type
1878
** string is suitable to indicating that the content-type is
1879
** infact a header name
1881
end_char = *(data +plen);
1887
/** Valid terminating characters found **/
1890
/** Otherwise, return 0 **/
1892
} /** switch end_char **/
1900
/*-----------------------------------------------------------------\
1901
Function Name : MIMEH_parse_contenttype_linear
1904
1. char *header_name,
1905
2. char *header_value,
1906
3. struct MIMEH_header_info *hinfo ,
1910
--------------------------------------------------------------------
1913
--------------------------------------------------------------------
1916
\------------------------------------------------------------------*/
1917
int MIMEH_parse_contenttype_linear_EXPERIMENT( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
1919
char *chv = header_value;
1920
char *chn = header_name;
1921
int boundary_found = 0;
1922
// int name_found = 0;
1923
// int filename_found = 0;
1925
/** Absorb whitespace **/
1926
while (isspace(*chn)) chn++;
1928
/** Test if the content-type string is valid **/
1929
if (MIMEH_is_valid_header_prefix(chn, "content-type")==0) return 0;
1931
/** Now, let's try parse our content-type parameter/value string **/
1934
while (isspace(*chv)) chv++;
1935
if ((boundary_found==0)&&(MIMEH_is_valid_header_prefix(chv,"boundary")==1))
1939
// if (strncasecmp(chv, "boundary"
1948
/*-----------------------------------------------------------------\
1949
Function Name : MIMEH_parse_contenttype
1952
1. char *header_name,
1953
2. char *header_value,
1954
3. struct MIMEH_header_info *hinfo ,
1958
--------------------------------------------------------------------
1961
--------------------------------------------------------------------
1964
\------------------------------------------------------------------*/
1965
int MIMEH_parse_contenttype( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
1970
char *hv = strdup( header_value );
1972
// CONTENT TYPE -------------------------------
1973
// CONTENT TYPE -------------------------------
1974
// CONTENT TYPE -------------------------------
1976
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Start",FL);
1978
p = strstr(header_name,"content-type");
1981
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype: Content-type string found in header-name",FL);
1983
/** 20041216-1106:PLD: Increase our sanity **/
1985
PLD_strlower( header_value );
1986
PLD_strlower( header_value );
1989
if (strstr(q,"multipart/appledouble")) hinfo->content_type = _CTYPE_MULTIPART_APPLEDOUBLE;
1990
else if (strstr(q,"multipart/signed")) hinfo->content_type = _CTYPE_MULTIPART_SIGNED;
1991
else if (strstr(q,"multipart/related")) hinfo->content_type = _CTYPE_MULTIPART_RELATED;
1992
else if (strstr(q,"multipart/mixed")) hinfo->content_type = _CTYPE_MULTIPART_MIXED;
1993
else if (strstr(q,"multipart/alternative")) hinfo->content_type = _CTYPE_MULTIPART_ALTERNATIVE;
1994
else if (strstr(q,"multipart/report")) hinfo->content_type = _CTYPE_MULTIPART_REPORT;
1995
else if (strstr(q,"multipart/")) hinfo->content_type = _CTYPE_MULTIPART;
1996
else if (strstr(q,"text/calendar")) hinfo->content_type = _CTYPE_TEXT_CALENDAR;
1997
else if (strstr(q,"text/plain")) hinfo->content_type = _CTYPE_TEXT_PLAIN;
1998
else if (strstr(q,"text/html")) hinfo->content_type = _CTYPE_TEXT_HTML;
1999
else if (strstr(q,"text/")) hinfo->content_type = _CTYPE_TEXT;
2000
else if (strstr(q,"image/gif")) hinfo->content_type = _CTYPE_IMAGE_GIF;
2001
else if (strstr(q,"image/jpeg")) hinfo->content_type = _CTYPE_IMAGE_JPEG;
2002
else if (strstr(q,"image/")) hinfo->content_type = _CTYPE_IMAGE;
2003
else if (strstr(q,"audio/")) hinfo->content_type = _CTYPE_AUDIO;
2004
else if (strstr(q,"message/rfc822")) hinfo->content_type = _CTYPE_RFC822;
2005
else if (strstr(q,"/octet-stream")) hinfo->content_type = _CTYPE_OCTECT;
2006
else if (strstr(q,"/ms-tnef")) hinfo->content_type = _CTYPE_TNEF;
2007
else if (strstr(q,"application/applefile"))
2009
hinfo->content_type = _CTYPE_APPLICATION_APPLEFILE;
2010
if ( hinfo->filename[0] == '\0' )
2012
if (strlen(glb.appledouble_filename)>0)
2014
snprintf(hinfo->filename, sizeof(hinfo->filename), "%s.applemeta", glb.appledouble_filename );
2016
snprintf(hinfo->filename, sizeof(hinfo->filename), "applefile");
2020
else hinfo->content_type = _CTYPE_UNKNOWN;
2022
/** Is there an x-mac-type|creator parameter? **/
2023
if ((strstr(header_value,"x-mac-type="))&&(strstr(header_value,"x-mac-creator=")))
2025
/** By setting this flag to 1, we are saying that if the
2026
** filename contains a forward slash '/' char, then it's
2027
** to be treated as a normal char, not a directory
2028
** separator. However, as we cannot generate a filename
2029
** with that char normally, we'll convert it to something
2032
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Located x-mac attachment",FL);
2034
FNFILTER_set_mac(hinfo->x_mac);
2038
// Copy the string to our content-type string storage field
2044
// Step 1 - jump over any whitespace
2045
while ( *c == ' ' || *c == '\t') c++;
2047
// Step 2 - Copy the string
2048
PLD_strncpy( hinfo->content_type_string, c, _MIMEH_CONTENT_TYPE_MAX);
2050
// Step 3 - clean up the string
2051
c = hinfo->content_type_string;
2052
while (*c && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r' && *c != ';') c++;
2054
// Step 4 - Terminate the string
2058
// If we have an additional parameter at the end of our content-type, then we
2059
// should search for a name="foobar" sequence.
2060
//p = strchr( hv, ';' );
2061
p = strpbrk( hv, ";\t\n\r " );
2065
char *data_end_point = param;
2068
param = strpbrk( p, ";\n\r\t " );
2069
while ( param != NULL )
2073
** The Process of decoding our line....
2074
** . While not end of the line...
2075
** . Remove whitespace
2076
** . test for 'name'
2077
** . test for 'boundary'
2078
** . Move to next char after parameter values
2080
** Go to the next character after the 'token separator' character
2081
** and then proceed to absorb any excess white space.
2082
** Once we've stopped at a new, non-white character, we can begin
2083
** to see if we've got a sensible parameter like name=, filename=
2087
param = MIMEH_absorb_whitespace(param);
2090
** If we get to the end of the line, just break out of the token
2091
** parsing while loop
2093
if (*param == '\0') break;
2096
** Look for name or filename specifications in the headers
2097
** Look for name or filename specifications in the headers
2098
** Look for name or filename specifications in the headers
2101
return_value = MIMEH_parse_header_parameter( hinfo, param, "name", hinfo->name, sizeof(hinfo->name), &data_end_point);
2102
/** Update param to point where data_end_point is
2103
** this is so when we come around here again due
2104
** to the while loop, we'll know where to pick up
2105
** the search for more parameters
2107
if (data_end_point > param) param = data_end_point;
2109
// If we finally had success, then copy the name into filename for hinfo
2110
if ( return_value == 0 )
2112
// Move the parameter search point up to where we stopped
2113
// processing the data in the MIMEH_parse_header_parameter() call
2115
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Pushing new filename to stack '%s'",FL, hinfo->name);
2116
/** Step 1: Check to see if this filename already
2117
** exists in the stack. We do this so that we don't
2118
** duplicate entries and also to prevent false
2119
** bad-header reports. **/
2120
if (SS_cmp(&(hinfo->ss_names), hinfo->name, strlen(hinfo->name))==NULL)
2122
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Filtering '%s'",FL, hinfo->name);
2123
FNFILTER_filter(hinfo->name, _MIMEH_FILENAMELEN_MAX);
2124
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Pushing '%s'",FL, hinfo->name);
2125
SS_push(&(hinfo->ss_names),hinfo->name,strlen(hinfo->name));
2126
if (SS_count(&(hinfo->ss_names)) > 1)
2128
MIMEH_set_defect(hinfo, MIMEH_DEFECT_MULTIPLE_NAMES);
2131
if ( hinfo->filename[0] == '\0' ) {
2132
snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", hinfo->name );
2134
} /* If the file name doesn't already exist in the stack */
2136
} /* If a filename was located in the headers */
2142
** Look for the MIME Boundary specification in the headers
2143
** Look for the MIME Boundary specification in the headers
2144
** Look for the MIME Boundary specification in the headers
2146
return_value = MIMEH_parse_header_parameter(hinfo, param, "boundary", hinfo->boundary, sizeof(hinfo->boundary), &data_end_point);
2147
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Param<=>data_end gap = %d", FL,data_end_point -param);
2148
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: param start pos = '%s'",FL, param);
2149
if (data_end_point > param) param = data_end_point;
2150
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: param start pos = '%s'",FL, param);
2152
if ( return_value == 0 ) {
2153
// Move the parameter search point up to where we stopped
2154
// processing the data in the MIMEH_parse_header_parameter() call
2156
//hinfo->boundary_located = 1;
2157
hinfo->boundary_located++;
2158
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Pushed boundary to stack (%s)",FL, hinfo->boundary);
2159
BS_push(hinfo->boundary);
2160
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Setting hinfo->boundary_located to %d",FL, hinfo->boundary_located );
2162
if (hinfo->boundary_located > 1)
2164
// Register the defect
2165
MIMEH_set_defect(hinfo, MIMEH_DEFECT_MULTIPLE_BOUNDARIES);
2167
//Reset the counter back to 1.
2168
hinfo->boundary_located=1;
2172
//param = PLD_strtok( &tx, NULL, ";\n\r" );
2173
// * PLD:20040831-22H15: Added 'if (param != NULL)' prefix to debugging lines
2174
// * In response to bug #32, submitted by ICL ZA
2175
if (param != NULL) DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: param start pos = '%s'",FL, param);
2176
param = strpbrk( param, ";\n\r " );
2177
if (param != NULL) DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: param start pos = '%s'",FL, param);
2183
if (hv != NULL) free(hv);
2185
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: end.",FL);
2200
/*-----------------------------------------------------------------\
2201
Function Name : MIMEH_parse_contentlocation
2204
1. char *header_name,
2205
2. char *header_value,
2206
3. struct MIMEH_header_info *hinfo ,
2210
--------------------------------------------------------------------
2213
--------------------------------------------------------------------
2216
\------------------------------------------------------------------*/
2217
int MIMEH_parse_contentlocation( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2221
// CONTENT LOCATION -------------------------------
2222
// CONTENT LOCATION -------------------------------
2223
// CONTENT LOCATION -------------------------------
2225
PLD_strlower( header_name );
2226
p = strstr(header_name,"content-location");
2229
/** 20041216-1108:PLD: Increase our sanity **/
2232
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_contentlocation:DEBUG: Content Location line found - '%s'\n", FL, header_value);
2235
p = q = header_value;
2238
q = strpbrk(p, "\\/");
2239
if (q != NULL) p = q+1;
2244
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_contentlocation:DEBUG: filename = %s\n", FL, p);
2245
snprintf(hinfo->name, sizeof(hinfo->name),"%s",p);
2246
snprintf(hinfo->filename, sizeof(hinfo->filename),"%s",p); //PLD:20100611 - fixed name mismatch,Cristian Rodríguez
2247
FNFILTER_filter(hinfo->filename, _MIMEH_FILENAMELEN_MAX);
2248
SS_push(&(hinfo->ss_filenames), hinfo->filename, strlen(hinfo->filename));
2270
/*-----------------------------------------------------------------\
2271
Function Name : MIMEH_parse_contenttransferencoding
2274
1. char *header_name,
2275
2. char *header_value,
2276
3. struct MIMEH_header_info *hinfo ,
2280
--------------------------------------------------------------------
2283
--------------------------------------------------------------------
2286
\------------------------------------------------------------------*/
2287
int MIMEH_parse_contenttransferencoding( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2292
// CONTENT TRANSFER ENCODING ---------------------
2293
// CONTENT TRANSFER ENCODING ---------------------
2294
// CONTENT TRANSFER ENCODING ---------------------
2297
p = strstr(header_name,"content-transfer-encoding");
2300
/** 20041216-1107:PLD: Increase our sanity **/
2303
q = strpbrk(header_value,"\n\r;");
2314
if (strstr(p,"base64"))
2316
hinfo->content_transfer_encoding = _CTRANS_ENCODING_B64;
2317
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to BASE64", FL);
2319
else if (strstr(p,"7bit"))
2321
hinfo->content_transfer_encoding = _CTRANS_ENCODING_7BIT;
2322
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to 7-BIT ", FL);
2324
else if (strstr(p,"8bit"))
2326
hinfo->content_transfer_encoding = _CTRANS_ENCODING_8BIT;
2327
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to 8-BIT", FL);
2329
else if (strstr(p,"quoted-printable"))
2331
hinfo->content_transfer_encoding = _CTRANS_ENCODING_QP;
2332
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to Quoted-Printable", FL);
2334
else if (strstr(p,"binary"))
2336
hinfo->content_transfer_encoding = _CTRANS_ENCODING_BINARY;
2337
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to Binary", FL);
2342
||(strcmp(p,"u") == 0)
2345
hinfo->content_transfer_encoding = _CTRANS_ENCODING_UUENCODE;
2346
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to UUENCODE", FL);
2348
else hinfo->content_transfer_encoding = _CTRANS_ENCODING_RAW;
2351
// Copy the string to our content-transfer string storage field
2357
// Step 1 - jump over any whitespace
2358
while ( *cp == ' ' || *cp == '\t') cp++;
2360
// Step 2 - Copy the string
2361
PLD_strncpy( hinfo->content_transfer_encoding_string, cp, _MIMEH_CONTENT_TRANSFER_ENCODING_MAX);
2363
// Step 3 - clean up the string
2364
cp = hinfo->content_transfer_encoding_string;
2365
while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\r' && *cp != ';') cp++;
2367
// Step 4 - Terminate the string
2371
// Set the character which we changed to a \0 back to its original form so that
2372
// we don't cause problems from tainted data for any further parsing calls
2373
// which use the data.
2374
if (q != NULL) *q = c;
2381
/*-----------------------------------------------------------------\
2382
Function Name : MIMEH_parse_contentdisposition
2385
1. char *header_name,
2386
2. char *header_value,
2387
3. struct MIMEH_header_info *hinfo ,
2391
--------------------------------------------------------------------
2394
--------------------------------------------------------------------
2397
\------------------------------------------------------------------*/
2398
int MIMEH_parse_contentdisposition( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2401
char *hv = strdup(header_value);
2403
// CONTENT DISPOSITION ------------------------------
2404
// CONTENT DISPOSITION ------------------------------
2405
// CONTENT DISPOSITION ------------------------------
2407
//LOGGER_log("%s:%d:DEBUG: Headers='%s'",FL,header_value);
2408
p = strstr(header_name,"content-disposition");
2411
/** 20041216-1107:PLD: Increase our sanity **/
2414
// Change p to now point to the header VALUE, p no longer
2415
// points to the content-disposition start!
2418
PLD_strlower( header_value );
2420
// Here we just check to find out what type of disposition we have.
2421
if (strstr(p,"inline"))
2423
hinfo->content_disposition = _CDISPOSITION_INLINE;
2425
else if (strstr(p,"form-data"))
2427
hinfo->content_disposition = _CDISPOSITION_FORMDATA;
2429
else if (strstr(p,"attachment"))
2431
hinfo->content_disposition = _CDISPOSITION_ATTACHMENT;
2435
hinfo->content_disposition = _CDISPOSITION_UNKNOWN;
2438
// Copy the string to our content-transfer string storage field
2443
// Step 1 - jump over any whitespace
2444
while ( *q == ' ' || *q == '\t') q++;
2446
// Step 2 - Copy the string
2447
PLD_strncpy( hinfo->content_disposition_string, q, _MIMEH_CONTENT_DISPOSITION_MAX);
2449
// Step 3 - clean up the string
2450
q = hinfo->content_disposition_string;
2451
while (*q && *q != ' ' && *q != '\t' && *q != '\n' && *q != '\r' && *q != ';') q++;
2453
// Step 4 - Terminate the string
2457
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_contentdisposition:DEBUG: Disposition string = '%s'",FL, hv);
2459
// Commence to decode the disposition string into its components.
2460
p = strpbrk( hv, ";\t\n\r " );
2463
// struct PLD_strtok tx;
2466
hinfo->name[0]='\0';
2470
while ( param != NULL )
2473
char *data_end_point;
2475
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contentdisposition:DEBUG: Parsing '%s'",FL,param);
2477
// Seek out possible 'filename' parameters
2479
parse_result = MIMEH_parse_header_parameter(hinfo, param, "filename", hinfo->name, sizeof(hinfo->name), &data_end_point);
2480
if (data_end_point > param) param = data_end_point;
2481
if (parse_result == 0) {
2482
FNFILTER_filter(hinfo->name, _MIMEH_FILENAMELEN_MAX);
2483
SS_push(&(hinfo->ss_filenames), hinfo->name, strlen(hinfo->name));
2484
if (SS_count(&(hinfo->ss_filenames)) > 1)
2486
MIMEH_set_defect(hinfo,MIMEH_DEFECT_MULTIPLE_FILENAMES);
2490
param = strpbrk( param , ";\n\r\t " );
2493
//param = PLD_strtok( &tx, NULL, ";\n\r\t " );
2496
if ( hinfo->filename[0] == '\0' )
2498
snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", hinfo->name );
2501
// Handle situations where we'll need the filename for the future.
2502
if ( hinfo->content_type == _CTYPE_MULTIPART_APPLEDOUBLE )
2504
snprintf( glb.appledouble_filename, sizeof(glb.appledouble_filename), "%s", hinfo->filename );
2505
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contentdisposition:DEBUG: Setting appledouble filename to: '%s'",FL,glb.appledouble_filename);
2508
} // If the header-value contained ;'s ( indicating parameters )
2510
} // If the header-name actually contained 'content-disposition'
2512
if (hv != NULL) free(hv);
2520
/*-----------------------------------------------------------------\
2521
Function Name : MIMEH_parse_subject
2524
1. char *header_name, contains the full headers
2525
2. char *header_value,
2526
3. struct MIMEH_header_info *hinfo ,
2530
--------------------------------------------------------------------
2533
--------------------------------------------------------------------
2536
\------------------------------------------------------------------*/
2537
int MIMEH_parse_generic( char *header_name, char *header_value, struct MIMEH_header_info *hinfo, char *tokenstr, char *buffer, size_t bsize )
2539
int compare_result = 0;
2542
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_generic:DEBUG: Searching for %s in %s",FL,tokenstr,header_name);
2543
/** Sanity check the parameters **/
2544
if (hinfo == NULL) return -1;
2545
if (tokenstr == NULL) return -1;
2546
if (header_name == NULL) return -1;
2547
if (header_value == NULL) return -1;
2548
if (buffer == NULL) return -1;
2549
if (bsize < 1) return -1;
2551
tlen = strlen(tokenstr);
2552
compare_result = strncmp( header_name, tokenstr, tlen );
2553
if (compare_result == 0)
2556
switch (*(header_name +tlen)) {
2561
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_generic:DEBUG: Located! Sanity up +1",FL);
2562
snprintf( buffer, bsize, "%s", header_value );
2572
/*-----------------------------------------------------------------\
2573
Function Name : MIMEH_parse_subject
2576
1. char *header_name,
2577
2. char *header_value,
2578
3. struct MIMEH_header_info *hinfo ,
2582
--------------------------------------------------------------------
2585
--------------------------------------------------------------------
2588
\------------------------------------------------------------------*/
2589
int MIMEH_parse_subject( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2592
result = MIMEH_parse_generic( header_name, header_value, hinfo, "subject", hinfo->subject, sizeof(hinfo->subject) );
2593
snprintf(glb.subject, sizeof(glb.subject),"%s", hinfo->subject);
2601
/*-----------------------------------------------------------------\
2602
Function Name : MIMEH_parse_date
2605
1. char *header_name,
2606
2. char *header_value,
2607
3. struct MIMEH_header_info *hinfo ,
2611
--------------------------------------------------------------------
2614
--------------------------------------------------------------------
2617
\------------------------------------------------------------------*/
2618
int MIMEH_parse_date( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2620
return MIMEH_parse_generic( header_name, header_value, hinfo, "date", hinfo->date, sizeof(hinfo->date) );
2622
/*-----------------------------------------------------------------\
2623
Function Name : MIMEH_parse_from
2626
1. char *header_name,
2627
2. char *header_value,
2628
3. struct MIMEH_header_info *hinfo ,
2632
--------------------------------------------------------------------
2635
--------------------------------------------------------------------
2638
\------------------------------------------------------------------*/
2639
int MIMEH_parse_from( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2641
return MIMEH_parse_generic( header_name, header_value, hinfo, "from", hinfo->from, sizeof(hinfo->from) );
2643
/*-----------------------------------------------------------------\
2644
Function Name : MIMEH_parse_to
2647
1. char *header_name,
2648
2. char *header_value,
2649
3. struct MIMEH_header_info *hinfo ,
2653
--------------------------------------------------------------------
2656
--------------------------------------------------------------------
2659
\------------------------------------------------------------------*/
2660
int MIMEH_parse_to( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2662
return MIMEH_parse_generic( header_name, header_value, hinfo, "to", hinfo->to, sizeof(hinfo->to) );
2664
/*-----------------------------------------------------------------\
2665
Function Name : MIMEH_parse_messageid
2668
1. char *header_name,
2669
2. char *header_value,
2670
3. struct MIMEH_header_info *hinfo ,
2674
--------------------------------------------------------------------
2677
--------------------------------------------------------------------
2680
\------------------------------------------------------------------*/
2681
int MIMEH_parse_messageid( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2683
return MIMEH_parse_generic( header_name, header_value, hinfo, "message-id", hinfo->messageid, sizeof(hinfo->messageid) );
2685
/*-----------------------------------------------------------------\
2686
Function Name : MIMEH_parse_received
2689
1. char *header_name,
2690
2. char *header_value,
2691
3. struct MIMEH_header_info *hinfo ,
2695
--------------------------------------------------------------------
2698
--------------------------------------------------------------------
2701
\------------------------------------------------------------------*/
2702
int MIMEH_parse_received( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
2704
return MIMEH_parse_generic( header_name, header_value, hinfo, "received", hinfo->received, sizeof(hinfo->received) );
2707
/*-----------------------------------------------------------------\
2708
Function Name : MIMEH_process_headers
2711
1. struct MIMEH_header_info *hinfo,
2716
--------------------------------------------------------------------
2719
--------------------------------------------------------------------
2722
\------------------------------------------------------------------*/
2723
int MIMEH_headers_process( struct MIMEH_header_info *hinfo, char *headers )
2725
/** scan through our headers string looking for information that is
2727
char *safeh, *h, *safehl;
2728
char *current_header_position;
2731
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Start [hinfo=%p]\n",FL, hinfo);
2733
safeh = h = headers;
2735
/** Duplicate the headers for processing - this way we don't 'taint' the
2736
** original headers during our searching / altering. **/
2738
headerlength = strlen(h);
2739
safehl = malloc(sizeof(char) *(headerlength+1));
2740
PLD_strncpy(safehl, h, headerlength+1);
2742
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_headers:DEBUG: Header length = %d\n", FL,headerlength);
2744
MIMEH_strip_comments(h);
2746
current_header_position = h;
2748
// Searching through the headers, we seek out header 'name:value;value;value' sets,
2749
// Each set is then cleaned up, seperated and parsed.
2751
while ((current_header_position != NULL)&&( current_header_position <= (h +headerlength) ))
2753
char *header_name, *header_value;
2754
char *header_name_end_position;
2755
char *header_value_end_position;
2757
DMIMEH LOGGER_log("%s:%d:MIMEH_headers_process:DEBUG: Processing '%s'",FL,current_header_position);
2759
/** Tokenise for the header 'name', ie, content-type, subject etc **/
2760
header_name = current_header_position;
2761
header_name_end_position = strpbrk( header_name, ":\t " );
2762
if (header_name_end_position == NULL)
2764
// We couldn't find a terminating :, so, instead we try to find
2765
// the first whitespace
2767
// PLD:DEV:11/08/2004-15H27
2768
// Issue: c030804-006a
2770
// NOTE: this may activate on the true-blank lines, hence why we
2771
// dump the source string, just for confirmation
2773
DMIMEH LOGGER_log("%s:%d:MIMEH_headers_process:DEBUG: Could not locate ':' separator, using whitespace (source='%s')",FL,header_name);
2774
header_name_end_position = strpbrk( header_name, "\t " );
2775
if (header_name_end_position == NULL)
2777
DMIMEH LOGGER_log("%s:%d:MIMEH_headers_process:DEBUG: Cannot find a header name:value pair in '%s'",FL, header_name);
2781
// Seek forward from the start of our header, looking for the first occurance
2782
// of the line end (implying the end of the current header name:value,
2783
// we can do this because we know that when the headers were read in, we
2784
// have already unfolded them, such that there should only be one header:value
2785
// pairing per 'line'.
2787
current_header_position = strpbrk( current_header_position, "\n\r");
2788
if ( current_header_position == NULL )
2790
// Theoretically, this should not happen, as headers are always
2791
// terminated with a \n\r\n\r finishing byte sequence, thus
2792
// if this _does_ happen, then we will simply jump out of the
2793
// current iteration and let the loop try find another pairing
2795
// There probably should be a logging entry here to indicate that
2796
// "something strange happened"
2801
// Shuffle our CHP (current-header-position) pointer along the header
2802
// data until it is no longer pointing to a \r or \n, this is so
2803
// that when the next iteration of this loop comes around, it'll
2804
// immediately be in the right place for starting the next parse
2806
while (( *current_header_position == '\n') ||( *current_header_position == '\r' )) current_header_position++;
2809
if (( header_name_end_position == NULL )||( header_name_end_position > current_header_position))
2811
// Some headers can contain various levels of non name/value pairings,
2812
// while their presence could be debatable in terms of RFC validity
2813
// we will 'ignore' them rather than throwing up our arms. This
2814
// ensures that we are not made to break over spurilous data.
2816
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: This line contains no header:value pair (%s)", FL, current_header_position);
2821
// Get the header-value string and prepare to
2822
// parse the data through our various parsing
2825
header_value = header_name_end_position +1;
2826
header_value_end_position = strpbrk( header_value, "\n\r" );
2827
if ( header_value_end_position != NULL )
2829
*header_name_end_position = '\0';
2830
*header_value_end_position = '\0';
2833
LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Header Name ='%s'", FL, header_name );
2834
LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Header Value='%s'", FL, header_value );
2837
// To make parsing simpler, convert our
2838
// header name to lowercase, that way
2839
// we also reduce the CPU requirements for
2840
// searching because pre-lowering the header-name
2841
// occurs once, but string testing against it
2842
// occurs multiple times ( at least once per parsing
2844
PLD_strlower( header_name );
2845
MIMEH_parse_subject( header_name, header_value, hinfo );
2846
MIMEH_parse_contenttype( header_name, header_value, hinfo );
2847
MIMEH_parse_contenttransferencoding( header_name, header_value, hinfo );
2848
MIMEH_parse_contentdisposition( header_name, header_value, hinfo );
2849
/** These items aren't really -imperative- to have, but they do
2850
** help with the sanity checking **/
2851
MIMEH_parse_date( header_name, header_value, hinfo );
2852
MIMEH_parse_from( header_name, header_value, hinfo );
2853
MIMEH_parse_to( header_name, header_value, hinfo );
2854
MIMEH_parse_messageid( header_name, header_value, hinfo );
2855
MIMEH_parse_received( header_name, header_value, hinfo );
2857
if (hinfo->filename[0] == '\0')
2859
MIMEH_parse_contentlocation( header_name, header_value, hinfo );
2863
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headerss:DEBUG: Header value end position is NULL",FL);
2871
// Final analysis on our headers:
2872
if ( hinfo->content_type == _CTYPE_MULTIPART_APPLEDOUBLE )
2875
snprintf( tmp, sizeof(tmp), "mac-%s", hinfo->filename );
2876
snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", tmp );
2877
snprintf( hinfo->name, sizeof(hinfo->name), "%s", tmp );
2881
// Act like Outlook *God forbid!* and if there's a octect-stream
2882
// content-type, but the encoding is still null/empty, then
2883
// change the content-encoding to be RAW
2885
if ( hinfo->content_type == _CTYPE_OCTECT )
2887
if ((hinfo->content_transfer_encoding == _CTRANS_ENCODING_UNSPECIFIED)
2888
|| (hinfo->content_transfer_encoding == _CTRANS_ENCODING_UNKNOWN)
2889
|| (strlen(hinfo->content_transfer_encoding_string) < 1)
2892
//LOGGER_log("%s:%d:DEBUG: Encoding pair was octet but no encoding, filename=%s\n",FL,hinfo->filename);
2893
hinfo->content_transfer_encoding = _CTRANS_ENCODING_RAW;
2902
else LOGGER_log("%s:%d:MIME_parse_headers:WARNING: Unable to free HEADERS allocated memory\n", FL);
2904
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: END [hinfo=%p]\n", FL, hinfo);
2910
/*-----------------------------------------------------------------\
2911
Function Name : MIMEH_get_headers
2914
1. struct MIMEH_header_info *hinfo,
2919
--------------------------------------------------------------------
2922
--------------------------------------------------------------------
2925
\------------------------------------------------------------------*/
2926
int MIMEH_headers_get( struct MIMEH_header_info *hinfo, FFGET_FILE *f )
2930
// Setup some basic defaults
2931
hinfo->filename[0] = '\0';
2932
hinfo->name[0] = '\0';
2933
hinfo->content_type = _CTYPE_UNKNOWN;
2934
hinfo->subject[0] = '\0';
2936
// 20040116-1234:PLD - added to appease valgrind
2937
hinfo->content_disposition = 0;
2938
hinfo->content_transfer_encoding = 0;
2939
hinfo->boundary_located = 0;
2941
hinfo->crlf_count=0;
2942
hinfo->crcr_count=0;
2944
snprintf(hinfo->delimeter,sizeof(hinfo->delimeter),"\r\n");
2946
// Initialise header defects array.
2947
hinfo->header_defect_count = 0;
2948
memset(hinfo->defects, 0, _MIMEH_DEFECT_ARRAY_SIZE);
2950
snprintf( hinfo->content_type_string, _MIMEH_CONTENT_TYPE_MAX , "text/plain" );
2953
// Read from the file, the headers we need
2954
FFGET_set_watch_SDL(1);
2955
result = MIMEH_read_headers(hinfo, f);
2956
FFGET_set_watch_SDL(0);
2958
if (hinfo->lf_count > hinfo->crlf_count) {
2959
snprintf(hinfo->delimeter,sizeof(hinfo->delimeter),"\n");
2962
// If we ran out of input whilst looking at headers, then, we basically
2963
// flag this, free up the headers, and return.
2966
if (glb.headerline) free(glb.headerline);
2970
// If we came back with an OKAY result, but there's nothing in the
2971
// headers, then flag off an error
2972
if (glb.headerline == NULL)
2974
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_headers:DEBUG: null headerline\n", FL);
2981
/*-----------------------------------------------------------------\
2982
Function Name : MIMEH_headers_cleanup
2989
--------------------------------------------------------------------
2992
--------------------------------------------------------------------
2995
\------------------------------------------------------------------*/
2996
int MIMEH_headers_cleanup( void )
2998
if (glb.headerline != NULL)
3000
free(glb.headerline);
3001
glb.headerline = NULL;
3004
if (glb.headerline_original != NULL)
3006
free(glb.headerline_original);
3007
glb.headerline_original = NULL;
3015
/*-----------------------------------------------------------------\
3016
Function Name : MIMEH_parse_headers
3020
2. struct MIMEH_header_info *hinfo ,
3024
--------------------------------------------------------------------
3027
--------------------------------------------------------------------
3030
\------------------------------------------------------------------*/
3031
int MIMEH_parse_headers( FFGET_FILE *f, struct MIMEH_header_info *hinfo )
3034
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Start [F=%p, hinfo=%p]\n", FL, f, hinfo);
3036
/** 20041216-1100:PLD: Set the header sanity to zero **/
3037
if ( result == 0 ) hinfo->sanity = 0;
3039
/** Proceed to read, process and finish headers **/
3040
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Getting headers",FL);
3041
if ( result == 0 ) result = MIMEH_headers_get( hinfo, f );
3042
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Processing headers",FL);
3043
if ( result == 0 ) result = MIMEH_headers_process( hinfo, glb.headerline );
3044
DMIMEH LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Cleanup of headers",FL);
3045
if ( result == 0 ) result = MIMEH_headers_cleanup();
3046
if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: END [F=%p, hinfo=%p, sanity=%d]\n", FL, f, hinfo, hinfo->sanity);
3051
/*-----------------------------------------------------------------\
3052
Function Name : MIMEH_dump_defects
3055
1. struct MIMEH_header_info *hinfo ,
3059
--------------------------------------------------------------------
3061
Displays a list of the located defects
3063
--------------------------------------------------------------------
3066
\------------------------------------------------------------------*/
3067
int MIMEH_dump_defects( struct MIMEH_header_info *hinfo )
3071
MIMEH_defect_description_array[MIMEH_DEFECT_MISSING_SEPARATORS] = strdup("Missing separators");
3072
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_FIELD_OCCURANCE] = strdup("Multiple field occurance");
3073
MIMEH_defect_description_array[MIMEH_DEFECT_UNBALANCED_BOUNDARY_QUOTE] = strdup("Unbalanced boundary quote");
3074
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_BOUNDARIES] = strdup("Multiple boundries");
3075
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_COLON_SEPARATORS] = strdup("Multiple colon separators");
3076
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_EQUALS_SEPARATORS] = strdup("Multiple equals separators");
3077
MIMEH_defect_description_array[MIMEH_DEFECT_UNBALANCED_QUOTES] = strdup("Unbalanced quotes");
3078
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_QUOTES] = strdup("Multiple quotes");
3079
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_NAMES] = strdup("Multiple names");
3080
MIMEH_defect_description_array[MIMEH_DEFECT_MULTIPLE_FILENAMES] = strdup("Multiple filenames");
3082
for (i = 0; i < _MIMEH_DEFECT_ARRAY_SIZE; i++)
3084
if (hinfo->defects[i] > 0)
3086
LOGGER_log("Header Defect: %s: %d",MIMEH_defect_description_array[i],hinfo->defects[i]);
3094
/*-----------------------------------------------------------------\
3095
Function Name : MIMEH_get_defect_count
3098
1. struct MIMEH_header_info *hinfo ,
3102
--------------------------------------------------------------------
3105
--------------------------------------------------------------------
3108
\------------------------------------------------------------------*/
3109
int MIMEH_get_defect_count( struct MIMEH_header_info *hinfo )
3112
return hinfo->header_defect_count;
3116
//----------------------END