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