Mercurial > libpst
annotate src/readpst.c @ 39:2ad7ef0a3c4f stable-0-5-10
more valgrind fixes
author | carl |
---|---|
date | Mon, 20 Aug 2007 20:43:17 -0700 |
parents | f5c024aa1dc5 |
children | 183ae993b9ad |
rev | line source |
---|---|
16 | 1 /*** |
2 * readpst.c | |
3 * Part of the LibPST project | |
4 * Written by David Smith | |
5 * dave.s@earthcorp.com | |
6 */ | |
7 #include <stdio.h> | |
8 #include <stdlib.h> | |
9 #include <time.h> | |
10 #include <string.h> | |
11 #include <ctype.h> | |
12 #include <limits.h> | |
13 #include <errno.h> | |
14 | |
15 #ifndef _WIN32 | |
16 # include <unistd.h> | |
17 # include <sys/stat.h> //mkdir | |
18 | |
19 // for reading of directory and clearing in function mk_seperate_dir | |
20 # include <sys/types.h> | |
21 # include <dirent.h> | |
22 #else | |
23 # include <direct.h> | |
24 # define chdir _chdir | |
25 # define int32_t __int32 | |
26 #endif | |
27 | |
28 #ifndef __GNUC__ | |
29 # include "XGetopt.h" | |
30 #endif | |
31 | |
32 #include "libstrfunc.h" // for base64_encoding | |
33 | |
21 | 34 #include "version.h" |
16 | 35 #include "define.h" |
36 #include "libpst.h" | |
37 #include "common.h" | |
38 #include "timeconv.h" | |
39 #include "lzfu.h" | |
40 #define OUTPUT_TEMPLATE "%s" | |
41 #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory" | |
42 #define KMAIL_INDEX ".%s.index" | |
25 | 43 #define SEP_MAIL_FILE_TEMPLATE "%i" /* "%09i" */ |
16 | 44 |
45 // max size of the c_time char*. It will store the date of the email | |
46 #define C_TIME_SIZE 500 | |
47 #define PERM_DIRS 0777 | |
48 | |
49 // macro used for creating directories | |
50 #ifndef WIN32 | |
51 #define D_MKDIR(x) mkdir(x, PERM_DIRS) | |
52 #else | |
53 #define D_MKDIR(x) mkdir(x) | |
54 #endif | |
55 struct file_ll { | |
26 | 56 char *name; |
57 char *dname; | |
58 FILE * output; | |
59 int32_t stored_count; | |
60 int32_t email_count; | |
61 int32_t skip_count; | |
62 int32_t type; | |
16 | 63 }; |
31 | 64 |
39 | 65 void process(pst_item *outeritem, pst_desc_ll *d_ptr); |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
66 void write_email_body(FILE *f, char *body); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
67 char* removeCR (char *c); |
16 | 68 int32_t usage(); |
69 int32_t version(); | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
70 char* mk_kmail_dir(char*); |
16 | 71 int32_t close_kmail_dir(); |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
72 char* mk_recurse_dir(char*); |
16 | 73 int32_t close_recurse_dir(); |
39 | 74 char* mk_seperate_dir(char *dir); |
16 | 75 int32_t close_seperate_dir(); |
76 int32_t mk_seperate_file(struct file_ll *f); | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
77 char* my_stristr(char *haystack, char *needle); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
78 char* check_filename(char *fname); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
79 char* rfc2426_escape(char *str); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
80 int32_t chr_count(char *str, char x); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
81 char* rfc2425_datetime_format(FILETIME *ft); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
82 char* rfc2445_datetime_format(FILETIME *ft); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
83 char* skip_header_prologue(char *headers); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
84 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
85 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
86 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
87 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
88 void write_appointment(FILE* f_output, pst_item_appointment* appointment, |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
89 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); |
39 | 90 void create_enter_dir(struct file_ll* f, pst_item *item); |
91 void close_enter_dir(struct file_ll *f); | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
92 |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
93 char* prog_name; |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
94 char* output_dir = "."; |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
95 char* kmail_chdir = NULL; |
16 | 96 // Normal mode just creates mbox format files in the current directory. Each file is named |
97 // the same as the folder's name that it represents | |
98 #define MODE_NORMAL 0 | |
99 // KMail mode creates a directory structure suitable for being used directly | |
100 // by the KMail application | |
101 #define MODE_KMAIL 1 | |
102 // recurse mode creates a directory structure like the PST file. Each directory | |
103 // contains only one file which stores the emails in mbox format. | |
104 #define MODE_RECURSE 2 | |
105 // seperate mode is similar directory structure to RECURSE. The emails are stored in | |
106 // seperate files, numbering from 1 upward. Attachments belonging to the emails are | |
107 // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip) | |
108 #define MODE_SEPERATE 3 | |
109 | |
110 | |
111 // Output Normal just prints the standard information about what is going on | |
112 #define OUTPUT_NORMAL 0 | |
113 // Output Quiet is provided so that only errors are printed | |
114 #define OUTPUT_QUIET 1 | |
115 | |
116 // default mime-type for attachments that have a null mime-type | |
117 #define MIME_TYPE_DEFAULT "application/octet-stream" | |
118 | |
119 // output mode for contacts | |
120 #define CMODE_VCARD 0 | |
121 #define CMODE_LIST 1 | |
122 | |
123 // output settings for RTF bodies | |
124 // filename for the attachment | |
125 #define RTF_ATTACH_NAME "rtf-body.rtf" | |
126 // mime type for the attachment | |
127 #define RTF_ATTACH_TYPE "application/rtf" | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
128 |
39 | 129 // global settings |
130 int mode = MODE_NORMAL; | |
131 int mode_MH = 0; | |
132 int output_mode = OUTPUT_NORMAL; | |
133 int contact_mode = CMODE_VCARD; | |
134 int overwrite = 0; | |
135 int save_rtf_body = 1; | |
136 pst_file pstfile; | |
137 | |
138 | |
139 | |
140 void process(pst_item *outeritem, pst_desc_ll *d_ptr) | |
141 { | |
142 struct file_ll ff; | |
143 pst_item *item = NULL; | |
144 | |
145 DEBUG_ENT("process"); | |
146 memset(&ff, 0, sizeof(ff)); | |
147 create_enter_dir(&ff, outeritem); | |
148 | |
149 while (d_ptr) { | |
150 DEBUG_MAIN(("main: New item record\n")); | |
151 if (!d_ptr->desc) { | |
152 DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); | |
153 ff.skip_count++; | |
154 } | |
155 else { | |
156 DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id)); | |
157 | |
158 item = _pst_parse_item(&pstfile, d_ptr); | |
159 DEBUG_MAIN(("main: About to process item\n")); | |
160 if (item && item->email && item->email->subject && item->email->subject->subj) { | |
161 DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject)); | |
162 DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); | |
163 } | |
164 if (item) { | |
165 if (item->message_store) { | |
166 // there should only be one message_store, and we have already done it | |
167 DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); | |
168 } | |
169 | |
170 if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) { | |
171 //if this is a non-empty folder other than deleted items, we want to recurse into it | |
172 if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as); | |
173 process(item, d_ptr->child); | |
174 | |
175 } else if (item->contact) { | |
176 // deal with a contact | |
177 // write them to the file, one per line in this format | |
178 // Desc Name <email@address>\n | |
179 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
180 ff.email_count++; | |
181 DEBUG_MAIN(("main: Processing Contact\n")); | |
182 if (ff.type != PST_TYPE_CONTACT) { | |
183 DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. " | |
184 "Will process anyway\n")); | |
185 } | |
186 if (item->type != PST_TYPE_CONTACT) { | |
187 DEBUG_MAIN(("main: I have an item that has contact info, but doesn't say that" | |
188 " it is a contact. Type is \"%s\"\n", item->ascii_type)); | |
189 DEBUG_MAIN(("main: Processing anyway\n")); | |
190 } | |
191 if (!item->contact) { // this is an incorrect situation. Inform user | |
192 DEBUG_MAIN(("main: ERROR. This contact has not been fully parsed. one of the pre-requisties is NULL\n")); | |
193 } else { | |
194 if (contact_mode == CMODE_VCARD) | |
195 write_vcard(ff.output, item->contact, item->comment); | |
196 else | |
197 fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); | |
198 } | |
199 | |
200 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { | |
201 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
202 ff.email_count++; | |
203 DEBUG_MAIN(("main: seen an email\n")); | |
204 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body); | |
205 | |
206 } else if (item->type == PST_TYPE_JOURNAL) { | |
207 // deal with journal items | |
208 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
209 ff.email_count++; | |
210 | |
211 DEBUG_MAIN(("main: Processing Journal Entry\n")); | |
212 if (ff.type != PST_TYPE_JOURNAL) { | |
213 DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); | |
214 } | |
215 | |
216 /* if (item->type != PST_TYPE_JOURNAL) { | |
217 DEBUG_MAIN(("main: I have an item with journal info, but it's type is \"%s\" \n. Processing...\n", | |
218 item->ascii_type)); | |
219 }*/ | |
220 fprintf(ff.output, "BEGIN:VJOURNAL\n"); | |
221 if (item->email->subject) | |
222 fprintf(ff.output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj)); | |
223 if (item->email->body) | |
224 fprintf(ff.output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body)); | |
225 if (item->journal->start) | |
226 fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->journal->start)); | |
227 fprintf(ff.output, "END:VJOURNAL\n\n"); | |
228 | |
229 } else if (item->type == PST_TYPE_APPOINTMENT) { | |
230 // deal with Calendar appointments | |
231 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
232 ff.email_count++; | |
233 DEBUG_MAIN(("main: Processing Appointment Entry\n")); | |
234 if (ff.type != PST_TYPE_APPOINTMENT) { | |
235 DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); | |
236 } | |
237 write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date); | |
238 | |
239 } else { | |
240 ff.skip_count++; | |
241 DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", | |
242 item->type, item->ascii_type)); | |
243 } | |
244 _pst_freeItem(item); | |
245 } else { | |
246 ff.skip_count++; | |
247 DEBUG_MAIN(("main: A NULL item was seen\n")); | |
248 } | |
249 d_ptr = d_ptr->next; | |
250 } | |
251 } | |
252 close_enter_dir(&ff); | |
253 DEBUG_RET(); | |
254 } | |
255 | |
256 | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
257 |
16 | 258 int main(int argc, char** argv) { |
26 | 259 pst_item *item = NULL; |
260 pst_desc_ll *d_ptr; | |
261 char * fname = NULL; | |
262 char *d_log=NULL; | |
263 int c,x; | |
31 | 264 char *temp = NULL; //temporary char pointer |
26 | 265 prog_name = argv[0]; |
16 | 266 |
31 | 267 // command-line option handling |
268 while ((c = getopt(argc, argv, "bd:hko:qrMSVwc:"))!= -1) { | |
26 | 269 switch (c) { |
31 | 270 case 'b': |
271 save_rtf_body = 0; | |
272 break; | |
26 | 273 case 'c': |
31 | 274 if (optarg && optarg[0]=='v') |
26 | 275 contact_mode=CMODE_VCARD; |
31 | 276 else if (optarg && optarg[0]=='l') |
26 | 277 contact_mode=CMODE_LIST; |
278 else { | |
279 usage(); | |
280 exit(0); | |
281 } | |
282 break; | |
283 case 'd': | |
284 d_log = optarg; | |
285 break; | |
286 case 'h': | |
287 usage(); | |
288 exit(0); | |
289 break; | |
290 case 'V': | |
291 version(); | |
292 exit(0); | |
293 break; | |
294 case 'k': | |
295 mode = MODE_KMAIL; | |
296 break; | |
297 case 'M': | |
298 mode = MODE_SEPERATE; | |
299 mode_MH = 1; | |
300 break; | |
301 case 'o': | |
302 output_dir = optarg; | |
303 break; | |
304 case 'q': | |
305 output_mode = OUTPUT_QUIET; | |
306 break; | |
307 case 'r': | |
308 mode = MODE_RECURSE; | |
309 break; | |
310 case 'S': | |
311 mode = MODE_SEPERATE; | |
312 break; | |
313 case 'w': | |
314 overwrite = 1; | |
315 break; | |
316 default: | |
317 usage(); | |
318 exit(1); | |
319 break; | |
320 } | |
16 | 321 } |
322 | |
26 | 323 if (argc > optind) { |
324 fname = argv[optind]; | |
325 } else { | |
326 usage(); | |
327 exit(2); | |
328 } | |
16 | 329 |
39 | 330 #ifdef DEBUG_ALL |
331 // force a log file | |
332 if (!d_log) d_log = "readpst.log"; | |
333 #endif // defined DEBUG_ALL | |
334 DEBUG_INIT(d_log); | |
335 DEBUG_REGISTER_CLOSE(); | |
336 DEBUG_ENT("main"); | |
337 | |
26 | 338 if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); |
16 | 339 |
26 | 340 RET_DERROR(pst_open(&pstfile, fname, "r"), 1, ("Error opening File\n")); |
341 RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); | |
16 | 342 |
26 | 343 pst_load_extended_attributes(&pstfile); |
16 | 344 |
26 | 345 if (chdir(output_dir)) { |
346 x = errno; | |
347 pst_close(&pstfile); | |
39 | 348 DEBUG_RET(); |
26 | 349 DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x))); |
350 } | |
16 | 351 |
26 | 352 if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n"); |
16 | 353 |
26 | 354 d_ptr = pstfile.d_head; // first record is main record |
39 | 355 item = (pst_item*)_pst_parse_item(&pstfile, d_ptr); |
356 if (!item || !item->message_store) { | |
357 DEBUG_RET(); | |
26 | 358 DIE(("main: Could not get root record\n")); |
359 } | |
16 | 360 |
26 | 361 // default the file_as to the same as the main filename if it doesn't exist |
31 | 362 if (!item->file_as) { |
363 if (!(temp = strrchr(fname, '/'))) | |
364 if (!(temp = strrchr(fname, '\\'))) | |
26 | 365 temp = fname; |
366 else | |
367 temp++; // get past the "\\" | |
368 else | |
369 temp++; // get past the "/" | |
370 item->file_as = (char*)xmalloc(strlen(temp)+1); | |
371 strcpy(item->file_as, temp); | |
372 DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as)); | |
373 } | |
374 DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as)); | |
16 | 375 |
39 | 376 d_ptr = pst_getTopOfFolders(&pstfile, item); |
377 if (!d_ptr) { | |
378 DEBUG_RET(); | |
26 | 379 DIE(("Top of folders record not found. Cannot continue\n")); |
16 | 380 } |
381 | |
39 | 382 process(item, d_ptr->child); // do the children of TOPF |
383 _pst_freeItem(item); | |
26 | 384 pst_close(&pstfile); |
16 | 385 |
26 | 386 DEBUG_RET(); |
387 return 0; | |
16 | 388 } |
31 | 389 |
390 | |
16 | 391 void write_email_body(FILE *f, char *body) { |
26 | 392 char *n = body; |
31 | 393 // DEBUG_MAIN(("write_email_body(): \"%s\"\n", body)); |
26 | 394 DEBUG_ENT("write_email_body"); |
31 | 395 while (n) { |
26 | 396 if (strncmp(body, "From ", 5) == 0) |
397 fprintf(f, ">"); | |
398 if ((n = strchr(body, '\n'))) { | |
399 n++; | |
400 fwrite(body, n-body, 1, f); //write just a line | |
16 | 401 |
26 | 402 body = n; |
403 } | |
16 | 404 } |
26 | 405 fwrite(body, strlen(body), 1, f); |
406 DEBUG_RET(); | |
16 | 407 } |
31 | 408 |
409 | |
16 | 410 char *removeCR (char *c) { |
26 | 411 // converts /r/n to /n |
412 char *a, *b; | |
413 DEBUG_ENT("removeCR"); | |
414 a = b = c; | |
415 while (*a != '\0') { | |
416 *b = *a; | |
417 if (*a != '\r') | |
418 b++; | |
419 a++; | |
420 } | |
421 *b = '\0'; | |
422 DEBUG_RET(); | |
423 return c; | |
16 | 424 } |
31 | 425 |
426 | |
16 | 427 int usage() { |
26 | 428 DEBUG_ENT("usage"); |
429 version(); | |
430 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); | |
431 printf("OPTIONS:\n"); | |
31 | 432 printf("\t-b\t- Don't save RTF-Body attachments\n"); |
26 | 433 printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n"); |
31 | 434 printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readlog to print it\n"); |
26 | 435 printf("\t-h\t- Help. This screen\n"); |
436 printf("\t-k\t- KMail. Output in kmail format\n"); | |
437 printf("\t-M\t- MH. Write emails in the MH format\n"); | |
31 | 438 printf("\t-o <dirname>\t- Output Dir. Directory to write files to. CWD is changed *after* opening pst file\n"); |
26 | 439 printf("\t-q\t- Quiet. Only print error messages\n"); |
440 printf("\t-r\t- Recursive. Output in a recursive format\n"); | |
441 printf("\t-S\t- Seperate. Write emails in the seperate format\n"); | |
442 printf("\t-V\t- Version. Display program version\n"); | |
443 printf("\t-w\t- Overwrite any output mbox files\n"); | |
444 DEBUG_RET(); | |
445 return 0; | |
16 | 446 } |
31 | 447 |
448 | |
16 | 449 int version() { |
26 | 450 DEBUG_ENT("version"); |
451 printf("ReadPST v%s\n", VERSION); | |
16 | 452 #if BYTE_ORDER == BIG_ENDIAN |
26 | 453 printf("Big Endian implementation being used.\n"); |
16 | 454 #elif BYTE_ORDER == LITTLE_ENDIAN |
26 | 455 printf("Little Endian implementation being used.\n"); |
16 | 456 #else |
457 # error "Byte order not supported by this library" | |
458 #endif | |
459 #ifdef __GNUC__ | |
26 | 460 printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); |
16 | 461 #endif |
26 | 462 DEBUG_RET(); |
463 return 0; | |
16 | 464 } |
31 | 465 |
466 | |
16 | 467 char *mk_kmail_dir(char *fname) { |
26 | 468 //change to that directory |
469 //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE | |
470 //allocate space for OUTPUT_TEMPLATE and form a char* with fname | |
471 //return that value | |
472 char *dir, *out_name, *index; | |
473 int x; | |
474 DEBUG_ENT("mk_kmail_dir"); | |
31 | 475 if (kmail_chdir && chdir(kmail_chdir)) { |
26 | 476 x = errno; |
477 DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x))); | |
16 | 478 } |
26 | 479 dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1); |
480 sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname); | |
481 dir = check_filename(dir); | |
482 if (D_MKDIR(dir)) { | |
483 //error occured | |
484 if (errno != EEXIST) { | |
485 x = errno; | |
486 DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
487 } | |
488 } | |
489 kmail_chdir = realloc(kmail_chdir, strlen(dir)+1); | |
490 strcpy(kmail_chdir, dir); | |
491 free (dir); | |
16 | 492 |
26 | 493 //we should remove any existing indexes created by KMail, cause they might be different now |
494 index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1); | |
495 sprintf(index, KMAIL_INDEX, fname); | |
496 unlink(index); | |
497 free(index); | |
16 | 498 |
26 | 499 out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1); |
500 sprintf(out_name, OUTPUT_TEMPLATE, fname); | |
501 DEBUG_RET(); | |
502 return out_name; | |
16 | 503 } |
31 | 504 |
505 | |
16 | 506 int close_kmail_dir() { |
26 | 507 // change .. |
508 int x; | |
509 DEBUG_ENT("close_kmail_dir"); | |
31 | 510 if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory |
26 | 511 free(kmail_chdir); |
512 kmail_chdir = NULL; | |
513 } else { | |
514 if (chdir("..")) { | |
515 x = errno; | |
516 DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x))); | |
517 } | |
16 | 518 } |
26 | 519 DEBUG_RET(); |
520 return 0; | |
16 | 521 } |
31 | 522 |
523 | |
16 | 524 // this will create a directory by that name, then make an mbox file inside |
525 // that dir. any subsequent dirs will be created by name, and they will | |
526 // contain mbox files | |
527 char *mk_recurse_dir(char *dir) { | |
26 | 528 int x; |
529 char *out_name; | |
530 DEBUG_ENT("mk_recurse_dir"); | |
531 dir = check_filename(dir); | |
532 if (D_MKDIR (dir)) { | |
533 if (errno != EEXIST) { // not an error because it exists | |
534 x = errno; | |
535 DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
536 } | |
16 | 537 } |
26 | 538 if (chdir (dir)) { |
539 x = errno; | |
540 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); | |
541 } | |
542 out_name = malloc(strlen("mbox")+1); | |
543 strcpy(out_name, "mbox"); | |
544 DEBUG_RET(); | |
545 return out_name; | |
16 | 546 } |
31 | 547 |
548 | |
16 | 549 int close_recurse_dir() { |
26 | 550 int x; |
551 DEBUG_ENT("close_recurse_dir"); | |
552 if (chdir("..")) { | |
553 x = errno; | |
554 DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x))); | |
555 } | |
556 DEBUG_RET(); | |
557 return 0; | |
16 | 558 } |
31 | 559 |
560 | |
39 | 561 char *mk_seperate_dir(char *dir) { |
31 | 562 DEBUG_ENT("mk_seperate_dir"); |
563 #if !defined(WIN32) && !defined(__CYGWIN__) | |
564 DIR * sdir = NULL; | |
565 struct dirent *dirent = NULL; | |
566 struct stat *filestat = xmalloc(sizeof(struct stat)); | |
567 #endif | |
16 | 568 |
26 | 569 char *dir_name = NULL; |
570 int x = 0, y = 0; | |
16 | 571 |
26 | 572 dir_name = xmalloc(strlen(dir)+10); |
16 | 573 |
26 | 574 do { |
575 if (y == 0) | |
576 sprintf(dir_name, "%s", dir); | |
577 else | |
578 sprintf(dir_name, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y); // enough for 9 digits allocated above | |
16 | 579 |
26 | 580 dir_name = check_filename(dir_name); |
31 | 581 DEBUG_MAIN(("about to try creating %s\n", dir_name)); |
26 | 582 if (D_MKDIR(dir_name)) { |
583 if (errno != EEXIST) { // if there is an error, and it doesn't already exist | |
584 x = errno; | |
585 DIE(("mk_seperate_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
586 } | |
587 } else { | |
588 break; | |
589 } | |
590 y++; | |
591 } while (overwrite == 0); | |
16 | 592 |
26 | 593 if (chdir (dir_name)) { |
594 x = errno; | |
595 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); | |
596 } | |
16 | 597 |
26 | 598 if (overwrite) { |
599 // we should probably delete all files from this directory | |
16 | 600 #if !defined(WIN32) && !defined(__CYGWIN__) |
31 | 601 if (!(sdir = opendir("./"))) { |
26 | 602 WARN(("mk_seperate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./")); |
603 } else { | |
31 | 604 while ((dirent = readdir(sdir))) { |
26 | 605 if (lstat(dirent->d_name, filestat) != -1) |
606 if (S_ISREG(filestat->st_mode)) { | |
607 if (unlink(dirent->d_name)) { | |
608 y = errno; | |
609 DIE(("mk_seperate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y))); | |
610 } | |
611 } | |
612 } | |
16 | 613 } |
26 | 614 #endif |
16 | 615 } |
616 | |
26 | 617 // we don't return a filename here cause it isn't necessary. |
618 DEBUG_RET(); | |
619 return NULL; | |
16 | 620 } |
31 | 621 |
622 | |
16 | 623 int close_seperate_dir() { |
26 | 624 int x; |
625 DEBUG_ENT("close_seperate_dir"); | |
626 if (chdir("..")) { | |
627 x = errno; | |
628 DIE(("close_seperate_dir: Cannot go up dir (..): %s\n", strerror(x))); | |
629 } | |
630 DEBUG_RET(); | |
631 return 0; | |
16 | 632 } |
31 | 633 |
634 | |
16 | 635 int mk_seperate_file(struct file_ll *f) { |
26 | 636 const int name_offset = 1; |
637 DEBUG_ENT("mk_seperate_file"); | |
31 | 638 DEBUG_MAIN(("opening next file to save email\n")); |
26 | 639 if (f->email_count > 999999999) { // bigger than nine 9's |
640 DIE(("mk_seperate_file: The number of emails in this folder has become too high to handle")); | |
641 } | |
642 sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset); | |
39 | 643 if (f->output) fclose(f->output); |
26 | 644 f->output = NULL; |
645 f->name = check_filename(f->name); | |
31 | 646 if (!(f->output = fopen(f->name, "w"))) { |
26 | 647 DIE(("mk_seperate_file: Cannot open file to save email \"%s\"\n", f->name)); |
648 } | |
649 DEBUG_RET(); | |
650 return 0; | |
16 | 651 } |
31 | 652 |
653 | |
16 | 654 char *my_stristr(char *haystack, char *needle) { |
31 | 655 // my_stristr varies from strstr in that its searches are case-insensitive |
26 | 656 char *x=haystack, *y=needle, *z = NULL; |
657 DEBUG_ENT("my_stristr"); | |
31 | 658 if (!haystack || !needle) |
26 | 659 return NULL; |
660 while (*y != '\0' && *x != '\0') { | |
661 if (tolower(*y) == tolower(*x)) { | |
662 // move y on one | |
663 y++; | |
31 | 664 if (!z) { |
26 | 665 z = x; // store first position in haystack where a match is made |
666 } | |
667 } else { | |
668 y = needle; // reset y to the beginning of the needle | |
669 z = NULL; // reset the haystack storage point | |
670 } | |
671 x++; // advance the search in the haystack | |
16 | 672 } |
26 | 673 DEBUG_RET(); |
674 return z; | |
16 | 675 } |
31 | 676 |
677 | |
16 | 678 char *check_filename(char *fname) { |
26 | 679 char *t = fname; |
680 DEBUG_ENT("check_filename"); | |
31 | 681 if (!t) { |
26 | 682 DEBUG_RET(); |
683 return fname; | |
684 } | |
31 | 685 while ((t = strpbrk(t, "/\\:"))) { |
26 | 686 // while there are characters in the second string that we don't want |
687 *t = '_'; //replace them with an underscore | |
688 } | |
16 | 689 DEBUG_RET(); |
690 return fname; | |
691 } | |
31 | 692 |
693 | |
16 | 694 char *rfc2426_escape(char *str) { |
26 | 695 static char* buf = NULL; |
696 char *ret, *a, *b; | |
697 int x = 0, y, z; | |
698 DEBUG_ENT("rfc2426_escape"); | |
31 | 699 if (!str) |
26 | 700 ret = str; |
16 | 701 else { |
26 | 702 |
703 // calculate space required to escape all the following characters | |
31 | 704 y = chr_count(str, ',') |
705 + chr_count(str, '\\') | |
706 + chr_count(str, ';') | |
707 + chr_count(str, '\n'); | |
26 | 708 z = chr_count(str, '\r'); |
709 if (y == 0 && z == 0) | |
710 // there isn't any extra space required | |
711 ret = str; | |
712 else { | |
38 | 713 x = strlen(str) + y - z + 1; // don't forget room for the NUL |
31 | 714 buf = (char*) realloc(buf, x); |
26 | 715 a = str; |
716 b = buf; | |
717 while (*a != '\0') { | |
31 | 718 switch (*a) { |
26 | 719 case ',' : |
720 case '\\': | |
721 case ';' : | |
31 | 722 *(b++) = '\\'; |
723 *b = *a; | |
26 | 724 break; |
31 | 725 case '\n': // newlines are encoded as "\n" |
726 *(b++) = '\\'; | |
727 *b = 'n'; | |
728 break; | |
729 case '\r': // skip cr | |
730 b--; | |
26 | 731 break; |
732 default: | |
733 *b=*a; | |
734 } | |
735 b++; | |
736 a++; | |
737 } | |
31 | 738 *b = '\0'; // NUL-terminate the string (buf) |
26 | 739 ret = buf; |
740 } | |
16 | 741 } |
26 | 742 DEBUG_RET(); |
743 return ret; | |
16 | 744 } |
31 | 745 |
746 | |
16 | 747 int chr_count(char *str, char x) { |
26 | 748 int r = 0; |
749 while (*str != '\0') { | |
750 if (*str == x) | |
751 r++; | |
752 str++; | |
753 } | |
754 return r; | |
16 | 755 } |
31 | 756 |
757 | |
16 | 758 char *rfc2425_datetime_format(FILETIME *ft) { |
39 | 759 static char* buffer = NULL; |
26 | 760 struct tm *stm = NULL; |
761 DEBUG_ENT("rfc2425_datetime_format"); | |
39 | 762 if (!buffer) buffer = malloc(30); // should be enough for the date as defined below |
26 | 763 stm = fileTimeToStructTM(ft); |
764 if (strftime(buffer, 30, "%Y-%m-%dT%H:%M:%SZ", stm)==0) { | |
765 DEBUG_INFO(("Problem occured formatting date\n")); | |
766 } | |
767 DEBUG_RET(); | |
768 return buffer; | |
16 | 769 } |
31 | 770 |
771 | |
16 | 772 char *rfc2445_datetime_format(FILETIME *ft) { |
26 | 773 static char* buffer = NULL; |
774 struct tm *stm = NULL; | |
775 DEBUG_ENT("rfc2445_datetime_format"); | |
39 | 776 if (!buffer) buffer = malloc(30); // should be enough for the date as defined below |
26 | 777 stm = fileTimeToStructTM(ft); |
778 if (strftime(buffer, 30, "%Y%m%dT%H%M%SZ", stm)==0) { | |
779 DEBUG_INFO(("Problem occured formatting date\n")); | |
780 } | |
781 DEBUG_RET(); | |
782 return buffer; | |
16 | 783 } |
31 | 784 |
785 | |
16 | 786 // The sole purpose of this function is to bypass the pseudo-header prologue |
787 // that Microsoft Outlook inserts at the beginning of the internet email | |
788 // headers for emails stored in their "Personal Folders" files. | |
789 char *skip_header_prologue(char *headers) { | |
790 const char *bad = "Microsoft Mail Internet Headers"; | |
791 if ( strncmp(headers, bad, strlen(bad)) == 0 ) { | |
792 // Found the offensive header prologue | |
31 | 793 char *pc = strchr(headers, '\n'); |
16 | 794 return pc + 1; |
795 } | |
796 return headers; | |
797 } | |
798 | |
31 | 799 |
25 | 800 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst) |
801 { | |
31 | 802 DEBUG_ENT("write_separate_attachment"); |
25 | 803 FILE *fp = NULL; |
804 int x = 0; | |
31 | 805 char *temp = NULL; |
806 | |
807 // If there is a long filename (filename2) use that, otherwise | |
808 // use the 8.3 filename (filename1) | |
809 char *attach_filename = (current_attach->filename2) ? current_attach->filename2 | |
810 : current_attach->filename1; | |
25 | 811 |
812 check_filename(f_name); | |
31 | 813 if (!attach_filename) { |
814 // generate our own (dummy) filename for the attachement | |
25 | 815 temp = xmalloc(strlen(f_name)+15); |
816 sprintf(temp, "%s-attach%i", f_name, attach_num); | |
817 } else { | |
31 | 818 // have an attachment name, make sure it's unique |
819 temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15); | |
25 | 820 do { |
31 | 821 if (fp) fclose(fp); |
25 | 822 if (x == 0) |
31 | 823 sprintf(temp, "%s-%s", f_name, attach_filename); |
25 | 824 else |
31 | 825 sprintf(temp, "%s-%s-%i", f_name, attach_filename, x); |
826 } while ((fp = fopen(temp, "r")) && ++x < 99999999); | |
25 | 827 if (x > 99999999) { |
828 DIE(("error finding attachment name. exhausted possibilities to %s\n", temp)); | |
829 } | |
830 } | |
31 | 831 DEBUG_EMAIL(("Saving attachment to %s\n", temp)); |
832 if (!(fp = fopen(temp, "w"))) { | |
25 | 833 WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); |
834 } else { | |
31 | 835 if (current_attach->data) |
25 | 836 fwrite(current_attach->data, 1, current_attach->size, fp); |
837 else { | |
838 pst_attach_to_file(pst, current_attach, fp); | |
839 } | |
840 fclose(fp); | |
841 } | |
31 | 842 if (temp) free(temp); |
843 DEBUG_RET(); | |
25 | 844 } |
845 | |
31 | 846 |
25 | 847 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst) |
848 { | |
31 | 849 DEBUG_ENT("write_inline_attachment"); |
25 | 850 char *enc; // base64 encoded attachment |
31 | 851 DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size)); |
852 DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data)); | |
853 if (current_attach->data) { | |
854 enc = base64_encode (current_attach->data, current_attach->size); | |
855 if (!enc) { | |
856 DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); | |
25 | 857 return; |
858 } | |
859 } | |
860 if (boundary) { | |
31 | 861 char *attach_filename; |
25 | 862 fprintf(f_output, "\n--%s\n", boundary); |
31 | 863 if (!current_attach->mimetype) { |
25 | 864 fprintf(f_output, "Content-type: %s\n", MIME_TYPE_DEFAULT); |
865 } else { | |
866 fprintf(f_output, "Content-type: %s\n", current_attach->mimetype); | |
867 } | |
868 fprintf(f_output, "Content-transfer-encoding: base64\n"); | |
31 | 869 // If there is a long filename (filename2) use that, otherwise |
870 // use the 8.3 filename (filename1) | |
871 if (current_attach->filename2) { | |
872 attach_filename = current_attach->filename2; | |
873 } else { | |
874 attach_filename = current_attach->filename1; | |
875 } | |
876 if (!attach_filename) { | |
25 | 877 fprintf(f_output, "Content-Disposition: inline\n\n"); |
878 } else { | |
31 | 879 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); |
25 | 880 } |
881 } | |
31 | 882 if (current_attach->data) { |
25 | 883 fwrite(enc, 1, strlen(enc), f_output); |
31 | 884 DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); |
36 | 885 free(enc); // caught by valgrind |
25 | 886 } else { |
887 pst_attach_to_file_base64(pst, current_attach, f_output); | |
888 } | |
889 fprintf(f_output, "\n\n"); | |
31 | 890 DEBUG_RET(); |
25 | 891 } |
892 | |
31 | 893 |
894 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf) | |
25 | 895 { |
31 | 896 DEBUG_ENT("write_normal_email"); |
897 char *boundary = NULL; // the boundary marker between multipart sections | |
898 int boundary_created = 0; // we have not (yet) created a new boundary | |
25 | 899 char *temp = NULL; |
900 int attach_num, base64_body = 0; | |
901 time_t em_time; | |
902 char *c_time; | |
31 | 903 pst_item_attach* current_attach; |
25 | 904 |
905 // convert the sent date if it exists, or set it to a fixed date | |
31 | 906 if (item->email->sent_date) { |
25 | 907 em_time = fileTimeToUnixTime(item->email->sent_date, 0); |
908 c_time = ctime(&em_time); | |
31 | 909 if (c_time) |
25 | 910 c_time[strlen(c_time)-1] = '\0'; //remove end \n |
911 else | |
912 c_time = "Fri Dec 28 12:06:21 2001"; | |
913 } else | |
914 c_time= "Fri Dec 28 12:06:21 2001"; | |
915 | |
916 // we will always look at the header to discover some stuff | |
31 | 917 if (item->email->header ) { |
25 | 918 char *b1, *b2; |
919 // see if there is a boundary variable there | |
920 // this search MUST be made case insensitive (DONE). | |
31 | 921 // Also, we should check to find out if we are looking |
922 // at the boundary associated with content-type, and that | |
923 // the content type really is multipart | |
25 | 924 |
925 removeCR(item->email->header); | |
926 | |
31 | 927 if ((b2 = my_stristr(item->email->header, "boundary="))) { |
928 int len; | |
25 | 929 b2 += strlen("boundary="); // move boundary to first char of marker |
31 | 930 |
25 | 931 if (*b2 == '"') { |
932 b2++; | |
933 b1 = strchr(b2, '"'); // find terminating quote | |
934 } else { | |
935 b1 = b2; | |
936 while (isgraph(*b1)) // find first char that isn't part of boundary | |
937 b1++; | |
938 } | |
31 | 939 len = b1 - b2; |
940 boundary = malloc(len+1); //malloc that length | |
941 strncpy(boundary, b2, len); // copy boundary to another variable | |
942 boundary[len] = '\0'; | |
25 | 943 b1 = b2 = boundary; |
944 while (*b2 != '\0') { // remove any CRs and Tabs | |
945 if (*b2 != '\n' && *b2 != '\r' && *b2 != '\t') { | |
946 *b1 = *b2; | |
947 b1++; | |
948 } | |
949 b2++; | |
950 } | |
951 *b1 = '\0'; | |
31 | 952 |
953 DEBUG_EMAIL(("Found boundary of - %s\n", boundary)); | |
25 | 954 } else { |
31 | 955 DEBUG_EMAIL(("boundary not found in header\n")); |
25 | 956 } |
957 | |
958 // also possible to set 7bit encoding detection here. | |
31 | 959 if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:"))) { |
960 if ((b2 = strchr(b2, ':'))) { | |
25 | 961 b2++; // skip to the : at the end of the string |
31 | 962 |
25 | 963 while (*b2 == ' ' || *b2 == '\t') |
964 b2++; | |
965 if (pst_strincmp(b2, "base64", 6)==0) { | |
31 | 966 DEBUG_EMAIL(("body is base64 encoded\n")); |
25 | 967 base64_body = 1; |
968 } | |
969 } else { | |
970 DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n")); | |
971 } | |
972 } | |
973 } | |
974 | |
31 | 975 if (!boundary && (item->attach || (item->email->body && item->email->htmlbody) |
976 || item->email->rtf_compressed || item->email->encrypted_body | |
977 || item->email->encrypted_htmlbody)) { | |
978 // we need to create a boundary here. | |
979 DEBUG_EMAIL(("must create own boundary. oh dear.\n")); | |
980 boundary = malloc(50 * sizeof(char)); // allow 50 chars for boundary | |
981 boundary[0] = '\0'; | |
982 sprintf(boundary, "--boundary-LibPST-iamunique-%i_-_-", rand()); | |
983 DEBUG_EMAIL(("created boundary is %s\n", boundary)); | |
984 boundary_created = 1; | |
25 | 985 } |
986 | |
31 | 987 DEBUG_EMAIL(("About to print Header\n")); |
988 | |
989 if (item && item->email && item->email->subject && item->email->subject->subj) { | |
990 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); | |
991 } | |
992 | |
993 if (item->email->header) { | |
994 int len; | |
995 char *soh = NULL; // real start of headers. | |
996 | |
25 | 997 // some of the headers we get from the file are not properly defined. |
998 // they can contain some email stuff too. We will cut off the header | |
999 // when we see a \n\n or \r\n\r\n | |
31 | 1000 removeCR(item->email->header); |
25 | 1001 temp = strstr(item->email->header, "\n\n"); |
1002 | |
31 | 1003 if (temp) { |
1004 DEBUG_EMAIL(("Found body text in header\n")); | |
1005 temp[1] = '\0'; // stop after first \n | |
25 | 1006 } |
31 | 1007 |
1008 // Now, write out the header... | |
1009 soh = skip_header_prologue(item->email->header); | |
25 | 1010 if (mode != MODE_SEPERATE) { |
1011 // don't put rubbish in if we are doing seperate | |
31 | 1012 if (strncmp(soh, "X-From_: ", 9) == 0 ) { |
1013 fputs("From ", f_output); | |
1014 soh += 9; | |
1015 } else | |
1016 fprintf(f_output, "From \"%s\" %s\n", item->email->outlook_sender_name, c_time); | |
25 | 1017 } |
31 | 1018 fprintf(f_output, "%s", soh); |
1019 len = strlen(soh); | |
1020 if (!len || (soh[len-1] != '\n')) fprintf(f_output, "\n"); | |
1021 | |
25 | 1022 } else { |
1023 //make up our own header! | |
1024 if (mode != MODE_SEPERATE) { | |
1025 // don't want this first line for this mode | |
31 | 1026 if (item->email->outlook_sender_name) { |
25 | 1027 temp = item->email->outlook_sender_name; |
1028 } else { | |
1029 temp = "(readpst_null)"; | |
1030 } | |
1031 fprintf(f_output, "From \"%s\" %s\n", temp, c_time); | |
1032 } | |
31 | 1033 |
1034 temp = item->email->outlook_sender; | |
1035 if (!temp) temp = ""; | |
25 | 1036 fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp); |
31 | 1037 |
1038 if (item->email->subject) { | |
25 | 1039 fprintf(f_output, "Subject: %s\n", item->email->subject->subj); |
1040 } else { | |
1041 fprintf(f_output, "Subject: \n"); | |
1042 } | |
31 | 1043 |
25 | 1044 fprintf(f_output, "To: %s\n", item->email->sentto_address); |
31 | 1045 if (item->email->cc_address) { |
25 | 1046 fprintf(f_output, "Cc: %s\n", item->email->cc_address); |
1047 } | |
31 | 1048 |
1049 if (item->email->sent_date) { | |
25 | 1050 c_time = (char*) xmalloc(C_TIME_SIZE); |
1051 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); | |
1052 fprintf(f_output, "Date: %s\n", c_time); | |
1053 free(c_time); | |
1054 } | |
1055 } | |
1056 | |
31 | 1057 fprintf(f_output, "MIME-Version: 1.0\n"); |
1058 if (boundary && boundary_created) { | |
1059 // if we created the boundary, then it has NOT already been printed | |
1060 // in the headers above. | |
1061 if (item->attach) { | |
25 | 1062 // write the boundary stuff if we have attachments |
31 | 1063 fprintf(f_output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); |
1064 } else if (boundary) { | |
25 | 1065 // else if we have multipart/alternative then tell it so |
31 | 1066 fprintf(f_output, "Content-type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); |
25 | 1067 } else if (item->email->htmlbody) { |
1068 fprintf(f_output, "Content-type: text/html\n"); | |
1069 } | |
1070 } | |
31 | 1071 fprintf(f_output, "\n"); // start the body |
1072 DEBUG_EMAIL(("About to print Body\n")); | |
25 | 1073 |
31 | 1074 if (item->email->body) { |
25 | 1075 if (boundary) { |
1076 fprintf(f_output, "\n--%s\n", boundary); | |
31 | 1077 fprintf(f_output, "Content-type: text/plain\n"); |
25 | 1078 if (base64_body) |
1079 fprintf(f_output, "Content-Transfer-Encoding: base64\n"); | |
31 | 1080 fprintf(f_output, "\n"); |
25 | 1081 } |
1082 removeCR(item->email->body); | |
36 | 1083 if (base64_body) { |
1084 char *enc = base64_encode(item->email->body, strlen(item->email->body)); | |
1085 if (enc) { | |
1086 write_email_body(f_output, enc); | |
1087 free(enc); | |
1088 } | |
1089 } | |
1090 else { | |
25 | 1091 write_email_body(f_output, item->email->body); |
36 | 1092 } |
25 | 1093 } |
31 | 1094 |
1095 if (item->email->htmlbody) { | |
25 | 1096 if (boundary) { |
1097 fprintf(f_output, "\n--%s\n", boundary); | |
31 | 1098 fprintf(f_output, "Content-type: text/html\n"); |
36 | 1099 if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n"); |
31 | 1100 fprintf(f_output, "\n"); |
25 | 1101 } |
1102 removeCR(item->email->htmlbody); | |
36 | 1103 if (base64_body) { |
1104 char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody)); | |
1105 if (enc) { | |
1106 write_email_body(f_output, enc); | |
1107 free(enc); | |
1108 } | |
1109 } | |
1110 else { | |
25 | 1111 write_email_body(f_output, item->email->htmlbody); |
36 | 1112 } |
25 | 1113 } |
1114 | |
31 | 1115 if (item->email->rtf_compressed && save_rtf) { |
37 | 1116 //int32_t tester; |
31 | 1117 DEBUG_EMAIL(("Adding RTF body as attachment\n")); |
1118 current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); | |
1119 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1120 current_attach->next = item->attach; | |
1121 item->attach = current_attach; | |
36 | 1122 current_attach->data = lzfu_decompress(item->email->rtf_compressed, ¤t_attach->size); |
31 | 1123 current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); |
1124 strcpy(current_attach->filename2, RTF_ATTACH_NAME); | |
1125 current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); | |
1126 strcpy(current_attach->mimetype, RTF_ATTACH_TYPE); | |
37 | 1127 //memcpy(&tester, item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); |
1128 //LE32_CPU(tester); | |
1129 //printf("lz produced %d bytes, rtf claims %d bytes\n", current_attach->size, tester); | |
25 | 1130 } |
31 | 1131 |
25 | 1132 if (item->email->encrypted_body || item->email->encrypted_htmlbody) { |
1133 // if either the body or htmlbody is encrypted, add them as attachments | |
1134 if (item->email->encrypted_body) { | |
31 | 1135 DEBUG_EMAIL(("Adding Encrypted Body as attachment\n")); |
1136 current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); | |
1137 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1138 current_attach->next = item->attach; | |
1139 item->attach = current_attach; | |
1140 current_attach->data = item->email->encrypted_body; | |
1141 current_attach->size = item->email->encrypted_body_size; | |
25 | 1142 item->email->encrypted_body = NULL; |
1143 } | |
31 | 1144 |
25 | 1145 if (item->email->encrypted_htmlbody) { |
31 | 1146 DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n")); |
1147 current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); | |
1148 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1149 current_attach->next = item->attach; | |
1150 item->attach = current_attach; | |
1151 current_attach->data = item->email->encrypted_htmlbody; | |
1152 current_attach->size = item->email->encrypted_htmlbody_size; | |
25 | 1153 item->email->encrypted_htmlbody = NULL; |
1154 } | |
1155 write_email_body(f_output, "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n"); | |
1156 } | |
31 | 1157 |
25 | 1158 // attachments |
1159 attach_num = 0; | |
39 | 1160 for (current_attach = item->attach; current_attach; current_attach = current_attach->next) { |
31 | 1161 DEBUG_EMAIL(("Attempting Attachment encoding\n")); |
1162 if (!current_attach->data) { | |
1163 DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size)); | |
25 | 1164 } |
1165 if (mode == MODE_SEPERATE && !mode_MH) | |
31 | 1166 write_separate_attachment(f_name, current_attach, ++attach_num, pst); |
25 | 1167 else |
31 | 1168 write_inline_attachment(f_output, current_attach, boundary, pst); |
25 | 1169 } |
1170 if (mode != MODE_SEPERATE) { /* do not add a boundary after the last attachment for mode_MH */ | |
31 | 1171 DEBUG_EMAIL(("Writing buffer between emails\n")); |
1172 if (boundary) fprintf(f_output, "\n--%s--\n", boundary); | |
25 | 1173 fprintf(f_output, "\n\n"); |
1174 } | |
31 | 1175 if (boundary) free (boundary); |
1176 DEBUG_RET(); | |
25 | 1177 } |
1178 | |
31 | 1179 |
25 | 1180 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]) |
1181 { | |
39 | 1182 // We can only call rfc escape once per printf, since the second call |
1183 // may free the buffer returned by the first call. | |
1184 // I had tried to place those into a single printf - Carl. | |
1185 | |
31 | 1186 DEBUG_ENT("write_vcard"); |
25 | 1187 // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile |
1188 fprintf(f_output, "BEGIN:VCARD\n"); | |
1189 fprintf(f_output, "FN:%s\n", rfc2426_escape(contact->fullname)); | |
39 | 1190 |
1191 //fprintf(f_output, "N:%s;%s;%s;%s;%s\n", | |
1192 fprintf(f_output, "N:%s;", (!contact->surname) ? "" : rfc2426_escape(contact->surname)); | |
1193 fprintf(f_output, "%s;", (!contact->first_name) ? "" : rfc2426_escape(contact->first_name)); | |
1194 fprintf(f_output, "%s;", (!contact->middle_name) ? "" : rfc2426_escape(contact->middle_name)); | |
1195 fprintf(f_output, "%s;", (!contact->display_name_prefix) ? "" : rfc2426_escape(contact->display_name_prefix)); | |
1196 fprintf(f_output, "%s\n", (!contact->suffix) ? "" : rfc2426_escape(contact->suffix)); | |
1197 | |
31 | 1198 if (contact->nickname) |
25 | 1199 fprintf(f_output, "NICKNAME:%s\n", rfc2426_escape(contact->nickname)); |
31 | 1200 if (contact->address1) |
25 | 1201 fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address1)); |
31 | 1202 if (contact->address2) |
25 | 1203 fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address2)); |
31 | 1204 if (contact->address3) |
25 | 1205 fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address3)); |
31 | 1206 if (contact->birthday) |
25 | 1207 fprintf(f_output, "BDAY:%s\n", rfc2425_datetime_format(contact->birthday)); |
39 | 1208 |
31 | 1209 if (contact->home_address) { |
39 | 1210 //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n", |
1211 fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box) ? "" : rfc2426_escape(contact->home_po_box)); | |
1212 fprintf(f_output, "%s;", ""); // extended Address | |
1213 fprintf(f_output, "%s;", (!contact->home_street) ? "" : rfc2426_escape(contact->home_street)); | |
1214 fprintf(f_output, "%s;", (!contact->home_city) ? "" : rfc2426_escape(contact->home_city)); | |
1215 fprintf(f_output, "%s;", (!contact->home_state) ? "" : rfc2426_escape(contact->home_state)); | |
1216 fprintf(f_output, "%s;", (!contact->home_postal_code) ? "" : rfc2426_escape(contact->home_postal_code)); | |
1217 fprintf(f_output, "%s\n", (!contact->home_country) ? "" : rfc2426_escape(contact->home_country)); | |
25 | 1218 fprintf(f_output, "LABEL;TYPE=home:%s\n", rfc2426_escape(contact->home_address)); |
1219 } | |
39 | 1220 |
31 | 1221 if (contact->business_address) { |
39 | 1222 //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", |
1223 fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box) ? "" : rfc2426_escape(contact->business_po_box)); | |
1224 fprintf(f_output, "%s;", ""); // extended Address | |
1225 fprintf(f_output, "%s;", (!contact->business_street) ? "" : rfc2426_escape(contact->business_street)); | |
1226 fprintf(f_output, "%s;", (!contact->business_city) ? "" : rfc2426_escape(contact->business_city)); | |
1227 fprintf(f_output, "%s;", (!contact->business_state) ? "" : rfc2426_escape(contact->business_state)); | |
1228 fprintf(f_output, "%s;", (!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code)); | |
1229 fprintf(f_output, "%s\n", (!contact->business_country) ? "" : rfc2426_escape(contact->business_country)); | |
25 | 1230 fprintf(f_output, "LABEL;TYPE=work:%s\n", rfc2426_escape(contact->business_address)); |
1231 } | |
39 | 1232 |
31 | 1233 if (contact->other_address) { |
39 | 1234 //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n", |
1235 fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box) ? "" : rfc2426_escape(contact->other_po_box)); | |
1236 fprintf(f_output, "%s;", ""); // extended Address | |
1237 fprintf(f_output, "%s;", (!contact->other_street) ? "" : rfc2426_escape(contact->other_street)); | |
1238 fprintf(f_output, "%s;", (!contact->other_city) ? "" : rfc2426_escape(contact->other_city)); | |
1239 fprintf(f_output, "%s;", (!contact->other_state) ? "" : rfc2426_escape(contact->other_state)); | |
1240 fprintf(f_output, "%s;", (!contact->other_postal_code) ? "" : rfc2426_escape(contact->other_postal_code)); | |
1241 fprintf(f_output, "%s\n", (!contact->other_country) ? "" : rfc2426_escape(contact->other_country)); | |
31 | 1242 fprintf(f_output, "LABEL;TYPE=postal:%s\n", rfc2426_escape(contact->other_address)); |
25 | 1243 } |
39 | 1244 |
1245 if (contact->business_fax) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", rfc2426_escape(contact->business_fax)); | |
1246 if (contact->business_phone) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(contact->business_phone)); | |
1247 if (contact->business_phone2) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(contact->business_phone2)); | |
1248 if (contact->car_phone) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", rfc2426_escape(contact->car_phone)); | |
1249 if (contact->home_fax) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", rfc2426_escape(contact->home_fax)); | |
1250 if (contact->home_phone) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(contact->home_phone)); | |
1251 if (contact->home_phone2) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(contact->home_phone2)); | |
1252 if (contact->isdn_phone) fprintf(f_output, "TEL;TYPE=isdn:%s\n", rfc2426_escape(contact->isdn_phone)); | |
1253 if (contact->mobile_phone) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", rfc2426_escape(contact->mobile_phone)); | |
1254 if (contact->other_phone) fprintf(f_output, "TEL;TYPE=msg:%s\n", rfc2426_escape(contact->other_phone)); | |
1255 if (contact->pager_phone) fprintf(f_output, "TEL;TYPE=pager:%s\n", rfc2426_escape(contact->pager_phone)); | |
1256 if (contact->primary_fax) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", rfc2426_escape(contact->primary_fax)); | |
1257 if (contact->primary_phone) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", rfc2426_escape(contact->primary_phone)); | |
1258 if (contact->radio_phone) fprintf(f_output, "TEL;TYPE=pcs:%s\n", rfc2426_escape(contact->radio_phone)); | |
1259 if (contact->telex) fprintf(f_output, "TEL;TYPE=bbs:%s\n", rfc2426_escape(contact->telex)); | |
1260 if (contact->job_title) fprintf(f_output, "TITLE:%s\n", rfc2426_escape(contact->job_title)); | |
1261 if (contact->profession) fprintf(f_output, "ROLE:%s\n", rfc2426_escape(contact->profession)); | |
1262 if (contact->assistant_name || contact->assistant_phone) { | |
31 | 1263 fprintf(f_output, "AGENT:BEGIN:VCARD\n"); |
39 | 1264 if (contact->assistant_name) fprintf(f_output, "FN:%s\n", rfc2426_escape(contact->assistant_name)); |
1265 if (contact->assistant_phone) fprintf(f_output, "TEL:%s\n", rfc2426_escape(contact->assistant_phone)); | |
25 | 1266 } |
39 | 1267 if (contact->company_name) fprintf(f_output, "ORG:%s\n", rfc2426_escape(contact->company_name)); |
1268 if (comment) fprintf(f_output, "NOTE:%s\n", rfc2426_escape(comment)); | |
25 | 1269 |
1270 fprintf(f_output, "VERSION: 3.0\n"); | |
1271 fprintf(f_output, "END:VCARD\n\n"); | |
31 | 1272 DEBUG_RET(); |
25 | 1273 } |
1274 | |
31 | 1275 |
25 | 1276 void write_appointment(FILE* f_output, pst_item_appointment* appointment, |
31 | 1277 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date) |
25 | 1278 { |
1279 fprintf(f_output, "BEGIN:VEVENT\n"); | |
31 | 1280 if (create_date) |
25 | 1281 fprintf(f_output, "CREATED:%s\n", |
1282 rfc2445_datetime_format(create_date)); | |
31 | 1283 if (modify_date) |
25 | 1284 fprintf(f_output, "LAST-MOD:%s\n", |
1285 rfc2445_datetime_format(modify_date)); | |
31 | 1286 if (email && email->subject) |
25 | 1287 fprintf(f_output, "SUMMARY:%s\n", |
1288 rfc2426_escape(email->subject->subj)); | |
31 | 1289 if (email && email->body) |
25 | 1290 fprintf(f_output, "DESCRIPTION:%s\n", |
1291 rfc2426_escape(email->body)); | |
31 | 1292 if (appointment && appointment->start) |
25 | 1293 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", |
1294 rfc2445_datetime_format(appointment->start)); | |
31 | 1295 if (appointment && appointment->end) |
25 | 1296 fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n", |
1297 rfc2445_datetime_format(appointment->end)); | |
31 | 1298 if (appointment && appointment->location) |
25 | 1299 fprintf(f_output, "LOCATION:%s\n", |
1300 rfc2426_escape(appointment->location)); | |
31 | 1301 if (appointment) { |
25 | 1302 switch (appointment->showas) { |
1303 case PST_FREEBUSY_TENTATIVE: | |
1304 fprintf(f_output, "STATUS:TENTATIVE\n"); | |
1305 break; | |
1306 case PST_FREEBUSY_FREE: | |
1307 // mark as transparent and as confirmed | |
1308 fprintf(f_output, "TRANSP:TRANSPARENT\n"); | |
1309 case PST_FREEBUSY_BUSY: | |
1310 case PST_FREEBUSY_OUT_OF_OFFICE: | |
1311 fprintf(f_output, "STATUS:CONFIRMED\n"); | |
1312 break; | |
1313 } | |
1314 switch (appointment->label) { | |
1315 case PST_APP_LABEL_NONE: | |
1316 fprintf(f_output, "CATEGORIES:NONE\n"); | |
1317 break; | |
1318 case PST_APP_LABEL_IMPORTANT: | |
1319 fprintf(f_output, "CATEGORIES:IMPORTANT\n"); | |
1320 break; | |
1321 case PST_APP_LABEL_BUSINESS: | |
1322 fprintf(f_output, "CATEGORIES:BUSINESS\n"); | |
1323 break; | |
1324 case PST_APP_LABEL_PERSONAL: | |
1325 fprintf(f_output, "CATEGORIES:PERSONAL\n"); | |
1326 break; | |
1327 case PST_APP_LABEL_VACATION: | |
1328 fprintf(f_output, "CATEGORIES:VACATION\n"); | |
1329 break; | |
1330 case PST_APP_LABEL_MUST_ATTEND: | |
1331 fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); | |
1332 break; | |
1333 case PST_APP_LABEL_TRAVEL_REQ: | |
1334 fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); | |
1335 break; | |
1336 case PST_APP_LABEL_NEEDS_PREP: | |
1337 fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); | |
1338 break; | |
1339 case PST_APP_LABEL_BIRTHDAY: | |
1340 fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); | |
1341 break; | |
1342 case PST_APP_LABEL_ANNIVERSARY: | |
1343 fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); | |
1344 break; | |
1345 case PST_APP_LABEL_PHONE_CALL: | |
1346 fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); | |
1347 break; | |
1348 } | |
1349 } | |
1350 fprintf(f_output, "END:VEVENT\n\n"); | |
1351 } | |
1352 | |
31 | 1353 |
39 | 1354 void create_enter_dir(struct file_ll* f, pst_item *item) |
25 | 1355 { |
39 | 1356 f->email_count = 0; |
1357 f->skip_count = 0; | |
1358 f->type = item->type; | |
1359 f->stored_count = (item->folder) ? item->folder->email_count : 0; | |
1360 | |
31 | 1361 DEBUG_ENT("create_enter_dir"); |
25 | 1362 if (mode == MODE_KMAIL) |
39 | 1363 f->name = mk_kmail_dir(item->file_as); //create directory and form filename |
25 | 1364 else if (mode == MODE_RECURSE) |
39 | 1365 f->name = mk_recurse_dir(item->file_as); |
25 | 1366 else if (mode == MODE_SEPERATE) { |
1367 // do similar stuff to recurse here. | |
39 | 1368 mk_seperate_dir(item->file_as); |
25 | 1369 f->name = (char*) xmalloc(10); |
1370 memset(f->name, 0, 10); | |
1371 // sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count); | |
1372 } else { | |
39 | 1373 f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1); |
1374 sprintf(f->name, OUTPUT_TEMPLATE, item->file_as); | |
25 | 1375 } |
1376 | |
39 | 1377 f->dname = (char*) xmalloc(strlen(item->file_as)+1); |
1378 strcpy(f->dname, item->file_as); | |
25 | 1379 |
1380 if (overwrite != 1) { | |
1381 int x = 0; | |
1382 char *temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits | |
1383 | |
1384 sprintf(temp, "%s", f->name); | |
1385 temp = check_filename(temp); | |
31 | 1386 while ((f->output = fopen(temp, "r"))) { |
1387 DEBUG_MAIN(("need to increase filename because one already exists with that name\n")); | |
1388 DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x)); | |
25 | 1389 x++; |
1390 sprintf(temp, "%s%08d", f->name, x); | |
31 | 1391 DEBUG_MAIN(("- trying \"%s\"\n", f->name)); |
25 | 1392 if (x == 99999999) { |
1393 DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x)); | |
1394 } | |
1395 fclose(f->output); | |
1396 } | |
1397 if (x > 0) { //then the f->name should change | |
1398 free (f->name); | |
1399 f->name = temp; | |
1400 } else { | |
1401 free(temp); | |
1402 } | |
1403 } | |
1404 | |
39 | 1405 DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); |
25 | 1406 if (mode != MODE_SEPERATE) { |
1407 f->name = check_filename(f->name); | |
31 | 1408 if (!(f->output = fopen(f->name, "w"))) { |
25 | 1409 DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name)); |
1410 } | |
1411 } | |
31 | 1412 DEBUG_RET(); |
25 | 1413 } |
1414 | |
39 | 1415 |
1416 void close_enter_dir(struct file_ll *f) | |
1417 { | |
1418 DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count)); | |
1419 if (output_mode != OUTPUT_QUIET) | |
1420 printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n", | |
1421 f->dname, f->email_count, f->skip_count, f->stored_count); | |
1422 if (f->output) fclose(f->output); | |
1423 free(f->name); | |
1424 free(f->dname); | |
1425 | |
1426 if (mode == MODE_KMAIL) | |
1427 close_kmail_dir(); | |
1428 else if (mode == MODE_RECURSE) | |
1429 close_recurse_dir(); | |
1430 else if (mode == MODE_SEPERATE) | |
1431 close_seperate_dir(); | |
1432 } | |
1433 |