diff --git a/AUTHORS b/AUTHORS index e80298d..747dda9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,12 +1,15 @@ Dave Smith Dave Smith With contributions by: Joseph Nahmias -- bounces Joseph Nahmias Carl Byington Arne Ahrend Nigel Horne - Chris Hall + Chris Halls Stevens Miller Brad Hards + Alexander Grau + Antonio Palama + Sean Loaring diff --git a/ChangeLog b/ChangeLog index 6f44ff9..8c258ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,469 +1,481 @@ +LibPST 0.6.1 (2008-01-06) +=============================== + + * Outlook 2003 64 bit parsing. Some documentation from Alexander Grau + and patches from Sean Loaring . + * fix from Antonio Palama for email items + that happen to have item->contact non null, and were being processed + as contacts. + * Add large file support so we can read .pst files larger than 2gb. + * Change lspst to be similar to readpst, properly using recursion to walk + the tree, and testing item types. Add a man page for lspst. + LibPST 0.5.12 (2007-10-02) =============================== * security fix from Brad Hards for buffer overruns in liv-zemple decoding for corrupted or malicious pst files. LibPST 0.5.11 (2007-08-24) =============================== * fix from Stevens Miller for unitialized variable. LibPST 0.5.10 (2007-08-20) =============================== * fix yet more valgrind errors - finally have a clean memory check. * restructure readpst.c for proper recursive tree walk. * buffer overrun test was backwards, introduced at 0.5.6 * fix broken email attachments, introduced at 0.5.6 LibPST 0.5.9 (2007-08-12) =============================== * fix more valgrind errors. LibPST 0.5.8 (2007-08-10) =============================== * fix more valgrind errors. lzfu_decompress needs to return the actual buffer size, since the lz header overestimates the size. This caused base64_encode to encode undefined bytes into the email attachment. LibPST 0.5.7 (2007-08-09) =============================== * fix valgrind errors, using uninitialized data. * improve debug logging and readpstlog for indented listings. * cleanup documentation. LibPST 0.5.6 (2007-07-15) =============================== * Fix to allow very small pst files with only one node in the tree. We were mixing signed/unsigned types in comparisons. * More progress decoding the basic structure 7c blocks. Many four byte values may be ID2 indices with data outside the buffer. * Start using doxygen to generate internal documentation. LibPST 0.5.5 (2007-07-10) =============================== * merge the following changes from Joe Nahmias version: * Lots of memory fixes. Thanks to Nigel Horne for his assistance tracking these down! * Fixed creation of vCards from contacts, thanks to Nigel Horne for his help with this! * fix for MIME multipart/alternative attachments. * added -c options to readpst manpage. * use 8.3 attachment filename if long filename isn't available. * new -b option to skip rtf-body.rtf attachments. * fix format of From header lines in mbox files. - * Add more appointment fields, thanks to Chris Hall for tracking + * Add more appointment fields, thanks to Chris Halls for tracking them down! LibPST 0.5.4 (2006-02-25) =============================== * patches from Arne, adding MH mode, remove leading zeros from the generated numbered filenames starting with one rather than zero. Miscellaneous code cleanup. * document the "7c" descriptor block format. LibPST 0.5.3 (2006-02-20) =============================== * switch to gnu autoconf/automake. This breaks the MS VC++ projects since the source code is now in the src subdirectory. * documentation switched to xml, building man pages and html from the master xml copy. * include rpm .spec file for building src and binary rpms. LibPST 0.5.2 (2006-02-18) =============================== * Added pst2ldif to convert the contacts to ldif format for import into ldap databases. * Major changes to libpst.c to properly use the node depth values from the b-tree nodes. We also use the item count values in the nodes rather than trying to guess how many items are active. * Cleanup whitespace - using tabs for every four columns. LibPST 0.5.1 (17 November 2004) =============================== Well, alot has happened since the last release of libpst. Release / Management: * The project has forked! The new maintainer is Joseph Nahmias. * We have changed hosting sites, thanks to sourceforge for hosting to this point. From this point forward we will be using alioth.debian.org. * The project is now using SubVersioN for source control. You can get the latest code by running: svn co svn://svn.debian.org/svn/libpst/trunk . * See for more information. Code Changes: * Added lspst program to list items in a PST. Still incomplete. * Added vim folding markers to readpst.c * avoid the pseudo-prologue that MS prepends to the email headers * fix build on msvc, since it doesn't have sys/param.h * Re-vamped Makefile: * Only define CFLAGS in Makefileif missing * fixed {un,}install targets in Makefile * Fixed up build process in Makefile * Added mozilla conversion script from David Binard * Fixed bogus creation of readpst.log on every invocation * escaped dashes and apostrophe in manpages * Updated TODO * added manpages from debian pkg * fix escaped-string length count to consider '\n', thanks to Paul Bakker . * ensure there's a blank line between header and body patch from (SourceForge #890745). * Apply accumulated endian-related patches * Removed unused files, upstream's debian/ dir -- Joe Nahmias LibPST v0.5 =========== It is with GREAT relief that I bring you version 0.5 of the LibPST tools! Through great difficulties, this tool has survived and expanded to become even better. The changes are as follows: * RTF support. We can now decompress RTF bodies in emails, and are saved as attachments * Better support in reading the indexes. Fixed many bugs with them * Improved reliability. "Now we are getting somewhere!" * Improved compiling. Hopefully we won't be hitting too many compile errors now. * vCard handling. Contacts are now exported as vCard entries. * vEvent handling. Support has begun on exporting Calendar entries as events * Support for Journal entries has also begun If you have any problems with this release, don't hesitate to contact me. These changes come to you, as always, free under the GPL license!! What a wonderful thing it is. It does mean that you can write your own program off of this library and distribute it also for free. However, anyone with commercial interests for developing applications they will be charging for are encouraged to get in touch with me, as I am sure we can come to some arrangement. Dave Smith LibPST v0.4.3 ============= Bug fix release. No extra functionality Dave Smith LibPST v0.4.2 ============= The debug system has had an overhaul. The debug messages are no longer printed to the screen when they are enabled. They are dumped to a binary file. There is another utility called "readlog" that I have written to handle these log files. It should make it easier to selectively view bits of a log file. It also shows the position that the log message was printed from. There is a new switch in readpst. It is -d. It enables the user to specify the log file which the binary log is written to. If the switch isn't used, the default file of "readpst.log" is used. The code is now Visual C++ compatible. It has compiled on Visual C++ .net Standard edition, and produces the readpst.exe file. Use the project file included in this distribution. There have been minor improvements elsewhere too. LibPST v0.4.1 ============= Fixed a couple more bugs. Is it me or do bugs just insert themselves in random, hard to find places! Cured a few problems with regard to emails with multiple embeded items. They are not fully re-created using Mime-types, but are accessible with the -S switch (which saves everything as seperate items) Fixed a problem reading the first index. Back sliders are now detected. (ie when the value following the current one is smaller, not bigger!) Added some error messages when we try and read outside of the PST file, this was causing a few problems before, cause the return value wasn't always checked, so it was possible to be reading random data, and trying to make sense of it! Anyway, if you find any problems, don't hesitate to mail me Dave Smith LibPST v0.4 =========== Fixed a nasty bug that occasionally corrupted attachments. Another bug with regard to reading of indexes (also occasional). Another output method has been added which is called "Seperate". It is activated with the -S switch. It operates in the following manor: |--Inbox-->000000 | 000001 | 000002 |--Sentmail-->0000000 | 0000001 | 0000002 All the emails are stored in seperate files counting from 0 upwards, in a folder named as the PST folder. When an email has an attachment, it is saved as a seperate file. The filename for the attachment is made up of 2 parts, the first is the email number to which it belongs, the second is its filename. The should now be runnable on big-endian machines, if the define.h file is first modified. The #define LITTLE_ENDIAN must be commented out, and the #define BIG_ENDIAN must be uncommented. More verbose error messages have been added. Apparently people got confused when the program stopped for no visible reason. This has now been resolved. Thanks for the continued support of all people involved. Dave Smith Libpst v0.3.4 ============= Several more fixes. An Infinite loop and incorrect interpreting of item index attributes. Work has started on making the code executable on big endian CPUs. At present it should work with Linux on these CPUs, but I would appreciate it if you could provide feedback with regard to it's performance. I am also working with some other people at make it operate on Solaris. A whole load more items are now recognized by the Item records. With more items in Emails and Folders. I haven't got to the Contacts yet. Anyway, this is what I would call a minor feature enhancment and bugfix release. Dave Smith LibPST v0.3.3 ============= Fixed several items. Mainly memory leaks. Loads of them! oops.. I have added a new program, mainly of debugging, which when passed an ID value and a pst file, will extract and decrypt that ID from the pst file. I don't see it being a huge attraction, or of much use to most people, but it is another example of writing an application to use the libpst interface. Another fix was in the reading of the item index. This has hopefully now been corrected. The result of this bug was that not all the emails in a folder were converted. Hopefully you should have more luck now. Dave Smith LibPST v0.3.2 ============= Quick bugfix release. There was a bug in the decryption of the basic encryption that outlook uses. One byte, 0x6c, was incorrectly decrypted to 0x6c instead of 0xcd. This release fixes this bug. Sorry... LibPST v0.3.1 ============= Minor improvements. Fixed bug when linking multiple blocks together, so now the linking blocks are not "encrypted" when trying to read them. LibPST v0.3 =========== A lot of bug fixing has been done for this release. Testing has been done on the creation of the files by readpst. Better handling of large binaries being extracted from the PST file has been implemented. Quite a few reports have come in about not being able to compile on Darwin. This could be down to using macros with variable parameter lists. This has now been changed to use C functions with variable parameters. I hope this fixes a lot of problems. Added support for recreating the folder structure into normal directories. For Instance: Personal Folders |-Inbox | |-Jokes | |-Meetings |-Send Items each folder containing an mbox file with the correct emails for that folder. Dave Smith LibPST v0.3 beta1 ================= Again, a shed load of enhancements. More work has been done on the mime creation. A bug has been fixed that was letting part of the attachments that were created disappear. A major enhancement is that "compressible encryption" support has been added. This was an incredibly simple method to use. It is basically a ceasar cipher. It has been noted by several users already that the PST password that Outlook uses, serves *no purpose*. It is not used to encrypt the PST, it is mearly stored there. This means that the readpst application is able to convert PST files without knowing the password. Microsoft have some explaning to do! Output files are now not overwritten if they already exist. This means that if you have two folders in your PST file named "fred", the first one encountered will be named "fred" and the second one will be named "fred00000001". As you can see, there is enough room there for many duplicate names! Output filenames are now restricted. Any "/" or "\" characters in the name are replaced with "_". If you find that there are any other characters that need to be changed, could you please make me aware! Thanks to Berry Wizard for help with supporting the encryption. Thanks to Auke Kok, Carolus Walraven and Yogesh Kumar Guatam for providing debugging information and testing. Dave Smith LibPST v0.2 beta1 ================= Hello once more... Attachments are now re-created in mime format. The method is very crude and could be prone to over generalisation. Please test this version, and if attachments are not recreated correctly, please send me the email (complete message source) of the original and converted. Cheers. I hope this will work for everyone who uses this program, but reality can be very different! Let us see how it goes... Dave Smith LibPST v0.2 alpha1 =========== Hello! Some improvements. The internal code has been changed so that attachments are now processed and loaded into the structures. The readpst program is not finished yet. It needs to convert these binary structs into mime data. At present it just saves them to the current directory, overwriting any previous files with the attachment name. Improvements over previous version: * KMail output is supported - if the "-k" flag is specified, all the directory hierarchy is created using the KMail standard * Lots of bugs and memory leaks fixed Usage: ReadPST v0.2alpha1 implementing LibPST v0.2alpha1 Usage: ./readpst [OPTIONS] {PST FILENAME} OPTIONS: -h - Help. This screen -k - KMail. Output in kmail format -o - Output Dir. Directory to write files to. CWD is changed *after* opening pst file -V - Version. Display program version If you want to view lots of debug output, modify a line in "define.h" from "//#define DEBUG_ALL" to "#define DEBUG_ALL". It would then be advisable to pipe all output to a log file: ./readpst -o out pst_file &> logfile Dave Smith LibPST v0.1 =========== Hi Folks! This has been a long, hard slog, but I now feel that I have got somewhere useful. The included program "main" is able to read an Outlook PST file and dump the emails into mbox files, separating each folder into a different mbox file. All the mbox files are stored in the current directory and no attempt is yet made to organise these files into a directory hierarchy. This would not be too difficult to achieve though. Email attachments are not yet handled, neither are Contacts. There is no pretty interface yet, but you can convert a PST file in the following manner ./main {path to PST file} This is very much a work in progress, but I thought I should release this code so that people can lose their conception that outlook files will never be converted to Linux. I am intending that the code I am writing will be developed into greater applications to provide USEFUL tools for accessing and converting PST files into a variety of formats. One point I feel I should make is that Outlook, by default, creates "Compressible Encryption" PST files. I have not, as yet, attempted to write any decryption routines, so you will not be able to convert these files. However, if you create a new PST file and choose not to make an encrypted one, you can copy all your emails into this new one and then convert the unencrypted one. I hope you enjoy, Dave Smith : vim: set tw=72 sw=4 ts=4: diff --git a/NEWS b/NEWS index 30a692d..6f44ba7 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,14 @@ $Id$ +0.6.1 2008-01-06 Outlook 2003 64 bit format and fix for bogus contacts. 0.5.12 2007-10-02 security fix for possible buffer overruns in liv-zemple decoding 0.5.11 2007-08-24 fix for unitialized variable 0.5.10 2007-08-20 fix yet more valgrind errors, restructure readpst recursive walk, backwards overrun test 0.5.9 2007-08-12 fix more valgrind errors, pst2ldif wrote undefined data 0.5.8 2007-08-10 lzfu_decompress/base64_encode encoded random data into attachment 0.5.7 2007-08-09 fix valgrind errors, using uninitialized data 0.5.6 2007-07-15 handle small pst files, better decoding of 7c blocks 0.5.5 2007-07-10 merge changes from Joe Nahmias version 0.5.4 2006-02-25 add MH mode, generated filenames with no leading zeros 0.5.3 2006-02-20 switch to gnu autoconf/automake 0.5.2 2006-02-18 add pst2ldif, fix btree processing in libpst.c diff --git a/configure.in b/configure.in index f553c97..ce0e1f3 100644 --- a/configure.in +++ b/configure.in @@ -1,41 +1,42 @@ AC_INIT(configure.in) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(libpst,0.5.12) +AM_INIT_AUTOMAKE(libpst,0.6.1) AC_PATH_PROGS(BASH, bash) AC_LANG_CPLUSPLUS AC_PROG_CXX AC_PROG_LIBTOOL +AC_SYS_LARGEFILE # The following lines adds the --enable-pst-debug option to configure: # # Give the user the choice to enter one of these: # --enable-pst-debug # --enable-pst-debug=yes # --enable-pst-debug=no # AC_MSG_CHECKING([whether we are forcing debug dump file creation]) AC_ARG_ENABLE(pst-debug, AC_HELP_STRING([--enable-pst-debug], [force debug dump file creation]), [if test "${enable_pst_debug}" = "no" ; then AC_MSG_RESULT([no]) else AC_DEFINE(DEBUG_ALL, 1, Define to 1 to force debug dump file creation) AC_MSG_RESULT([yes]) fi], # Default value for configure AC_MSG_RESULT([no]) ) AC_OUTPUT( \ Makefile \ libpst.spec \ html/Makefile \ info/Makefile \ man/Makefile \ src/Makefile \ src/version.h \ xml/Makefile \ xml/libpst \ ) diff --git a/regression/regression-tests.bash b/regression/regression-tests.bash index 5b496d5..3fbe701 100644 --- a/regression/regression-tests.bash +++ b/regression/regression-tests.bash @@ -1,24 +1,27 @@ #!/bin/bash val="valgrind --leak-check=full" -for i in {1..6}; do +for i in {1..7}; do rm -rf output$i mkdir output$i done $val ../src/pst2ldif -b 'o=ams-cc.com, c=US' -c 'newPerson' ams.pst >ams.err 2>&1 $val ../src/readpst -cv -o output1 ams.pst >out1.err 2>&1 $val ../src/readpst -cl -r -o output2 ams.pst >out2.err 2>&1 $val ../src/readpst -S -o output3 ams.pst >out3.err 2>&1 $val ../src/readpst -M -o output4 ams.pst >out4.err 2>&1 $val ../src/readpst -o output5 mbmg.archive.pst >out5.err 2>&1 $val ../src/readpst -o output6 test.pst >out6.err 2>&1 -# ../src/readpst -o output1 -d dumper ams.pst -# ../src/readpstlog -f I dumper >dumperams.log -# +$val ../src/readpst -o output7 -d dumper ams.pst >out7.err 2>&1 + ../src/readpstlog -f I dumper >dumperams.log + +$val ../src/lspst ams.pst >out8.err 2>&1 + ../src/readpstlog -f I lspst.debug >lspst.log + # ../src/readpst -o output6 -d dumper /tmp/test.pst # ../src/readpstlog -f I dumper >dumpertest.log rm -f dumper diff --git a/src/Makefile.am b/src/Makefile.am index 8cf0f88..750448a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,29 +1,29 @@ hfiles = $(wildcard *.h) bin_PROGRAMS = lspst readpst readpstlog pst2ldif noinst_PROGRAMS = deltasearch dumpblocks getidblock -lspst_SOURCES = $(hfiles) debug.c libpst.c libstrfunc.c lspst.c timeconv.c -readpst_SOURCES = $(hfiles) readpst.c libpst.c timeconv.c libstrfunc.c debug.c lzfu.c +lspst_SOURCES = $(hfiles) debug.c libpst.c libstrfunc.c lspst.c timeconv.c vbuf.c generic.c +readpst_SOURCES = $(hfiles) readpst.c libpst.c timeconv.c libstrfunc.c debug.c lzfu.c vbuf.c generic.c readpstlog_SOURCES = $(hfiles) readpstlog.c debug.c -pst2ldif_SOURCES = $(hfiles) pst2ldif.cpp libpst.c timeconv.c libstrfunc.c debug.c lzfu.c +pst2ldif_SOURCES = $(hfiles) pst2ldif.cpp libpst.c timeconv.c libstrfunc.c debug.c lzfu.c vbuf.c generic.c deltasearch_SOURCES = deltasearch.cpp debug.c -dumpblocks_SOURCES = dumpblocks.c debug.c libpst.c libstrfunc.c timeconv.c -getidblock_SOURCES = getidblock.c debug.c libpst.c libstrfunc.c timeconv.c +dumpblocks_SOURCES = dumpblocks.c debug.c libpst.c libstrfunc.c timeconv.c vbuf.c generic.c +getidblock_SOURCES = getidblock.c debug.c libpst.c libstrfunc.c timeconv.c vbuf.c generic.c EXTRA_DIST = testdebug.c # set the include path found by configure INCLUDES= $(all_includes) # the library search path. lspst_LDFLAGS = $(all_libraries) readpst_LDFLAGS = $(all_libraries) readpstlog_LDFLAGS = $(all_libraries) pst2ldif_LDFLAGS = $(all_libraries) # default compile flags # lspst_CXXFLAGS = # readpst_CXXFLAGS = # readpstlog_CXXFLAGS = # pst2ldif_CXXFLAGS = diff --git a/src/debug.c b/src/debug.c index f53e6d4..40978d4 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,438 +1,439 @@ /* Contains the debug functions */ #include #include #include #include #include #include #include "define.h" #ifdef _WIN32 # define vsnprintf _vsnprintf #endif struct _debug_item { int type; char * function; unsigned int line; char * file; char * text; struct _debug_item *next; } *item_head=NULL, *item_tail=NULL, *item_ptr=NULL, *info_ptr=NULL, *temp_list=NULL; struct _debug_func { char * name; struct _debug_func *next; } *func_head=NULL, *func_ptr=NULL; void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size); void _debug_write_hex(struct _debug_item *item, unsigned char *buf, int size, int col); void * xmalloc(size_t size); // the largest text size we will store in memory. Otherwise we // will do a debug_write, then create a new record, and write the // text body directly to the file #define MAX_MESSAGE_SIZE 4096 void _pst_debug(char *fmt, ...) { va_list ap; va_start(ap,fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #define NUM_COL 30 void _pst_debug_hexdump(FILE *out, unsigned char *buf, size_t size, int col, int delta) { int off = 0, toff; int count = 0; if (!out) return; // no file if (col == -1) col = NUM_COL; fprintf(out, "\n"); while (off < size) { fprintf(out, "%06X\t:", off+delta); toff = off; while (count < col && off < size) { fprintf(out, "%02hhx ", buf[off]); off++; count++; } off = toff; while (count < col) { // only happens at end of block to pad the text over to the text column fprintf(out, " "); count++; } count = 0; fprintf(out, ":"); while (count < col && off < size) { fprintf(out, "%c", isgraph(buf[off])?buf[off]:'.'); off++; count ++; } fprintf(out, "\n"); count=0; } fprintf(out, "\n"); } FILE *debug_fp = NULL; unsigned int max_items=DEBUG_MAX_ITEMS, curr_items=0; void _debug_init(char* fname) { unsigned char version = DEBUG_VERSION; item_head = item_tail = NULL; curr_items = 0; if (debug_fp) _debug_close(); if (!fname) return; if ((debug_fp = fopen(fname, "wb")) == NULL) { fprintf(stderr, "Opening of file %s failed\n", fname); exit(1); } fwrite(&version, 1, sizeof(char), debug_fp); } // function must be called before _debug_msg. It sets up the // structure for the function that follows void _debug_msg_info(int line, char* file, int type) { char *x; if (!debug_fp) return; // no file info_ptr = (struct _debug_item*) xmalloc(sizeof(struct _debug_item)); info_ptr->type = type; info_ptr->line = line; x = (func_head==NULL?"No Function":func_head->name); info_ptr->function = (char*) xmalloc(strlen(x)+1); strcpy(info_ptr->function, x); info_ptr->file = (char*) xmalloc(strlen(file)+1); strcpy(info_ptr->file, file); //put the current record on a temp linked list info_ptr->next = temp_list; temp_list = info_ptr; } void _debug_msg_text(char* fmt, ...) { va_list ap; int f, g; char x[2]; struct _debug_item *temp; if (!debug_fp) return; // no file va_start(ap, fmt); // get the record off of the temp_list info_ptr = temp_list; if (info_ptr) temp_list = info_ptr->next; else { fprintf(stderr, "NULL info_ptr. ERROR!!\n"); exit(-2); } // according to glibc 2.1, this should return the req. number of bytes for // the string #ifdef _WIN32 // vsnprintf trick doesn't work. must use function called _vscprintf // cannot find much documentation about this on internet or anywhere. // I assume it isn't a standard function, but only in VisualC++ f = _vscprintf(fmt, ap); #else f = vsnprintf(x, 1, fmt, ap); #endif va_end(ap); // must be called after vsnprintf() if (f > 0 && f < MAX_MESSAGE_SIZE) { info_ptr->text = (char*) xmalloc(f+1); va_start(ap, fmt); if ((g = vsnprintf(info_ptr->text, f, fmt, ap)) == -1) { fprintf(stderr, "_debug_msg: Dieing! vsnprintf returned -1 for format \"%s\"\n", fmt); exit(-2); } va_end(ap); info_ptr->text[g] = '\0'; if (f != g) { fprintf(stderr, "_debug_msg: f != g\n"); } } else if (f > 0) { // it is over the max_message_size then f += strlen(info_ptr->file)+strlen(info_ptr->function); temp = info_ptr; _debug_write(); // dump the current messages info_ptr = temp; va_start(ap, fmt); _debug_write_msg(info_ptr, fmt, &ap, f); va_end(ap); free(info_ptr->function); free(info_ptr->file); free(info_ptr); info_ptr = NULL; return; } else { fprintf(stderr, "_debug_msg: error getting requested size of debug message\n"); info_ptr->text = "ERROR Saving\n"; } if (!item_head) item_head = info_ptr; info_ptr->next = NULL; if (item_tail) item_tail->next = info_ptr; item_tail = info_ptr; if (++curr_items == max_items) { // here we will jump off and save the contents _debug_write(); info_ptr = NULL; } } void _debug_hexdump(unsigned char *x, int y, int cols, int delta) { struct _debug_item *temp; if (!debug_fp) return; // no file info_ptr = temp_list; if (info_ptr) temp_list = info_ptr->next; temp = info_ptr; _debug_write(); info_ptr = temp; _debug_write_hex(info_ptr, x, y, cols); free(info_ptr->function); free(info_ptr->file); free(info_ptr); info_ptr = NULL; } void _debug_func(char *function) { func_ptr = xmalloc (sizeof(struct _debug_func)); func_ptr->name = xmalloc(strlen(function)+1); strcpy(func_ptr->name, function); func_ptr->next = func_head; func_head = func_ptr; } void _debug_func_ret() { //remove the head item func_ptr = func_head; if (func_head) { func_head = func_head->next; free(func_ptr->name); free(func_ptr); } else { DIE(("function list is empty!\n")); } } void _debug_close(void) { _debug_write(); while (func_head) { func_ptr = func_head; func_head = func_head->next; free(func_ptr->name); free(func_ptr); } if (debug_fp) fclose(debug_fp); debug_fp = NULL; } void _debug_write() { size_t size, ptr, funcname, filename, text, end; char *buf = NULL, rec_type; if (!debug_fp) return; // no file - long index_pos = ftell (debug_fp), file_pos = index_pos; + off_t index_pos = ftell (debug_fp); + off_t file_pos = index_pos; // add 2. One for the pointer to the next index, // one for the count of this index - int index_size = ((curr_items+2) * sizeof(int)); - int *index; + int index_size = ((curr_items+2) * sizeof(off_t)); + off_t *index; int index_ptr = 0; struct _debug_file_rec_m mfile_rec; struct _debug_file_rec_l lfile_rec; if (curr_items == 0) return; // no items to write. index = (int*) xmalloc(index_size); memset(index, 0, index_size); // valgrind, avoid writing uninitialized data file_pos += index_size; // write the index first, we will re-write it later, but // we want to allocate the space fwrite(index, index_size, 1, debug_fp); index[index_ptr++] = curr_items; item_ptr = item_head; while (item_ptr) { file_pos = ftell(debug_fp); index[index_ptr++] = file_pos; size = strlen(item_ptr->function) + strlen(item_ptr->file) + strlen(item_ptr->text) + 3; //for the three \0s if (buf) free(buf); buf = xmalloc(size+1); ptr = 0; funcname=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->function)+1; filename=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->file)+1; text=ptr; ptr += sprintf(&(buf[ptr]), "%s", item_ptr->text)+1; end=ptr; if (end > USHRT_MAX) { // bigger than can be stored in a short rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.type = item_ptr->type; lfile_rec.line = item_ptr->line; lfile_rec.funcname = funcname; lfile_rec.filename = filename; lfile_rec.text = text; lfile_rec.end = end; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { rec_type = 'M'; fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.type = item_ptr->type; mfile_rec.line = item_ptr->line; mfile_rec.funcname = funcname; mfile_rec.filename = filename; mfile_rec.text = text; mfile_rec.end = end; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } fwrite(buf, 1, ptr, debug_fp); if (buf) free(buf); buf = NULL; item_head = item_ptr->next; free(item_ptr->function); free(item_ptr->file); free(item_ptr->text); free(item_ptr); item_ptr = item_head; } curr_items = 0; index[index_ptr] = ftell(debug_fp); // we should now have a complete index fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); fseek(debug_fp, 0, SEEK_END); item_ptr = item_head = item_tail = NULL; free(index); if (buf) free(buf); } void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size) { struct _debug_file_rec_l lfile_rec; struct _debug_file_rec_m mfile_rec; unsigned char rec_type; - int index_size = 3 * sizeof(int); - int index[3]; - int index_pos, file_pos; + int index_size = 3 * sizeof(off_t); + off_t index[3]; + off_t index_pos, file_pos; char zero='\0'; unsigned int end; if (!debug_fp) return; // no file index[0] = 1; //only one item in this index index_pos = ftell(debug_fp); fwrite(index, index_size, 1, debug_fp); index[1] = ftell(debug_fp); if (size > USHRT_MAX) { // bigger than can be stored in a short rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.type = item->type; lfile_rec.line = item->line; lfile_rec.funcname = 0; lfile_rec.filename = strlen(item->function)+1; lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { rec_type = 'M'; fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.type = item->type; mfile_rec.line = item->line; mfile_rec.funcname = 0; mfile_rec.filename = strlen(item->function)+1; mfile_rec.text = mfile_rec.filename+strlen(item->file)+1; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } file_pos = ftell(debug_fp); fwrite(item->function, strlen(item->function)+1, 1, debug_fp); fwrite(item->file, strlen(item->file)+1, 1, debug_fp); vfprintf(debug_fp, fmt, *ap); fwrite(&zero, 1, 1, debug_fp); end = ftell(debug_fp)-file_pos; index[2] = ftell(debug_fp); fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); if (size > USHRT_MAX) { fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.end = end; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); } else { fwrite(&rec_type, 1, sizeof(char), debug_fp); mfile_rec.end = end; fwrite(&mfile_rec, sizeof(mfile_rec), 1, debug_fp); } fseek(debug_fp, 0, SEEK_END); } void _debug_write_hex(struct _debug_item *item, unsigned char *buf, int size, int col) { struct _debug_file_rec_l lfile_rec; unsigned char rec_type; - int index_size = 3 * sizeof(int); - int index_pos, file_pos, index[3]; + int index_size = 3 * sizeof(off_t); + off_t index_pos, file_pos, index[3]; char zero='\0'; if (!debug_fp) return; // no file index[0] = 1; // only one item in this index run index[1] = 0; // valgrind, avoid writing uninitialized data index[2] = 0; // "" index_pos = ftell(debug_fp); fwrite(index, index_size, 1, debug_fp); index[1] = ftell(debug_fp); // always use the long rec_type = 'L'; fwrite(&rec_type, 1, sizeof(char), debug_fp); lfile_rec.funcname = 0; lfile_rec.filename = strlen(item->function)+1; lfile_rec.text = lfile_rec.filename+strlen(item->file)+1; lfile_rec.end = 0; // valgrind, avoid writing uninitialized data lfile_rec.line = item->line; lfile_rec.type = item->type; fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); file_pos = ftell(debug_fp); fwrite(item->function, strlen(item->function)+1, 1, debug_fp); fwrite(item->file, strlen(item->file)+1, 1, debug_fp); _pst_debug_hexdump(debug_fp, buf, size, col, 0); fwrite(&zero, 1, 1, debug_fp); - lfile_rec.end = ftell(debug_fp)-file_pos; + lfile_rec.end = ftell(debug_fp) - file_pos; index[2] = ftell(debug_fp); fseek(debug_fp, index_pos, SEEK_SET); fwrite(index, index_size, 1, debug_fp); fwrite(&rec_type, 1, sizeof(char), debug_fp); fwrite(&lfile_rec, sizeof(lfile_rec), 1, debug_fp); fseek(debug_fp, 0, SEEK_END); } void *xmalloc(size_t size) { void *mem = malloc(size); if (!mem) { fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); exit(1); } //memset(mem, 0, size); // valgrind return mem; } diff --git a/src/define.h b/src/define.h index 659f445..34392c6 100644 --- a/src/define.h +++ b/src/define.h @@ -1,209 +1,207 @@ /*** * define.h * Part of the LibPST project * Written by David Smith * dave.s@earthcorp.com */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef DEFINEH_H #define DEFINEH_H -// #ifdef DEBUG_ALL #define DEBUG_MODE_GEN #define DEBUGPRINT #define DEBUG_MODE_WARN #define DEBUG_MODE_READ #define DEBUG_MODE_EMAIL #define DEBUG_MODE_MAIN #define DEBUG_MODE_INDEX #define DEBUG_MODE_CODE #define DEBUG_MODE_INFO #define DEBUG_MODE_HEXDUMP #define DEBUG_MODE_FUNC -// #endif //number of items to save in memory between writes #define DEBUG_MAX_ITEMS 0 #define DEBUG_FILE_NO 1 #define DEBUG_INDEX_NO 2 #define DEBUG_EMAIL_NO 3 #define DEBUG_WARN_NO 4 #define DEBUG_READ_NO 5 #define DEBUG_INFO_NO 6 #define DEBUG_MAIN_NO 7 #define DEBUG_DECRYPT_NO 8 #define DEBUG_FUNCENT_NO 9 #define DEBUG_FUNCRET_NO 10 #define DEBUG_HEXDUMP_NO 11 //variable number of arguments to this macro. will expand them into // ## args, then exit with status of 1 #include #include #include #ifdef __LINUX__ #include #include #endif void _pst_debug(char *fmt, ...); void _pst_debug_hexdump(FILE* out, unsigned char* buf, size_t size, int col, int delta); void _pst_debug_hexprint(char *data, int size); void _debug_init(char *fname); void _debug_msg_info (int line, char *file, int type); void _debug_msg_text(char* fmt, ...); void _debug_hexdump(unsigned char *x, int y, int cols, int delta); void _debug_func(char *function); void _debug_func_ret(); void _debug_close(void); void _debug_write(); void * xmalloc(size_t size); #define MESSAGEPRINT(x,y) {_debug_msg_info(__LINE__,__FILE__,y);\ _debug_msg_text x;} #define LOGSTOP() {MESSAGESTOP();DEBUGSTOP();} #define DIE(x) {\ MESSAGEPRINT(x, 0);\ printf x;\ exit(EXIT_FAILURE);\ } #define WARN(x) {\ MESSAGEPRINT(x, 0);\ printf x;\ } #ifdef DEBUGPRINT #define DEBUG_PRINT(x) _pst_debug x; #else #define DEBUG_PRINT(x) {} #endif #ifdef DEBUG_MODE_GEN #define DEBUG(x) {DEBUG_PRINT(x);} #else #define DEBUG(x) {} #endif #ifdef DEBUG_MODE_INDEX #define DEBUG_INDEX(x) MESSAGEPRINT(x, DEBUG_INDEX_NO); #else #define DEBUG_INDEX(x) {} #endif #ifdef DEBUG_MODE_EMAIL #define DEBUG_EMAIL(x) MESSAGEPRINT(x, DEBUG_EMAIL_NO); #define DEBUG_EMAIL_HEXPRINT(x,y) {_debug_msg_info(__LINE__, __FILE__, 11);\ _debug_hexdump(x, y, 0x10, 0);} #else #define DEBUG_EMAIL(x) {} #define DEBUG_EMAIL_HEXPRINT(x,y) {} #endif #ifdef DEBUG_MODE_WARN #define DEBUG_WARN(x) MESSAGEPRINT(x, DEBUG_WARN_NO); #else #define DEBUG_WARN(x) {} #endif #ifdef DEBUG_MODE_READ #define DEBUG_READ(x) MESSAGEPRINT(x, DEBUG_READ_NO); #else #define DEBUG_READ(x) {} #endif #ifdef DEBUG_MODE_INFO #define DEBUG_INFO(x) MESSAGEPRINT(x, DEBUG_INFO_NO); #else #define DEBUG_INFO(x) {} #endif #ifdef DEBUG_MODE_MAIN #define DEBUG_MAIN(x) MESSAGEPRINT(x, DEBUG_MAIN_NO); #else #define DEBUG_MAIN(x) {} #endif #ifdef DEBUG_MODE_CODE #define DEBUG_CODE(x) {x} #else #define DEBUG_CODE(x) {} #endif #ifdef DEBUG_MODE_DECRYPT #define DEBUG_DECRYPT(x) MESSAGEPRINT(x, DEBUG_DECRYPT_NO); #else #define DEBUG_DECRYPT(x) {} #endif #ifdef DEBUG_MODE_HEXDUMP #define DEBUG_HEXDUMP(x, s)\ {_debug_msg_info(__LINE__, __FILE__, DEBUG_HEXDUMP_NO);\ _debug_hexdump(x, s, 0x10, 0);} #define DEBUG_HEXDUMPC(x, s, c)\ {_debug_msg_info(__LINE__, __FILE__, DEBUG_HEXDUMP_NO);\ _debug_hexdump(x, s, c, 0);} #else #define DEBUG_HEXDUMP(x, s) {} #define DEBUG_HEXDUMPC(x, s, c) {} #endif #define DEBUG_FILE(x) {_debug_msg_info(__LINE__, __FILE__, DEBUG_FILE_NO);\ _debug_msg_text x;} #ifdef DEBUG_MODE_FUNC # define DEBUG_ENT(x) \ { \ _debug_func(x); \ MESSAGEPRINT(("Entering function\n"),DEBUG_FUNCENT_NO); \ } # define DEBUG_RET() \ { \ MESSAGEPRINT(("Leaving function\n"),DEBUG_FUNCRET_NO); \ _debug_func_ret(); \ } #else # define DEBUG_ENT(x) {} # define DEBUG_RET() {} #endif #define DEBUG_INIT(fname) {_debug_init(fname);} #define DEBUG_CLOSE() {_debug_close();} #define DEBUG_REGISTER_CLOSE() {if(atexit(_debug_close)!=0) fprintf(stderr, "Error registering atexit function\n");} #define RET_DERROR(res, ret_val, x)\ if (res) { DIE(x);} #define RET_ERROR(res, ret_val)\ if (res) {return ret_val;} #define DEBUG_VERSION 1 struct _debug_file_rec_m { unsigned short int funcname; unsigned short int filename; unsigned short int text; unsigned short int end; unsigned int line; unsigned int type; }; struct _debug_file_rec_l { unsigned int funcname; unsigned int filename; unsigned int text; unsigned int end; unsigned int line; unsigned int type; }; #endif //DEFINEH_H diff --git a/src/deltasearch.cpp b/src/deltasearch.cpp new file mode 100644 index 0000000..81100f6 --- /dev/null +++ b/src/deltasearch.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +using namespace std; +extern "C" { + #include "define.h" +}; + +unsigned char comp_enc [] = + { 0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, + 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, /*0x0f*/ + 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, + 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, /*0x1f*/ + 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, + 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, /*0x2f*/ + 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, + 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, /*0x3f*/ + 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, + 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, /*0x4f*/ + 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, + 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, /*0x5f*/ + 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, + 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, /*0x6f*/ + 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, + 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, /*0x7f*/ + 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, + 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, /*0x8f*/ + 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, + 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, /*0x9f*/ + 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, + 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, /*0xaf*/ + 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, + 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, /*0xbf*/ + 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, + 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, /*0xcf*/ + 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, + 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, /*0xdf*/ + 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, + 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, /*0xef*/ + 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, + 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec}; /*0xff*/ + +int main(int argc, char *argv[]) { + if (argc < 4) { + cout << "usage: " << argv[0] << " filename.pst integer-delta search-string" << endl; + return 0; + } + int fd = open(argv[1], O_RDONLY); + int d = atoi(argv[2]); + string search(argv[3]); + cout << "using file " << argv[1] << " with delta " << d << " looking for " << search << endl; + if (fd) { + struct stat st; + fstat(fd, &st); + off_t size = st.st_size; + unsigned char buf[size]; + size_t s = read(fd, buf, size); + _pst_debug_hexdump(stdout, buf, s, 16, 0); + cout << endl; + cout << endl; + cout << " dump decrypted data " << endl; + for (off_t i=0; i +#include +#include +#include +#include +#include +#include +#include +#include "generic.h" + +#ifdef WITH_DMALLOC +#include +#endif + + + + +void pDIE( char *fmt, ... ) +{ + va_list ap; + va_start( ap, fmt ); + //fprintf( stderr, "Fatal error (will segfault): "); + vfprintf( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + va_end(ap); + raise( SIGSEGV ); +} + +void pWARN( char *fmt, ... ) +{ + va_list ap; + va_start( ap, fmt ); + fprintf( stderr, "WARNING: "); + vfprintf( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + va_end(ap); +} + +void *F_MALLOC( size_t size ) +{ + void *result; + + result = malloc( size ); + ASSERT( NULL != result, "malloc() failure." ); + + return result; +} + +void *F_REALLOC( void *p, size_t size ) +{ + void *result; + + //if( NULL != p ) hexdump((char*)p - 128, 0, 128, 1 ); + if(!p) { + ASSERT( NULL != ( result = malloc( size ) ), "malloc() failure." ); + } + else { + ASSERT( NULL != ( result = realloc( p, size ) ), "realloc() failure." ); + } + + //hexdump((char*)result - 128, 0, 128, 1 ); + fflush(stderr); + return result; +} + + + +int DEBUG_LEVEL = DB_INFO; + +void db_default( char *file, int line, int level, char *fmt, ... ) +{ + va_list ap; + if( level <= DEBUG_LEVEL ) { + switch( level ) { + case DB_CRASH: + fprintf(stderr, "CRASH"); + break; + case DB_ERR: + fprintf(stderr, "ERROR"); + break; + case DB_WARN: + fprintf(stderr, "WARNING"); + break; + case DB_INFO: + case DB_VERB: + break; + default: + fprintf(stderr, "DEBUG(%d)", level ); + } + + if( level <= DB_WARN ) + fprintf(stderr, " (%s:%d)", file, line ); + + if( DB_INFO != level && DB_VERB != level ) + fprintf(stderr, ": "); + + va_start( ap, fmt ); + vfprintf(stderr, fmt, ap ); + fprintf(stderr, "\n" ); + va_end( ap ); + } +} + +void (*dbfunc)(char *file, int line, int level, char *fmt, ...) = &db_default; + + + + diff --git a/src/generic.h b/src/generic.h new file mode 100644 index 0000000..04846a3 --- /dev/null +++ b/src/generic.h @@ -0,0 +1,48 @@ +/* {{{ Generic.h - thigns every program does: + * + * - user output (log, debug, etc) + * - crash and burn + * - allocate memory (or explode) + * }}} */ +#ifndef GENERIC_H +#define GENERIC_H +#include +#include +#include +/***************************************************/ + +#define LOAD_DEBUG 1 + +#define DIE(...) { fprintf(stderr, "Fatal Error at %s,%d: ", __FILE__, __LINE__); pDIE(__VA_ARGS__); } + +//#define WARN(...) { fprintf(stderr, "WARN: %s,%d: ", __FILE__, __LINE__); pWARN(__VA_ARGS__); } +void pDIE( char *fmt, ... ); +//void pWARN( char *fmt, ... ); + +#define WARN(...) DB( DB_WARN, __VA_ARGS__ ) +#define ASSERT(x,...) { if( !(x) ) DIE( __VA_ARGS__ ); } + +void *F_MALLOC( size_t size ); +void *F_REALLOC( void *p, size_t size ); + +#define DO_DEBUG 0 +#define DEBUG(x) if( DO_DEBUG ) { x; } +#define STUPID_CR "\r\n" + +#define DB_CRASH 0 // crashing +#define DB_ERR 1 // error +#define DB_WARN 2 // warning +#define DB_INFO 3 // normal, but significant, condition +#define DB_VERB 4 // verbose information +#define DB_0 5 // debug-level message +#define DB_1 6 // debug-level message +#define DB_2 7 // debug-level message + +extern int DEBUG_LEVEL; +extern void (*dbfunc)(char *file, int line, int level, char *fmt, ...); + +#define DB(...) { dbfunc( __FILE__, __LINE__, __VA_ARGS__ ); } + +int set_db_function( void (*func)( char *file, int line, int level, char *fmt, ...) ); + +#endif diff --git a/src/libpst.c b/src/libpst.c index 08d7d09..03c4907 100644 --- a/src/libpst.c +++ b/src/libpst.c @@ -1,4150 +1,4411 @@ /*** * libpst.c * Part of the LibPST project * Written by David Smith - * dave.s@earthcorp.com + * dave.s@earthcorp.com */ #include #include #include #include #include #include #include - +#include #include -#include // mkdir -#include // for Win32 definition of _O_BINARY +#include // mkdir +#include // for Win32 definition of _O_BINARY #include "define.h" #include "libstrfunc.h" +#include "vbuf.h" + +#define ASSERT(x) { if(!(x)) raise( SIGSEGV ); } #ifdef _MSC_VER # include #else # include #endif //ifdef _MSC_VER #include "libpst.h" #include "timeconv.h" - -#define FILE_SIZE_POINTER 0xA8 -#define INDEX_POINTER 0xC4 -#define SECOND_POINTER 0xBC -// the encryption setting could be at 0x1CC. Will require field testing -#define ENC_OFFSET 0x1CD -// says the type of index we have -#define INDEX_TYPE_OFFSET 0x0A - -// for the 64bit 2003 outlook PST we need new file offsets -// perhaps someone can figure out the header format for the pst files... -#define FILE_SIZE_POINTER_64 0xB8 -#define INDEX_POINTER_64 0xF0 -#define SECOND_POINTER_64 0xE0 +#define INDEX_DEPTH 0x4C +#define SECOND_DEPTH 0x5C +#define INDEX_TYPE32 0x0E +#define INDEX_TYPE64 0x17 + +#define FILE_SIZE_POINTER32 0xA8 +#define INDEX_POINTER32 0xC4 +#define INDEX_COUNT32 0xC0 +#define SECOND_POINTER32 0xBC +#define SECOND_COUNT32 0xB8 +#define INDEX_TYPE_OFFSET32 0x0A +#define ENC_OFFSET32 0x1CD + +#define FILE_SIZE_POINTER64 0xB8 +#define INDEX_POINTER64 0xF0 +#define INDEX_COUNT64 0xE8 +#define SECOND_POINTER64 0xE0 +#define SECOND_COUNT64 0xD8 +#define INDEX_TYPE_OFFSET64 0x0A +#define ENC_OFFSET64 0x201 + +#define FILE_SIZE_POINTER ((do_read64) ? FILE_SIZE_POINTER64 : FILE_SIZE_POINTER32) +#define INDEX_POINTER ((do_read64) ? INDEX_POINTER64 : INDEX_POINTER32) +#define INDEX_COUNT ((do_read64) ? INDEX_COUNT64 : INDEX_COUNT32) +#define SECOND_POINTER ((do_read64) ? SECOND_POINTER64 : SECOND_POINTER32) +#define SECOND_COUNT ((do_read64) ? SECOND_COUNT64 : SECOND_COUNT32) +#define INDEX_TYPE_OFFSET ((do_read64) ? INDEX_TYPE_OFFSET64 : INDEX_TYPE_OFFSET32) +#define INDEX_TYPE ((do_read64) ? INDEX_TYPE64 : INDEX_TYPE32) +#define ENC_OFFSET ((do_read64) ? ENC_OFFSET64 : ENC_OFFSET32) #define PST_SIGNATURE 0x4E444221 -struct _pst_table_ptr_struct{ - int32_t start; - int32_t u1; - int32_t offset; +int do_read64 = 0; //set this to 1 in order to try and read 64-bit pst files (Outlook 2003) + +struct _pst_table_ptr_struct32{ + int32_t start; + int32_t u1; + int32_t offset; +}; +struct _pst_table_ptr_structn{ + int64_t start; + int64_t u1; + int64_t offset; }; typedef struct _pst_block_header { - int16_t type; - int16_t count; + int16_t type; + int16_t count; } pst_block_header; typedef struct _pst_id2_assoc { - u_int32_t id2; - u_int32_t id; - int32_t table2; + uint32_t id2; + uint32_t id; + int32_t table2; } pst_id2_assoc; // this is an array of the un-encrypted values. the un-encrypted value is in the position // of the encrypted value. ie the encrypted value 0x13 represents 0x02 -// 0 1 2 3 4 5 6 7 -// 8 9 a b c d e f +// 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f unsigned char comp_enc [] = { 0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, - 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, /*0x0f*/ - 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, - 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, /*0x1f*/ - 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, - 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, /*0x2f*/ - 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, - 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, /*0x3f*/ - 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, - 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, /*0x4f*/ - 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, - 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, /*0x5f*/ - 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, - 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, /*0x6f*/ - 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, - 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, /*0x7f*/ - 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, - 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, /*0x8f*/ - 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, - 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, /*0x9f*/ - 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, - 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, /*0xaf*/ - 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, - 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, /*0xbf*/ - 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, - 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, /*0xcf*/ - 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, - 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, /*0xdf*/ - 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, - 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, /*0xef*/ - 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, - 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec}; /*0xff*/ + 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53, /*0x0f*/ + 0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, + 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd, /*0x1f*/ + 0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, + 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb, /*0x2f*/ + 0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, + 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23, /*0x3f*/ + 0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, + 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83, /*0x4f*/ + 0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, + 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29, /*0x5f*/ + 0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, + 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3, /*0x6f*/ + 0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, + 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c, /*0x7f*/ + 0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, + 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50, /*0x8f*/ + 0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, + 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b, /*0x9f*/ + 0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, + 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a, /*0xaf*/ + 0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, + 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f, /*0xbf*/ + 0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, + 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88, /*0xcf*/ + 0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, + 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36, /*0xdf*/ + 0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, + 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a, /*0xef*/ + 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, + 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec}; /*0xff*/ + + +void dump_desc(off_t off, int depth, int i, pst_descn *desc_rec ) { // {{{ + //desc_rec->d_id = 0x0102030405060708; + DEBUG_INDEX(("%08x [%i] Item(%#x) = [d_id = %#llx, desc_id = %#llx, " + "list_id = %#llx, parent_id = %#x, u1 = %#x] %#x %p %p\n", + off, + depth, i, desc_rec->d_id, + desc_rec->desc_id, desc_rec->list_id, desc_rec->parent_id, desc_rec->u1)); + DEBUG_HEXDUMPC( (char*)desc_rec, sizeof( pst_descn ), 0x10 ); + DEBUG_INDEX(("WTF? %d %x %x %x %x %x\n", + sizeof( uint32_t ), + (int)(&desc_rec->d_id) - (int)desc_rec, + (int)(&desc_rec->desc_id) - (int)desc_rec, + (int)(&desc_rec->list_id) - (int)desc_rec, + (int)(&desc_rec->parent_id) - (int)desc_rec, + (int)(&desc_rec->u1) - (int)desc_rec )); +} + int32_t pst_open(pst_file *pf, char *name, char *mode) { - u_int32_t sig; + uint32_t sig; - DEBUG_ENT("pst_open"); + DEBUG_ENT("pst_open"); - if (!pf) { - WARN (("cannot be passed a NULL pst_file\n")); - DEBUG_RET(); - return -1; - } - memset(pf, 0, sizeof(pst_file)); + if (!pf) { + WARN (("cannot be passed a NULL pst_file\n")); + DEBUG_RET(); + return -1; + } + memset(pf, 0, sizeof(pst_file)); #ifdef _MSC_VER - // set the default open mode for windows - _fmode = _O_BINARY; + // set the default open mode for windows + _fmode = _O_BINARY; #endif //_MSC_VER - if ((pf->fp = fopen(name, mode)) == NULL) { - WARN(("cannot open PST file. Error\n")); - DEBUG_RET(); - return -1; - } - - // Check pst file magic - if (fread(&sig, sizeof(sig), 1, pf->fp) == 0) { - fclose(pf->fp); - WARN(("cannot read signature from PST file. Closing on error\n")); - DEBUG_RET(); - return -1; - } - LE32_CPU(sig); // architecture independant byte-swapping (little, big, pdp) - DEBUG_INFO(("sig = %X\n", sig)); - if (sig != PST_SIGNATURE) { - fclose(pf->fp); - WARN(("not a PST file that I know. Closing with error\n")); - DEBUG_RET(); - return -1; - } - - // read index type - _pst_getAtPos(pf->fp, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(unsigned char)); - DEBUG_INFO(("index_type = %i\n", pf->ind_type)); - if (pf->ind_type != 0x0E) { - WARN(("unknown index structure. Could this be a new Outlook 2003 PST file?\n")); - DEBUG_RET(); - return -1; - } - - // read encryption setting - _pst_getAtPos(pf->fp, ENC_OFFSET, &(pf->encryption), sizeof(unsigned char)); - DEBUG_INFO(("encrypt = %i\n", pf->encryption)); - - _pst_getAtPos(pf->fp, SECOND_POINTER-4, &(pf->index2_count), sizeof(pf->index2_count)); - _pst_getAtPos(pf->fp, SECOND_POINTER, &(pf->index2), sizeof(pf->index2)); - LE32_CPU(pf->index2_count); - LE32_CPU(pf->index2); - DEBUG_INFO(("Pointer2 is %#X, count %i[%#x]\n", pf->index2, pf->index2_count, pf->index2_count)); - - _pst_getAtPos(pf->fp, FILE_SIZE_POINTER, &(pf->size), sizeof(pf->size)); - LE32_CPU(pf->size); - - _pst_getAtPos(pf->fp, INDEX_POINTER-4, &(pf->index1_count), sizeof(pf->index1_count)); - _pst_getAtPos(pf->fp, INDEX_POINTER, &(pf->index1), sizeof(pf->index1)); - LE32_CPU(pf->index1_count); - LE32_CPU(pf->index1); - DEBUG_INFO(("Pointer1 is %#X, count %i[%#x]\n", pf->index1, pf->index1_count, pf->index1_count)); - - DEBUG_RET(); - return 0; + if ((pf->fp = fopen(name, mode)) == NULL) { + WARN(("cannot open PST file. Error\n")); + DEBUG_RET(); + return -1; + } + + // Check pst file magic + if (fread(&sig, sizeof(sig), 1, pf->fp) == 0) { + fclose(pf->fp); + WARN(("cannot read signature from PST file. Closing on error\n")); + DEBUG_RET(); + return -1; + } + LE32_CPU(sig); + DEBUG_INFO(("sig = %X\n", sig)); + if (sig != PST_SIGNATURE) { + fclose(pf->fp); + WARN(("not a PST file that I know. Closing with error\n")); + DEBUG_RET(); + return -1; + } + + // read index type + do_read64 = 0; // start with 32 bit format + _pst_getAtPos(pf->fp, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(unsigned char)); + DEBUG_INFO(("index_type = %i\n", pf->ind_type)); + if (pf->ind_type != INDEX_TYPE) { + // try with 64 bit format + do_read64 = 1; + if (pf->ind_type != INDEX_TYPE) { + WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n")); + DEBUG_RET(); + return -1; + } + } + + // read encryption setting + _pst_getAtPos(pf->fp, ENC_OFFSET, &(pf->encryption), sizeof(unsigned char)); + DEBUG_INFO(("encrypt = %i\n", pf->encryption)); + + pf->index2_count = _pst_getIntAtPos(pf->fp, SECOND_COUNT); + pf->index2 = _pst_getIntAtPos(pf->fp, SECOND_POINTER ); + pf->size = _pst_getIntAtPos( pf->fp, FILE_SIZE_POINTER ); + DEBUG_INFO(("Pointer2 is %#X, count %i[%#x]\n", pf->index2, pf->index2_count, pf->index2_count)); + + pf->index1_count = _pst_getIntAtPos(pf->fp, INDEX_COUNT); + pf->index1 = _pst_getIntAtPos(pf->fp, INDEX_POINTER); + DEBUG_INFO(("Pointer1 is %#X, count %i[%#x]\n", pf->index1, pf->index1_count, pf->index1_count)); + + DEBUG_RET(); + return 0; } int32_t pst_close(pst_file *pf) { - DEBUG_ENT("pst_close"); - if (!pf->fp) { - WARN(("cannot close NULL fp\n")); - DEBUG_RET(); - return -1; - } - if (fclose(pf->fp)) { - WARN(("fclose returned non-zero value\n")); - DEBUG_RET(); - return -1; - } - // we must free the id linklist and the desc tree - _pst_free_id (pf->i_head); - _pst_free_desc (pf->d_head); - _pst_free_xattrib (pf->x_head); - DEBUG_RET(); - return 0; + DEBUG_ENT("pst_close"); + if (!pf->fp) { + WARN(("cannot close NULL fp\n")); + DEBUG_RET(); + return -1; + } + if (fclose(pf->fp)) { + WARN(("fclose returned non-zero value\n")); + DEBUG_RET(); + return -1; + } + // we must free the id linklist and the desc tree + _pst_free_id (pf->i_head); + _pst_free_desc (pf->d_head); + _pst_free_xattrib (pf->x_head); + DEBUG_RET(); + return 0; } pst_desc_ll* pst_getTopOfFolders(pst_file *pf, pst_item *root) { - pst_desc_ll *ret; - DEBUG_ENT("pst_getTopOfFolders"); - if (!root || !root->message_store) { - DEBUG_INDEX(("There isn't a top of folder record here.\n")); - ret = NULL; - } else if (!root->message_store->top_of_personal_folder) { - // this is the OST way - // ASSUMPTION: Top Of Folders record in PST files is *always* descid 0x2142 - ret = _pst_getDptr(pf, 0x2142); - } else { - ret = _pst_getDptr(pf, root->message_store->top_of_personal_folder->id); - } - DEBUG_RET(); - return ret; + pst_desc_ll *ret; + DEBUG_ENT("pst_getTopOfFolders"); + if (!root || !root->message_store) { + DEBUG_INDEX(("There isn't a top of folder record here.\n")); + ret = NULL; + } else if (!root->message_store->top_of_personal_folder) { + // this is the OST way + // ASSUMPTION: Top Of Folders record in PST files is *always* descid 0x2142 + ret = _pst_getDptr(pf, 0x2142); + } else { + ret = _pst_getDptr(pf, root->message_store->top_of_personal_folder->id); + } + DEBUG_RET(); + return ret; } int32_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, unsigned char **b){ - int32_t size=0; - pst_index_ll *ptr; - struct holder h = {b, NULL, 0, "", 0}; - DEBUG_ENT("pst_attach_to_mem"); - if (attach->id_val != -1) { - ptr = _pst_getID(pf, attach->id_val); - if (ptr) { - size = _pst_ff_getID2data(pf, ptr, &h); - } else { - DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n")); - size = 0; - } - attach->size = size; // may as well update it to what is correct for this instance - } else { - size = attach->size; - } - DEBUG_RET(); - return size; + int32_t size=0; + pst_index_ll *ptr; + struct holder h = {b, NULL, 0, "", 0}; + DEBUG_ENT("pst_attach_to_mem"); + if (attach->id_val != -1) { + ptr = _pst_getID(pf, attach->id_val); + if (ptr) { + size = _pst_ff_getID2data(pf, ptr, &h); + } else { + DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n")); + size = 0; + } + attach->size = size; // may as well update it to what is correct for this instance + } else { + size = attach->size; + } + DEBUG_RET(); + return size; } int32_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) { - pst_index_ll *ptr; - struct holder h = {NULL, fp, 0, "", 0}; - int32_t size; - DEBUG_ENT("pst_attach_to_file"); - if (attach->id_val != -1) { - ptr = _pst_getID(pf, attach->id_val); - if (ptr) { - size = _pst_ff_getID2data(pf, ptr, &h); - } else { - DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n")); - size = 0; - } - attach->size = size; - } else { - // save the attachment to file - size = attach->size; - pst_fwrite(attach->data, 1, size, fp); - } - DEBUG_RET(); - return 1; + pst_index_ll *ptr; + struct holder h = {NULL, fp, 0, "", 0}; + int32_t size; + DEBUG_ENT("pst_attach_to_file"); + if (attach->id_val != -1) { + ptr = _pst_getID(pf, attach->id_val); + if (ptr) { + size = _pst_ff_getID2data(pf, ptr, &h); + } else { + DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n")); + size = 0; + } + attach->size = size; + } else { + // save the attachment to file + size = attach->size; + pst_fwrite(attach->data, 1, size, fp); + } + DEBUG_RET(); + return 1; } int32_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp) { - pst_index_ll *ptr; - struct holder h = {NULL, fp, 1, "", 0}; - int32_t size; - char *c; - DEBUG_ENT("pst_attach_to_file_base64"); - if (attach->id_val != -1) { - ptr = _pst_getID(pf, attach->id_val); - if (ptr) { - size = _pst_ff_getID2data(pf, ptr, &h); - // will need to encode any bytes left over - c = base64_encode(h.base64_extra_chars, h.base64_extra); - if (c) { - pst_fwrite(c, 1, strlen(c), fp); - free(c); // caught by valgrind - } - } else { - DEBUG_WARN (("Couldn't find ID pointer. Cannot save attachment to Base64\n")); - size = 0; - } - attach->size = size; - } else { - // encode the attachment to the file - c = base64_encode(attach->data, attach->size); - if (c) { - pst_fwrite(c, 1, strlen(c), fp); - free(c); // caught by valgrind - } - size = attach->size; - } - DEBUG_RET(); - return 1; + pst_index_ll *ptr; + struct holder h = {NULL, fp, 1, "", 0}; + int32_t size; + char *c; + DEBUG_ENT("pst_attach_to_file_base64"); + if (attach->id_val != -1) { + ptr = _pst_getID(pf, attach->id_val); + if (ptr) { + size = _pst_ff_getID2data(pf, ptr, &h); + // will need to encode any bytes left over + c = base64_encode(h.base64_extra_chars, h.base64_extra); + if (c) { + pst_fwrite(c, 1, strlen(c), fp); + free(c); // caught by valgrind + } + } else { + DEBUG_WARN (("Couldn't find ID pointer. Cannot save attachment to Base64\n")); + size = 0; + } + attach->size = size; + } else { + // encode the attachment to the file + c = base64_encode(attach->data, attach->size); + if (c) { + pst_fwrite(c, 1, strlen(c), fp); + free(c); // caught by valgrind + } + size = attach->size; + } + DEBUG_RET(); + return 1; } int32_t pst_load_index (pst_file *pf) { - int32_t x; - u_int32_t y; - DEBUG_ENT("pst_load_index"); - if (!pf) { - WARN(("Cannot load index for a NULL pst_file\n")); - DEBUG_RET(); - return -1; - } - - x = _pst_build_id_ptr(pf, pf->index1, 0, pf->index1_count, 0, INT32_MAX); - DEBUG_INDEX(("build id ptr returns %i\n", x)); - - y = 0; - x = _pst_build_desc_ptr(pf, pf->index2, 0, pf->index2_count, &y, 0x21, INT32_MAX); - DEBUG_INDEX(("build desc ptr returns %i\n", x)); - - DEBUG_CODE(_pst_printDptr(pf);); - DEBUG_RET(); - return 0; + int32_t x; + uint64_t y; + DEBUG_ENT("pst_load_index"); + if (!pf) { + WARN(("Cannot load index for a NULL pst_file\n")); + DEBUG_RET(); + return -1; + } + + x = _pst_build_id_ptr(pf, pf->index1, 0, pf->index1_count, 0, UINT64_MAX); + DEBUG_INDEX(("build id ptr returns %i\n", x)); + + y = 0; + x = _pst_build_desc_ptr(pf, pf->index2, 0, pf->index2_count, &y, 0x21, UINT64_MAX); + DEBUG_INDEX(("build desc ptr returns %i\n", x)); + + DEBUG_CODE(_pst_printDptr(pf);); + DEBUG_RET(); + return 0; } pst_desc_ll* pst_getNextDptr(pst_desc_ll* d) { - pst_desc_ll* r = NULL; - DEBUG_ENT("pst_getNextDptr"); - if (d) { - if ((r = d->child) == NULL) { - while (!d->next && d->parent) d = d->parent; - r = d->next; - } - } - DEBUG_RET(); - return r; + pst_desc_ll* r = NULL; + DEBUG_ENT("pst_getNextDptr"); + if (d) { + if ((r = d->child) == NULL) { + while (!d->next && d->parent) d = d->parent; + r = d->next; + } + } + DEBUG_RET(); + return r; } typedef struct _pst_x_attrib { - u_int16_t extended; - u_int16_t zero; - u_int16_t type; - u_int16_t map; + uint16_t extended; + uint16_t zero; + uint16_t type; + uint16_t map; } pst_x_attrib; int32_t pst_load_extended_attributes(pst_file *pf) { - // for PST files this will load up ID2 0x61 and check it's "list" attribute. - pst_desc_ll *p; - pst_num_array *na; - pst_index2_ll *list2 = NULL; - unsigned char * buffer=NULL, *headerbuffer=NULL;//, *tc; - pst_x_attrib xattrib; - int32_t bptr = 0, bsize, hsize, tint, err=0, x; - pst_x_attrib_ll *ptr, *p_head=NULL, *p_sh=NULL, *p_sh2=NULL; - - DEBUG_ENT("pst_loadExtendedAttributes"); - if ((p = _pst_getDptr(pf, 0x61)) == NULL) { - DEBUG_WARN(("Cannot find DescID 0x61 for loading the Extended Attributes\n")); - DEBUG_RET(); - return 0; - } - - if (!p->desc) { - DEBUG_WARN(("desc is NULL for item 0x61. Cannot load Extended Attributes\n")); - DEBUG_RET(); - return 0; - } - - if (p->list_index) { - list2 = _pst_build_id2(pf, p->list_index, NULL); - _pst_printID2ptr(list2); - } else { - DEBUG_WARN(("Have not been able to fetch any id2 values for item 0x61. Brace yourself!\n")); - } - - na = _pst_parse_block(pf, p->desc->id, list2); - if (!na) { - DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n")); - if (list2) _pst_free_id2(list2); - DEBUG_RET(); - return 0; - } - - x = 0; - while (x < na->count_item) { - if (na->items[x]->id == 0x0003) { - buffer = na->items[x]->data; - bsize = na->items[x]->size; - } else if (na->items[x]->id == 0x0004) { - headerbuffer = na->items[x]->data; - hsize = na->items[x]->size; - } - x++; - } - - if (!buffer) { - if (na) _pst_free_list(na); - DEBUG_WARN(("No extended attributes buffer found. Not processing\n")); - DEBUG_RET(); - return 0; - } - - memcpy(&xattrib, &(buffer[bptr]), sizeof(xattrib)); - LE16_CPU(xattrib.extended); - LE16_CPU(xattrib.zero); - LE16_CPU(xattrib.type); - LE16_CPU(xattrib.map); - bptr += sizeof(xattrib); - - while (xattrib.type != 0 && bptr < bsize) { - ptr = (pst_x_attrib_ll*) xmalloc(sizeof(pst_x_attrib_ll)); - memset(ptr, 0, sizeof(pst_x_attrib_ll)); - ptr->type = xattrib.type; - ptr->map = xattrib.map+0x8000; - ptr->next = NULL; - DEBUG_INDEX(("xattrib: ext = %#hx, zero = %#hx, type = %#hx, map = %#hx\n", - xattrib.extended, xattrib.zero, xattrib.type, xattrib.map)); - err=0; - if (xattrib.type & 0x0001) { // if the Bit 1 is set - // pointer to Unicode field in buffer - if (xattrib.extended < hsize) { - char *wt; - // copy the size of the header. It is 32 bit int - memcpy(&tint, &(headerbuffer[xattrib.extended]), sizeof(tint)); - LE32_CPU(tint); - wt = (char*) xmalloc(tint+2); // plus 2 for a uni-code zero - memset(wt, 0, tint+2); - memcpy(wt, &(headerbuffer[xattrib.extended+sizeof(tint)]), tint); - ptr->data = _pst_wide_to_single(wt, tint); - free(wt); - DEBUG_INDEX(("Read string (converted from UTF-16): %s\n", ptr->data)); - } else { - DEBUG_INDEX(("Cannot read outside of buffer [%i !< %i]\n", xattrib.extended, hsize)); - } - ptr->mytype = PST_MAP_HEADER; - } else { - // contains the attribute code to map to. - ptr->data = (int*)xmalloc(sizeof(int32_t)); - memset(ptr->data, 0, sizeof(int32_t)); - *((int32_t*)ptr->data) = xattrib.extended; - ptr->mytype = PST_MAP_ATTRIB; - DEBUG_INDEX(("Mapped attribute %#x to %#x\n", ptr->map, *((int32_t*)ptr->data))); - } - - if (err==0) { - // add it to the list - p_sh = p_head; - p_sh2 = NULL; - while (p_sh && ptr->map > p_sh->map) { - p_sh2 = p_sh; - p_sh = p_sh->next; - } - if (!p_sh2) { - // needs to go before first item - ptr->next = p_head; - p_head = ptr; - } else { - // it will go after p_sh2 - ptr->next = p_sh2->next; - p_sh2->next = ptr; - } - } else { - free(ptr); - ptr = NULL; - } - memcpy(&xattrib, &(buffer[bptr]), sizeof(xattrib)); - LE16_CPU(xattrib.extended); - LE16_CPU(xattrib.zero); - LE16_CPU(xattrib.type); - LE16_CPU(xattrib.map); - bptr += sizeof(xattrib); - } - if (list2) _pst_free_id2(list2); - if (na) _pst_free_list(na); - pf->x_head = p_head; - DEBUG_RET(); - return 1; + // for PST files this will load up ID2 0x61 and check it's "list" attribute. + pst_desc_ll *p; + pst_num_array *na; + pst_index2_ll *list2 = NULL; + unsigned char * buffer=NULL, *headerbuffer=NULL;//, *tc; + pst_x_attrib xattrib; + int32_t bptr = 0, bsize, hsize, tint, err=0, x; + pst_x_attrib_ll *ptr, *p_head=NULL, *p_sh=NULL, *p_sh2=NULL; + + DEBUG_ENT("pst_loadExtendedAttributes"); + if ((p = _pst_getDptr(pf, 0x61)) == NULL) { + DEBUG_WARN(("Cannot find DescID 0x61 for loading the Extended Attributes\n")); + DEBUG_RET(); + return 0; + } + + if (!p->desc) { + DEBUG_WARN(("desc is NULL for item 0x61. Cannot load Extended Attributes\n")); + DEBUG_RET(); + return 0; + } + + if (p->list_index) { + list2 = _pst_build_id2(pf, p->list_index, NULL); + _pst_printID2ptr(list2); + } else { + DEBUG_WARN(("Have not been able to fetch any id2 values for item 0x61. Brace yourself!\n")); + } + + na = _pst_parse_block(pf, p->desc->id, list2); + if (!na) { + DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n")); + if (list2) _pst_free_id2(list2); + DEBUG_RET(); + return 0; + } + + x = 0; + while (x < na->count_item) { + if (na->items[x]->id == 0x0003) { + buffer = na->items[x]->data; + bsize = na->items[x]->size; + } else if (na->items[x]->id == 0x0004) { + headerbuffer = na->items[x]->data; + hsize = na->items[x]->size; + } + x++; + } + + if (!buffer) { + if (na) _pst_free_list(na); + DEBUG_WARN(("No extended attributes buffer found. Not processing\n")); + DEBUG_RET(); + return 0; + } + + memcpy(&xattrib, &(buffer[bptr]), sizeof(xattrib)); + LE16_CPU(xattrib.extended); + LE16_CPU(xattrib.zero); + LE16_CPU(xattrib.type); + LE16_CPU(xattrib.map); + bptr += sizeof(xattrib); + + while (xattrib.type != 0 && bptr < bsize) { + ptr = (pst_x_attrib_ll*) xmalloc(sizeof(pst_x_attrib_ll)); + memset(ptr, 0, sizeof(pst_x_attrib_ll)); + ptr->type = xattrib.type; + ptr->map = xattrib.map+0x8000; + ptr->next = NULL; + DEBUG_INDEX(("xattrib: ext = %#hx, zero = %#hx, type = %#hx, map = %#hx\n", + xattrib.extended, xattrib.zero, xattrib.type, xattrib.map)); + err=0; + if (xattrib.type & 0x0001) { // if the Bit 1 is set + // pointer to Unicode field in buffer + if (xattrib.extended < hsize) { + char *wt; + // copy the size of the header. It is 32 bit int + memcpy(&tint, &(headerbuffer[xattrib.extended]), sizeof(tint)); + LE32_CPU(tint); + wt = (char*) xmalloc(tint+2); // plus 2 for a uni-code zero + memset(wt, 0, tint+2); + memcpy(wt, &(headerbuffer[xattrib.extended+sizeof(tint)]), tint); + ptr->data = _pst_wide_to_single(wt, tint); + free(wt); + DEBUG_INDEX(("Read string (converted from UTF-16): %s\n", ptr->data)); + } else { + DEBUG_INDEX(("Cannot read outside of buffer [%i !< %i]\n", xattrib.extended, hsize)); + } + ptr->mytype = PST_MAP_HEADER; + } else { + // contains the attribute code to map to. + ptr->data = (int*)xmalloc(sizeof(int32_t)); + memset(ptr->data, 0, sizeof(int32_t)); + *((int32_t*)ptr->data) = xattrib.extended; + ptr->mytype = PST_MAP_ATTRIB; + DEBUG_INDEX(("Mapped attribute %#x to %#x\n", ptr->map, *((int32_t*)ptr->data))); + } + + if (err==0) { + // add it to the list + p_sh = p_head; + p_sh2 = NULL; + while (p_sh && ptr->map > p_sh->map) { + p_sh2 = p_sh; + p_sh = p_sh->next; + } + if (!p_sh2) { + // needs to go before first item + ptr->next = p_head; + p_head = ptr; + } else { + // it will go after p_sh2 + ptr->next = p_sh2->next; + p_sh2->next = ptr; + } + } else { + free(ptr); + ptr = NULL; + } + memcpy(&xattrib, &(buffer[bptr]), sizeof(xattrib)); + LE16_CPU(xattrib.extended); + LE16_CPU(xattrib.zero); + LE16_CPU(xattrib.type); + LE16_CPU(xattrib.map); + bptr += sizeof(xattrib); + } + if (list2) _pst_free_id2(list2); + if (na) _pst_free_list(na); + pf->x_head = p_head; + DEBUG_RET(); + return 1; +} + + +#define BLOCK_SIZE 516 // index blocks +#define DESC_BLOCK_SIZE 516 // descriptor blocks +#define ITEM_COUNT_OFFSET 0x1f0 // count byte +#define LEVEL_INDICATOR_OFFSET 0x1f3 // node or leaf +#define BACKLINK_OFFSET 0x1f8 // backlink u1 value +#define ITEM_SIZE 12 +#define DESC_SIZE 16 +#define INDEX_COUNT_MAX 41 // max active items +#define DESC_COUNT_MAX 31 // max active items + + +int _pst_decode_desc( pst_descn *desc, char *buf ) { + int r; + if (do_read64) { + DEBUG_INDEX(("Decoding desc64 ")); + DEBUG_HEXDUMPC(buf, sizeof(pst_descn), 0x10); + memcpy(desc, buf, sizeof(pst_descn)); + LE64_CPU(desc->d_id); + LE64_CPU(desc->desc_id); + LE64_CPU(desc->list_id); + LE32_CPU(desc->parent_id); + LE32_CPU(desc->u1); + r = sizeof(pst_descn); + } + else { + pst_desc32 d32; + DEBUG_INDEX(("Decoding desc32 ")); + DEBUG_HEXDUMPC(buf, sizeof(pst_desc32), 0x10); + memcpy(&d32, buf, sizeof(pst_desc32)); + LE32_CPU(d32.d_id); + LE32_CPU(d32.desc_id); + LE32_CPU(d32.list_id); + LE32_CPU(d32.parent_id); + desc->d_id = d32.d_id; + desc->desc_id = d32.desc_id; + desc->list_id = d32.list_id; + desc->parent_id = d32.parent_id; + desc->u1 = 0; + r = sizeof(pst_desc32); + } + return r; +} + + +int _pst_decode_table( struct _pst_table_ptr_structn *table, char *buf ) { + int r; + if (do_read64) { + DEBUG_INDEX(("Decoding table64")); + DEBUG_HEXDUMPC(buf, sizeof(struct _pst_table_ptr_structn), 0x10); + memcpy(table, buf, sizeof(struct _pst_table_ptr_structn)); + LE64_CPU(table->start); + LE64_CPU(table->u1); + LE64_CPU(table->offset); + r =sizeof(struct _pst_table_ptr_structn); + } + else { + struct _pst_table_ptr_struct32 t32; + DEBUG_INDEX(("Decoding table32")); + DEBUG_HEXDUMPC(buf, sizeof( struct _pst_table_ptr_struct32), 0x10); + memcpy(&t32, buf, sizeof(struct _pst_table_ptr_struct32)); + LE32_CPU(t32.start); + LE32_CPU(t32.u1); + LE32_CPU(t32.offset); + table->start = t32.start; + table->u1 = t32.u1; + table->offset = t32.offset; + r = sizeof(struct _pst_table_ptr_struct32); + } + return r; } -#define BLOCK_SIZE 516 // index blocks -#define DESC_BLOCK_SIZE 516 // descriptor blocks was 520 but bogus -#define ITEM_COUNT_OFFSET 0x1f0 // count byte -#define LEVEL_INDICATOR_OFFSET 0x1f3 // node or leaf -#define BACKLINK_OFFSET 0x1f8 // backlink u1 value -#define ITEM_SIZE 12 -#define DESC_SIZE 16 -#define INDEX_COUNT_MAX 41 // max active items -#define DESC_COUNT_MAX 31 // max active items - -int32_t _pst_build_id_ptr(pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t start_val, u_int32_t end_val) { - struct _pst_table_ptr_struct table, table2; - pst_index_ll *i_ptr=NULL; - pst_index index; - int32_t x, item_count; - u_int32_t old = start_val; - char *buf = NULL, *bptr; - - DEBUG_ENT("_pst_build_id_ptr"); - DEBUG_INDEX(("offset %x depth %i linku1 %x start %x end %x\n", offset, depth, linku1, start_val, end_val)); - if (end_val <= start_val) { - DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#x, end:%#x]\n", start_val, end_val)); - DEBUG_RET(); - return -1; - } - DEBUG_INDEX(("Reading index block\n")); - if (_pst_read_block_size(pf, offset, BLOCK_SIZE, &buf, 0, 0) < BLOCK_SIZE) { - DEBUG_WARN(("Failed to read %i bytes\n", BLOCK_SIZE)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - bptr = buf; - DEBUG_HEXDUMPC(buf, BLOCK_SIZE, ITEM_SIZE); - item_count = (int)(unsigned)(buf[ITEM_COUNT_OFFSET]); - if (item_count > INDEX_COUNT_MAX) { - DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - memcpy(&index, buf+BACKLINK_OFFSET, sizeof(index)); - LE32_CPU(index.id); - if (index.id != linku1) { - DEBUG_WARN(("Backlink %#x in this node does not match required %#x\n", index.id, linku1)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - - if (buf[LEVEL_INDICATOR_OFFSET] == '\0') { - // this node contains leaf pointers - x = 0; - while (x < item_count) { - memcpy(&index, bptr, sizeof(index)); - LE32_CPU(index.id); - LE32_CPU(index.offset); - LE16_CPU(index.size); - LE16_CPU(index.u1); - bptr += sizeof(index); - x++; - if (index.id == 0) break; - DEBUG_INDEX(("[%i]%i Item [id = %#x, offset = %#x, u1 = %#x, size = %i(%#x)]\n", - depth, x, index.id, index.offset, index.u1, index.size, index.size)); - // if (index.id & 0x02) DEBUG_INDEX(("two-bit set!!\n")); - if ((index.id >= end_val) || (index.id < old)) { - DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - old = index.id; - if (x == 1) { // first entry - if ((start_val) && (index.id != start_val)) { - DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - } - i_ptr = (pst_index_ll*) xmalloc(sizeof(pst_index_ll)); - i_ptr->id = index.id; - i_ptr->offset = index.offset; - i_ptr->u1 = index.u1; - i_ptr->size = index.size; - i_ptr->next = NULL; - if (pf->i_tail) pf->i_tail->next = i_ptr; - if (!pf->i_head) pf->i_head = i_ptr; - pf->i_tail = i_ptr; - } - } else { - // this node contains node pointers - x = 0; - while (x < item_count) { - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr += sizeof(table); - x++; - if (table.start == 0) break; - if (x < item_count) { - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - } - else { - table2.start = end_val; - } - DEBUG_INDEX(("[%i] %i Index Table [start id = %#x, u1 = %#x, offset = %#x, end id = %#x]\n", - depth, x, table.start, table.u1, table.offset, table2.start)); - if ((table.start >= end_val) || (table.start < old)) { - DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - old = table.start; - if (x == 1) { // first entry - if ((start_val) && (table.start != start_val)) { - DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - } - _pst_build_id_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start); - } - } - if (buf) free (buf); - DEBUG_RET(); - return 0; +int _pst_decode_index( pst_index *index, char *buf ) { + int r; + if (do_read64) { + DEBUG_INDEX(("Decoding index64")); + DEBUG_HEXDUMPC(buf, sizeof(pst_index), 0x10); + memcpy(index, buf, sizeof(pst_index)); + LE64_CPU(index->id); + LE64_CPU(index->offset); + LE16_CPU(index->size); + LE16_CPU(index->u0); + LE16_CPU(index->u1); + r = sizeof(pst_index); + } else { + pst_index32 index32; + DEBUG_INDEX(("Decoding index32")); + DEBUG_HEXDUMPC(buf, sizeof(pst_index32), 0x10); + memcpy(&index32, buf, sizeof(pst_index32)); + LE32_CPU(index32->id); + LE32_CPU(index32->offset); + LE16_CPU(index32->size); + LE16_CPU(index32->u1); + index->id = index32.id; + index->offset = index32.offset; + index->size = index32.size; + index->u1 = index32.u1; + r = sizeof(pst_index32); + } + return r; +} + + +int32_t _pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, int64_t linku1, uint64_t start_val, uint64_t end_val) { + struct _pst_table_ptr_structn table, table2; + pst_index_ll *i_ptr=NULL; + pst_index index; + int32_t x, item_count; + uint64_t old = start_val; + char *buf = NULL, *bptr; + + DEBUG_ENT("_pst_build_id_ptr"); + DEBUG_INDEX(("offset %x depth %i linku1 %llx start %llx end %llx\n", offset, depth, linku1, start_val, end_val)); + if (end_val <= start_val) { + DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#llx, end:%#llx]\n", start_val, end_val)); + DEBUG_RET(); + return -1; + } + DEBUG_INDEX(("Reading index block\n")); + if (_pst_read_block_size(pf, offset, BLOCK_SIZE, &buf, 0, 0) < BLOCK_SIZE) { + DEBUG_WARN(("Failed to read %i bytes\n", BLOCK_SIZE)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + bptr = buf; + DEBUG_HEXDUMPC(buf, BLOCK_SIZE, ITEM_SIZE); + item_count = (int)(unsigned)(buf[ITEM_COUNT_OFFSET]); + if (item_count > INDEX_COUNT_MAX) { + DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + index.id = _getIntAt(buf+BACKLINK_OFFSET); + if (index.id != linku1) { + DEBUG_WARN(("Backlink %#llx in this node does not match required %#llx\n", index.id, linku1)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + + if (buf[LEVEL_INDICATOR_OFFSET] == '\0') { + // this node contains leaf pointers + x = 0; + while (x < item_count) { + bptr += _pst_decode_index(&index, bptr); + x++; + if (index.id == 0) break; + DEBUG_INDEX(("[%i]%i Item [id = %#x, offset = %#x, u1 = %#x, size = %i(%#x)]\n", + depth, x, index.id, index.offset, index.u1, index.size, index.size)); + // if (index.id & 0x02) DEBUG_INDEX(("two-bit set!!\n")); + if ((index.id >= end_val) || (index.id < old)) { + DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + old = index.id; + if (x == 1) { // first entry + if ((start_val) && (index.id != start_val)) { + DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + } + i_ptr = (pst_index_ll*) xmalloc(sizeof(pst_index_ll)); + i_ptr->id = index.id; + i_ptr->offset = index.offset; + i_ptr->u1 = index.u1; + i_ptr->size = index.size; + i_ptr->next = NULL; + if (pf->i_tail) pf->i_tail->next = i_ptr; + if (!pf->i_head) pf->i_head = i_ptr; + pf->i_tail = i_ptr; + } + } else { + // this node contains node pointers + x = 0; + while (x < item_count) { + bptr += _pst_decode_table(&table, bptr); + x++; + if (table.start == 0) break; + if (x < item_count) { + _pst_decode_table(&table2, bptr); + } + else { + table2.start = end_val; + } + DEBUG_INDEX(("[%i] %i Index Table [start id = %#x, u1 = %#x, offset = %#x, end id = %#x]\n", + depth, x, table.start, table.u1, table.offset, table2.start)); + if ((table.start >= end_val) || (table.start < old)) { + DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + old = table.start; + if (x == 1) { // first entry + if ((start_val) && (table.start != start_val)) { + DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + } + _pst_build_id_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start); + } + } + if (buf) free (buf); + DEBUG_RET(); + return 0; } /** this list node type is used for a quick cache - of the descriptor tree nodes (rooted at pf->d_head) - and for a "lost and found" list. - If the parent isn't found yet, put it on the lost and found - list and check it each time you read a new item. + of the descriptor tree nodes (rooted at pf->d_head) + and for a "lost and found" list. + If the parent isn't found yet, put it on the lost and found + list and check it each time you read a new item. */ struct cache_list_node { - pst_desc_ll *ptr; - /** only used for lost and found lists */ - u_int32_t parent; - struct cache_list_node *next; - struct cache_list_node *prev; + pst_desc_ll *ptr; + /** only used for lost and found lists */ + uint32_t parent; + struct cache_list_node *next; + struct cache_list_node *prev; }; struct cache_list_node *cache_head; struct cache_list_node *cache_tail; struct cache_list_node *lostfound_head; int32_t cache_count; /** - add the d_ptr descriptor into the global tree + add the d_ptr descriptor into the global tree */ -void record_descriptor(pst_file *pf, pst_desc_ll *d_ptr, u_int32_t parent_id) { - struct cache_list_node *lostfound_ptr = NULL; - struct cache_list_node *cache_ptr = NULL; - pst_desc_ll *parent = NULL; - - if (parent_id == 0 || parent_id == d_ptr->id) { - // add top level node to the descriptor tree - if (parent_id == 0) { - DEBUG_INDEX(("No Parent\n")); - } else { - DEBUG_INDEX(("Record is its own parent. What is this world coming to?\n")); - } - if (pf->d_tail) pf->d_tail->next = d_ptr; - if (!pf->d_head) pf->d_head = d_ptr; - d_ptr->prev = pf->d_tail; - pf->d_tail = d_ptr; - } else { - DEBUG_INDEX(("Searching for parent\n")); - // check in the cache for the parent - cache_ptr = cache_head; - while (cache_ptr && (cache_ptr->ptr->id != parent_id)) { - cache_ptr = cache_ptr->next; - } - if (!cache_ptr && (parent = _pst_getDptr(pf, parent_id)) == NULL) { - // check in the lost/found list - lostfound_ptr = lostfound_head; - while (lostfound_ptr && (lostfound_ptr->ptr->id != parent_id)) { - lostfound_ptr = lostfound_ptr->next; - } - if (!lostfound_ptr) { - DEBUG_WARN(("ERROR -- cannot find parent with id %#x. Adding to lost/found\n", parent_id)); - lostfound_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node)); - lostfound_ptr->prev = NULL; - lostfound_ptr->next = lostfound_head; - lostfound_ptr->parent = parent_id; - lostfound_ptr->ptr = d_ptr; - lostfound_head = lostfound_ptr; - } else { - parent = lostfound_ptr->ptr; - DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", parent->id)); - } - } - - if (cache_ptr || parent) { - if (cache_ptr) - // parent is already in the cache - parent = cache_ptr->ptr; - else { - //add the parent to the cache - DEBUG_INDEX(("Cache addition\n")); - cache_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node)); - cache_ptr->prev = NULL; - cache_ptr->next = cache_head; - cache_ptr->ptr = parent; - cache_head = cache_ptr; - if (!cache_tail) cache_tail = cache_ptr; - cache_count++; - if (cache_count > 100) { - DEBUG_INDEX(("trimming quick cache\n")); - //remove one from the end - cache_ptr = cache_tail; - cache_tail = cache_ptr->prev; - free (cache_ptr); - cache_count--; - } - } - DEBUG_INDEX(("Found a parent\n")); - parent->no_child++; - d_ptr->parent = parent; - if (parent->child_tail) parent->child_tail->next = d_ptr; - if (!parent->child) parent->child = d_ptr; - d_ptr->prev = parent->child_tail; - parent->child_tail = d_ptr; - } - } +void record_descriptor(pst_file *pf, pst_desc_ll *d_ptr, uint32_t parent_id) { + struct cache_list_node *lostfound_ptr = NULL; + struct cache_list_node *cache_ptr = NULL; + pst_desc_ll *parent = NULL; + + if (parent_id == 0 || parent_id == d_ptr->id) { + // add top level node to the descriptor tree + if (parent_id == 0) { + DEBUG_INDEX(("No Parent\n")); + } else { + DEBUG_INDEX(("Record is its own parent. What is this world coming to?\n")); + } + if (pf->d_tail) pf->d_tail->next = d_ptr; + if (!pf->d_head) pf->d_head = d_ptr; + d_ptr->prev = pf->d_tail; + pf->d_tail = d_ptr; + } else { + DEBUG_INDEX(("Searching for parent\n")); + // check in the cache for the parent + cache_ptr = cache_head; + while (cache_ptr && (cache_ptr->ptr->id != parent_id)) { + cache_ptr = cache_ptr->next; + } + if (!cache_ptr && (parent = _pst_getDptr(pf, parent_id)) == NULL) { + // check in the lost/found list + lostfound_ptr = lostfound_head; + while (lostfound_ptr && (lostfound_ptr->ptr->id != parent_id)) { + lostfound_ptr = lostfound_ptr->next; + } + if (!lostfound_ptr) { + DEBUG_WARN(("ERROR -- cannot find parent with id %#x. Adding to lost/found\n", parent_id)); + lostfound_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node)); + lostfound_ptr->prev = NULL; + lostfound_ptr->next = lostfound_head; + lostfound_ptr->parent = parent_id; + lostfound_ptr->ptr = d_ptr; + lostfound_head = lostfound_ptr; + } else { + parent = lostfound_ptr->ptr; + DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", parent->id)); + } + } + + if (cache_ptr || parent) { + if (cache_ptr) + // parent is already in the cache + parent = cache_ptr->ptr; + else { + //add the parent to the cache + DEBUG_INDEX(("Cache addition\n")); + cache_ptr = (struct cache_list_node*) xmalloc(sizeof(struct cache_list_node)); + cache_ptr->prev = NULL; + cache_ptr->next = cache_head; + cache_ptr->ptr = parent; + cache_head = cache_ptr; + if (!cache_tail) cache_tail = cache_ptr; + cache_count++; + if (cache_count > 100) { + DEBUG_INDEX(("trimming quick cache\n")); + //remove one from the end + cache_ptr = cache_tail; + cache_tail = cache_ptr->prev; + free (cache_ptr); + cache_count--; + } + } + DEBUG_INDEX(("Found a parent\n")); + parent->no_child++; + d_ptr->parent = parent; + if (parent->child_tail) parent->child_tail->next = d_ptr; + if (!parent->child) parent->child = d_ptr; + d_ptr->prev = parent->child_tail; + parent->child_tail = d_ptr; + } + } } -int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t *high_id, u_int32_t start_val, u_int32_t end_val) { - struct _pst_table_ptr_struct table, table2; - pst_desc desc_rec; - pst_desc_ll *d_ptr=NULL, *parent=NULL; - int32_t x, item_count; - u_int32_t old = start_val; - char *buf = NULL, *bptr; - struct cache_list_node *cache_ptr = NULL; - struct cache_list_node *lostfound_ptr = NULL; - struct cache_list_node *lostfound_shd = NULL; - struct cache_list_node *lostfound_tmp = NULL; - - if (depth == 0) { - // initialize the linked list and lost/found list. - cache_head = NULL; - cache_tail = NULL; - lostfound_head = NULL; - cache_count = 0; - } - - DEBUG_ENT("_pst_build_desc_ptr"); - DEBUG_INDEX(("offset %x depth %i linku1 %x start %x end %x\n", offset, depth, linku1, start_val, end_val)); - if (end_val <= start_val) { - DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#x, end:%#x]\n", start_val, end_val)); - DEBUG_RET(); - return -1; - } - DEBUG_INDEX(("Reading desc block\n")); - if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { - DEBUG_WARN(("Failed to read %i bytes\n", DESC_BLOCK_SIZE)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - bptr = buf; - item_count = (int)(unsigned)(buf[ITEM_COUNT_OFFSET]); - memcpy(&desc_rec.d_id, buf+BACKLINK_OFFSET, sizeof(u_int32_t)); // for valgrind, only have 3 ints here, not 4 - LE32_CPU(desc_rec.d_id); - if (desc_rec.d_id != linku1) { - DEBUG_WARN(("Backlink %#x in this node does not match required %#x\n", desc_rec.d_id, linku1)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - if (buf[LEVEL_INDICATOR_OFFSET] == '\0') { - // this node contains leaf pointers - DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); - if (item_count > DESC_COUNT_MAX) { - DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, DESC_COUNT_MAX)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - x = 0; - while (x < item_count) { - memcpy(&desc_rec, bptr, sizeof(desc_rec)); - LE32_CPU(desc_rec.d_id); - LE32_CPU(desc_rec.desc_id); - LE32_CPU(desc_rec.list_id); - LE32_CPU(desc_rec.parent_id); - bptr+= sizeof(desc_rec); - x++; - if (desc_rec.d_id == 0) break; - DEBUG_INDEX(("[%i] Item(%#x) = [d_id = %#x, desc_id = %#x, list_id = %#x, parent_id = %#x]\n", - depth, x, desc_rec.d_id, desc_rec.desc_id, desc_rec.list_id, desc_rec.parent_id)); - if ((desc_rec.d_id >= end_val) || (desc_rec.d_id < old)) { - DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); - DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - old = desc_rec.d_id; - if (x == 1) { // first entry - if (start_val && (desc_rec.d_id != start_val)) { - DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - } - // When duplicates found, just update the info.... perhaps this is correct functionality - DEBUG_INDEX(("Searching for existing record\n")); - if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id))) { - DEBUG_INDEX(("Updating Existing Values\n")); - d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); - d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); - DEBUG_INDEX(("\tdesc = %#x\tlist_index=%#x\n", - (d_ptr->desc==NULL?0:d_ptr->desc->id), - (d_ptr->list_index==NULL?0:d_ptr->list_index->id))); - if (d_ptr->parent && desc_rec.parent_id != d_ptr->parent->id) { - DEBUG_INDEX(("WARNING -- Parent of record has changed. Moving it\n")); - //hmmm, we must move the record. - // first we must remove from current location - // change previous record to point next to our next - // if no previous, then use parent's child - // if no parent then change pf->d_head; - // change next's prev to our prev - // if no next then change parent's child_tail - // if no parent then change pf->d_tail - if (d_ptr->prev) - d_ptr->prev->next = d_ptr->next; - else if (d_ptr->parent) - d_ptr->parent->child = d_ptr->next; - else - pf->d_head = d_ptr->next; - - if (d_ptr->next) - d_ptr->next->prev = d_ptr->prev; - else if (d_ptr->parent) - d_ptr->parent->child_tail = d_ptr->prev; - else - pf->d_tail = d_ptr->prev; - - d_ptr->prev = NULL; - d_ptr->next = NULL; - d_ptr->parent = NULL; - record_descriptor(pf, d_ptr, desc_rec.parent_id); // add to the global tree - } - } else { - if (*high_id < desc_rec.d_id) { - DEBUG_INDEX(("Updating New High\n")); - *high_id = desc_rec.d_id; - } - DEBUG_INDEX(("New Record\n")); - d_ptr = (pst_desc_ll*) xmalloc(sizeof(pst_desc_ll)); - d_ptr->id = desc_rec.d_id; - d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); - d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); - d_ptr->prev = NULL; - d_ptr->next = NULL; - d_ptr->parent = NULL; - d_ptr->child = NULL; - d_ptr->child_tail = NULL; - d_ptr->no_child = 0; - record_descriptor(pf, d_ptr, desc_rec.parent_id); // add to the global tree - - } - // check here to see if d_ptr is the parent of any of the items in the lost / found list - lostfound_ptr = lostfound_head; - lostfound_shd = NULL; - while (lostfound_ptr) { - if (lostfound_ptr->parent == d_ptr->id) { - DEBUG_INDEX(("Found a child (%#x) of the current record. Joining to main structure.\n", lostfound_ptr->ptr->id)); - parent = d_ptr; - d_ptr = lostfound_ptr->ptr; - parent->no_child++; - d_ptr->parent = parent; - if (parent->child_tail) parent->child_tail->next = d_ptr; - if (!parent->child) parent->child = d_ptr; - d_ptr->prev = parent->child_tail; - parent->child_tail = d_ptr; - if (!lostfound_shd) lostfound_head = lostfound_ptr->next; - else lostfound_shd->next = lostfound_ptr->next; - lostfound_tmp = lostfound_ptr->next; - free(lostfound_ptr); - lostfound_ptr = lostfound_tmp; - } else { - lostfound_shd = lostfound_ptr; - lostfound_ptr = lostfound_ptr->next; - } - } - } - } else { - // this node contains node pointers - DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, ITEM_SIZE); - if (item_count > INDEX_COUNT_MAX) { - DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX)); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - x = 0; - while (x < item_count) { - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr += sizeof(table); - x++; - if (table.start == 0) break; - if (x < item_count) { - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - } - else { - table2.start = end_val; - } - DEBUG_INDEX(("[%i] %i Descriptor Table [start id = %#x, u1 = %#x, offset = %#x, end id = %#x]\n", - depth, x, table.start, table.u1, table.offset, table2.start)); - if ((table.start >= end_val) || (table.start < old)) { - DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - old = table.start; - if (x == 1) { // first entry - if (start_val != -1 && table.start != start_val) { - DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); - if (buf) free(buf); - DEBUG_RET(); - return -1; - } - } - _pst_build_desc_ptr(pf, table.offset, depth+1, table.u1, high_id, table.start, table2.start); - } - } - if (depth == 0) { - // free the quick cache - while (cache_head) { - cache_ptr = cache_head->next; - free(cache_head); - cache_head = cache_ptr; - } - // free the lost and found - while (lostfound_head) { - lostfound_ptr = lostfound_head->next; - WARN(("unused lost/found item with parent %d))", lostfound_head->parent)); - free(lostfound_head); - lostfound_head = lostfound_ptr; - } - } - if (buf) free(buf); - DEBUG_RET(); - return 0; +int32_t _pst_build_desc_ptr (pst_file *pf, off_t offset, int32_t depth, int64_t linku1, uint64_t *high_id, uint64_t start_val, uint64_t end_val) { + struct _pst_table_ptr_structn table, table2; + pst_descn desc_rec; + pst_desc_ll *d_ptr=NULL, *parent=NULL; + int32_t x, item_count; + uint32_t old = start_val; + char *buf = NULL, *bptr; + struct cache_list_node *cache_ptr = NULL; + struct cache_list_node *lostfound_ptr = NULL; + struct cache_list_node *lostfound_shd = NULL; + struct cache_list_node *lostfound_tmp = NULL; + + if (depth == 0) { + // initialize the linked list and lost/found list. + cache_head = NULL; + cache_tail = NULL; + lostfound_head = NULL; + cache_count = 0; + } + + DEBUG_ENT("_pst_build_desc_ptr"); + DEBUG_INDEX(("offset %x depth %i linku1 %x start %x end %x\n", offset, depth, linku1, start_val, end_val)); + if (end_val <= start_val) { + DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#x, end:%#x]\n", start_val, end_val)); + DEBUG_RET(); + return -1; + } + DEBUG_INDEX(("Reading desc block\n")); + if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { + DEBUG_WARN(("Failed to read %i bytes\n", DESC_BLOCK_SIZE)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + bptr = buf; + item_count = (int)(unsigned)(buf[ITEM_COUNT_OFFSET]); + + desc_rec.d_id = _getIntAt(buf+BACKLINK_OFFSET); + if (desc_rec.d_id != linku1) { + DEBUG_WARN(("Backlink %#x in this node does not match required %#x\n", desc_rec.d_id, linku1)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + if (buf[LEVEL_INDICATOR_OFFSET] == '\0') { + // this node contains leaf pointers + DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); + if (item_count > DESC_COUNT_MAX) { + DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, DESC_COUNT_MAX)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + x = 0; + while (x < item_count) { + bptr += _pst_decode_desc(&desc_rec, bptr); + x++; + if (desc_rec.d_id == 0) break; + DEBUG_INDEX(("[%i] Item(%#x) = [d_id = %#x, desc_id = %#x, list_id = %#x, parent_id = %#x]\n", + depth, x, desc_rec.d_id, desc_rec.desc_id, desc_rec.list_id, desc_rec.parent_id)); + if ((desc_rec.d_id >= end_val) || (desc_rec.d_id < old)) { + DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); + DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + old = desc_rec.d_id; + if (x == 1) { // first entry + if (start_val && (desc_rec.d_id != start_val)) { + DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + } + // When duplicates found, just update the info.... perhaps this is correct functionality + DEBUG_INDEX(("Searching for existing record\n")); + if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id))) { + DEBUG_INDEX(("Updating Existing Values\n")); + d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); + d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); + DEBUG_INDEX(("\tdesc = %#x\tlist_index=%#x\n", + (d_ptr->desc==NULL?0:d_ptr->desc->id), + (d_ptr->list_index==NULL?0:d_ptr->list_index->id))); + if (d_ptr->parent && desc_rec.parent_id != d_ptr->parent->id) { + DEBUG_INDEX(("WARNING -- Parent of record has changed. Moving it\n")); + //hmmm, we must move the record. + // first we must remove from current location + // change previous record to point next to our next + // if no previous, then use parent's child + // if no parent then change pf->d_head; + // change next's prev to our prev + // if no next then change parent's child_tail + // if no parent then change pf->d_tail + if (d_ptr->prev) + d_ptr->prev->next = d_ptr->next; + else if (d_ptr->parent) + d_ptr->parent->child = d_ptr->next; + else + pf->d_head = d_ptr->next; + + if (d_ptr->next) + d_ptr->next->prev = d_ptr->prev; + else if (d_ptr->parent) + d_ptr->parent->child_tail = d_ptr->prev; + else + pf->d_tail = d_ptr->prev; + + d_ptr->prev = NULL; + d_ptr->next = NULL; + d_ptr->parent = NULL; + record_descriptor(pf, d_ptr, desc_rec.parent_id); // add to the global tree + } + } else { + if (*high_id < desc_rec.d_id) { + DEBUG_INDEX(("Updating New High\n")); + *high_id = desc_rec.d_id; + } + DEBUG_INDEX(("New Record\n")); + d_ptr = (pst_desc_ll*) xmalloc(sizeof(pst_desc_ll)); + d_ptr->id = desc_rec.d_id; + d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); + d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); + d_ptr->prev = NULL; + d_ptr->next = NULL; + d_ptr->parent = NULL; + d_ptr->child = NULL; + d_ptr->child_tail = NULL; + d_ptr->no_child = 0; + record_descriptor(pf, d_ptr, desc_rec.parent_id); // add to the global tree + + } + // check here to see if d_ptr is the parent of any of the items in the lost / found list + lostfound_ptr = lostfound_head; + lostfound_shd = NULL; + while (lostfound_ptr) { + if (lostfound_ptr->parent == d_ptr->id) { + DEBUG_INDEX(("Found a child (%#x) of the current record. Joining to main structure.\n", lostfound_ptr->ptr->id)); + parent = d_ptr; + d_ptr = lostfound_ptr->ptr; + parent->no_child++; + d_ptr->parent = parent; + if (parent->child_tail) parent->child_tail->next = d_ptr; + if (!parent->child) parent->child = d_ptr; + d_ptr->prev = parent->child_tail; + parent->child_tail = d_ptr; + if (!lostfound_shd) lostfound_head = lostfound_ptr->next; + else lostfound_shd->next = lostfound_ptr->next; + lostfound_tmp = lostfound_ptr->next; + free(lostfound_ptr); + lostfound_ptr = lostfound_tmp; + } else { + lostfound_shd = lostfound_ptr; + lostfound_ptr = lostfound_ptr->next; + } + } + } + } else { + // this node contains node pointers + DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, ITEM_SIZE); + if (item_count > INDEX_COUNT_MAX) { + DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX)); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + x = 0; + while (x < item_count) { + bptr+=_pst_decode_table(&table, bptr); + x++; + if (table.start == 0) break; + if (x < item_count) { + _pst_decode_table(&table2, bptr); + } + else { + table2.start = end_val; + } + DEBUG_INDEX(("[%i] %i Descriptor Table [start id = %#x, u1 = %#x, offset = %#x, end id = %#x]\n", + depth, x, table.start, table.u1, table.offset, table2.start)); + if ((table.start >= end_val) || (table.start < old)) { + DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + old = table.start; + if (x == 1) { // first entry + if (start_val != -1 && table.start != start_val) { + DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + } + _pst_build_desc_ptr(pf, table.offset, depth+1, table.u1, high_id, table.start, table2.start); + } + } + if (depth == 0) { + // free the quick cache + while (cache_head) { + cache_ptr = cache_head->next; + free(cache_head); + cache_head = cache_ptr; + } + // free the lost and found + while (lostfound_head) { + lostfound_ptr = lostfound_head->next; + WARN(("unused lost/found item with parent %d))", lostfound_head->parent)); + free(lostfound_head); + lostfound_head = lostfound_ptr; + } + } + if (buf) free(buf); + DEBUG_RET(); + return 0; } void* _pst_parse_item(pst_file *pf, pst_desc_ll *d_ptr) { - pst_num_array * list; - pst_index2_ll *id2_head = NULL; - pst_index_ll *id_ptr = NULL; - pst_item *item = NULL; - pst_item_attach *attach = NULL; - int x; - DEBUG_ENT("_pst_parse_item"); - if (!d_ptr) { - DEBUG_WARN(("you cannot pass me a NULL! I don't want it!\n")); - DEBUG_RET(); - return NULL; - } - - if (!d_ptr->desc) { - DEBUG_WARN(("why is d_ptr->desc == NULL? I don't want to do anything else with this record\n")); - DEBUG_RET(); - return NULL; - } - - if (d_ptr->list_index) { - id2_head = _pst_build_id2(pf, d_ptr->list_index, NULL); - _pst_printID2ptr(id2_head); - } else { - DEBUG_WARN(("Have not been able to fetch any id2 values for this item. Brace yourself!\n")); - } - - list = _pst_parse_block(pf, d_ptr->desc->id, id2_head); - if (!list) { - DEBUG_WARN(("_pst_parse_block() returned an error for d_ptr->desc->id [%#x]\n", d_ptr->desc->id)); - if (id2_head) _pst_free_id2(id2_head); - DEBUG_RET(); - return NULL; - } - - item = (pst_item*) xmalloc(sizeof(pst_item)); - memset(item, 0, sizeof(pst_item)); - - if (_pst_process(list, item, NULL)) { - DEBUG_WARN(("_pst_process() returned non-zero value. That is an error\n")); - if (item) _pst_freeItem(item); - if (list) _pst_free_list(list); - if (id2_head) _pst_free_id2(id2_head); - DEBUG_RET(); - return NULL; - } - if (list) _pst_free_list(list); - list = NULL; //_pst_process will free the items in the list - - if ((id_ptr = _pst_getID2(id2_head, 0x671))) { - // attachments exist - so we will process them - while (item->attach) { - attach = item->attach->next; - free(item->attach); - item->attach = attach; - } - - DEBUG_EMAIL(("ATTACHMENT processing attachment\n")); - if ((list = _pst_parse_block(pf, id_ptr->id, id2_head)) == NULL) { - DEBUG_WARN(("ERROR error processing main attachment record\n")); - if (item) _pst_freeItem(item); - if (id2_head) _pst_free_id2(id2_head); - DEBUG_RET(); - return NULL; - } - else { - x = 0; - while (x < list->count_array) { - attach = (pst_item_attach*) xmalloc (sizeof(pst_item_attach)); - memset (attach, 0, sizeof(pst_item_attach)); - attach->next = item->attach; - item->attach = attach; - x++; - } - - if (_pst_process(list, item, item->attach)) { - DEBUG_WARN(("ERROR _pst_process() failed with attachments\n")); - if (item) _pst_freeItem(item); - if (list) _pst_free_list(list); - if (id2_head) _pst_free_id2(id2_head); - DEBUG_RET(); - return NULL; - } - if (list) _pst_free_list(list); - list = NULL; - - // now we will have initial information of each attachment stored in item->attach... - // we must now read the secondary record for each based on the id2 val associated with - // each attachment - attach = item->attach; - while (attach) { - if ((id_ptr = _pst_getID2(id2_head, attach->id2_val))) { - // id_ptr is a record describing the attachment - // we pass NULL instead of id2_head cause we don't want it to - // load all the extra stuff here. - if ((list = _pst_parse_block(pf, id_ptr->id, NULL)) == NULL) { - DEBUG_WARN(("ERROR error processing an attachment record\n")); - attach = attach->next; - continue; - } - if (_pst_process(list, item, attach)) { - DEBUG_WARN(("ERROR _pst_process() failed with an attachment\n")); - if (list) _pst_free_list(list); - list = NULL; - attach = attach->next; - continue; - } - if (list) _pst_free_list(list); - list = NULL; - id_ptr = _pst_getID2(id2_head, attach->id2_val); - if (id_ptr) { - // id2_val has been updated to the ID2 value of the datablock containing the - // attachment data - attach->id_val = id_ptr->id; - } else { - DEBUG_WARN(("have not located the correct value for the attachment [%#x]\n", attach->id2_val)); - } - } else { - DEBUG_WARN(("ERROR cannot locate id2 value %#x\n", attach->id2_val)); - } - attach = attach->next; - } - } - } - - _pst_free_id2(id2_head); - id2_head = NULL; - DEBUG_RET(); - return item; + pst_num_array * list; + pst_index2_ll *id2_head = NULL; + pst_index_ll *id_ptr = NULL; + pst_item *item = NULL; + pst_item_attach *attach = NULL; + int x; + DEBUG_ENT("_pst_parse_item"); + if (!d_ptr) { + DEBUG_WARN(("you cannot pass me a NULL! I don't want it!\n")); + DEBUG_RET(); + return NULL; + } + + if (!d_ptr->desc) { + DEBUG_WARN(("why is d_ptr->desc == NULL? I don't want to do anything else with this record\n")); + DEBUG_RET(); + return NULL; + } + + if (d_ptr->list_index) { + id2_head = _pst_build_id2(pf, d_ptr->list_index, NULL); + _pst_printID2ptr(id2_head); + } else { + DEBUG_WARN(("Have not been able to fetch any id2 values for this item. Brace yourself!\n")); + } + + list = _pst_parse_block(pf, d_ptr->desc->id, id2_head); + if (!list) { + DEBUG_WARN(("_pst_parse_block() returned an error for d_ptr->desc->id [%#x]\n", d_ptr->desc->id)); + if (id2_head) _pst_free_id2(id2_head); + DEBUG_RET(); + return NULL; + } + + item = (pst_item*) xmalloc(sizeof(pst_item)); + memset(item, 0, sizeof(pst_item)); + + if (_pst_process(list, item, NULL)) { + DEBUG_WARN(("_pst_process() returned non-zero value. That is an error\n")); + if (item) _pst_freeItem(item); + if (list) _pst_free_list(list); + if (id2_head) _pst_free_id2(id2_head); + DEBUG_RET(); + return NULL; + } + if (list) _pst_free_list(list); + list = NULL; //_pst_process will free the items in the list + + if ((id_ptr = _pst_getID2(id2_head, 0x671))) { + // attachments exist - so we will process them + while (item->attach) { + attach = item->attach->next; + free(item->attach); + item->attach = attach; + } + + DEBUG_EMAIL(("ATTACHMENT processing attachment\n")); + if ((list = _pst_parse_block(pf, id_ptr->id, id2_head)) == NULL) { + DEBUG_WARN(("ERROR error processing main attachment record\n")); + if (item) _pst_freeItem(item); + if (id2_head) _pst_free_id2(id2_head); + DEBUG_RET(); + return NULL; + } + else { + x = 0; + while (x < list->count_array) { + attach = (pst_item_attach*) xmalloc (sizeof(pst_item_attach)); + memset (attach, 0, sizeof(pst_item_attach)); + attach->next = item->attach; + item->attach = attach; + x++; + } + + if (_pst_process(list, item, item->attach)) { + DEBUG_WARN(("ERROR _pst_process() failed with attachments\n")); + if (item) _pst_freeItem(item); + if (list) _pst_free_list(list); + if (id2_head) _pst_free_id2(id2_head); + DEBUG_RET(); + return NULL; + } + if (list) _pst_free_list(list); + list = NULL; + + // now we will have initial information of each attachment stored in item->attach... + // we must now read the secondary record for each based on the id2 val associated with + // each attachment + attach = item->attach; + while (attach) { + if ((id_ptr = _pst_getID2(id2_head, attach->id2_val))) { + // id_ptr is a record describing the attachment + // we pass NULL instead of id2_head cause we don't want it to + // load all the extra stuff here. + if ((list = _pst_parse_block(pf, id_ptr->id, NULL)) == NULL) { + DEBUG_WARN(("ERROR error processing an attachment record\n")); + attach = attach->next; + continue; + } + if (_pst_process(list, item, attach)) { + DEBUG_WARN(("ERROR _pst_process() failed with an attachment\n")); + if (list) _pst_free_list(list); + list = NULL; + attach = attach->next; + continue; + } + if (list) _pst_free_list(list); + list = NULL; + id_ptr = _pst_getID2(id2_head, attach->id2_val); + if (id_ptr) { + // id2_val has been updated to the ID2 value of the datablock containing the + // attachment data + attach->id_val = id_ptr->id; + } else { + DEBUG_WARN(("have not located the correct value for the attachment [%#x]\n", attach->id2_val)); + } + } else { + DEBUG_WARN(("ERROR cannot locate id2 value %#x\n", attach->id2_val)); + } + attach = attach->next; + } + } + } + + _pst_free_id2(id2_head); + id2_head = NULL; + DEBUG_RET(); + return item; } void freeall(unsigned char *buf, pst_block_offset_pointer *p1, - pst_block_offset_pointer *p2, - pst_block_offset_pointer *p3, - pst_block_offset_pointer *p4, - pst_block_offset_pointer *p5, - pst_block_offset_pointer *p6, - pst_block_offset_pointer *p7) { - if (buf) free(buf); - if (p1->needfree) free(p1->from); - if (p2->needfree) free(p2->from); - if (p3->needfree) free(p3->from); - if (p4->needfree) free(p4->from); - if (p5->needfree) free(p5->from); - if (p6->needfree) free(p6->from); - if (p7->needfree) free(p7->from); + pst_block_offset_pointer *p2, + pst_block_offset_pointer *p3, + pst_block_offset_pointer *p4, + pst_block_offset_pointer *p5, + pst_block_offset_pointer *p6, + pst_block_offset_pointer *p7) { + if (buf) free(buf); + if (p1->needfree) free(p1->from); + if (p2->needfree) free(p2->from); + if (p3->needfree) free(p3->from); + if (p4->needfree) free(p4->from); + if (p5->needfree) free(p5->from); + if (p6->needfree) free(p6->from); + if (p7->needfree) free(p7->from); } -pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head) { - unsigned char *buf = NULL; - pst_num_array *na_ptr = NULL, *na_head = NULL; - pst_block_offset_pointer block_offset1; - pst_block_offset_pointer block_offset2; - pst_block_offset_pointer block_offset3; - pst_block_offset_pointer block_offset4; - pst_block_offset_pointer block_offset5; - pst_block_offset_pointer block_offset6; - pst_block_offset_pointer block_offset7; - u_int32_t size; - u_int32_t x; - u_int32_t num_recs; - u_int32_t count_rec; - u_int32_t num_list; - u_int32_t cur_list; - u_int32_t block_type; - u_int32_t rec_size = 0; - u_int32_t ind_ptr; - unsigned char* list_start; - unsigned char* t_ptr; - unsigned char* fr_ptr; - unsigned char* to_ptr; - unsigned char* ind2_end; - unsigned char* ind2_ptr = NULL; - size_t read_size=0; - pst_x_attrib_ll *mapptr; - - struct { - u_int16_t type; - u_int16_t ref_type; - u_int32_t value; - } table_rec; //for type 1 (0xBCEC) blocks - struct { - u_int16_t ref_type; - u_int16_t type; - u_int16_t ind2_off; - u_int8_t size; - u_int8_t slot; - } table2_rec; //for type 2 (0x7CEC) blocks - struct { - u_int32_t id; - } table3_rec; //for type 3 (0x0101) blocks - struct { - u_int16_t index_offset; - u_int16_t type; - u_int32_t offset; - } block_hdr; - struct { - unsigned char seven_c; - unsigned char item_count; - u_int16_t u1; - u_int16_t u2; - u_int16_t u3; - u_int16_t rec_size; - u_int32_t b_five_offset; - u_int32_t ind2_offset; - u_int16_t u7; - u_int16_t u8; - } seven_c_blk; - struct _type_d_rec { - u_int32_t id; - u_int32_t u1; - } * type_d_rec; - - DEBUG_ENT("_pst_parse_block"); - if ((read_size = _pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { - WARN(("Error reading block id %#x\n", block_id)); - if (buf) free (buf); - DEBUG_RET(); - return NULL; - } - - block_offset1.needfree = 0; - block_offset2.needfree = 0; - block_offset3.needfree = 0; - block_offset4.needfree = 0; - block_offset5.needfree = 0; - block_offset6.needfree = 0; - block_offset7.needfree = 0; - - memcpy(&block_hdr, buf, sizeof(block_hdr)); - LE16_CPU(block_hdr.index_offset); - LE16_CPU(block_hdr.type); - LE32_CPU(block_hdr.offset); - DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); - - ind_ptr = block_hdr.index_offset; - - if (block_hdr.type == 0xBCEC) { //type 1 - block_type = 1; - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset1)) { - DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - memcpy(&table_rec, block_offset1.from, sizeof(table_rec)); - LE16_CPU(table_rec.type); - LE16_CPU(table_rec.ref_type); - LE32_CPU(table_rec.value); - DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value)); - - if (table_rec.type != 0x02B5) { - WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id)); - DEBUG_HEXDUMPC(buf, sizeof(table_rec), 0x10); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset2)) { - DEBUG_WARN(("internal error (bc.b5.desc offset) in reading block id %#x\n", table_rec.value, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - list_start = block_offset2.from; - to_ptr = block_offset2.to; - num_list = (to_ptr - list_start)/sizeof(table_rec); - num_recs = 1; // only going to be one object in these blocks - } - else if (block_hdr.type == 0x7CEC) { //type 2 - block_type = 2; - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset3)) { - DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - fr_ptr = block_offset3.from; //now got pointer to "7C block" - memset(&seven_c_blk, 0, sizeof(seven_c_blk)); - memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk)); - LE16_CPU(seven_c_blk.u1); - LE16_CPU(seven_c_blk.u2); - LE16_CPU(seven_c_blk.u3); - LE16_CPU(seven_c_blk.rec_size); - LE32_CPU(seven_c_blk.b_five_offset); - LE32_CPU(seven_c_blk.ind2_offset); - LE16_CPU(seven_c_blk.u7); - LE16_CPU(seven_c_blk.u8); - - list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record - - if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block! - WARN(("Error. There isn't a 7C where I want to see 7C!\n")); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - - rec_size = seven_c_blk.rec_size; - num_list = seven_c_blk.item_count; - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.b_five_offset, &block_offset4)) { - DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#x\n", seven_c_blk.b_five_offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - memcpy(&table_rec, block_offset4.from, sizeof(table_rec)); - LE16_CPU(table_rec.type); - LE16_CPU(table_rec.ref_type); - LE32_CPU(table_rec.value); - - if (table_rec.type != 0x04B5) { // different constant than a type 1 record - WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset5)) { - DEBUG_WARN(("internal error (7c.5b.desc offset %#x) in reading block id %#x\n", table_rec.value, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - num_recs = (block_offset5.to - block_offset5.from) / 6; // this will give the number of records in this block - - if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset6)) { - DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#x\n", seven_c_blk.ind2_offset, block_id)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return NULL; - } - ind2_ptr = block_offset6.from; - ind2_end = block_offset6.to; - } - else if (block_hdr.index_offset == 0x0101) { //type 2 - unsigned char *buf2 = NULL; - int n = block_hdr.type; // count - int m = sizeof(table3_rec); - int i; - block_type = 3; - for (i=0; inext = na_head; - na_head = na_ptr; - // allocate an array of count num_recs to contain sizeof(struct_pst_num_item) - na_ptr->items = (struct _pst_num_item**) xmalloc(sizeof(struct _pst_num_item)*num_list); - na_ptr->count_item = num_list; - na_ptr->orig_count = num_list; - na_ptr->count_array = num_recs; // each record will have a record of the total number of records - for (x=0; xitems[x] = NULL; - x = 0; - - DEBUG_EMAIL(("going to read %i (%#x) items\n", na_ptr->count_item, na_ptr->count_item)); - - fr_ptr = list_start; // initialize fr_ptr to the start of the list. - for (cur_list=0; cur_list= (table2_rec.ind2_off + table2_rec.size)) { - int n = table2_rec.size; - int m = sizeof(table_rec.value); - if (n <= m) { - memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n); - } - else { - value_pointer = ind2_ptr + table2_rec.ind2_off; - value_size = n; - } - //LE32_CPU(table_rec.value); // done later, some may be order invariant - } - else { - DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n", - read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size)); - } - fr_ptr += sizeof(table2_rec); - } else { - WARN(("Missing code for block_type %i\n", block_type)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - if (na_head) _pst_free_list(na_head); - DEBUG_RET(); - return NULL; - } - DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n", - x, table_rec.type, table_rec.ref_type, table_rec.value)); - - if (!na_ptr->items[x]) { - na_ptr->items[x] = (struct _pst_num_item*) xmalloc(sizeof(struct _pst_num_item)); - } - memset(na_ptr->items[x], 0, sizeof(struct _pst_num_item)); //init it - - // check here to see if the id of the attribute is a mapped one - mapptr = pf->x_head; - while (mapptr && (mapptr->map < table_rec.type)) mapptr = mapptr->next; - if (mapptr && (mapptr->map == table_rec.type)) { - if (mapptr->mytype == PST_MAP_ATTRIB) { - na_ptr->items[x]->id = *((int*)mapptr->data); - DEBUG_EMAIL(("Mapped attrib %#x to %#x\n", table_rec.type, na_ptr->items[x]->id)); - } else if (mapptr->mytype == PST_MAP_HEADER) { - DEBUG_EMAIL(("Internet Header mapping found %#x\n", table_rec.type)); - na_ptr->items[x]->id = PST_ATTRIB_HEADER; - na_ptr->items[x]->extra = mapptr->data; - } - } else { - na_ptr->items[x]->id = table_rec.type; - } - na_ptr->items[x]->type = 0; // checked later before it is set - /* Reference Types - 0x0002 - Signed 16bit value - 0x0003 - Signed 32bit value - 0x0004 - 4-byte floating point - 0x0005 - Floating point double - 0x0006 - Signed 64-bit int - 0x0007 - Application Time - 0x000A - 32-bit error value - 0x000B - Boolean (non-zero = true) - 0x000D - Embedded Object - 0x0014 - 8-byte signed integer (64-bit) - 0x001E - Null terminated String - 0x001F - Unicode string - 0x0040 - Systime - Filetime structure - 0x0048 - OLE Guid - 0x0102 - Binary data - 0x1003 - Array of 32bit values - 0x1014 - Array of 64bit values - 0x101E - Array of Strings - 0x1102 - Array of Binary data - */ - - if (table_rec.ref_type == 0x0002 || - table_rec.ref_type == 0x0003 || - table_rec.ref_type == 0x000b) { - //contains 32 bits of data - na_ptr->items[x]->size = sizeof(int32_t); - na_ptr->items[x]->type = table_rec.ref_type; - na_ptr->items[x]->data = xmalloc(sizeof(int32_t)); - memcpy(na_ptr->items[x]->data, &(table_rec.value), sizeof(int32_t)); - - } else if (table_rec.ref_type == 0x0005 || - table_rec.ref_type == 0x000d || - table_rec.ref_type == 0x0014 || - table_rec.ref_type == 0x001e || - table_rec.ref_type == 0x0040 || - table_rec.ref_type == 0x0048 || - table_rec.ref_type == 0x0102 || - table_rec.ref_type == 0x1003 || - table_rec.ref_type == 0x1014 || - table_rec.ref_type == 0x101e || - table_rec.ref_type == 0x1102) { - //contains index reference to data - LE32_CPU(table_rec.value); - if (value_pointer) { - // in a type 2 block, with a value that is more than 4 bytes - // directly stored in this block. - na_ptr->items[x]->size = value_size; - na_ptr->items[x]->type = table_rec.ref_type; - na_ptr->items[x]->data = xmalloc(value_size); - memcpy(na_ptr->items[x]->data, value_pointer, value_size); - } - else if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset7)) { - if ((table_rec.value & 0xf) == 0xf) { - DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value)); - na_ptr->items[x]->size = 0; - na_ptr->items[x]->data = NULL; - na_ptr->items[x]->type = table_rec.value; - } - else { - if (table_rec.value) { - DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value)); - } - na_ptr->count_item --; //we will be skipping a row - continue; - } - } - else { - value_size = block_offset7.to - block_offset7.from; - na_ptr->items[x]->size = value_size; - na_ptr->items[x]->type = table_rec.ref_type; - na_ptr->items[x]->data = xmalloc(value_size+1); - memcpy(na_ptr->items[x]->data, block_offset7.from, value_size); - na_ptr->items[x]->data[value_size] = '\0'; // it might be a string, null terminate it. - } - if (table_rec.ref_type == 0xd) { - // there is still more to do for the type of 0xD - type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data; - LE32_CPU(type_d_rec->id); - na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data)); - if (!na_ptr->items[x]->size){ - DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id)); - na_ptr->items[x]->type = type_d_rec->id; // fetch before freeing data, alias pointer - free(na_ptr->items[x]->data); - na_ptr->items[x]->data = NULL; - } - } - if (na_ptr->items[x]->type == 0) na_ptr->items[x]->type = table_rec.ref_type; - } else { - WARN(("ERROR Unknown ref_type %#x\n", table_rec.ref_type)); - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - if (na_head) _pst_free_list(na_head); - DEBUG_RET(); - return NULL; - } - x++; - } - DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size)); - ind2_ptr += rec_size; - } - freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); - DEBUG_RET(); - return na_head; +pst_num_array * _pst_parse_block(pst_file *pf, uint32_t block_id, pst_index2_ll *i2_head) { + unsigned char *buf = NULL; + pst_num_array *na_ptr = NULL, *na_head = NULL; + pst_block_offset_pointer block_offset1; + pst_block_offset_pointer block_offset2; + pst_block_offset_pointer block_offset3; + pst_block_offset_pointer block_offset4; + pst_block_offset_pointer block_offset5; + pst_block_offset_pointer block_offset6; + pst_block_offset_pointer block_offset7; + uint32_t size; + uint32_t x; + uint32_t num_recs; + uint32_t count_rec; + uint32_t num_list; + uint32_t cur_list; + uint32_t block_type; + uint32_t rec_size = 0; + uint32_t ind_ptr; + unsigned char* list_start; + unsigned char* t_ptr; + unsigned char* fr_ptr; + unsigned char* to_ptr; + unsigned char* ind2_end; + unsigned char* ind2_ptr = NULL; + size_t read_size=0; + pst_x_attrib_ll *mapptr; + + struct { + uint16_t type; + uint16_t ref_type; + uint32_t value; + } table_rec; //for type 1 (0xBCEC) blocks + struct { + uint16_t ref_type; + uint16_t type; + uint16_t ind2_off; + uint8_t size; + uint8_t slot; + } table2_rec; //for type 2 (0x7CEC) blocks + struct { + uint32_t id; + } table3_rec; //for type 3 (0x0101) blocks + struct { + uint16_t index_offset; + uint16_t type; + uint32_t offset; + } block_hdr; + struct { + unsigned char seven_c; + unsigned char item_count; + uint16_t u1; + uint16_t u2; + uint16_t u3; + uint16_t rec_size; + uint32_t b_five_offset; + uint32_t ind2_offset; + uint16_t u7; + uint16_t u8; + } seven_c_blk; + struct _type_d_rec { + uint32_t id; + uint32_t u1; + } * type_d_rec; + + DEBUG_ENT("_pst_parse_block"); + if ((read_size = _pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { + WARN(("Error reading block id %#x\n", block_id)); + if (buf) free (buf); + DEBUG_RET(); + return NULL; + } + + block_offset1.needfree = 0; + block_offset2.needfree = 0; + block_offset3.needfree = 0; + block_offset4.needfree = 0; + block_offset5.needfree = 0; + block_offset6.needfree = 0; + block_offset7.needfree = 0; + + memcpy(&block_hdr, buf, sizeof(block_hdr)); + LE16_CPU(block_hdr.index_offset); + LE16_CPU(block_hdr.type); + LE32_CPU(block_hdr.offset); + DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); + + ind_ptr = block_hdr.index_offset; + + if (block_hdr.type == 0xBCEC) { //type 1 + block_type = 1; + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset1)) { + DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + memcpy(&table_rec, block_offset1.from, sizeof(table_rec)); + LE16_CPU(table_rec.type); + LE16_CPU(table_rec.ref_type); + LE32_CPU(table_rec.value); + DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value)); + + if (table_rec.type != 0x02B5) { + WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id)); + DEBUG_HEXDUMPC(buf, sizeof(table_rec), 0x10); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset2)) { + DEBUG_WARN(("internal error (bc.b5.desc offset) in reading block id %#x\n", table_rec.value, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + list_start = block_offset2.from; + to_ptr = block_offset2.to; + num_list = (to_ptr - list_start)/sizeof(table_rec); + num_recs = 1; // only going to be one object in these blocks + } + else if (block_hdr.type == 0x7CEC) { //type 2 + block_type = 2; + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, block_hdr.offset, &block_offset3)) { + DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#x\n", block_hdr.offset, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + fr_ptr = block_offset3.from; //now got pointer to "7C block" + memset(&seven_c_blk, 0, sizeof(seven_c_blk)); + memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk)); + LE16_CPU(seven_c_blk.u1); + LE16_CPU(seven_c_blk.u2); + LE16_CPU(seven_c_blk.u3); + LE16_CPU(seven_c_blk.rec_size); + LE32_CPU(seven_c_blk.b_five_offset); + LE32_CPU(seven_c_blk.ind2_offset); + LE16_CPU(seven_c_blk.u7); + LE16_CPU(seven_c_blk.u8); + + list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record + + if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block! + WARN(("Error. There isn't a 7C where I want to see 7C!\n")); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + + rec_size = seven_c_blk.rec_size; + num_list = seven_c_blk.item_count; + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.b_five_offset, &block_offset4)) { + DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#x\n", seven_c_blk.b_five_offset, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + memcpy(&table_rec, block_offset4.from, sizeof(table_rec)); + LE16_CPU(table_rec.type); + LE16_CPU(table_rec.ref_type); + LE32_CPU(table_rec.value); + + if (table_rec.type != 0x04B5) { // different constant than a type 1 record + WARN(("Unknown second block constant - %#X for id %#x\n", table_rec.type, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset5)) { + DEBUG_WARN(("internal error (7c.5b.desc offset %#x) in reading block id %#x\n", table_rec.value, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + num_recs = (block_offset5.to - block_offset5.from) / 6; // this will give the number of records in this block + + if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, seven_c_blk.ind2_offset, &block_offset6)) { + DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#x\n", seven_c_blk.ind2_offset, block_id)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return NULL; + } + ind2_ptr = block_offset6.from; + ind2_end = block_offset6.to; + } + else if (block_hdr.index_offset == 0x0101) { //type 2 + unsigned char *buf2 = NULL; + int n = block_hdr.type; // count + int m = sizeof(table3_rec); + int i; + block_type = 3; + for (i=0; inext = na_head; + na_head = na_ptr; + // allocate an array of count num_recs to contain sizeof(struct_pst_num_item) + na_ptr->items = (struct _pst_num_item**) xmalloc(sizeof(struct _pst_num_item)*num_list); + na_ptr->count_item = num_list; + na_ptr->orig_count = num_list; + na_ptr->count_array = num_recs; // each record will have a record of the total number of records + for (x=0; xitems[x] = NULL; + x = 0; + + DEBUG_EMAIL(("going to read %i (%#x) items\n", na_ptr->count_item, na_ptr->count_item)); + + fr_ptr = list_start; // initialize fr_ptr to the start of the list. + for (cur_list=0; cur_list= (table2_rec.ind2_off + table2_rec.size)) { + int n = table2_rec.size; + int m = sizeof(table_rec.value); + if (n <= m) { + memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n); + } + else { + value_pointer = ind2_ptr + table2_rec.ind2_off; + value_size = n; + } + //LE32_CPU(table_rec.value); // done later, some may be order invariant + } + else { + DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n", + read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size)); + } + fr_ptr += sizeof(table2_rec); + } else { + WARN(("Missing code for block_type %i\n", block_type)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + if (na_head) _pst_free_list(na_head); + DEBUG_RET(); + return NULL; + } + DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n", + x, table_rec.type, table_rec.ref_type, table_rec.value)); + + if (!na_ptr->items[x]) { + na_ptr->items[x] = (struct _pst_num_item*) xmalloc(sizeof(struct _pst_num_item)); + } + memset(na_ptr->items[x], 0, sizeof(struct _pst_num_item)); //init it + + // check here to see if the id of the attribute is a mapped one + mapptr = pf->x_head; + while (mapptr && (mapptr->map < table_rec.type)) mapptr = mapptr->next; + if (mapptr && (mapptr->map == table_rec.type)) { + if (mapptr->mytype == PST_MAP_ATTRIB) { + na_ptr->items[x]->id = *((int*)mapptr->data); + DEBUG_EMAIL(("Mapped attrib %#x to %#x\n", table_rec.type, na_ptr->items[x]->id)); + } else if (mapptr->mytype == PST_MAP_HEADER) { + DEBUG_EMAIL(("Internet Header mapping found %#x\n", table_rec.type)); + na_ptr->items[x]->id = PST_ATTRIB_HEADER; + na_ptr->items[x]->extra = mapptr->data; + } + } else { + na_ptr->items[x]->id = table_rec.type; + } + na_ptr->items[x]->type = 0; // checked later before it is set + /* Reference Types + 0x0002 - Signed 16bit value + 0x0003 - Signed 32bit value + 0x0004 - 4-byte floating point + 0x0005 - Floating point double + 0x0006 - Signed 64-bit int + 0x0007 - Application Time + 0x000A - 32-bit error value + 0x000B - Boolean (non-zero = true) + 0x000D - Embedded Object + 0x0014 - 8-byte signed integer (64-bit) + 0x001E - Null terminated String + 0x001F - Unicode string + 0x0040 - Systime - Filetime structure + 0x0048 - OLE Guid + 0x0102 - Binary data + 0x1003 - Array of 32bit values + 0x1014 - Array of 64bit values + 0x101E - Array of Strings + 0x1102 - Array of Binary data + */ + + if (table_rec.ref_type == 0x0002 || + table_rec.ref_type == 0x0003 || + table_rec.ref_type == 0x000b) { + //contains 32 bits of data + na_ptr->items[x]->size = sizeof(int32_t); + na_ptr->items[x]->type = table_rec.ref_type; + na_ptr->items[x]->data = xmalloc(sizeof(int32_t)); + memcpy(na_ptr->items[x]->data, &(table_rec.value), sizeof(int32_t)); + + } else if (table_rec.ref_type == 0x0005 || + table_rec.ref_type == 0x000d || + table_rec.ref_type == 0x0014 || + table_rec.ref_type == 0x001e || + table_rec.ref_type == 0x001f || + table_rec.ref_type == 0x0040 || + table_rec.ref_type == 0x0048 || + table_rec.ref_type == 0x0102 || + table_rec.ref_type == 0x1003 || + table_rec.ref_type == 0x1014 || + table_rec.ref_type == 0x101e || + table_rec.ref_type == 0x1102) { + //contains index reference to data + LE32_CPU(table_rec.value); + if (value_pointer) { + // in a type 2 block, with a value that is more than 4 bytes + // directly stored in this block. + na_ptr->items[x]->size = value_size; + na_ptr->items[x]->type = table_rec.ref_type; + na_ptr->items[x]->data = xmalloc(value_size); + memcpy(na_ptr->items[x]->data, value_pointer, value_size); + } + else if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset7)) { + if ((table_rec.value & 0xf) == 0xf) { + DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value)); + na_ptr->items[x]->size = 0; + na_ptr->items[x]->data = NULL; + na_ptr->items[x]->type = table_rec.value; + } + else { + if (table_rec.value) { + DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value)); + } + na_ptr->count_item --; //we will be skipping a row + continue; + } + } + else { + value_size = block_offset7.to - block_offset7.from; + na_ptr->items[x]->size = value_size; + na_ptr->items[x]->type = table_rec.ref_type; + na_ptr->items[x]->data = xmalloc(value_size+1); + memcpy(na_ptr->items[x]->data, block_offset7.from, value_size); + na_ptr->items[x]->data[value_size] = '\0'; // it might be a string, null terminate it. + } + if (table_rec.ref_type == 0xd) { + // there is still more to do for the type of 0xD embedded objects + type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data; + LE32_CPU(type_d_rec->id); + na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data)); + if (!na_ptr->items[x]->size){ + DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id)); + na_ptr->items[x]->type = type_d_rec->id; // fetch before freeing data, alias pointer + free(na_ptr->items[x]->data); + na_ptr->items[x]->data = NULL; + } + } + if (table_rec.ref_type == 0x1f) { + // there is more to do for the type 0x1f unicode strings + VBUF_STATIC(strbuf, 1024); + VBUF_STATIC(unibuf, 1024); + //need UTF-16 zero-termination + vbset(strbuf, na_ptr->items[x]->data, na_ptr->items[x]->size); + vbappend(strbuf, "\0\0", 2); + DEBUG_INDEX(("Iconv in: ")); + DEBUG_HEXDUMPC(strbuf->b, strbuf->dlen, 0x10); + vb_utf16to8(unibuf, strbuf->b, strbuf->dlen); + free(na_ptr->items[x]->data); + na_ptr->items[x]->size = unibuf->dlen; + na_ptr->items[x]->data = xmalloc(unibuf->dlen); + memcpy(na_ptr->items[x]->data, unibuf->b, unibuf->dlen); + DEBUG_INDEX(("Iconv out: ")); + DEBUG_HEXDUMPC(na_ptr->items[x]->data, na_ptr->items[x]->size, 0x10); + } + if (na_ptr->items[x]->type == 0) na_ptr->items[x]->type = table_rec.ref_type; + } else { + WARN(("ERROR Unknown ref_type %#x\n", table_rec.ref_type)); + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + if (na_head) _pst_free_list(na_head); + DEBUG_RET(); + return NULL; + } + x++; + } + DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size)); + ind2_ptr += rec_size; + } + freeall(buf, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7); + DEBUG_RET(); + return na_head; } // check if item->email is NULL, and init if so -#define MALLOC_EMAIL(x) { if (!x->email) { x->email = (pst_item_email*) xmalloc(sizeof(pst_item_email)); memset(x->email, 0, sizeof(pst_item_email) );} } -#define MALLOC_FOLDER(x) { if (!x->folder) { x->folder = (pst_item_folder*) xmalloc(sizeof(pst_item_folder)); memset(x->folder, 0, sizeof(pst_item_folder) );} } -#define MALLOC_CONTACT(x) { if (!x->contact) { x->contact = (pst_item_contact*) xmalloc(sizeof(pst_item_contact)); memset(x->contact, 0, sizeof(pst_item_contact) );} } +#define MALLOC_EMAIL(x) { if (!x->email) { x->email = (pst_item_email*) xmalloc(sizeof(pst_item_email)); memset(x->email, 0, sizeof(pst_item_email) );} } +#define MALLOC_FOLDER(x) { if (!x->folder) { x->folder = (pst_item_folder*) xmalloc(sizeof(pst_item_folder)); memset(x->folder, 0, sizeof(pst_item_folder) );} } +#define MALLOC_CONTACT(x) { if (!x->contact) { x->contact = (pst_item_contact*) xmalloc(sizeof(pst_item_contact)); memset(x->contact, 0, sizeof(pst_item_contact) );} } #define MALLOC_MESSAGESTORE(x) { if (!x->message_store) { x->message_store = (pst_item_message_store*) xmalloc(sizeof(pst_item_message_store)); memset(x->message_store, 0, sizeof(pst_item_message_store));} } -#define MALLOC_JOURNAL(x) { if (!x->journal) { x->journal = (pst_item_journal*) xmalloc(sizeof(pst_item_journal)); memset(x->journal, 0, sizeof(pst_item_journal) );} } -#define MALLOC_APPOINTMENT(x) { if (!x->appointment) { x->appointment = (pst_item_appointment*) xmalloc(sizeof(pst_item_appointment)); memset(x->appointment, 0, sizeof(pst_item_appointment) );} } +#define MALLOC_JOURNAL(x) { if (!x->journal) { x->journal = (pst_item_journal*) xmalloc(sizeof(pst_item_journal)); memset(x->journal, 0, sizeof(pst_item_journal) );} } +#define MALLOC_APPOINTMENT(x) { if (!x->appointment) { x->appointment = (pst_item_appointment*) xmalloc(sizeof(pst_item_appointment)); memset(x->appointment, 0, sizeof(pst_item_appointment) );} } // malloc space and copy the current item's data null terminated -#define LIST_COPY(targ, type) { \ - targ = type realloc(targ, list->items[x]->size+1); \ - memcpy(targ, list->items[x]->data, list->items[x]->size); \ - memset(((char*)targ)+list->items[x]->size, 0, 1); \ +#define LIST_COPY(targ, type) { \ + targ = type realloc(targ, list->items[x]->size+1); \ + memcpy(targ, list->items[x]->data, list->items[x]->size); \ + memset(((char*)targ)+list->items[x]->size, 0, 1); \ } // malloc space and copy the current item's data and size -#define LIST_COPY_SIZE(targ, type, mysize) { \ - mysize = list->items[x]->size; \ - targ = type realloc(targ, mysize); \ - memcpy(targ, list->items[x]->data, mysize); \ +#define LIST_COPY_SIZE(targ, type, mysize) { \ + mysize = list->items[x]->size; \ + targ = type realloc(targ, mysize); \ + memcpy(targ, list->items[x]->data, mysize); \ } #define NULL_CHECK(x) { if (!x) { DEBUG_EMAIL(("NULL_CHECK: Null Found\n")); break;} } #define MOVE_NEXT(targ) { \ - if (next){\ - if (!targ) {\ - DEBUG_EMAIL(("MOVE_NEXT: Target is NULL. Will stop processing this option\n"));\ - break;\ - }\ - targ = targ->next;\ - if (!targ) {\ - DEBUG_EMAIL(("MOVE_NEXT: Target is NULL after next. Will stop processing this option\n"));\ - break;\ - }\ - next=0;\ - }\ + if (next){\ + if (!targ) {\ + DEBUG_EMAIL(("MOVE_NEXT: Target is NULL. Will stop processing this option\n"));\ + break;\ + }\ + targ = targ->next;\ + if (!targ) {\ + DEBUG_EMAIL(("MOVE_NEXT: Target is NULL after next. Will stop processing this option\n"));\ + break;\ + }\ + next=0;\ + }\ } int32_t _pst_process(pst_num_array *list , pst_item *item, pst_item_attach *attach) { - int32_t x, t; - int32_t next = 0; - pst_item_extra_field *ef; - - DEBUG_ENT("_pst_process"); - if (!item) { - DEBUG_EMAIL(("item cannot be NULL.\n")); - DEBUG_RET(); - return -1; - } - - while (list) { - x = 0; - while (x < list->count_item) { - // check here to see if the id is one that is mapped. - DEBUG_EMAIL(("#%d - id: %#x type: %#x length: %#x\n", x, list->items[x]->id, list->items[x]->type, list->items[x]->size)); - - switch (list->items[x]->id) { - case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers - DEBUG_EMAIL(("Extra Field - ")); - ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field)); - memset(ef, 0, sizeof(pst_item_extra_field)); - ef->field_name = (char*) xmalloc(strlen(list->items[x]->extra)+1); - strcpy(ef->field_name, list->items[x]->extra); - LIST_COPY(ef->value, (char*)); - ef->next = item->extra_fields; - item->extra_fields = ef; - DEBUG_EMAIL(("\"%s\" = \"%s\"\n", ef->field_name, ef->value)); - break; - case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED - // If set to true, the sender allows this email to be autoforwarded - DEBUG_EMAIL(("AutoForward allowed - ")); - MALLOC_EMAIL(item); - if (*((short int*)list->items[x]->data) != 0) { - DEBUG_EMAIL(("True\n")); - item->email->autoforward = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->autoforward = -1; - } - break; - case 0x0003: // Extended Attributes table - DEBUG_EMAIL(("Extended Attributes Table - NOT PROCESSED\n")); - break; - case 0x0017: // PR_IMPORTANCE - // How important the sender deems it to be - // 0 - Low - // 1 - Normal - // 2 - High - - DEBUG_EMAIL(("Importance Level - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->importance), list->items[x]->data, sizeof(item->email->importance)); - LE32_CPU(item->email->importance); - t = item->email->importance; - DEBUG_EMAIL(("%s [%i]\n", (t==0?"Low":(t==1?"Normal":"High")), t)); - break; - case 0x001A: // PR_MESSAGE_CLASS Ascii type of messages - NOT FOLDERS - // must be case insensitive - DEBUG_EMAIL(("IPM.x - ")); - LIST_COPY(item->ascii_type, (char*)); - if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0) - // the string begins with IPM.Note... - item->type = PST_TYPE_NOTE; - else if (pst_stricmp("IPM", item->ascii_type) == 0) - // the whole string is just IPM - item->type = PST_TYPE_NOTE; - else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0) - // the string begins with IPM.Contact... - item->type = PST_TYPE_CONTACT; - else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0) - // the string begins with the above - item->type = PST_TYPE_REPORT; - else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0) - item->type = PST_TYPE_JOURNAL; - else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0) - item->type = PST_TYPE_APPOINTMENT; - else - item->type = PST_TYPE_OTHER; - - DEBUG_EMAIL(("%s\n", item->ascii_type)); - break; - case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED - // set if the sender wants a delivery report from all recipients - DEBUG_EMAIL(("Global Delivery Report - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->delivery_report = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->delivery_report = 0; - } - break; - case 0x0026: // PR_PRIORITY - // Priority of a message - // -1 NonUrgent - // 0 Normal - // 1 Urgent - DEBUG_EMAIL(("Priority - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->priority), list->items[x]->data, sizeof(item->email->priority)); - LE32_CPU(item->email->priority); - t = item->email->priority; - DEBUG_EMAIL(("%s [%i]\n", (t<0?"NonUrgent":(t==0?"Normal":"Urgent")), t)); - break; - case 0x0029:// PR_READ_RECEIPT_REQUESTED - DEBUG_EMAIL(("Read Receipt - ")); - MALLOC_EMAIL(item); - if (*(short int*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->read_receipt = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->read_receipt = 0; - } - break; - case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED - DEBUG_EMAIL(("Reassignment Prohibited (Private) - ")); - if (*(short int*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->private_member = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->private_member = 0; - } - break; - case 0x002E: // PR_ORIGINAL_SENSITIVITY - // the sensitivity of the message before being replied to or forwarded - // 0 - None - // 1 - Personal - // 2 - Private - // 3 - Company Confidential - DEBUG_EMAIL(("Original Sensitivity - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->orig_sensitivity), list->items[x]->data, sizeof(item->email->orig_sensitivity)); - LE32_CPU(item->email->orig_sensitivity); - t = item->email->orig_sensitivity; - DEBUG_EMAIL(("%s [%i]\n", (t==0?"None":(t==1?"Personal": - (t==2?"Private":"Company Confidential"))), t)); - break; - case 0x0036: // PR_SENSITIVITY - // sender's opinion of the sensitivity of an email - // 0 - None - // 1 - Personal - // 2 - Private - // 3 - Company Confidiential - DEBUG_EMAIL(("Sensitivity - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->sensitivity), list->items[x]->data, sizeof(item->email->sensitivity)); - LE32_CPU(item->email->sensitivity); - t = item->email->sensitivity; - DEBUG_EMAIL(("%s [%i]\n", (t==0?"None":(t==1?"Personal": - (t==2?"Private":"Company Confidential"))), t)); - break; - case 0x0037: // PR_SUBJECT raw subject - // if (list->items[x]->id == 0x0037) { - DEBUG_EMAIL(("Raw Subject - ")); - MALLOC_EMAIL(item); - item->email->subject = (pst_item_email_subject*) realloc(item->email->subject, sizeof(pst_item_email_subject)); - memset(item->email->subject, 0, sizeof(pst_item_email_subject)); - DEBUG_EMAIL((" [size = %i] ", list->items[x]->size)); - if (list->items[x]->size > 0) { - if (isprint(list->items[x]->data[0])) { - // then there are no control bytes at the front - item->email->subject->off1 = 0; - item->email->subject->off2 = 0; - item->email->subject->subj = realloc(item->email->subject->subj, list->items[x]->size+1); - memset(item->email->subject->subj, 0, list->items[x]->size+1); - memcpy(item->email->subject->subj, list->items[x]->data, list->items[x]->size); - } else { - DEBUG_EMAIL(("Raw Subject has control codes\n")); - // there might be some control bytes in the first and second bytes - item->email->subject->off1 = list->items[x]->data[0]; - item->email->subject->off2 = list->items[x]->data[1]; - item->email->subject->subj = realloc(item->email->subject->subj, (list->items[x]->size-2)+1); - memset(item->email->subject->subj, 0, list->items[x]->size-1); - memcpy(item->email->subject->subj, &(list->items[x]->data[2]), list->items[x]->size-2); - } - DEBUG_EMAIL(("%s\n", item->email->subject->subj)); - } else { - // obviously outlook has decided not to be straight with this one. - item->email->subject->off1 = 0; - item->email->subject->off2 = 0; - item->email->subject = NULL; - DEBUG_EMAIL(("NULL subject detected\n")); - } - break; - case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created - DEBUG_EMAIL(("Date sent - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sent_date, (FILETIME*)); - LE32_CPU(item->email->sent_date->dwLowDateTime); - LE32_CPU(item->email->sent_date->dwHighDateTime); - DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->sent_date))); - break; - case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1 - DEBUG_EMAIL(("Sent on behalf of address 1 - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->outlook_sender, (char*)); - DEBUG_EMAIL(("%s\n", item->email->outlook_sender)); - break; - case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient - DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n")); - break; - case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure - DEBUG_EMAIL(("Received By Name 1 -- NOT HANDLED\n")); - break; - case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender - DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n")); - break; - case 0x0042: // PR_SENT_REPRESENTING_NAME Name of Sender Structure - DEBUG_EMAIL(("Sent on behalf of Structure Name - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->outlook_sender_name, (char*)); - DEBUG_EMAIL(("%s\n", item->email->outlook_sender_name)); - break; - case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2 - DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n")); - break; - case 0x0044: // PR_RCVD_REPRESENTING_NAME Name of Recipient Structure 2 - DEBUG_EMAIL(("Received on behalf of Structure Name -- NOT HANDLED\n")); - break; - case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure - DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n")); - break; - case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure - DEBUG_EMAIL(("Name of Reply-To Structure -")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->reply_to, (char*)); - DEBUG_EMAIL(("%s\n", item->email->reply_to)); - break; - case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1 - DEBUG_EMAIL(("Recipient's Address 1 (Search Key) - ")); - MALLOC_EMAIL(item); - LIST_COPY (item->email->outlook_recipient, (char*)); - DEBUG_EMAIL(("%s\n", item->email->outlook_recipient)); - break; - case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2 - DEBUG_EMAIL(("Received on behalf of Address (Search Key) - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->outlook_recipient2, (char*)); - DEBUG_EMAIL(("%s\n", item->email->outlook_recipient2)); - break; - case 0x0057: // PR_MESSAGE_TO_ME - // this user is listed explicitly in the TO address - DEBUG_EMAIL(("My address in TO field - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->message_to_me = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->message_to_me = 0; - } - break; - case 0x0058: // PR_MESSAGE_CC_ME - // this user is listed explicitly in the CC address - DEBUG_EMAIL(("My address in CC field - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->message_cc_me = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->message_cc_me = 0; - } - break; - case 0x0059: //PR_MESSAGE_RECIP_ME - // this user appears in TO, CC or BCC address list - DEBUG_EMAIL(("Message addressed to me - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->message_recip_me = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->message_recip_me = 0; - } - break; - case 0x0063: // PR_RESPONSE_REQUESTED - DEBUG_EMAIL(("Response requested - ")); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->response_requested = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->response_requested = 0; - } - break; - case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address - DEBUG_EMAIL(("Sent on behalf of address type - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sender_access, (char*)); - DEBUG_EMAIL(("%s\n", item->email->sender_access)); - break; - case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address - DEBUG_EMAIL(("Sent on behalf of Address - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sender_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->sender_address)); - break; - case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject - DEBUG_EMAIL(("Processed Subject (Conversation Topic) - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->proc_subject, (char*)); - DEBUG_EMAIL(("%s\n", item->email->proc_subject)); - break; - case 0x0071: // PR_CONVERSATION_INDEX Date 2 - DEBUG_EMAIL(("Conversation Index - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->conv_index), list->items[x]->data, sizeof(item->email->conv_index)); - DEBUG_EMAIL(("%i\n", item->email->conv_index)); - break; - case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method - DEBUG_EMAIL(("Received by Address type - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->recip_access, (char*)); - DEBUG_EMAIL(("%s\n", item->email->recip_access)); - break; - case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address - DEBUG_EMAIL(("Received by Address - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->recip_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->recip_address)); - break; - case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2 - DEBUG_EMAIL(("Received on behalf of Address type - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->recip2_access, (char*)); - DEBUG_EMAIL(("%s\n", item->email->recip2_access)); - break; - case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2 - DEBUG_EMAIL(("Received on behalf of Address -")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->recip2_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->recip2_address)); - break; - case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header - DEBUG_EMAIL(("Internet Header - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->header, (char*)); - //DEBUG_EMAIL(("%s\n", item->email->header)); - DEBUG_EMAIL(("NOT PRINTED\n")); - break; - case 0x0C17: // PR_REPLY_REQUESTED - DEBUG_EMAIL(("Reply Requested - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->reply_requested = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->reply_requested = 0; - } - break; - case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2 - DEBUG_EMAIL(("Sender Structure 2 -- NOT HANDLED\n")); - break; - case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2 - DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n")); - break; - case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2 - DEBUG_EMAIL(("Name of Sender Address 2 (Sender search key) - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->outlook_sender2, (char*)); - DEBUG_EMAIL(("%s\n", item->email->outlook_sender2)); - break; - case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method - DEBUG_EMAIL(("Sender Address type - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sender2_access, (char*)); - DEBUG_EMAIL(("%s\n", item->email->sender2_access)); - break; - case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2 - DEBUG_EMAIL(("Sender Address - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sender2_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->sender2_address)); - break; - case 0x0E01: // PR_DELETE_AFTER_SUBMIT - // I am not too sure how this works - DEBUG_EMAIL(("Delete after submit - ")); - MALLOC_EMAIL(item); - if (*(int16_t*) list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->delete_after_submit = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->delete_after_submit = 0; - } - break; - case 0x0E03: // PR_DISPLAY_CC CC Addresses - DEBUG_EMAIL(("Display CC Addresses - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->cc_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->cc_address)); - break; - case 0x0E04: // PR_DISPLAY_TO Address Sent-To - DEBUG_EMAIL(("Display Sent-To Address - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sentto_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->sentto_address)); - break; - case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date - DEBUG_EMAIL(("Date 3 (Delivery Time) - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->arrival_date, (FILETIME*)); - DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->arrival_date))); - break; - case 0x0E07: // PR_MESSAGE_FLAGS Email Flag - // 0x01 - Read - // 0x02 - Unmodified - // 0x04 - Submit - // 0x08 - Unsent - // 0x10 - Has Attachments - // 0x20 - From Me - // 0x40 - Associated - // 0x80 - Resend - // 0x100 - RN Pending - // 0x200 - NRN Pending - DEBUG_EMAIL(("Message Flags - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->flag), list->items[x]->data, sizeof(item->email->flag)); - LE32_CPU(item->email->flag); - DEBUG_EMAIL(("%i\n", item->email->flag)); - break; - case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object - DEBUG_EMAIL(("Message Size - ")); - memcpy(&(item->message_size), list->items[x]->data, sizeof(item->message_size)); - LE32_CPU(item->message_size); - DEBUG_EMAIL(("%i [%#x]\n", item->message_size, item->message_size)); - break; - case 0x0E0A: // PR_SENTMAIL_ENTRYID - // folder that this message is sent to after submission - DEBUG_EMAIL(("Sentmail EntryID - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->sentmail_folder, (pst_entryid*)); - LE32_CPU(item->email->sentmail_folder->id); - DEBUG_EMAIL(("[id = %#x]\n", item->email->sentmail_folder->id)); - break; - case 0x0E1F: // PR_RTF_IN_SYNC - // True means that the rtf version is same as text body - // False means rtf version is more up-to-date than text body - // if this value doesn't exist, text body is more up-to-date than rtf and - // cannot update to the rtf - DEBUG_EMAIL(("Compressed RTF in Sync - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->rtf_in_sync = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->rtf_in_sync = 0; - } - break; - case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record - DEBUG_EMAIL(("Attachment Size - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - memcpy(&(attach->size), list->items[x]->data, sizeof(attach->size)); - DEBUG_EMAIL(("%i\n", attach->size)); - break; - case 0x0FF9: // PR_RECORD_KEY Record Header 1 - DEBUG_EMAIL(("Record Key 1 - ")); - LIST_COPY(item->record_key, (char*)); - item->record_key_size = list->items[x]->size; - DEBUG_EMAIL_HEXPRINT(item->record_key, item->record_key_size); - DEBUG_EMAIL(("\n")); - break; - case 0x1000: // PR_BODY Plain Text body - DEBUG_EMAIL(("Plain Text body - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->body, (char*)); - //DEBUG_EMAIL("%s\n", item->email->body); - DEBUG_EMAIL(("NOT PRINTED\n")); - break; - case 0x1006: // PR_RTF_SYNC_BODY_CRC - DEBUG_EMAIL(("RTF Sync Body CRC - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->rtf_body_crc), list->items[x]->data, sizeof(item->email->rtf_body_crc)); - LE32_CPU(item->email->rtf_body_crc); - DEBUG_EMAIL(("%#x\n", item->email->rtf_body_crc)); - break; - case 0x1007: // PR_RTF_SYNC_BODY_COUNT - // a count of the *significant* charcters in the rtf body. Doesn't count - // whitespace and other ignorable characters - DEBUG_EMAIL(("RTF Sync Body character count - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->rtf_body_char_count), list->items[x]->data, sizeof(item->email->rtf_body_char_count)); - LE32_CPU(item->email->rtf_body_char_count); - DEBUG_EMAIL(("%i [%#x]\n", item->email->rtf_body_char_count, item->email->rtf_body_char_count)); - break; - case 0x1008: // PR_RTF_SYNC_BODY_TAG - // the first couple of lines of RTF body so that after modification, then beginning can - // once again be found - DEBUG_EMAIL(("RTF Sync body tag - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->rtf_body_tag, (char*)); - DEBUG_EMAIL(("%s\n", item->email->rtf_body_tag)); - break; - case 0x1009: // PR_RTF_COMPRESSED - // some compression algorithm has been applied to this. At present - // it is unknown - DEBUG_EMAIL(("RTF Compressed body - ")); - MALLOC_EMAIL(item); - LIST_COPY_SIZE(item->email->rtf_compressed, (char*), item->email->rtf_compressed_size); - DEBUG_EMAIL(("NOT PRINTED\n")); - break; - case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT - // a count of the ignored characters before the first significant character - DEBUG_EMAIL(("RTF whitespace prefix count - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->rtf_ws_prefix_count), list->items[x]->data, sizeof(item->email->rtf_ws_prefix_count)); - DEBUG_EMAIL(("%i\n", item->email->rtf_ws_prefix_count)); - break; - case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT - // a count of the ignored characters after the last significant character - DEBUG_EMAIL(("RTF whitespace tailing count - ")); - MALLOC_EMAIL(item); - memcpy(&(item->email->rtf_ws_trailing_count), list->items[x]->data, sizeof(item->email->rtf_ws_trailing_count)); - DEBUG_EMAIL(("%i\n", item->email->rtf_ws_trailing_count)); - break; - case 0x1013: // HTML body - DEBUG_EMAIL(("HTML body - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->htmlbody, (char*)); - // DEBUG_EMAIL(("%s\n", item->email->htmlbody)); - DEBUG_EMAIL(("NOT PRINTED\n")); - break; - case 0x1035: // Message ID - DEBUG_EMAIL(("Message ID - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->messageid, (char*)); - DEBUG_EMAIL(("%s\n", item->email->messageid)); - break; - case 0x1042: // in-reply-to - DEBUG_EMAIL(("In-Reply-To - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->in_reply_to, (char*)); - DEBUG_EMAIL(("%s\n", item->email->in_reply_to)); - break; - case 0x1046: // Return Path - DEBUG_EMAIL(("Return Path - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->return_path_address, (char*)); - DEBUG_EMAIL(("%s\n", item->email->return_path_address)); - break; - case 0x3001: // PR_DISPLAY_NAME File As - DEBUG_EMAIL(("Display Name - ")); - LIST_COPY(item->file_as, (char*)); - DEBUG_EMAIL(("%s\n", item->file_as)); - break; - case 0x3002: // PR_ADDRTYPE - DEBUG_EMAIL(("Address Type - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1_transport, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport)); - break; - case 0x3003: // PR_EMAIL_ADDRESS - // Contact's email address - DEBUG_EMAIL(("Contact Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1)); - break; - case 0x3004: // PR_COMMENT Comment for item - usually folders - DEBUG_EMAIL(("Comment - ")); - LIST_COPY(item->comment, (char*)); - DEBUG_EMAIL(("%s\n", item->comment)); - break; - case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date? - DEBUG_EMAIL(("Date 4 (Item Creation Date) - ")); - LIST_COPY(item->create_date, (FILETIME*)); - DEBUG_EMAIL(("%s", fileTimeToAscii(item->create_date))); - break; - case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date - DEBUG_EMAIL(("Date 5 (Modify Date) - ")); - LIST_COPY(item->modify_date, (FILETIME*)); - DEBUG_EMAIL(("%s", fileTimeToAscii(item->modify_date))); - break; - case 0x300B: // PR_SEARCH_KEY Record Header 2 - DEBUG_EMAIL(("Record Search 2 -- NOT HANDLED\n")); - break; - case 0x35DF: // PR_VALID_FOLDER_MASK - // States which folders are valid for this message store - // FOLDER_IPM_SUBTREE_VALID 0x1 - // FOLDER_IPM_INBOX_VALID 0x2 - // FOLDER_IPM_OUTBOX_VALID 0x4 - // FOLDER_IPM_WASTEBOX_VALID 0x8 - // FOLDER_IPM_SENTMAIL_VALID 0x10 - // FOLDER_VIEWS_VALID 0x20 - // FOLDER_COMMON_VIEWS_VALID 0x40 - // FOLDER_FINDER_VALID 0x80 - DEBUG_EMAIL(("Valid Folder Mask - ")); - MALLOC_MESSAGESTORE(item); - memcpy(&(item->message_store->valid_mask), list->items[x]->data, sizeof(int)); - LE32_CPU(item->message_store->valid_mask); - DEBUG_EMAIL(("%i\n", item->message_store->valid_mask)); - break; - case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record - DEBUG_EMAIL(("Top of Personal Folder Record - ")); - MALLOC_MESSAGESTORE(item); - LIST_COPY(item->message_store->top_of_personal_folder, (pst_entryid*)); - LE32_CPU(item->message_store->top_of_personal_folder->id); - DEBUG_EMAIL(("[id = %#x]\n", item->message_store->top_of_personal_folder->id)); - break; - case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID Deleted Items Folder Record - DEBUG_EMAIL(("Deleted Items Folder record - ")); - MALLOC_MESSAGESTORE(item); - LIST_COPY(item->message_store->deleted_items_folder, (pst_entryid*)); - LE32_CPU(item->message_store->deleted_items_folder->id); - DEBUG_EMAIL(("[id = %#x]\n", item->message_store->deleted_items_folder->id)); - break; - case 0x35E7: // PR_FINDER_ENTRYID Search Root Record - DEBUG_EMAIL(("Search Root record - ")); - MALLOC_MESSAGESTORE(item); - LIST_COPY(item->message_store->search_root_folder, (pst_entryid*)); - LE32_CPU(item->message_store->search_root_folder->id); - DEBUG_EMAIL(("[id = %#x]\n", item->message_store->search_root_folder->id)); - break; - case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder - DEBUG_EMAIL(("Folder Email Count - ")); - MALLOC_FOLDER(item); - memcpy(&(item->folder->email_count), list->items[x]->data, sizeof(item->folder->email_count)); - LE32_CPU(item->folder->email_count); - DEBUG_EMAIL(("%i\n", item->folder->email_count)); - break; - case 0x3603: // PR_CONTENT_UNREAD Number of unread emails - DEBUG_EMAIL(("Unread Email Count - ")); - MALLOC_FOLDER(item); - memcpy(&(item->folder->unseen_email_count), list->items[x]->data, sizeof(item->folder->unseen_email_count)); - LE32_CPU(item->folder->unseen_email_count); - DEBUG_EMAIL(("%i\n", item->folder->unseen_email_count)); - break; - case 0x360A: // PR_SUBFOLDERS Has children - DEBUG_EMAIL(("Has Subfolders - ")); - MALLOC_FOLDER(item); - if (*((int32_t*)list->items[x]->data) != 0) { - DEBUG_EMAIL(("True\n")); - item->folder->subfolder = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->folder->subfolder = 0; - } - break; - case 0x3613: // PR_CONTAINER_CLASS IPF.x - DEBUG_EMAIL(("IPF.x - ")); - LIST_COPY(item->ascii_type, (char*)); - if (strncmp("IPF.Note", item->ascii_type, 8) == 0) - item->type = PST_TYPE_NOTE; - else if (strncmp("IPF.Contact", item->ascii_type, 11) == 0) - item->type = PST_TYPE_CONTACT; - else if (strncmp("IPF.Journal", item->ascii_type, 11) == 0) - item->type = PST_TYPE_JOURNAL; - else if (strncmp("IPF.Appointment", item->ascii_type, 15) == 0) - item->type = PST_TYPE_APPOINTMENT; - else if (strncmp("IPF.StickyNote", item->ascii_type, 14) == 0) - item->type = PST_TYPE_STICKYNOTE; - else if (strncmp("IPF.Task", item->ascii_type, 8) == 0) - item->type = PST_TYPE_TASK; - else - item->type = PST_TYPE_OTHER; - - DEBUG_EMAIL(("%s [%i]\n", item->ascii_type, item->type)); - break; - case 0x3617: // PR_ASSOC_CONTENT_COUNT - // associated content are items that are attached to this folder - // but are hidden from users - DEBUG_EMAIL(("Associate Content count - ")); - MALLOC_FOLDER(item); - memcpy(&(item->folder->assoc_count), list->items[x]->data, sizeof(item->folder->assoc_count)); - LE32_CPU(item->folder->assoc_count); - DEBUG_EMAIL(("%i [%#x]\n", item->folder->assoc_count, item->folder->assoc_count)); - break; - case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment - DEBUG_EMAIL(("Binary Data [Size %i] - ", list->items[x]->size)); - NULL_CHECK(attach); - MOVE_NEXT(attach); - if (!list->items[x]->data) { //special case - attach->id2_val = list->items[x]->type; - DEBUG_EMAIL(("Seen a Reference. The data hasn't been loaded yet. [%#x][%#x]\n", - attach->id2_val, list->items[x]->type)); - } else { - LIST_COPY(attach->data, (char*)); - attach->size = list->items[x]->size; - DEBUG_EMAIL(("NOT PRINTED\n")); - } - break; - case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3) - DEBUG_EMAIL(("Attachment Filename - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - LIST_COPY(attach->filename1, (char*)); - DEBUG_EMAIL(("%s\n", attach->filename1)); - break; - case 0x3705: // PR_ATTACH_METHOD - // 0 - No Attachment - // 1 - Attach by Value - // 2 - Attach by reference - // 3 - Attach by ref resolve - // 4 - Attach by ref only - // 5 - Embedded Message - // 6 - OLE - DEBUG_EMAIL(("Attachment method - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - memcpy(&(attach->method), list->items[x]->data, sizeof(attach->method)); - LE32_CPU(attach->method); - t = attach->method; - DEBUG_EMAIL(("%s [%i]\n", (t==0?"No Attachment": - (t==1?"Attach By Value": - (t==2?"Attach By Reference": - (t==3?"Attach by Ref. Resolve": - (t==4?"Attach by Ref. Only": - (t==5?"Embedded Message":"OLE")))))),t)); - break; - case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?) - DEBUG_EMAIL(("Attachment Filename long - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - LIST_COPY(attach->filename2, (char*)); - DEBUG_EMAIL(("%s\n", attach->filename2)); - break; - case 0x370B: // PR_RENDERING_POSITION - // position in characters that the attachment appears in the plain text body - DEBUG_EMAIL(("Attachment Position - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - memcpy(&(attach->position), list->items[x]->data, sizeof(attach->position)); - LE32_CPU(attach->position); - DEBUG_EMAIL(("%i [%#x]\n", attach->position)); - break; - case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding - DEBUG_EMAIL(("Attachment mime encoding - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - LIST_COPY(attach->mimetype, (char*)); - DEBUG_EMAIL(("%s\n", attach->mimetype)); - break; - case 0x3710: // PR_ATTACH_MIME_SEQUENCE - // sequence number for mime parts. Includes body - DEBUG_EMAIL(("Attachment Mime Sequence - ")); - NULL_CHECK(attach); - MOVE_NEXT(attach); - memcpy(&(attach->sequence), list->items[x]->data, sizeof(attach->sequence)); - LE32_CPU(attach->sequence); - DEBUG_EMAIL(("%i\n", attach->sequence)); - break; - case 0x3A00: // PR_ACCOUNT - DEBUG_EMAIL(("Contact's Account name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->account_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->account_name)); - break; - case 0x3A01: // PR_ALTERNATE_RECIPIENT - DEBUG_EMAIL(("Contact Alternate Recipient - NOT PROCESSED\n")); - break; - case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER - DEBUG_EMAIL(("Callback telephone number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->callback_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->callback_phone)); - break; - case 0x3A03: // PR_CONVERSION_PROHIBITED - DEBUG_EMAIL(("Message Conversion Prohibited - ")); - MALLOC_EMAIL(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->email->conversion_prohib = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->email->conversion_prohib = 0; - } - break; - case 0x3A05: // PR_GENERATION suffix - DEBUG_EMAIL(("Contacts Suffix - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->suffix, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->suffix)); - break; - case 0x3A06: // PR_GIVEN_NAME Contact's first name - DEBUG_EMAIL(("Contacts First Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->first_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->first_name)); - break; - case 0x3A07: // PR_GOVERNMENT_ID_NUMBER - DEBUG_EMAIL(("Contacts Government ID Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->gov_id, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->gov_id)); - break; - case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER - DEBUG_EMAIL(("Business Telephone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_phone)); - break; - case 0x3A09: // PR_HOME_TELEPHONE_NUMBER - DEBUG_EMAIL(("Home Telephone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_phone)); - break; - case 0x3A0A: // PR_INITIALS Contact's Initials - DEBUG_EMAIL(("Contacts Initials - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->initials, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->initials)); - break; - case 0x3A0B: // PR_KEYWORD - DEBUG_EMAIL(("Keyword - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->keyword, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->keyword)); - break; - case 0x3A0C: // PR_LANGUAGE - DEBUG_EMAIL(("Contact's Language - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->language, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->language)); - break; - case 0x3A0D: // PR_LOCATION - DEBUG_EMAIL(("Contact's Location - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->location, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->location)); - break; - case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email - DEBUG_EMAIL(("Mail Permission - ")); - MALLOC_CONTACT(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->contact->mail_permission = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->contact->mail_permission = 0; - } - break; - case 0x3A0F: // PR_MHS_COMMON_NAME - DEBUG_EMAIL(("MHS Common Name - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->common_name, (char*)); - DEBUG_EMAIL(("%s\n", item->email->common_name)); - break; - case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER - DEBUG_EMAIL(("Organizational ID # - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->org_id, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->org_id)); - break; - case 0x3A11: // PR_SURNAME Contact's Surname - DEBUG_EMAIL(("Contacts Surname - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->surname, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->surname)); - break; - case 0x3A12: // PR_ORIGINAL_ENTRY_ID - DEBUG_EMAIL(("Original Entry ID - NOT PROCESSED\n")); - break; - case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME - DEBUG_EMAIL(("Original Display Name - NOT PROCESSED\n")); - break; - case 0x3A14: // PR_ORIGINAL_SEARCH_KEY - DEBUG_EMAIL(("Original Search Key - NOT PROCESSED\n")); - break; - case 0x3A15: // PR_POSTAL_ADDRESS - DEBUG_EMAIL(("Default Postal Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->def_postal_address, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->def_postal_address)); - break; - case 0x3A16: // PR_COMPANY_NAME - DEBUG_EMAIL(("Company Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->company_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->company_name)); - break; - case 0x3A17: // PR_TITLE - Job Title - DEBUG_EMAIL(("Job Title - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->job_title, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->job_title)); - break; - case 0x3A18: // PR_DEPARTMENT_NAME - DEBUG_EMAIL(("Department Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->department, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->department)); - break; - case 0x3A19: // PR_OFFICE_LOCATION - DEBUG_EMAIL(("Office Location - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->office_loc, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->office_loc)); - break; - case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER - DEBUG_EMAIL(("Primary Telephone - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->primary_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->primary_phone)); - break; - case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER - DEBUG_EMAIL(("Business Phone Number 2 - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_phone2, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_phone2)); - break; - case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER - DEBUG_EMAIL(("Mobile Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->mobile_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->mobile_phone)); - break; - case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER - DEBUG_EMAIL(("Radio Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->radio_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->radio_phone)); - break; - case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER - DEBUG_EMAIL(("Car Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->car_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->car_phone)); - break; - case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER - DEBUG_EMAIL(("Other Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_phone)); - break; - case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME - DEBUG_EMAIL(("Transmittable Display Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->transmittable_display_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->transmittable_display_name)); - break; - case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER - DEBUG_EMAIL(("Pager Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->pager_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->pager_phone)); - break; - case 0x3A22: // PR_USER_CERTIFICATE - DEBUG_EMAIL(("User Certificate - NOT PROCESSED")); - break; - case 0x3A23: // PR_PRIMARY_FAX_NUMBER - DEBUG_EMAIL(("Primary Fax Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->primary_fax, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->primary_fax)); - break; - case 0x3A24: // PR_BUSINESS_FAX_NUMBER - DEBUG_EMAIL(("Business Fax Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_fax, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_fax)); - break; - case 0x3A25: // PR_HOME_FAX_NUMBER - DEBUG_EMAIL(("Home Fax Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_fax, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_fax)); - break; - case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY - DEBUG_EMAIL(("Business Address Country - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_country, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_country)); - break; - case 0x3A27: // PR_BUSINESS_ADDRESS_CITY - DEBUG_EMAIL(("Business Address City - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_city, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_city)); - break; - case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE - DEBUG_EMAIL(("Business Address State - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_state, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_state)); - break; - case 0x3A29: // PR_BUSINESS_ADDRESS_STREET - DEBUG_EMAIL(("Business Address Street - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_street, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_street)); - break; - case 0x3A2A: // PR_BUSINESS_POSTAL_CODE - DEBUG_EMAIL(("Business Postal Code - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_postal_code, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_postal_code)); - break; - case 0x3A2B: // PR_BUSINESS_PO_BOX - DEBUG_EMAIL(("Business PO Box - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_po_box, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_po_box)); - break; - case 0x3A2C: // PR_TELEX_NUMBER - DEBUG_EMAIL(("Telex Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->telex, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->telex)); - break; - case 0x3A2D: // PR_ISDN_NUMBER - DEBUG_EMAIL(("ISDN Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->isdn_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->isdn_phone)); - break; - case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER - DEBUG_EMAIL(("Assistant Phone Number - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->assistant_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->assistant_phone)); - break; - case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER - DEBUG_EMAIL(("Home Phone 2 - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_phone2, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_phone2)); - break; - case 0x3A30: // PR_ASSISTANT - DEBUG_EMAIL(("Assistant's Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->assistant_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->assistant_name)); - break; - case 0x3A40: // PR_SEND_RICH_INFO - DEBUG_EMAIL(("Can receive Rich Text - ")); - MALLOC_CONTACT(item); - if(*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->contact->rich_text = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->contact->rich_text = 0; - } - break; - case 0x3A41: // PR_WEDDING_ANNIVERSARY - DEBUG_EMAIL(("Wedding Anniversary - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->wedding_anniversary, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->contact->wedding_anniversary))); - break; - case 0x3A42: // PR_BIRTHDAY - DEBUG_EMAIL(("Birthday - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->birthday, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->contact->birthday))); - break; - case 0x3A43: // PR_HOBBIES - DEBUG_EMAIL(("Hobbies - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->hobbies, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->hobbies)); - break; - case 0x3A44: // PR_MIDDLE_NAME - DEBUG_EMAIL(("Middle Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->middle_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->middle_name)); - break; - case 0x3A45: // PR_DISPLAY_NAME_PREFIX - DEBUG_EMAIL(("Display Name Prefix (Title) - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->display_name_prefix, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->display_name_prefix)); - break; - case 0x3A46: // PR_PROFESSION - DEBUG_EMAIL(("Profession - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->profession, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->profession)); - break; - case 0x3A47: // PR_PREFERRED_BY_NAME - DEBUG_EMAIL(("Preferred By Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->pref_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->pref_name)); - break; - case 0x3A48: // PR_SPOUSE_NAME - DEBUG_EMAIL(("Spouse's Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->spouse_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->spouse_name)); - break; - case 0x3A49: // PR_COMPUTER_NETWORK_NAME - DEBUG_EMAIL(("Computer Network Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->computer_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->computer_name)); - break; - case 0x3A4A: // PR_CUSTOMER_ID - DEBUG_EMAIL(("Customer ID - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->customer_id, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->customer_id)); - break; - case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER - DEBUG_EMAIL(("TTY/TDD Phone - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->ttytdd_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->ttytdd_phone)); - break; - case 0x3A4C: // PR_FTP_SITE - DEBUG_EMAIL(("Ftp Site - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->ftp_site, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->ftp_site)); - break; - case 0x3A4D: // PR_GENDER - DEBUG_EMAIL(("Gender - ")); - MALLOC_CONTACT(item); - memcpy(&item->contact->gender, list->items[x]->data, sizeof(int16_t)); - LE16_CPU(item->contact->gender); - switch(item->contact->gender) { - case 0: - DEBUG_EMAIL(("Unspecified\n")); - break; - case 1: - DEBUG_EMAIL(("Female\n")); - break; - case 2: - DEBUG_EMAIL(("Male\n")); - break; - default: - DEBUG_EMAIL(("Error processing\n")); - } - break; - case 0x3A4E: // PR_MANAGER_NAME - DEBUG_EMAIL(("Manager's Name - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->manager_name, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->manager_name)); - break; - case 0x3A4F: // PR_NICKNAME - DEBUG_EMAIL(("Nickname - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->nickname, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->nickname)); - break; - case 0x3A50: // PR_PERSONAL_HOME_PAGE - DEBUG_EMAIL(("Personal Home Page - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->personal_homepage, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->personal_homepage)); - break; - case 0x3A51: // PR_BUSINESS_HOME_PAGE - DEBUG_EMAIL(("Business Home Page - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_homepage, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_homepage)); - break; - case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER - DEBUG_EMAIL(("Company Main Phone - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->company_main_phone, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->company_main_phone)); - break; - case 0x3A58: // PR_CHILDRENS_NAMES - DEBUG_EMAIL(("Children's Names - NOT PROCESSED\n")); - break; - case 0x3A59: // PR_HOME_ADDRESS_CITY - DEBUG_EMAIL(("Home Address City - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_city, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_city)); - break; - case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY - DEBUG_EMAIL(("Home Address Country - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_country, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_country)); - break; - case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE - DEBUG_EMAIL(("Home Address Postal Code - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_postal_code, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_postal_code)); - break; - case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE - DEBUG_EMAIL(("Home Address State or Province - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_state, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_state)); - break; - case 0x3A5D: // PR_HOME_ADDRESS_STREET - DEBUG_EMAIL(("Home Address Street - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_street, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_street)); - break; - case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX - DEBUG_EMAIL(("Home Address Post Office Box - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_po_box, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_po_box)); - break; - case 0x3A5F: // PR_OTHER_ADDRESS_CITY - DEBUG_EMAIL(("Other Address City - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_city, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_city)); - break; - case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY - DEBUG_EMAIL(("Other Address Country - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_country, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_country)); - break; - case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE - DEBUG_EMAIL(("Other Address Postal Code - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_postal_code, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_postal_code)); - break; - case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE - DEBUG_EMAIL(("Other Address State - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_state, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_state)); - break; - case 0x3A63: // PR_OTHER_ADDRESS_STREET - DEBUG_EMAIL(("Other Address Street - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_street, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_street)); - break; - case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX - DEBUG_EMAIL(("Other Address Post Office box - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_po_box, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_po_box)); - break; - case 0x65E3: // Entry ID? - DEBUG_EMAIL(("Entry ID - ")); - item->record_key = (char*) xmalloc(16+1); - memcpy(item->record_key, &(list->items[x]->data[1]), 16); //skip first byte - item->record_key[16]='\0'; - item->record_key_size=16; - DEBUG_EMAIL_HEXPRINT((char*)item->record_key, 16); - break; - case 0x67F2: // ID2 value of the attachments proper record - DEBUG_EMAIL(("Attachment ID2 value - ")); - if (attach){ - MOVE_NEXT(attach); - memcpy(&(attach->id2_val), list->items[x]->data, sizeof(attach->id2_val)); - LE32_CPU(attach->id2_val); - DEBUG_EMAIL(("%#x\n", attach->id2_val)); - } else { - DEBUG_EMAIL(("NOT AN ATTACHMENT: %#x\n", list->items[x]->id)); - } - break; - case 0x67FF: // Extra Property Identifier (Password CheckSum) - DEBUG_EMAIL(("Password checksum [0x67FF] - ")); - MALLOC_MESSAGESTORE(item); - memcpy(&(item->message_store->pwd_chksum), list->items[x]->data, - sizeof(item->message_store->pwd_chksum)); - DEBUG_EMAIL(("%#x\n", item->message_store->pwd_chksum)); - break; - case 0x6F02: // Secure HTML Body - DEBUG_EMAIL(("Secure HTML Body - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->encrypted_htmlbody, (char*)); - item->email->encrypted_htmlbody_size = list->items[x]->size; - DEBUG_EMAIL(("Not Printed\n")); - break; - case 0x6F04: // Secure Text Body - DEBUG_EMAIL(("Secure Text Body - ")); - MALLOC_EMAIL(item); - LIST_COPY(item->email->encrypted_body, (char*)); - item->email->encrypted_body_size = list->items[x]->size; - DEBUG_EMAIL(("Not Printed\n")); - break; - case 0x7C07: // top of folders ENTRYID - DEBUG_EMAIL(("Top of folders RecID [0x7c07] - ")); - MALLOC_MESSAGESTORE(item); - item->message_store->top_of_folder = (pst_entryid*) xmalloc(sizeof(pst_entryid)); - memcpy(item->message_store->top_of_folder, list->items[x]->data, sizeof(pst_entryid)); - LE32_CPU(item->message_store->top_of_folder->u1); - LE32_CPU(item->message_store->top_of_folder->id); - DEBUG_EMAIL_HEXPRINT((char*)item->message_store->top_of_folder->entryid, 16); - break; - case 0x8005: // Contact's Fullname - DEBUG_EMAIL(("Contact Fullname - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->fullname, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->fullname)); - break; - case 0x801A: // Full Home Address - DEBUG_EMAIL(("Home Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->home_address, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->home_address)); - break; - case 0x801B: // Full Business Address - DEBUG_EMAIL(("Business Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->business_address, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->business_address)); - break; - case 0x801C: // Full Other Address - DEBUG_EMAIL(("Other Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->other_address, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->other_address)); - break; - case 0x8082: // Email Address 1 Transport - DEBUG_EMAIL(("Email Address 1 Transport - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1_transport, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport)); - break; - case 0x8083: // Email Address 1 Address - DEBUG_EMAIL(("Email Address 1 Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1)); - break; - case 0x8084: // Email Address 1 Description - DEBUG_EMAIL(("Email Address 1 Description - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1_desc, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1_desc)); - break; - case 0x8085: // Email Address 1 Record - DEBUG_EMAIL(("Email Address 1 Record - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address1a, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address1a)); - break; - case 0x8092: // Email Address 2 Transport - DEBUG_EMAIL(("Email Address 2 Transport - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address2_transport, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address2_transport)); - break; - case 0x8093: // Email Address 2 Address - DEBUG_EMAIL(("Email Address 2 Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address2, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address2)); - break; - case 0x8094: // Email Address 2 Description - DEBUG_EMAIL (("Email Address 2 Description - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address2_desc, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address2_desc)); - break; - case 0x8095: // Email Address 2 Record - DEBUG_EMAIL(("Email Address 2 Record - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address2a, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address2a)); - break; - case 0x80A2: // Email Address 3 Transport - DEBUG_EMAIL (("Email Address 3 Transport - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address3_transport, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address3_transport)); - break; - case 0x80A3: // Email Address 3 Address - DEBUG_EMAIL(("Email Address 3 Address - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address3, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address3)); - break; - case 0x80A4: // Email Address 3 Description - DEBUG_EMAIL(("Email Address 3 Description - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address3_desc, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address3_desc)); - break; - case 0x80A5: // Email Address 3 Record - DEBUG_EMAIL(("Email Address 3 Record - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->address3a, (char*)); - DEBUG_EMAIL(("|%s|\n", item->contact->address3a)); - break; - case 0x80D8: // Internet Free/Busy - DEBUG_EMAIL(("Internet Free/Busy - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->free_busy_address, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->free_busy_address)); - break; - case 0x8205: // Show on Free/Busy as - // 0: Free - // 1: Tentative - // 2: Busy - // 3: Out Of Office - DEBUG_EMAIL(("Appointment shows as - ")); - MALLOC_APPOINTMENT(item); - memcpy(&(item->appointment->showas), list->items[x]->data, sizeof(item->appointment->showas)); - LE32_CPU(item->appointment->showas); - switch (item->appointment->showas) { - case PST_FREEBUSY_FREE: - DEBUG_EMAIL(("Free\n")); break; - case PST_FREEBUSY_TENTATIVE: - DEBUG_EMAIL(("Tentative\n")); break; - case PST_FREEBUSY_BUSY: - DEBUG_EMAIL(("Busy\n")); break; - case PST_FREEBUSY_OUT_OF_OFFICE: - DEBUG_EMAIL(("Out Of Office\n")); break; - default: - DEBUG_EMAIL(("Unknown Value: %d\n", item->appointment->showas)); break; - } - break; - case 0x8208: // Location of an appointment - DEBUG_EMAIL(("Appointment Location - ")); - MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->location, (char*)); - DEBUG_EMAIL(("%s\n", item->appointment->location)); - break; - case 0x8214: // Label for an appointment - DEBUG_EMAIL(("Label for appointment - ")); - MALLOC_APPOINTMENT(item); - memcpy(&(item->appointment->label), list->items[x]->data, sizeof(item->appointment->label)); - LE32_CPU(item->appointment->label); - switch (item->appointment->label) { - case PST_APP_LABEL_NONE: - DEBUG_EMAIL(("None\n")); break; - case PST_APP_LABEL_IMPORTANT: - DEBUG_EMAIL(("Important\n")); break; - case PST_APP_LABEL_BUSINESS: - DEBUG_EMAIL(("Business\n")); break; - case PST_APP_LABEL_PERSONAL: - DEBUG_EMAIL(("Personal\n")); break; - case PST_APP_LABEL_VACATION: - DEBUG_EMAIL(("Vacation\n")); break; - case PST_APP_LABEL_MUST_ATTEND: - DEBUG_EMAIL(("Must Attend\n")); break; - case PST_APP_LABEL_TRAVEL_REQ: - DEBUG_EMAIL(("Travel Required\n")); break; - case PST_APP_LABEL_NEEDS_PREP: - DEBUG_EMAIL(("Needs Preparation\n")); break; - case PST_APP_LABEL_BIRTHDAY: - DEBUG_EMAIL(("Birthday\n")); break; - case PST_APP_LABEL_ANNIVERSARY: - DEBUG_EMAIL(("Anniversary\n")); break; - case PST_APP_LABEL_PHONE_CALL: - DEBUG_EMAIL(("Phone Call\n")); break; - } - break; - case 0x8215: // All day appointment flag - DEBUG_EMAIL(("All day flag - ")); - MALLOC_APPOINTMENT(item); - if (*(int16_t*)list->items[x]->data != 0) { - DEBUG_EMAIL(("True\n")); - item->appointment->all_day = 1; - } else { - DEBUG_EMAIL(("False\n")); - item->appointment->all_day = 0; - } - break; - case 0x8234: // TimeZone as String - DEBUG_EMAIL(("TimeZone of times - ")); - MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->timezonestring, (char*)); - DEBUG_EMAIL(("%s\n", item->appointment->timezonestring)); - break; - case 0x8235: // Appointment start time - DEBUG_EMAIL(("Appointment Start Time - ")); - MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->start, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); - break; - case 0x8236: // Appointment end time - DEBUG_EMAIL(("Appointment End Time - ")); - MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->end, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); - break; - case 0x8516: // Journal time start - DEBUG_EMAIL(("Duplicate Time Start - ")); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); - break; - case 0x8517: // Journal time end - DEBUG_EMAIL(("Duplicate Time End - ")); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); - break; - case 0x8530: // Followup - DEBUG_EMAIL(("Followup String - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->followup, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->followup)); - break; - case 0x8534: // Mileage - DEBUG_EMAIL(("Mileage - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->mileage, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->mileage)); - break; - case 0x8535: // Billing Information - DEBUG_EMAIL(("Billing Information - ")); - MALLOC_CONTACT(item); - LIST_COPY(item->contact->billing_information, (char*)); - DEBUG_EMAIL(("%s\n", item->contact->billing_information)); - break; - case 0x8554: // Outlook Version - DEBUG_EMAIL(("Outlook Version - ")); - LIST_COPY(item->outlook_version, (char*)); - DEBUG_EMAIL(("%s\n", item->outlook_version)); - break; - case 0x8560: // Appointment Reminder Time - DEBUG_EMAIL(("Appointment Reminder Time - ")); - MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->reminder, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->reminder))); - break; - case 0x8700: // Journal Type - DEBUG_EMAIL(("Journal Entry Type - ")); - MALLOC_JOURNAL(item); - LIST_COPY(item->journal->type, (char*)); - DEBUG_EMAIL(("%s\n", item->journal->type)); - break; - case 0x8706: // Journal Start date/time - DEBUG_EMAIL(("Start Timestamp - ")); - MALLOC_JOURNAL(item); - LIST_COPY(item->journal->start, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->journal->start))); - break; - case 0x8708: // Journal End date/time - DEBUG_EMAIL(("End Timestamp - ")); - MALLOC_JOURNAL(item); - LIST_COPY(item->journal->end, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->journal->end))); - break; - case 0x8712: // Title? - DEBUG_EMAIL(("Journal Entry Type - ")); - MALLOC_JOURNAL(item); - LIST_COPY(item->journal->type, (char*)); - DEBUG_EMAIL(("%s\n", item->journal->type)); - break; - default: - DEBUG_EMAIL(("unknown type %#x\n", list->items[x]->id)); - /* Reference Types - - 2 - 0x0002 - Signed 16bit value - 3 - 0x0003 - Signed 32bit value - 11 - 0x000B - Boolean (non-zero = true) - 13 - 0x000D - Embedded Object - 30 - 0x001E - Null terminated String - 31 - 0x001F - Unicode string - 64 - 0x0040 - Systime - Filetime structure - 72 - 0x0048 - OLE Guid - 258 - 0x0102 - Binary data - - - 0x1003 - Array of 32bit values - - 0x101E - Array of Strings - - 0x1102 - Array of Binary data - */ - // DEBUG_EMAIL(("Unknown id [%#x, size=%#x]\n", list->items[x]->id, list->items[x]->size)); - if (list->items[x]->type == 0x02) { - DEBUG_EMAIL(("Unknown 16bit int = %hi\n", *(int16_t*)list->items[x]->data)); - } else if (list->items[x]->type == 0x03) { - DEBUG_EMAIL(("Unknown 32bit int = %i\n", *(int32_t*)list->items[x]->data)); - } else if (list->items[x]->type == 0x0b) { - DEBUG_EMAIL(("Unknown 16bit boolean = %s [%hi]\n", - (*((int16_t*)list->items[x]->data)!=0?"True":"False"), - *((int16_t*)list->items[x]->data))); - } else if (list->items[x]->type == 0x1e) { - DEBUG_EMAIL(("Unknown String Data = \"%s\" [%#x]\n", - list->items[x]->data, list->items[x]->type)); - } else if (list->items[x]->type == 0x40) { - DEBUG_EMAIL(("Unknown Date = \"%s\" [%#x]\n", - fileTimeToAscii((FILETIME*)list->items[x]->data), - list->items[x]->type)); - } else if (list->items[x]->type == 0x102) { - DEBUG_EMAIL(("Unknown Binary Data [size = %#x]\n", - list->items[x]->size)); - DEBUG_HEXDUMP(list->items[x]->data, list->items[x]->size); - } else if (list->items[x]->type == 0x101E) { - DEBUG_EMAIL(("Unknown Array of Strings [%#x]\n", - list->items[x]->type)); - } else { - DEBUG_EMAIL(("Unknown Not Printable [%#x]\n", - list->items[x]->type)); - } - if (list->items[x]->data) { - free(list->items[x]->data); - list->items[x]->data = NULL; - } - } - x++; - } - x = 0; - list = list->next; - next = 1; - } - DEBUG_RET(); - return 0; + int32_t x, t; + int32_t next = 0; + pst_item_extra_field *ef; + + DEBUG_ENT("_pst_process"); + if (!item) { + DEBUG_EMAIL(("item cannot be NULL.\n")); + DEBUG_RET(); + return -1; + } + + while (list) { + x = 0; + while (x < list->count_item) { + // check here to see if the id is one that is mapped. + DEBUG_EMAIL(("#%d - id: %#x type: %#x length: %#x\n", x, list->items[x]->id, list->items[x]->type, list->items[x]->size)); + + switch (list->items[x]->id) { + case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers + DEBUG_EMAIL(("Extra Field - ")); + ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field)); + memset(ef, 0, sizeof(pst_item_extra_field)); + ef->field_name = (char*) xmalloc(strlen(list->items[x]->extra)+1); + strcpy(ef->field_name, list->items[x]->extra); + LIST_COPY(ef->value, (char*)); + ef->next = item->extra_fields; + item->extra_fields = ef; + DEBUG_EMAIL(("\"%s\" = \"%s\"\n", ef->field_name, ef->value)); + break; + case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED + // If set to true, the sender allows this email to be autoforwarded + DEBUG_EMAIL(("AutoForward allowed - ")); + MALLOC_EMAIL(item); + if (*((short int*)list->items[x]->data) != 0) { + DEBUG_EMAIL(("True\n")); + item->email->autoforward = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->autoforward = -1; + } + break; + case 0x0003: // Extended Attributes table + DEBUG_EMAIL(("Extended Attributes Table - NOT PROCESSED\n")); + break; + case 0x0017: // PR_IMPORTANCE + // How important the sender deems it to be + // 0 - Low + // 1 - Normal + // 2 - High + + DEBUG_EMAIL(("Importance Level - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->importance), list->items[x]->data, sizeof(item->email->importance)); + LE32_CPU(item->email->importance); + t = item->email->importance; + DEBUG_EMAIL(("%s [%i]\n", (t==0?"Low":(t==1?"Normal":"High")), t)); + break; + case 0x001A: // PR_MESSAGE_CLASS Ascii type of messages - NOT FOLDERS + // must be case insensitive + DEBUG_EMAIL(("IPM.x - ")); + LIST_COPY(item->ascii_type, (char*)); + if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0) + // the string begins with IPM.Note... + item->type = PST_TYPE_NOTE; + else if (pst_stricmp("IPM", item->ascii_type) == 0) + // the whole string is just IPM + item->type = PST_TYPE_NOTE; + else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0) + // the string begins with IPM.Contact... + item->type = PST_TYPE_CONTACT; + else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0) + // the string begins with the above + item->type = PST_TYPE_REPORT; + else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0) + item->type = PST_TYPE_JOURNAL; + else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0) + item->type = PST_TYPE_APPOINTMENT; + else + item->type = PST_TYPE_OTHER; + + DEBUG_EMAIL(("%s\n", item->ascii_type)); + break; + case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED + // set if the sender wants a delivery report from all recipients + DEBUG_EMAIL(("Global Delivery Report - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->delivery_report = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->delivery_report = 0; + } + break; + case 0x0026: // PR_PRIORITY + // Priority of a message + // -1 NonUrgent + // 0 Normal + // 1 Urgent + DEBUG_EMAIL(("Priority - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->priority), list->items[x]->data, sizeof(item->email->priority)); + LE32_CPU(item->email->priority); + t = item->email->priority; + DEBUG_EMAIL(("%s [%i]\n", (t<0?"NonUrgent":(t==0?"Normal":"Urgent")), t)); + break; + case 0x0029:// PR_READ_RECEIPT_REQUESTED + DEBUG_EMAIL(("Read Receipt - ")); + MALLOC_EMAIL(item); + if (*(short int*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->read_receipt = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->read_receipt = 0; + } + break; + case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED + DEBUG_EMAIL(("Reassignment Prohibited (Private) - ")); + if (*(short int*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->private_member = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->private_member = 0; + } + break; + case 0x002E: // PR_ORIGINAL_SENSITIVITY + // the sensitivity of the message before being replied to or forwarded + // 0 - None + // 1 - Personal + // 2 - Private + // 3 - Company Confidential + DEBUG_EMAIL(("Original Sensitivity - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->orig_sensitivity), list->items[x]->data, sizeof(item->email->orig_sensitivity)); + LE32_CPU(item->email->orig_sensitivity); + t = item->email->orig_sensitivity; + DEBUG_EMAIL(("%s [%i]\n", (t==0?"None":(t==1?"Personal": + (t==2?"Private":"Company Confidential"))), t)); + break; + case 0x0036: // PR_SENSITIVITY + // sender's opinion of the sensitivity of an email + // 0 - None + // 1 - Personal + // 2 - Private + // 3 - Company Confidiential + DEBUG_EMAIL(("Sensitivity - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->sensitivity), list->items[x]->data, sizeof(item->email->sensitivity)); + LE32_CPU(item->email->sensitivity); + t = item->email->sensitivity; + DEBUG_EMAIL(("%s [%i]\n", (t==0?"None":(t==1?"Personal": + (t==2?"Private":"Company Confidential"))), t)); + break; + case 0x0037: // PR_SUBJECT raw subject + // if (list->items[x]->id == 0x0037) { + DEBUG_EMAIL(("Raw Subject - ")); + MALLOC_EMAIL(item); + item->email->subject = (pst_item_email_subject*) realloc(item->email->subject, sizeof(pst_item_email_subject)); + memset(item->email->subject, 0, sizeof(pst_item_email_subject)); + DEBUG_EMAIL((" [size = %i] ", list->items[x]->size)); + if (list->items[x]->size > 0) { + if (isprint(list->items[x]->data[0])) { + // then there are no control bytes at the front + item->email->subject->off1 = 0; + item->email->subject->off2 = 0; + item->email->subject->subj = realloc(item->email->subject->subj, list->items[x]->size+1); + memset(item->email->subject->subj, 0, list->items[x]->size+1); + memcpy(item->email->subject->subj, list->items[x]->data, list->items[x]->size); + } else { + DEBUG_EMAIL(("Raw Subject has control codes\n")); + // there might be some control bytes in the first and second bytes + item->email->subject->off1 = list->items[x]->data[0]; + item->email->subject->off2 = list->items[x]->data[1]; + item->email->subject->subj = realloc(item->email->subject->subj, (list->items[x]->size-2)+1); + memset(item->email->subject->subj, 0, list->items[x]->size-1); + memcpy(item->email->subject->subj, &(list->items[x]->data[2]), list->items[x]->size-2); + } + DEBUG_EMAIL(("%s\n", item->email->subject->subj)); + } else { + // obviously outlook has decided not to be straight with this one. + item->email->subject->off1 = 0; + item->email->subject->off2 = 0; + item->email->subject = NULL; + DEBUG_EMAIL(("NULL subject detected\n")); + } + break; + case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created + DEBUG_EMAIL(("Date sent - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sent_date, (FILETIME*)); + LE32_CPU(item->email->sent_date->dwLowDateTime); + LE32_CPU(item->email->sent_date->dwHighDateTime); + DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->sent_date))); + break; + case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1 + DEBUG_EMAIL(("Sent on behalf of address 1 - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->outlook_sender, (char*)); + DEBUG_EMAIL(("%s\n", item->email->outlook_sender)); + break; + case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient + DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n")); + break; + case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure + DEBUG_EMAIL(("Received By Name 1 -- NOT HANDLED\n")); + break; + case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender + DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n")); + break; + case 0x0042: // PR_SENT_REPRESENTING_NAME Name of Sender Structure + DEBUG_EMAIL(("Sent on behalf of Structure Name - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->outlook_sender_name, (char*)); + DEBUG_EMAIL(("%s\n", item->email->outlook_sender_name)); + break; + case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2 + DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n")); + break; + case 0x0044: // PR_RCVD_REPRESENTING_NAME Name of Recipient Structure 2 + DEBUG_EMAIL(("Received on behalf of Structure Name -- NOT HANDLED\n")); + break; + case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure + DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n")); + break; + case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure + DEBUG_EMAIL(("Name of Reply-To Structure -")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->reply_to, (char*)); + DEBUG_EMAIL(("%s\n", item->email->reply_to)); + break; + case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1 + DEBUG_EMAIL(("Recipient's Address 1 (Search Key) - ")); + MALLOC_EMAIL(item); + LIST_COPY (item->email->outlook_recipient, (char*)); + DEBUG_EMAIL(("%s\n", item->email->outlook_recipient)); + break; + case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2 + DEBUG_EMAIL(("Received on behalf of Address (Search Key) - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->outlook_recipient2, (char*)); + DEBUG_EMAIL(("%s\n", item->email->outlook_recipient2)); + break; + case 0x0057: // PR_MESSAGE_TO_ME + // this user is listed explicitly in the TO address + DEBUG_EMAIL(("My address in TO field - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->message_to_me = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->message_to_me = 0; + } + break; + case 0x0058: // PR_MESSAGE_CC_ME + // this user is listed explicitly in the CC address + DEBUG_EMAIL(("My address in CC field - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->message_cc_me = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->message_cc_me = 0; + } + break; + case 0x0059: //PR_MESSAGE_RECIP_ME + // this user appears in TO, CC or BCC address list + DEBUG_EMAIL(("Message addressed to me - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->message_recip_me = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->message_recip_me = 0; + } + break; + case 0x0063: // PR_RESPONSE_REQUESTED + DEBUG_EMAIL(("Response requested - ")); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->response_requested = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->response_requested = 0; + } + break; + case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address + DEBUG_EMAIL(("Sent on behalf of address type - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sender_access, (char*)); + DEBUG_EMAIL(("%s\n", item->email->sender_access)); + break; + case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address + DEBUG_EMAIL(("Sent on behalf of Address - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sender_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->sender_address)); + break; + case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject + DEBUG_EMAIL(("Processed Subject (Conversation Topic) - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->proc_subject, (char*)); + DEBUG_EMAIL(("%s\n", item->email->proc_subject)); + break; + case 0x0071: // PR_CONVERSATION_INDEX Date 2 + DEBUG_EMAIL(("Conversation Index - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->conv_index), list->items[x]->data, sizeof(item->email->conv_index)); + DEBUG_EMAIL(("%i\n", item->email->conv_index)); + break; + case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method + DEBUG_EMAIL(("Received by Address type - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->recip_access, (char*)); + DEBUG_EMAIL(("%s\n", item->email->recip_access)); + break; + case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address + DEBUG_EMAIL(("Received by Address - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->recip_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->recip_address)); + break; + case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2 + DEBUG_EMAIL(("Received on behalf of Address type - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->recip2_access, (char*)); + DEBUG_EMAIL(("%s\n", item->email->recip2_access)); + break; + case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2 + DEBUG_EMAIL(("Received on behalf of Address -")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->recip2_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->recip2_address)); + break; + case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header + DEBUG_EMAIL(("Internet Header - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->header, (char*)); + //DEBUG_EMAIL(("%s\n", item->email->header)); + DEBUG_EMAIL(("NOT PRINTED\n")); + break; + case 0x0C17: // PR_REPLY_REQUESTED + DEBUG_EMAIL(("Reply Requested - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->reply_requested = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->reply_requested = 0; + } + break; + case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2 + DEBUG_EMAIL(("Sender Structure 2 -- NOT HANDLED\n")); + break; + case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2 + DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n")); + break; + case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2 + DEBUG_EMAIL(("Name of Sender Address 2 (Sender search key) - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->outlook_sender2, (char*)); + DEBUG_EMAIL(("%s\n", item->email->outlook_sender2)); + break; + case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method + DEBUG_EMAIL(("Sender Address type - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sender2_access, (char*)); + DEBUG_EMAIL(("%s\n", item->email->sender2_access)); + break; + case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2 + DEBUG_EMAIL(("Sender Address - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sender2_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->sender2_address)); + break; + case 0x0E01: // PR_DELETE_AFTER_SUBMIT + // I am not too sure how this works + DEBUG_EMAIL(("Delete after submit - ")); + MALLOC_EMAIL(item); + if (*(int16_t*) list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->delete_after_submit = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->delete_after_submit = 0; + } + break; + case 0x0E03: // PR_DISPLAY_CC CC Addresses + DEBUG_EMAIL(("Display CC Addresses - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->cc_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->cc_address)); + break; + case 0x0E04: // PR_DISPLAY_TO Address Sent-To + DEBUG_EMAIL(("Display Sent-To Address - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sentto_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->sentto_address)); + break; + case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date + DEBUG_EMAIL(("Date 3 (Delivery Time) - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->arrival_date, (FILETIME*)); + DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->arrival_date))); + break; + case 0x0E07: // PR_MESSAGE_FLAGS Email Flag + // 0x01 - Read + // 0x02 - Unmodified + // 0x04 - Submit + // 0x08 - Unsent + // 0x10 - Has Attachments + // 0x20 - From Me + // 0x40 - Associated + // 0x80 - Resend + // 0x100 - RN Pending + // 0x200 - NRN Pending + DEBUG_EMAIL(("Message Flags - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->flag), list->items[x]->data, sizeof(item->email->flag)); + LE32_CPU(item->email->flag); + DEBUG_EMAIL(("%i\n", item->email->flag)); + break; + case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object + DEBUG_EMAIL(("Message Size - ")); + memcpy(&(item->message_size), list->items[x]->data, sizeof(item->message_size)); + LE32_CPU(item->message_size); + DEBUG_EMAIL(("%i [%#x]\n", item->message_size, item->message_size)); + break; + case 0x0E0A: // PR_SENTMAIL_ENTRYID + // folder that this message is sent to after submission + DEBUG_EMAIL(("Sentmail EntryID - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->sentmail_folder, (pst_entryid*)); + LE32_CPU(item->email->sentmail_folder->id); + DEBUG_EMAIL(("[id = %#x]\n", item->email->sentmail_folder->id)); + break; + case 0x0E1F: // PR_RTF_IN_SYNC + // True means that the rtf version is same as text body + // False means rtf version is more up-to-date than text body + // if this value doesn't exist, text body is more up-to-date than rtf and + // cannot update to the rtf + DEBUG_EMAIL(("Compressed RTF in Sync - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->rtf_in_sync = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->rtf_in_sync = 0; + } + break; + case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record + DEBUG_EMAIL(("Attachment Size - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + memcpy(&(attach->size), list->items[x]->data, sizeof(attach->size)); + DEBUG_EMAIL(("%i\n", attach->size)); + break; + case 0x0FF9: // PR_RECORD_KEY Record Header 1 + DEBUG_EMAIL(("Record Key 1 - ")); + LIST_COPY(item->record_key, (char*)); + item->record_key_size = list->items[x]->size; + DEBUG_EMAIL_HEXPRINT(item->record_key, item->record_key_size); + DEBUG_EMAIL(("\n")); + break; + case 0x1000: // PR_BODY Plain Text body + DEBUG_EMAIL(("Plain Text body - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->body, (char*)); + //DEBUG_EMAIL("%s\n", item->email->body); + DEBUG_EMAIL(("NOT PRINTED\n")); + break; + case 0x1006: // PR_RTF_SYNC_BODY_CRC + DEBUG_EMAIL(("RTF Sync Body CRC - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->rtf_body_crc), list->items[x]->data, sizeof(item->email->rtf_body_crc)); + LE32_CPU(item->email->rtf_body_crc); + DEBUG_EMAIL(("%#x\n", item->email->rtf_body_crc)); + break; + case 0x1007: // PR_RTF_SYNC_BODY_COUNT + // a count of the *significant* charcters in the rtf body. Doesn't count + // whitespace and other ignorable characters + DEBUG_EMAIL(("RTF Sync Body character count - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->rtf_body_char_count), list->items[x]->data, sizeof(item->email->rtf_body_char_count)); + LE32_CPU(item->email->rtf_body_char_count); + DEBUG_EMAIL(("%i [%#x]\n", item->email->rtf_body_char_count, item->email->rtf_body_char_count)); + break; + case 0x1008: // PR_RTF_SYNC_BODY_TAG + // the first couple of lines of RTF body so that after modification, then beginning can + // once again be found + DEBUG_EMAIL(("RTF Sync body tag - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->rtf_body_tag, (char*)); + DEBUG_EMAIL(("%s\n", item->email->rtf_body_tag)); + break; + case 0x1009: // PR_RTF_COMPRESSED + // some compression algorithm has been applied to this. At present + // it is unknown + DEBUG_EMAIL(("RTF Compressed body - ")); + MALLOC_EMAIL(item); + LIST_COPY_SIZE(item->email->rtf_compressed, (char*), item->email->rtf_compressed_size); + DEBUG_EMAIL(("NOT PRINTED\n")); + break; + case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT + // a count of the ignored characters before the first significant character + DEBUG_EMAIL(("RTF whitespace prefix count - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->rtf_ws_prefix_count), list->items[x]->data, sizeof(item->email->rtf_ws_prefix_count)); + DEBUG_EMAIL(("%i\n", item->email->rtf_ws_prefix_count)); + break; + case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT + // a count of the ignored characters after the last significant character + DEBUG_EMAIL(("RTF whitespace tailing count - ")); + MALLOC_EMAIL(item); + memcpy(&(item->email->rtf_ws_trailing_count), list->items[x]->data, sizeof(item->email->rtf_ws_trailing_count)); + DEBUG_EMAIL(("%i\n", item->email->rtf_ws_trailing_count)); + break; + case 0x1013: // HTML body + DEBUG_EMAIL(("HTML body - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->htmlbody, (char*)); + // DEBUG_EMAIL(("%s\n", item->email->htmlbody)); + DEBUG_EMAIL(("NOT PRINTED\n")); + break; + case 0x1035: // Message ID + DEBUG_EMAIL(("Message ID - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->messageid, (char*)); + DEBUG_EMAIL(("%s\n", item->email->messageid)); + break; + case 0x1042: // in-reply-to + DEBUG_EMAIL(("In-Reply-To - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->in_reply_to, (char*)); + DEBUG_EMAIL(("%s\n", item->email->in_reply_to)); + break; + case 0x1046: // Return Path + DEBUG_EMAIL(("Return Path - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->return_path_address, (char*)); + DEBUG_EMAIL(("%s\n", item->email->return_path_address)); + break; + case 0x3001: // PR_DISPLAY_NAME File As + DEBUG_EMAIL(("Display Name - ")); + LIST_COPY(item->file_as, (char*)); + DEBUG_EMAIL(("%s\n", item->file_as)); + break; + case 0x3002: // PR_ADDRTYPE + DEBUG_EMAIL(("Address Type - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1_transport, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport)); + break; + case 0x3003: // PR_EMAIL_ADDRESS + // Contact's email address + DEBUG_EMAIL(("Contact Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1)); + break; + case 0x3004: // PR_COMMENT Comment for item - usually folders + DEBUG_EMAIL(("Comment - ")); + LIST_COPY(item->comment, (char*)); + DEBUG_EMAIL(("%s\n", item->comment)); + break; + case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date? + DEBUG_EMAIL(("Date 4 (Item Creation Date) - ")); + LIST_COPY(item->create_date, (FILETIME*)); + DEBUG_EMAIL(("%s", fileTimeToAscii(item->create_date))); + break; + case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date + DEBUG_EMAIL(("Date 5 (Modify Date) - ")); + LIST_COPY(item->modify_date, (FILETIME*)); + DEBUG_EMAIL(("%s", fileTimeToAscii(item->modify_date))); + break; + case 0x300B: // PR_SEARCH_KEY Record Header 2 + DEBUG_EMAIL(("Record Search 2 -- NOT HANDLED\n")); + break; + case 0x35DF: // PR_VALID_FOLDER_MASK + // States which folders are valid for this message store + // FOLDER_IPM_SUBTREE_VALID 0x1 + // FOLDER_IPM_INBOX_VALID 0x2 + // FOLDER_IPM_OUTBOX_VALID 0x4 + // FOLDER_IPM_WASTEBOX_VALID 0x8 + // FOLDER_IPM_SENTMAIL_VALID 0x10 + // FOLDER_VIEWS_VALID 0x20 + // FOLDER_COMMON_VIEWS_VALID 0x40 + // FOLDER_FINDER_VALID 0x80 + DEBUG_EMAIL(("Valid Folder Mask - ")); + MALLOC_MESSAGESTORE(item); + memcpy(&(item->message_store->valid_mask), list->items[x]->data, sizeof(int)); + LE32_CPU(item->message_store->valid_mask); + DEBUG_EMAIL(("%i\n", item->message_store->valid_mask)); + break; + case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record + DEBUG_EMAIL(("Top of Personal Folder Record - ")); + MALLOC_MESSAGESTORE(item); + LIST_COPY(item->message_store->top_of_personal_folder, (pst_entryid*)); + LE32_CPU(item->message_store->top_of_personal_folder->id); + DEBUG_EMAIL(("[id = %#x]\n", item->message_store->top_of_personal_folder->id)); + break; + case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID Deleted Items Folder Record + DEBUG_EMAIL(("Deleted Items Folder record - ")); + MALLOC_MESSAGESTORE(item); + LIST_COPY(item->message_store->deleted_items_folder, (pst_entryid*)); + LE32_CPU(item->message_store->deleted_items_folder->id); + DEBUG_EMAIL(("[id = %#x]\n", item->message_store->deleted_items_folder->id)); + break; + case 0x35E7: // PR_FINDER_ENTRYID Search Root Record + DEBUG_EMAIL(("Search Root record - ")); + MALLOC_MESSAGESTORE(item); + LIST_COPY(item->message_store->search_root_folder, (pst_entryid*)); + LE32_CPU(item->message_store->search_root_folder->id); + DEBUG_EMAIL(("[id = %#x]\n", item->message_store->search_root_folder->id)); + break; + case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder + DEBUG_EMAIL(("Folder Email Count - ")); + MALLOC_FOLDER(item); + memcpy(&(item->folder->email_count), list->items[x]->data, sizeof(item->folder->email_count)); + LE32_CPU(item->folder->email_count); + DEBUG_EMAIL(("%i\n", item->folder->email_count)); + break; + case 0x3603: // PR_CONTENT_UNREAD Number of unread emails + DEBUG_EMAIL(("Unread Email Count - ")); + MALLOC_FOLDER(item); + memcpy(&(item->folder->unseen_email_count), list->items[x]->data, sizeof(item->folder->unseen_email_count)); + LE32_CPU(item->folder->unseen_email_count); + DEBUG_EMAIL(("%i\n", item->folder->unseen_email_count)); + break; + case 0x360A: // PR_SUBFOLDERS Has children + DEBUG_EMAIL(("Has Subfolders - ")); + MALLOC_FOLDER(item); + if (*((int32_t*)list->items[x]->data) != 0) { + DEBUG_EMAIL(("True\n")); + item->folder->subfolder = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->folder->subfolder = 0; + } + break; + case 0x3613: // PR_CONTAINER_CLASS IPF.x + DEBUG_EMAIL(("IPF.x - ")); + LIST_COPY(item->ascii_type, (char*)); + if (strncmp("IPF.Note", item->ascii_type, 8) == 0) + item->type = PST_TYPE_NOTE; + else if (strncmp("IPF.Contact", item->ascii_type, 11) == 0) + item->type = PST_TYPE_CONTACT; + else if (strncmp("IPF.Journal", item->ascii_type, 11) == 0) + item->type = PST_TYPE_JOURNAL; + else if (strncmp("IPF.Appointment", item->ascii_type, 15) == 0) + item->type = PST_TYPE_APPOINTMENT; + else if (strncmp("IPF.StickyNote", item->ascii_type, 14) == 0) + item->type = PST_TYPE_STICKYNOTE; + else if (strncmp("IPF.Task", item->ascii_type, 8) == 0) + item->type = PST_TYPE_TASK; + else + item->type = PST_TYPE_OTHER; + + DEBUG_EMAIL(("%s [%i]\n", item->ascii_type, item->type)); + break; + case 0x3617: // PR_ASSOC_CONTENT_COUNT + // associated content are items that are attached to this folder + // but are hidden from users + DEBUG_EMAIL(("Associate Content count - ")); + MALLOC_FOLDER(item); + memcpy(&(item->folder->assoc_count), list->items[x]->data, sizeof(item->folder->assoc_count)); + LE32_CPU(item->folder->assoc_count); + DEBUG_EMAIL(("%i [%#x]\n", item->folder->assoc_count, item->folder->assoc_count)); + break; + case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment + DEBUG_EMAIL(("Binary Data [Size %i] - ", list->items[x]->size)); + NULL_CHECK(attach); + MOVE_NEXT(attach); + if (!list->items[x]->data) { //special case + attach->id2_val = list->items[x]->type; + DEBUG_EMAIL(("Seen a Reference. The data hasn't been loaded yet. [%#x][%#x]\n", + attach->id2_val, list->items[x]->type)); + } else { + LIST_COPY(attach->data, (char*)); + attach->size = list->items[x]->size; + DEBUG_EMAIL(("NOT PRINTED\n")); + } + break; + case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3) + DEBUG_EMAIL(("Attachment Filename - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + LIST_COPY(attach->filename1, (char*)); + DEBUG_EMAIL(("%s\n", attach->filename1)); + break; + case 0x3705: // PR_ATTACH_METHOD + // 0 - No Attachment + // 1 - Attach by Value + // 2 - Attach by reference + // 3 - Attach by ref resolve + // 4 - Attach by ref only + // 5 - Embedded Message + // 6 - OLE + DEBUG_EMAIL(("Attachment method - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + memcpy(&(attach->method), list->items[x]->data, sizeof(attach->method)); + LE32_CPU(attach->method); + t = attach->method; + DEBUG_EMAIL(("%s [%i]\n", (t==0?"No Attachment": + (t==1?"Attach By Value": + (t==2?"Attach By Reference": + (t==3?"Attach by Ref. Resolve": + (t==4?"Attach by Ref. Only": + (t==5?"Embedded Message":"OLE")))))),t)); + break; + case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?) + DEBUG_EMAIL(("Attachment Filename long - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + LIST_COPY(attach->filename2, (char*)); + DEBUG_EMAIL(("%s\n", attach->filename2)); + break; + case 0x370B: // PR_RENDERING_POSITION + // position in characters that the attachment appears in the plain text body + DEBUG_EMAIL(("Attachment Position - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + memcpy(&(attach->position), list->items[x]->data, sizeof(attach->position)); + LE32_CPU(attach->position); + DEBUG_EMAIL(("%i [%#x]\n", attach->position)); + break; + case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding + DEBUG_EMAIL(("Attachment mime encoding - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + LIST_COPY(attach->mimetype, (char*)); + DEBUG_EMAIL(("%s\n", attach->mimetype)); + break; + case 0x3710: // PR_ATTACH_MIME_SEQUENCE + // sequence number for mime parts. Includes body + DEBUG_EMAIL(("Attachment Mime Sequence - ")); + NULL_CHECK(attach); + MOVE_NEXT(attach); + memcpy(&(attach->sequence), list->items[x]->data, sizeof(attach->sequence)); + LE32_CPU(attach->sequence); + DEBUG_EMAIL(("%i\n", attach->sequence)); + break; + case 0x3A00: // PR_ACCOUNT + DEBUG_EMAIL(("Contact's Account name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->account_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->account_name)); + break; + case 0x3A01: // PR_ALTERNATE_RECIPIENT + DEBUG_EMAIL(("Contact Alternate Recipient - NOT PROCESSED\n")); + break; + case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER + DEBUG_EMAIL(("Callback telephone number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->callback_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->callback_phone)); + break; + case 0x3A03: // PR_CONVERSION_PROHIBITED + DEBUG_EMAIL(("Message Conversion Prohibited - ")); + MALLOC_EMAIL(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->email->conversion_prohib = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->email->conversion_prohib = 0; + } + break; + case 0x3A05: // PR_GENERATION suffix + DEBUG_EMAIL(("Contacts Suffix - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->suffix, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->suffix)); + break; + case 0x3A06: // PR_GIVEN_NAME Contact's first name + DEBUG_EMAIL(("Contacts First Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->first_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->first_name)); + break; + case 0x3A07: // PR_GOVERNMENT_ID_NUMBER + DEBUG_EMAIL(("Contacts Government ID Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->gov_id, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->gov_id)); + break; + case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER + DEBUG_EMAIL(("Business Telephone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_phone)); + break; + case 0x3A09: // PR_HOME_TELEPHONE_NUMBER + DEBUG_EMAIL(("Home Telephone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_phone)); + break; + case 0x3A0A: // PR_INITIALS Contact's Initials + DEBUG_EMAIL(("Contacts Initials - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->initials, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->initials)); + break; + case 0x3A0B: // PR_KEYWORD + DEBUG_EMAIL(("Keyword - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->keyword, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->keyword)); + break; + case 0x3A0C: // PR_LANGUAGE + DEBUG_EMAIL(("Contact's Language - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->language, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->language)); + break; + case 0x3A0D: // PR_LOCATION + DEBUG_EMAIL(("Contact's Location - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->location, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->location)); + break; + case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email + DEBUG_EMAIL(("Mail Permission - ")); + MALLOC_CONTACT(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->contact->mail_permission = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->contact->mail_permission = 0; + } + break; + case 0x3A0F: // PR_MHS_COMMON_NAME + DEBUG_EMAIL(("MHS Common Name - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->common_name, (char*)); + DEBUG_EMAIL(("%s\n", item->email->common_name)); + break; + case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER + DEBUG_EMAIL(("Organizational ID # - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->org_id, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->org_id)); + break; + case 0x3A11: // PR_SURNAME Contact's Surname + DEBUG_EMAIL(("Contacts Surname - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->surname, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->surname)); + break; + case 0x3A12: // PR_ORIGINAL_ENTRY_ID + DEBUG_EMAIL(("Original Entry ID - NOT PROCESSED\n")); + break; + case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME + DEBUG_EMAIL(("Original Display Name - NOT PROCESSED\n")); + break; + case 0x3A14: // PR_ORIGINAL_SEARCH_KEY + DEBUG_EMAIL(("Original Search Key - NOT PROCESSED\n")); + break; + case 0x3A15: // PR_POSTAL_ADDRESS + DEBUG_EMAIL(("Default Postal Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->def_postal_address, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->def_postal_address)); + break; + case 0x3A16: // PR_COMPANY_NAME + DEBUG_EMAIL(("Company Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->company_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->company_name)); + break; + case 0x3A17: // PR_TITLE - Job Title + DEBUG_EMAIL(("Job Title - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->job_title, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->job_title)); + break; + case 0x3A18: // PR_DEPARTMENT_NAME + DEBUG_EMAIL(("Department Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->department, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->department)); + break; + case 0x3A19: // PR_OFFICE_LOCATION + DEBUG_EMAIL(("Office Location - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->office_loc, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->office_loc)); + break; + case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER + DEBUG_EMAIL(("Primary Telephone - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->primary_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->primary_phone)); + break; + case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER + DEBUG_EMAIL(("Business Phone Number 2 - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_phone2, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_phone2)); + break; + case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER + DEBUG_EMAIL(("Mobile Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->mobile_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->mobile_phone)); + break; + case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER + DEBUG_EMAIL(("Radio Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->radio_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->radio_phone)); + break; + case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER + DEBUG_EMAIL(("Car Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->car_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->car_phone)); + break; + case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER + DEBUG_EMAIL(("Other Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_phone)); + break; + case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME + DEBUG_EMAIL(("Transmittable Display Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->transmittable_display_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->transmittable_display_name)); + break; + case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER + DEBUG_EMAIL(("Pager Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->pager_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->pager_phone)); + break; + case 0x3A22: // PR_USER_CERTIFICATE + DEBUG_EMAIL(("User Certificate - NOT PROCESSED")); + break; + case 0x3A23: // PR_PRIMARY_FAX_NUMBER + DEBUG_EMAIL(("Primary Fax Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->primary_fax, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->primary_fax)); + break; + case 0x3A24: // PR_BUSINESS_FAX_NUMBER + DEBUG_EMAIL(("Business Fax Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_fax, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_fax)); + break; + case 0x3A25: // PR_HOME_FAX_NUMBER + DEBUG_EMAIL(("Home Fax Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_fax, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_fax)); + break; + case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY + DEBUG_EMAIL(("Business Address Country - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_country, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_country)); + break; + case 0x3A27: // PR_BUSINESS_ADDRESS_CITY + DEBUG_EMAIL(("Business Address City - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_city, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_city)); + break; + case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE + DEBUG_EMAIL(("Business Address State - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_state, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_state)); + break; + case 0x3A29: // PR_BUSINESS_ADDRESS_STREET + DEBUG_EMAIL(("Business Address Street - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_street, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_street)); + break; + case 0x3A2A: // PR_BUSINESS_POSTAL_CODE + DEBUG_EMAIL(("Business Postal Code - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_postal_code, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_postal_code)); + break; + case 0x3A2B: // PR_BUSINESS_PO_BOX + DEBUG_EMAIL(("Business PO Box - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_po_box, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_po_box)); + break; + case 0x3A2C: // PR_TELEX_NUMBER + DEBUG_EMAIL(("Telex Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->telex, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->telex)); + break; + case 0x3A2D: // PR_ISDN_NUMBER + DEBUG_EMAIL(("ISDN Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->isdn_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->isdn_phone)); + break; + case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER + DEBUG_EMAIL(("Assistant Phone Number - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->assistant_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->assistant_phone)); + break; + case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER + DEBUG_EMAIL(("Home Phone 2 - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_phone2, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_phone2)); + break; + case 0x3A30: // PR_ASSISTANT + DEBUG_EMAIL(("Assistant's Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->assistant_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->assistant_name)); + break; + case 0x3A40: // PR_SEND_RICH_INFO + DEBUG_EMAIL(("Can receive Rich Text - ")); + MALLOC_CONTACT(item); + if(*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->contact->rich_text = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->contact->rich_text = 0; + } + break; + case 0x3A41: // PR_WEDDING_ANNIVERSARY + DEBUG_EMAIL(("Wedding Anniversary - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->wedding_anniversary, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->contact->wedding_anniversary))); + break; + case 0x3A42: // PR_BIRTHDAY + DEBUG_EMAIL(("Birthday - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->birthday, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->contact->birthday))); + break; + case 0x3A43: // PR_HOBBIES + DEBUG_EMAIL(("Hobbies - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->hobbies, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->hobbies)); + break; + case 0x3A44: // PR_MIDDLE_NAME + DEBUG_EMAIL(("Middle Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->middle_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->middle_name)); + break; + case 0x3A45: // PR_DISPLAY_NAME_PREFIX + DEBUG_EMAIL(("Display Name Prefix (Title) - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->display_name_prefix, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->display_name_prefix)); + break; + case 0x3A46: // PR_PROFESSION + DEBUG_EMAIL(("Profession - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->profession, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->profession)); + break; + case 0x3A47: // PR_PREFERRED_BY_NAME + DEBUG_EMAIL(("Preferred By Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->pref_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->pref_name)); + break; + case 0x3A48: // PR_SPOUSE_NAME + DEBUG_EMAIL(("Spouse's Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->spouse_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->spouse_name)); + break; + case 0x3A49: // PR_COMPUTER_NETWORK_NAME + DEBUG_EMAIL(("Computer Network Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->computer_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->computer_name)); + break; + case 0x3A4A: // PR_CUSTOMER_ID + DEBUG_EMAIL(("Customer ID - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->customer_id, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->customer_id)); + break; + case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER + DEBUG_EMAIL(("TTY/TDD Phone - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->ttytdd_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->ttytdd_phone)); + break; + case 0x3A4C: // PR_FTP_SITE + DEBUG_EMAIL(("Ftp Site - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->ftp_site, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->ftp_site)); + break; + case 0x3A4D: // PR_GENDER + DEBUG_EMAIL(("Gender - ")); + MALLOC_CONTACT(item); + memcpy(&item->contact->gender, list->items[x]->data, sizeof(int16_t)); + LE16_CPU(item->contact->gender); + switch(item->contact->gender) { + case 0: + DEBUG_EMAIL(("Unspecified\n")); + break; + case 1: + DEBUG_EMAIL(("Female\n")); + break; + case 2: + DEBUG_EMAIL(("Male\n")); + break; + default: + DEBUG_EMAIL(("Error processing\n")); + } + break; + case 0x3A4E: // PR_MANAGER_NAME + DEBUG_EMAIL(("Manager's Name - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->manager_name, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->manager_name)); + break; + case 0x3A4F: // PR_NICKNAME + DEBUG_EMAIL(("Nickname - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->nickname, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->nickname)); + break; + case 0x3A50: // PR_PERSONAL_HOME_PAGE + DEBUG_EMAIL(("Personal Home Page - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->personal_homepage, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->personal_homepage)); + break; + case 0x3A51: // PR_BUSINESS_HOME_PAGE + DEBUG_EMAIL(("Business Home Page - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_homepage, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_homepage)); + break; + case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER + DEBUG_EMAIL(("Company Main Phone - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->company_main_phone, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->company_main_phone)); + break; + case 0x3A58: // PR_CHILDRENS_NAMES + DEBUG_EMAIL(("Children's Names - NOT PROCESSED\n")); + break; + case 0x3A59: // PR_HOME_ADDRESS_CITY + DEBUG_EMAIL(("Home Address City - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_city, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_city)); + break; + case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY + DEBUG_EMAIL(("Home Address Country - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_country, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_country)); + break; + case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE + DEBUG_EMAIL(("Home Address Postal Code - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_postal_code, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_postal_code)); + break; + case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE + DEBUG_EMAIL(("Home Address State or Province - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_state, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_state)); + break; + case 0x3A5D: // PR_HOME_ADDRESS_STREET + DEBUG_EMAIL(("Home Address Street - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_street, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_street)); + break; + case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX + DEBUG_EMAIL(("Home Address Post Office Box - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_po_box, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_po_box)); + break; + case 0x3A5F: // PR_OTHER_ADDRESS_CITY + DEBUG_EMAIL(("Other Address City - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_city, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_city)); + break; + case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY + DEBUG_EMAIL(("Other Address Country - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_country, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_country)); + break; + case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE + DEBUG_EMAIL(("Other Address Postal Code - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_postal_code, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_postal_code)); + break; + case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE + DEBUG_EMAIL(("Other Address State - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_state, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_state)); + break; + case 0x3A63: // PR_OTHER_ADDRESS_STREET + DEBUG_EMAIL(("Other Address Street - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_street, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_street)); + break; + case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX + DEBUG_EMAIL(("Other Address Post Office box - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_po_box, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_po_box)); + break; + case 0x65E3: // Entry ID? + DEBUG_EMAIL(("Entry ID - ")); + item->record_key = (char*) xmalloc(16+1); + memcpy(item->record_key, &(list->items[x]->data[1]), 16); //skip first byte + item->record_key[16]='\0'; + item->record_key_size=16; + DEBUG_EMAIL_HEXPRINT((char*)item->record_key, 16); + break; + case 0x67F2: // ID2 value of the attachments proper record + DEBUG_EMAIL(("Attachment ID2 value - ")); + if (attach){ + MOVE_NEXT(attach); + memcpy(&(attach->id2_val), list->items[x]->data, sizeof(attach->id2_val)); + LE32_CPU(attach->id2_val); + DEBUG_EMAIL(("%#x\n", attach->id2_val)); + } else { + DEBUG_EMAIL(("NOT AN ATTACHMENT: %#x\n", list->items[x]->id)); + } + break; + case 0x67FF: // Extra Property Identifier (Password CheckSum) + DEBUG_EMAIL(("Password checksum [0x67FF] - ")); + MALLOC_MESSAGESTORE(item); + memcpy(&(item->message_store->pwd_chksum), list->items[x]->data, + sizeof(item->message_store->pwd_chksum)); + DEBUG_EMAIL(("%#x\n", item->message_store->pwd_chksum)); + break; + case 0x6F02: // Secure HTML Body + DEBUG_EMAIL(("Secure HTML Body - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->encrypted_htmlbody, (char*)); + item->email->encrypted_htmlbody_size = list->items[x]->size; + DEBUG_EMAIL(("Not Printed\n")); + break; + case 0x6F04: // Secure Text Body + DEBUG_EMAIL(("Secure Text Body - ")); + MALLOC_EMAIL(item); + LIST_COPY(item->email->encrypted_body, (char*)); + item->email->encrypted_body_size = list->items[x]->size; + DEBUG_EMAIL(("Not Printed\n")); + break; + case 0x7C07: // top of folders ENTRYID + DEBUG_EMAIL(("Top of folders RecID [0x7c07] - ")); + MALLOC_MESSAGESTORE(item); + item->message_store->top_of_folder = (pst_entryid*) xmalloc(sizeof(pst_entryid)); + memcpy(item->message_store->top_of_folder, list->items[x]->data, sizeof(pst_entryid)); + LE32_CPU(item->message_store->top_of_folder->u1); + LE32_CPU(item->message_store->top_of_folder->id); + DEBUG_EMAIL_HEXPRINT((char*)item->message_store->top_of_folder->entryid, 16); + break; + case 0x8005: // Contact's Fullname + DEBUG_EMAIL(("Contact Fullname - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->fullname, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->fullname)); + break; + case 0x801A: // Full Home Address + DEBUG_EMAIL(("Home Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->home_address, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->home_address)); + break; + case 0x801B: // Full Business Address + DEBUG_EMAIL(("Business Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->business_address, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->business_address)); + break; + case 0x801C: // Full Other Address + DEBUG_EMAIL(("Other Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->other_address, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->other_address)); + break; + case 0x8082: // Email Address 1 Transport + DEBUG_EMAIL(("Email Address 1 Transport - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1_transport, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport)); + break; + case 0x8083: // Email Address 1 Address + DEBUG_EMAIL(("Email Address 1 Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1)); + break; + case 0x8084: // Email Address 1 Description + DEBUG_EMAIL(("Email Address 1 Description - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1_desc, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1_desc)); + break; + case 0x8085: // Email Address 1 Record + DEBUG_EMAIL(("Email Address 1 Record - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address1a, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address1a)); + break; + case 0x8092: // Email Address 2 Transport + DEBUG_EMAIL(("Email Address 2 Transport - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address2_transport, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address2_transport)); + break; + case 0x8093: // Email Address 2 Address + DEBUG_EMAIL(("Email Address 2 Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address2, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address2)); + break; + case 0x8094: // Email Address 2 Description + DEBUG_EMAIL (("Email Address 2 Description - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address2_desc, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address2_desc)); + break; + case 0x8095: // Email Address 2 Record + DEBUG_EMAIL(("Email Address 2 Record - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address2a, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address2a)); + break; + case 0x80A2: // Email Address 3 Transport + DEBUG_EMAIL (("Email Address 3 Transport - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address3_transport, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address3_transport)); + break; + case 0x80A3: // Email Address 3 Address + DEBUG_EMAIL(("Email Address 3 Address - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address3, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address3)); + break; + case 0x80A4: // Email Address 3 Description + DEBUG_EMAIL(("Email Address 3 Description - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address3_desc, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address3_desc)); + break; + case 0x80A5: // Email Address 3 Record + DEBUG_EMAIL(("Email Address 3 Record - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->address3a, (char*)); + DEBUG_EMAIL(("|%s|\n", item->contact->address3a)); + break; + case 0x80D8: // Internet Free/Busy + DEBUG_EMAIL(("Internet Free/Busy - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->free_busy_address, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->free_busy_address)); + break; + case 0x8205: // Show on Free/Busy as + // 0: Free + // 1: Tentative + // 2: Busy + // 3: Out Of Office + DEBUG_EMAIL(("Appointment shows as - ")); + MALLOC_APPOINTMENT(item); + memcpy(&(item->appointment->showas), list->items[x]->data, sizeof(item->appointment->showas)); + LE32_CPU(item->appointment->showas); + switch (item->appointment->showas) { + case PST_FREEBUSY_FREE: + DEBUG_EMAIL(("Free\n")); break; + case PST_FREEBUSY_TENTATIVE: + DEBUG_EMAIL(("Tentative\n")); break; + case PST_FREEBUSY_BUSY: + DEBUG_EMAIL(("Busy\n")); break; + case PST_FREEBUSY_OUT_OF_OFFICE: + DEBUG_EMAIL(("Out Of Office\n")); break; + default: + DEBUG_EMAIL(("Unknown Value: %d\n", item->appointment->showas)); break; + } + break; + case 0x8208: // Location of an appointment + DEBUG_EMAIL(("Appointment Location - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->location, (char*)); + DEBUG_EMAIL(("%s\n", item->appointment->location)); + break; + case 0x8214: // Label for an appointment + DEBUG_EMAIL(("Label for appointment - ")); + MALLOC_APPOINTMENT(item); + memcpy(&(item->appointment->label), list->items[x]->data, sizeof(item->appointment->label)); + LE32_CPU(item->appointment->label); + switch (item->appointment->label) { + case PST_APP_LABEL_NONE: + DEBUG_EMAIL(("None\n")); break; + case PST_APP_LABEL_IMPORTANT: + DEBUG_EMAIL(("Important\n")); break; + case PST_APP_LABEL_BUSINESS: + DEBUG_EMAIL(("Business\n")); break; + case PST_APP_LABEL_PERSONAL: + DEBUG_EMAIL(("Personal\n")); break; + case PST_APP_LABEL_VACATION: + DEBUG_EMAIL(("Vacation\n")); break; + case PST_APP_LABEL_MUST_ATTEND: + DEBUG_EMAIL(("Must Attend\n")); break; + case PST_APP_LABEL_TRAVEL_REQ: + DEBUG_EMAIL(("Travel Required\n")); break; + case PST_APP_LABEL_NEEDS_PREP: + DEBUG_EMAIL(("Needs Preparation\n")); break; + case PST_APP_LABEL_BIRTHDAY: + DEBUG_EMAIL(("Birthday\n")); break; + case PST_APP_LABEL_ANNIVERSARY: + DEBUG_EMAIL(("Anniversary\n")); break; + case PST_APP_LABEL_PHONE_CALL: + DEBUG_EMAIL(("Phone Call\n")); break; + } + break; + case 0x8215: // All day appointment flag + DEBUG_EMAIL(("All day flag - ")); + MALLOC_APPOINTMENT(item); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->appointment->all_day = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->appointment->all_day = 0; + } + break; + case 0x8234: // TimeZone as String + DEBUG_EMAIL(("TimeZone of times - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->timezonestring, (char*)); + DEBUG_EMAIL(("%s\n", item->appointment->timezonestring)); + break; + case 0x8235: // Appointment start time + DEBUG_EMAIL(("Appointment Start Time - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->start, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); + break; + case 0x8236: // Appointment end time + DEBUG_EMAIL(("Appointment End Time - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->end, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); + break; + case 0x8516: // Journal time start + DEBUG_EMAIL(("Duplicate Time Start - ")); + DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); + break; + case 0x8517: // Journal time end + DEBUG_EMAIL(("Duplicate Time End - ")); + DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); + break; + case 0x8530: // Followup + DEBUG_EMAIL(("Followup String - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->followup, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->followup)); + break; + case 0x8534: // Mileage + DEBUG_EMAIL(("Mileage - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->mileage, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->mileage)); + break; + case 0x8535: // Billing Information + DEBUG_EMAIL(("Billing Information - ")); + MALLOC_CONTACT(item); + LIST_COPY(item->contact->billing_information, (char*)); + DEBUG_EMAIL(("%s\n", item->contact->billing_information)); + break; + case 0x8554: // Outlook Version + DEBUG_EMAIL(("Outlook Version - ")); + LIST_COPY(item->outlook_version, (char*)); + DEBUG_EMAIL(("%s\n", item->outlook_version)); + break; + case 0x8560: // Appointment Reminder Time + DEBUG_EMAIL(("Appointment Reminder Time - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->reminder, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->reminder))); + break; + case 0x8700: // Journal Type + DEBUG_EMAIL(("Journal Entry Type - ")); + MALLOC_JOURNAL(item); + LIST_COPY(item->journal->type, (char*)); + DEBUG_EMAIL(("%s\n", item->journal->type)); + break; + case 0x8706: // Journal Start date/time + DEBUG_EMAIL(("Start Timestamp - ")); + MALLOC_JOURNAL(item); + LIST_COPY(item->journal->start, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->journal->start))); + break; + case 0x8708: // Journal End date/time + DEBUG_EMAIL(("End Timestamp - ")); + MALLOC_JOURNAL(item); + LIST_COPY(item->journal->end, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->journal->end))); + break; + case 0x8712: // Title? + DEBUG_EMAIL(("Journal Entry Type - ")); + MALLOC_JOURNAL(item); + LIST_COPY(item->journal->type, (char*)); + DEBUG_EMAIL(("%s\n", item->journal->type)); + break; + default: + DEBUG_EMAIL(("unknown type %#x\n", list->items[x]->id)); + /* Reference Types + + 2 - 0x0002 - Signed 16bit value + 3 - 0x0003 - Signed 32bit value + 11 - 0x000B - Boolean (non-zero = true) + 13 - 0x000D - Embedded Object + 30 - 0x001E - Null terminated String + 31 - 0x001F - Unicode string + 64 - 0x0040 - Systime - Filetime structure + 72 - 0x0048 - OLE Guid + 258 - 0x0102 - Binary data + + - 0x1003 - Array of 32bit values + - 0x101E - Array of Strings + - 0x1102 - Array of Binary data + */ + // DEBUG_EMAIL(("Unknown id [%#x, size=%#x]\n", list->items[x]->id, list->items[x]->size)); + if (list->items[x]->type == 0x02) { + DEBUG_EMAIL(("Unknown 16bit int = %hi\n", *(int16_t*)list->items[x]->data)); + } else if (list->items[x]->type == 0x03) { + DEBUG_EMAIL(("Unknown 32bit int = %i\n", *(int32_t*)list->items[x]->data)); + } else if (list->items[x]->type == 0x0b) { + DEBUG_EMAIL(("Unknown 16bit boolean = %s [%hi]\n", + (*((int16_t*)list->items[x]->data)!=0?"True":"False"), + *((int16_t*)list->items[x]->data))); + } else if (list->items[x]->type == 0x1e) { + DEBUG_EMAIL(("Unknown String Data = \"%s\" [%#x]\n", + list->items[x]->data, list->items[x]->type)); + } else if (list->items[x]->type == 0x40) { + DEBUG_EMAIL(("Unknown Date = \"%s\" [%#x]\n", + fileTimeToAscii((FILETIME*)list->items[x]->data), + list->items[x]->type)); + } else if (list->items[x]->type == 0x102) { + DEBUG_EMAIL(("Unknown Binary Data [size = %#x]\n", + list->items[x]->size)); + DEBUG_HEXDUMP(list->items[x]->data, list->items[x]->size); + } else if (list->items[x]->type == 0x101E) { + DEBUG_EMAIL(("Unknown Array of Strings [%#x]\n", + list->items[x]->type)); + } else { + DEBUG_EMAIL(("Unknown Not Printable [%#x]\n", + list->items[x]->type)); + } + if (list->items[x]->data) { + free(list->items[x]->data); + list->items[x]->data = NULL; + } + } + x++; + } + x = 0; + list = list->next; + next = 1; + } + DEBUG_RET(); + return 0; } int32_t _pst_free_list(pst_num_array *list) { - pst_num_array *l; - DEBUG_ENT("_pst_free_list"); - while (list) { - if (list->items) { - int32_t x; - for (x=0; x < list->orig_count; x++) { - if (list->items[x]) { - if (list->items[x]->data) free(list->items[x]->data); - free(list->items[x]); - } - } - free(list->items); - } - l = list; - list = list->next; - free (l); - } - DEBUG_RET(); - return 1; + pst_num_array *l; + DEBUG_ENT("_pst_free_list"); + while (list) { + if (list->items) { + int32_t x; + for (x=0; x < list->orig_count; x++) { + if (list->items[x]) { + if (list->items[x]->data) free(list->items[x]->data); + free(list->items[x]); + } + } + free(list->items); + } + l = list; + list = list->next; + free (l); + } + DEBUG_RET(); + return 1; } int32_t _pst_free_id2(pst_index2_ll * head) { - pst_index2_ll *t; - DEBUG_ENT("_pst_free_id2"); - while (head) { - t = head->next; - free (head); - head = t; - } - DEBUG_RET(); - return 1; + pst_index2_ll *t; + DEBUG_ENT("_pst_free_id2"); + while (head) { + t = head->next; + free (head); + head = t; + } + DEBUG_RET(); + return 1; } int32_t _pst_free_id (pst_index_ll *head) { - pst_index_ll *t; - DEBUG_ENT("_pst_free_id"); - while (head) { - t = head->next; - free(head); - head = t; - } - DEBUG_RET(); - return 1; + pst_index_ll *t; + DEBUG_ENT("_pst_free_id"); + while (head) { + t = head->next; + free(head); + head = t; + } + DEBUG_RET(); + return 1; } int32_t _pst_free_desc (pst_desc_ll *head) { - pst_desc_ll *t; - DEBUG_ENT("_pst_free_desc"); - while (head) { - while (head->child) { - head = head->child; - } - - // point t to the next item - t = head->next; - if (!t && head->parent) { - t = head->parent; - t->child = NULL; // set the child to NULL so we don't come back here again! - } - - if (head) free(head); - else DIE(("head is NULL")); - - head = t; - } - DEBUG_RET(); - return 1; + pst_desc_ll *t; + DEBUG_ENT("_pst_free_desc"); + while (head) { + while (head->child) { + head = head->child; + } + + // point t to the next item + t = head->next; + if (!t && head->parent) { + t = head->parent; + t->child = NULL; // set the child to NULL so we don't come back here again! + } + + if (head) free(head); + else DIE(("head is NULL")); + + head = t; + } + DEBUG_RET(); + return 1; } int32_t _pst_free_xattrib(pst_x_attrib_ll *x) { - pst_x_attrib_ll *t; - DEBUG_ENT("_pst_free_xattrib"); - while (x) { - if (x->data) free(x->data); - t = x->next; - free(x); - x = t; - } - DEBUG_RET(); - return 1; + pst_x_attrib_ll *t; + DEBUG_ENT("_pst_free_xattrib"); + while (x) { + if (x->data) free(x->data); + t = x->next; + free(x); + x = t; + } + DEBUG_RET(); + return 1; } pst_index2_ll * _pst_build_id2(pst_file *pf, pst_index_ll* list, pst_index2_ll* head_ptr) { - pst_block_header block_head; - pst_index2_ll *head = NULL, *tail = NULL; - int32_t x = 0, b_ptr = 0; - char *buf = NULL; - pst_id2_assoc id2_rec; - pst_index_ll *i_ptr = NULL; - pst_index2_ll *i2_ptr = NULL; - DEBUG_ENT("_pst_build_id2"); - - if (head_ptr) { - head = head_ptr; - while (head_ptr) head_ptr = (tail = head_ptr)->next; - } - if (_pst_read_block_size(pf, list->offset, list->size, &buf, PST_NO_ENC, 0) < list->size) { - //an error occured in block read - WARN(("block read error occured. offset = %#x, size = %#x\n", list->offset, list->size)); - if (buf) free(buf); - DEBUG_RET(); - return NULL; - } - DEBUG_HEXDUMPC(buf, list->size, 16); - - memcpy(&block_head, buf, sizeof(block_head)); - LE16_CPU(block_head.type); - LE16_CPU(block_head.count); - - if (block_head.type != 0x0002) { // some sort of constant? - WARN(("Unknown constant [%#x] at start of id2 values [offset %#x].\n", block_head.type, list->offset)); - if (buf) free(buf); - DEBUG_RET(); - return NULL; - } - - DEBUG_INDEX(("ID %#x is likely to be a description record. Count is %i (offset %#x)\n", - list->id, block_head.count, list->offset)); - x = 0; - b_ptr = 0x04; - while (x < block_head.count) { - memcpy(&id2_rec, &(buf[b_ptr]), sizeof(id2_rec)); - LE32_CPU(id2_rec.id2); - LE32_CPU(id2_rec.id); - LE32_CPU(id2_rec.table2); - - b_ptr += sizeof(id2_rec); - DEBUG_INDEX(("\tid2 = %#x, id = %#x, table2 = %#x\n", id2_rec.id2, id2_rec.id, id2_rec.table2)); - if ((i_ptr = _pst_getID(pf, id2_rec.id)) == NULL) { - DEBUG_WARN(("\t\t%#x - Not Found\n", id2_rec.id)); - } else { - DEBUG_INDEX(("\t\t%#x - Offset %#x, u1 %#x, Size %i(%#x)\n", i_ptr->id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->size)); - // add it to the linked list - i2_ptr = (pst_index2_ll*) xmalloc(sizeof(pst_index2_ll)); - i2_ptr->id2 = id2_rec.id2; - i2_ptr->id = i_ptr; - i2_ptr->next = NULL; - if (!head) head = i2_ptr; - if (tail) tail->next = i2_ptr; - tail = i2_ptr; - if (id2_rec.table2 != 0) { - if ((i_ptr = _pst_getID(pf, id2_rec.table2)) == NULL) { - DEBUG_WARN(("\tTable2 [%#x] not found\n", id2_rec.table2)); - } - else { - DEBUG_INDEX(("\tGoing deeper for table2 [%#x]\n", id2_rec.table2)); - if ((i2_ptr = _pst_build_id2(pf, i_ptr, head))) { - // DEBUG_INDEX(("_pst_build_id2(): \t\tAdding new list onto end of current\n")); - // if (!head) - // head = i2_ptr; - // if (tail) - // tail->next = i2_ptr; - // while (i2_ptr->next) - // i2_ptr = i2_ptr->next; - // tail = i2_ptr; - } - // need to re-establish tail - DEBUG_INDEX(("Returned from depth\n")); - if (tail) { - while (tail->next) tail = tail->next; - } - } - } - } - x++; - } - if (buf) free (buf); - DEBUG_RET(); - return head; + pst_block_header block_head; + pst_index2_ll *head = NULL, *tail = NULL; + int32_t x = 0, b_ptr = 0; + char *buf = NULL; + pst_id2_assoc id2_rec; + pst_index_ll *i_ptr = NULL; + pst_index2_ll *i2_ptr = NULL; + DEBUG_ENT("_pst_build_id2"); + + if (head_ptr) { + head = head_ptr; + while (head_ptr) head_ptr = (tail = head_ptr)->next; + } + if (_pst_read_block_size(pf, list->offset, list->size, &buf, PST_NO_ENC, 0) < list->size) { + //an error occured in block read + WARN(("block read error occured. offset = %#llx, size = %#llx\n", list->offset, list->size)); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + DEBUG_HEXDUMPC(buf, list->size, 16); + + memcpy(&block_head, buf, sizeof(block_head)); + LE16_CPU(block_head.type); + LE16_CPU(block_head.count); + + if (block_head.type != 0x0002) { // some sort of constant? + WARN(("Unknown constant [%#x] at start of id2 values [offset %#llx].\n", block_head.type, list->offset)); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + + DEBUG_INDEX(("ID %#x is likely to be a description record. Count is %i (offset %#x)\n", + list->id, block_head.count, list->offset)); + x = 0; + b_ptr = 0x04; + while (x < block_head.count) { + memcpy(&id2_rec, &(buf[b_ptr]), sizeof(id2_rec)); + LE32_CPU(id2_rec.id2); + LE32_CPU(id2_rec.id); + LE32_CPU(id2_rec.table2); + + b_ptr += sizeof(id2_rec); + DEBUG_INDEX(("\tid2 = %#x, id = %#x, table2 = %#x\n", id2_rec.id2, id2_rec.id, id2_rec.table2)); + if ((i_ptr = _pst_getID(pf, id2_rec.id)) == NULL) { + DEBUG_WARN(("\t\t%#x - Not Found\n", id2_rec.id)); + } else { + DEBUG_INDEX(("\t\t%#x - Offset %#x, u1 %#x, Size %i(%#x)\n", i_ptr->id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->size)); + // add it to the linked list + i2_ptr = (pst_index2_ll*) xmalloc(sizeof(pst_index2_ll)); + i2_ptr->id2 = id2_rec.id2; + i2_ptr->id = i_ptr; + i2_ptr->next = NULL; + if (!head) head = i2_ptr; + if (tail) tail->next = i2_ptr; + tail = i2_ptr; + if (id2_rec.table2 != 0) { + if ((i_ptr = _pst_getID(pf, id2_rec.table2)) == NULL) { + DEBUG_WARN(("\tTable2 [%#x] not found\n", id2_rec.table2)); + } + else { + DEBUG_INDEX(("\tGoing deeper for table2 [%#x]\n", id2_rec.table2)); + if ((i2_ptr = _pst_build_id2(pf, i_ptr, head))) { + // DEBUG_INDEX(("_pst_build_id2(): \t\tAdding new list onto end of current\n")); + // if (!head) + // head = i2_ptr; + // if (tail) + // tail->next = i2_ptr; + // while (i2_ptr->next) + // i2_ptr = i2_ptr->next; + // tail = i2_ptr; + } + // need to re-establish tail + DEBUG_INDEX(("Returned from depth\n")); + if (tail) { + while (tail->next) tail = tail->next; + } + } + } + } + x++; + } + if (buf) free (buf); + DEBUG_RET(); + return head; } // This version of free does NULL check first #define SAFE_FREE(x) {if (x) free(x);} void _pst_freeItem(pst_item *item) { - pst_item_attach *t; - pst_item_extra_field *et; - - DEBUG_ENT("_pst_freeItem"); - if (item) { - if (item->email) { - SAFE_FREE(item->email->arrival_date); - SAFE_FREE(item->email->body); - SAFE_FREE(item->email->cc_address); - SAFE_FREE(item->email->common_name); - SAFE_FREE(item->email->encrypted_body); - SAFE_FREE(item->email->encrypted_htmlbody); - SAFE_FREE(item->email->header); - SAFE_FREE(item->email->htmlbody); - SAFE_FREE(item->email->in_reply_to); - SAFE_FREE(item->email->messageid); - SAFE_FREE(item->email->outlook_recipient); - SAFE_FREE(item->email->outlook_recipient2); - SAFE_FREE(item->email->outlook_sender); - SAFE_FREE(item->email->outlook_sender_name); - SAFE_FREE(item->email->outlook_sender2); - SAFE_FREE(item->email->proc_subject); - SAFE_FREE(item->email->recip_access); - SAFE_FREE(item->email->recip_address); - SAFE_FREE(item->email->recip2_access); - SAFE_FREE(item->email->recip2_address); - SAFE_FREE(item->email->reply_to); - SAFE_FREE(item->email->rtf_body_tag); - SAFE_FREE(item->email->rtf_compressed); - SAFE_FREE(item->email->return_path_address); - SAFE_FREE(item->email->sender_access); - SAFE_FREE(item->email->sender_address); - SAFE_FREE(item->email->sender2_access); - SAFE_FREE(item->email->sender2_address); - SAFE_FREE(item->email->sent_date); - SAFE_FREE(item->email->sentmail_folder); - SAFE_FREE(item->email->sentto_address); - if (item->email->subject) - SAFE_FREE(item->email->subject->subj); - SAFE_FREE(item->email->subject); - free(item->email); - } - if (item->folder) { - free(item->folder); - } - if (item->message_store) { - SAFE_FREE(item->message_store->deleted_items_folder); - SAFE_FREE(item->message_store->search_root_folder); - SAFE_FREE(item->message_store->top_of_personal_folder); - SAFE_FREE(item->message_store->top_of_folder); - free(item->message_store); - } - if (item->contact) { - SAFE_FREE(item->contact->access_method); - SAFE_FREE(item->contact->account_name); - SAFE_FREE(item->contact->address1); - SAFE_FREE(item->contact->address1a); - SAFE_FREE(item->contact->address1_desc); - SAFE_FREE(item->contact->address1_transport); - SAFE_FREE(item->contact->address2); - SAFE_FREE(item->contact->address2a); - SAFE_FREE(item->contact->address2_desc); - SAFE_FREE(item->contact->address2_transport); - SAFE_FREE(item->contact->address3); - SAFE_FREE(item->contact->address3a); - SAFE_FREE(item->contact->address3_desc); - SAFE_FREE(item->contact->address3_transport); - SAFE_FREE(item->contact->assistant_name); - SAFE_FREE(item->contact->assistant_phone); - SAFE_FREE(item->contact->billing_information); - SAFE_FREE(item->contact->birthday); - SAFE_FREE(item->contact->business_address); - SAFE_FREE(item->contact->business_city); - SAFE_FREE(item->contact->business_country); - SAFE_FREE(item->contact->business_fax); - SAFE_FREE(item->contact->business_homepage); - SAFE_FREE(item->contact->business_phone); - SAFE_FREE(item->contact->business_phone2); - SAFE_FREE(item->contact->business_po_box); - SAFE_FREE(item->contact->business_postal_code); - SAFE_FREE(item->contact->business_state); - SAFE_FREE(item->contact->business_street); - SAFE_FREE(item->contact->callback_phone); - SAFE_FREE(item->contact->car_phone); - SAFE_FREE(item->contact->company_main_phone); - SAFE_FREE(item->contact->company_name); - SAFE_FREE(item->contact->computer_name); - SAFE_FREE(item->contact->customer_id); - SAFE_FREE(item->contact->def_postal_address); - SAFE_FREE(item->contact->department); - SAFE_FREE(item->contact->display_name_prefix); - SAFE_FREE(item->contact->first_name); - SAFE_FREE(item->contact->followup); - SAFE_FREE(item->contact->free_busy_address); - SAFE_FREE(item->contact->ftp_site); - SAFE_FREE(item->contact->fullname); - SAFE_FREE(item->contact->gov_id); - SAFE_FREE(item->contact->hobbies); - SAFE_FREE(item->contact->home_address); - SAFE_FREE(item->contact->home_city); - SAFE_FREE(item->contact->home_country); - SAFE_FREE(item->contact->home_fax); - SAFE_FREE(item->contact->home_po_box); - SAFE_FREE(item->contact->home_phone); - SAFE_FREE(item->contact->home_phone2); - SAFE_FREE(item->contact->home_postal_code); - SAFE_FREE(item->contact->home_state); - SAFE_FREE(item->contact->home_street); - SAFE_FREE(item->contact->initials); - SAFE_FREE(item->contact->isdn_phone); - SAFE_FREE(item->contact->job_title); - SAFE_FREE(item->contact->keyword); - SAFE_FREE(item->contact->language); - SAFE_FREE(item->contact->location); - SAFE_FREE(item->contact->manager_name); - SAFE_FREE(item->contact->middle_name); - SAFE_FREE(item->contact->mileage); - SAFE_FREE(item->contact->mobile_phone); - SAFE_FREE(item->contact->nickname); - SAFE_FREE(item->contact->office_loc); - SAFE_FREE(item->contact->org_id); - SAFE_FREE(item->contact->other_address); - SAFE_FREE(item->contact->other_city); - SAFE_FREE(item->contact->other_country); - SAFE_FREE(item->contact->other_phone); - SAFE_FREE(item->contact->other_po_box); - SAFE_FREE(item->contact->other_postal_code); - SAFE_FREE(item->contact->other_state); - SAFE_FREE(item->contact->other_street); - SAFE_FREE(item->contact->pager_phone); - SAFE_FREE(item->contact->personal_homepage); - SAFE_FREE(item->contact->pref_name); - SAFE_FREE(item->contact->primary_fax); - SAFE_FREE(item->contact->primary_phone); - SAFE_FREE(item->contact->profession); - SAFE_FREE(item->contact->radio_phone); - SAFE_FREE(item->contact->spouse_name); - SAFE_FREE(item->contact->suffix); - SAFE_FREE(item->contact->surname); - SAFE_FREE(item->contact->telex); - SAFE_FREE(item->contact->transmittable_display_name); - SAFE_FREE(item->contact->ttytdd_phone); - SAFE_FREE(item->contact->wedding_anniversary); - free(item->contact); - } - while (item->attach) { - SAFE_FREE(item->attach->filename1); - SAFE_FREE(item->attach->filename2); - SAFE_FREE(item->attach->mimetype); - SAFE_FREE(item->attach->data); - t = item->attach->next; - free(item->attach); - item->attach = t; - } - while (item->extra_fields) { - SAFE_FREE(item->extra_fields->field_name); - SAFE_FREE(item->extra_fields->value); - et = item->extra_fields->next; - free(item->extra_fields); - item->extra_fields = et; - } - if (item->journal) { - SAFE_FREE(item->journal->end); - SAFE_FREE(item->journal->start); - SAFE_FREE(item->journal->type); - free(item->journal); - } - if (item->appointment) { - SAFE_FREE(item->appointment->location); - SAFE_FREE(item->appointment->reminder); - SAFE_FREE(item->appointment->start); - SAFE_FREE(item->appointment->end); - SAFE_FREE(item->appointment->timezonestring); - free(item->appointment); - } - SAFE_FREE(item->ascii_type); - SAFE_FREE(item->comment); - SAFE_FREE(item->create_date); - SAFE_FREE(item->file_as); - SAFE_FREE(item->modify_date); - SAFE_FREE(item->outlook_version); - SAFE_FREE(item->record_key); - free(item); - } - DEBUG_RET(); + pst_item_attach *t; + pst_item_extra_field *et; + + DEBUG_ENT("_pst_freeItem"); + if (item) { + if (item->email) { + SAFE_FREE(item->email->arrival_date); + SAFE_FREE(item->email->body); + SAFE_FREE(item->email->cc_address); + SAFE_FREE(item->email->common_name); + SAFE_FREE(item->email->encrypted_body); + SAFE_FREE(item->email->encrypted_htmlbody); + SAFE_FREE(item->email->header); + SAFE_FREE(item->email->htmlbody); + SAFE_FREE(item->email->in_reply_to); + SAFE_FREE(item->email->messageid); + SAFE_FREE(item->email->outlook_recipient); + SAFE_FREE(item->email->outlook_recipient2); + SAFE_FREE(item->email->outlook_sender); + SAFE_FREE(item->email->outlook_sender_name); + SAFE_FREE(item->email->outlook_sender2); + SAFE_FREE(item->email->proc_subject); + SAFE_FREE(item->email->recip_access); + SAFE_FREE(item->email->recip_address); + SAFE_FREE(item->email->recip2_access); + SAFE_FREE(item->email->recip2_address); + SAFE_FREE(item->email->reply_to); + SAFE_FREE(item->email->rtf_body_tag); + SAFE_FREE(item->email->rtf_compressed); + SAFE_FREE(item->email->return_path_address); + SAFE_FREE(item->email->sender_access); + SAFE_FREE(item->email->sender_address); + SAFE_FREE(item->email->sender2_access); + SAFE_FREE(item->email->sender2_address); + SAFE_FREE(item->email->sent_date); + SAFE_FREE(item->email->sentmail_folder); + SAFE_FREE(item->email->sentto_address); + if (item->email->subject) + SAFE_FREE(item->email->subject->subj); + SAFE_FREE(item->email->subject); + free(item->email); + } + if (item->folder) { + free(item->folder); + } + if (item->message_store) { + SAFE_FREE(item->message_store->deleted_items_folder); + SAFE_FREE(item->message_store->search_root_folder); + SAFE_FREE(item->message_store->top_of_personal_folder); + SAFE_FREE(item->message_store->top_of_folder); + free(item->message_store); + } + if (item->contact) { + SAFE_FREE(item->contact->access_method); + SAFE_FREE(item->contact->account_name); + SAFE_FREE(item->contact->address1); + SAFE_FREE(item->contact->address1a); + SAFE_FREE(item->contact->address1_desc); + SAFE_FREE(item->contact->address1_transport); + SAFE_FREE(item->contact->address2); + SAFE_FREE(item->contact->address2a); + SAFE_FREE(item->contact->address2_desc); + SAFE_FREE(item->contact->address2_transport); + SAFE_FREE(item->contact->address3); + SAFE_FREE(item->contact->address3a); + SAFE_FREE(item->contact->address3_desc); + SAFE_FREE(item->contact->address3_transport); + SAFE_FREE(item->contact->assistant_name); + SAFE_FREE(item->contact->assistant_phone); + SAFE_FREE(item->contact->billing_information); + SAFE_FREE(item->contact->birthday); + SAFE_FREE(item->contact->business_address); + SAFE_FREE(item->contact->business_city); + SAFE_FREE(item->contact->business_country); + SAFE_FREE(item->contact->business_fax); + SAFE_FREE(item->contact->business_homepage); + SAFE_FREE(item->contact->business_phone); + SAFE_FREE(item->contact->business_phone2); + SAFE_FREE(item->contact->business_po_box); + SAFE_FREE(item->contact->business_postal_code); + SAFE_FREE(item->contact->business_state); + SAFE_FREE(item->contact->business_street); + SAFE_FREE(item->contact->callback_phone); + SAFE_FREE(item->contact->car_phone); + SAFE_FREE(item->contact->company_main_phone); + SAFE_FREE(item->contact->company_name); + SAFE_FREE(item->contact->computer_name); + SAFE_FREE(item->contact->customer_id); + SAFE_FREE(item->contact->def_postal_address); + SAFE_FREE(item->contact->department); + SAFE_FREE(item->contact->display_name_prefix); + SAFE_FREE(item->contact->first_name); + SAFE_FREE(item->contact->followup); + SAFE_FREE(item->contact->free_busy_address); + SAFE_FREE(item->contact->ftp_site); + SAFE_FREE(item->contact->fullname); + SAFE_FREE(item->contact->gov_id); + SAFE_FREE(item->contact->hobbies); + SAFE_FREE(item->contact->home_address); + SAFE_FREE(item->contact->home_city); + SAFE_FREE(item->contact->home_country); + SAFE_FREE(item->contact->home_fax); + SAFE_FREE(item->contact->home_po_box); + SAFE_FREE(item->contact->home_phone); + SAFE_FREE(item->contact->home_phone2); + SAFE_FREE(item->contact->home_postal_code); + SAFE_FREE(item->contact->home_state); + SAFE_FREE(item->contact->home_street); + SAFE_FREE(item->contact->initials); + SAFE_FREE(item->contact->isdn_phone); + SAFE_FREE(item->contact->job_title); + SAFE_FREE(item->contact->keyword); + SAFE_FREE(item->contact->language); + SAFE_FREE(item->contact->location); + SAFE_FREE(item->contact->manager_name); + SAFE_FREE(item->contact->middle_name); + SAFE_FREE(item->contact->mileage); + SAFE_FREE(item->contact->mobile_phone); + SAFE_FREE(item->contact->nickname); + SAFE_FREE(item->contact->office_loc); + SAFE_FREE(item->contact->org_id); + SAFE_FREE(item->contact->other_address); + SAFE_FREE(item->contact->other_city); + SAFE_FREE(item->contact->other_country); + SAFE_FREE(item->contact->other_phone); + SAFE_FREE(item->contact->other_po_box); + SAFE_FREE(item->contact->other_postal_code); + SAFE_FREE(item->contact->other_state); + SAFE_FREE(item->contact->other_street); + SAFE_FREE(item->contact->pager_phone); + SAFE_FREE(item->contact->personal_homepage); + SAFE_FREE(item->contact->pref_name); + SAFE_FREE(item->contact->primary_fax); + SAFE_FREE(item->contact->primary_phone); + SAFE_FREE(item->contact->profession); + SAFE_FREE(item->contact->radio_phone); + SAFE_FREE(item->contact->spouse_name); + SAFE_FREE(item->contact->suffix); + SAFE_FREE(item->contact->surname); + SAFE_FREE(item->contact->telex); + SAFE_FREE(item->contact->transmittable_display_name); + SAFE_FREE(item->contact->ttytdd_phone); + SAFE_FREE(item->contact->wedding_anniversary); + free(item->contact); + } + while (item->attach) { + SAFE_FREE(item->attach->filename1); + SAFE_FREE(item->attach->filename2); + SAFE_FREE(item->attach->mimetype); + SAFE_FREE(item->attach->data); + t = item->attach->next; + free(item->attach); + item->attach = t; + } + while (item->extra_fields) { + SAFE_FREE(item->extra_fields->field_name); + SAFE_FREE(item->extra_fields->value); + et = item->extra_fields->next; + free(item->extra_fields); + item->extra_fields = et; + } + if (item->journal) { + SAFE_FREE(item->journal->end); + SAFE_FREE(item->journal->start); + SAFE_FREE(item->journal->type); + free(item->journal); + } + if (item->appointment) { + SAFE_FREE(item->appointment->location); + SAFE_FREE(item->appointment->reminder); + SAFE_FREE(item->appointment->start); + SAFE_FREE(item->appointment->end); + SAFE_FREE(item->appointment->timezonestring); + free(item->appointment); + } + SAFE_FREE(item->ascii_type); + SAFE_FREE(item->comment); + SAFE_FREE(item->create_date); + SAFE_FREE(item->file_as); + SAFE_FREE(item->modify_date); + SAFE_FREE(item->outlook_version); + SAFE_FREE(item->record_key); + free(item); + } + DEBUG_RET(); } /** * The offset might be zero, in which case we have no data, so return a pair of null pointers. * Or, the offset might end in 0xf, so it is an id2 pointer, in which case we read the id2 block. * Otherwise, the offset>>4 is an index into the table of offsets in the buffer. */ int32_t _pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset_pointer *p) { - int32_t size; - pst_block_offset block_offset; - DEBUG_ENT("_pst_getBlockOffsetPointer"); - if (p->needfree) free(p->from); - p->from = NULL; - p->needfree = 0; - if (!offset) { - p->from = p->to = NULL; - } - else if ((offset & 0xf) == 0xf) { - DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset)); - size = _pst_ff_getID2block(pf, offset, i2_head, &(p->from)); - if (size) { - p->to = p->from + size; - p->needfree = 1; - } - else { - p->from = p->to = NULL; - } - } - else if (_pst_getBlockOffset(buf, read_size, i_offset, offset, &block_offset)) { - p->from = p->to = NULL; - } - else { - p->from = buf + block_offset.from; - p->to = buf + block_offset.to; - } - DEBUG_RET(); - return (p->from) ? 0 : 1; + int32_t size; + pst_block_offset block_offset; + DEBUG_ENT("_pst_getBlockOffsetPointer"); + if (p->needfree) free(p->from); + p->from = NULL; + p->needfree = 0; + if (!offset) { + p->from = p->to = NULL; + } + else if ((offset & 0xf) == 0xf) { + DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset)); + size = _pst_ff_getID2block(pf, offset, i2_head, &(p->from)); + if (size) { + p->to = p->from + size; + p->needfree = 1; + } + else { + p->from = p->to = NULL; + } + } + else if (_pst_getBlockOffset(buf, read_size, i_offset, offset, &block_offset)) { + p->from = p->to = NULL; + } + else { + p->from = buf + block_offset.from; + p->to = buf + block_offset.to; + } + DEBUG_RET(); + return (p->from) ? 0 : 1; } int32_t _pst_getBlockOffset(unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset *p) { - int32_t low = offset & 0xf; - int32_t of1 = offset >> 4; - DEBUG_ENT("_pst_getBlockOffset"); - if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) { - DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 or offset has low bits or beyond read size (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset)); - DEBUG_RET(); - return -1; - } - memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from)); - memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to)); - LE16_CPU(p->from); - LE16_CPU(p->to); - DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to)); - if (p->from > p->to) { - DEBUG_WARN(("get block offset from > to")); - return -1; - } - DEBUG_RET(); - return 0; + int32_t low = offset & 0xf; + int32_t of1 = offset >> 4; + DEBUG_ENT("_pst_getBlockOffset"); + if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) { + DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 or offset has low bits or beyond read size (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset)); + DEBUG_RET(); + return -1; + } + memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from)); + memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to)); + LE16_CPU(p->from); + LE16_CPU(p->to); + DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to)); + if (p->from > p->to) { + DEBUG_WARN(("get block offset from > to")); + return -1; + } + DEBUG_RET(); + return 0; } -pst_index_ll* _pst_getID(pst_file* pf, u_int32_t id) { - pst_index_ll *ptr = NULL; - DEBUG_ENT("_pst_getID"); - if (id == 0) { - DEBUG_RET(); - return NULL; - } - - //if (id & 1) DEBUG_INDEX(("have odd id bit %#x\n", id)); - //if (id & 2) DEBUG_INDEX(("have two id bit %#x\n", id)); - id &= 0xFFFFFFFE; - - DEBUG_INDEX(("Trying to find %#x\n", id)); - if (!ptr) ptr = pf->i_head; - while (ptr && (ptr->id != id)) { - ptr = ptr->next; - } - if (ptr) {DEBUG_INDEX(("Found Value %#x\n", id)); } - else {DEBUG_INDEX(("ERROR: Value %#x not found\n", id)); } - DEBUG_RET(); - return ptr; +pst_index_ll* _pst_getID(pst_file* pf, uint64_t id) { + pst_index_ll *ptr = NULL; + DEBUG_ENT("_pst_getID"); + if (id == 0) { + DEBUG_RET(); + return NULL; + } + + //if (id & 1) DEBUG_INDEX(("have odd id bit %#x\n", id)); + //if (id & 2) DEBUG_INDEX(("have two id bit %#x\n", id)); + id -= (id & 1); + + DEBUG_INDEX(("Trying to find %#llx\n", id)); + if (!ptr) ptr = pf->i_head; + while (ptr && (ptr->id != id)) { + ptr = ptr->next; + } + if (ptr) {DEBUG_INDEX(("Found Value %#x\n", id)); } + else {DEBUG_INDEX(("ERROR: Value %#x not found\n", id)); } + DEBUG_RET(); + return ptr; } -pst_index_ll * _pst_getID2(pst_index2_ll *ptr, u_int32_t id) { - DEBUG_ENT("_pst_getID2"); - DEBUG_INDEX(("Head = %p\n", ptr)); - DEBUG_INDEX(("Trying to find %#x\n", id)); - while (ptr && (ptr->id2 != id)) { - ptr = ptr->next; - } - if (ptr) { - if (ptr->id) {DEBUG_INDEX(("Found value %#x\n", ptr->id->id)); } - else {DEBUG_INDEX(("Found value, though it is NULL!\n"));} - DEBUG_RET(); - return ptr->id; - } - DEBUG_INDEX(("ERROR Not Found\n")); - DEBUG_RET(); - return NULL; +pst_index_ll * _pst_getID2(pst_index2_ll *ptr, uint32_t id) { + DEBUG_ENT("_pst_getID2"); + DEBUG_INDEX(("Head = %p\n", ptr)); + DEBUG_INDEX(("Trying to find %#x\n", id)); + while (ptr && (ptr->id2 != id)) { + ptr = ptr->next; + } + if (ptr) { + if (ptr->id) {DEBUG_INDEX(("Found value %#x\n", ptr->id->id)); } + else {DEBUG_INDEX(("Found value, though it is NULL!\n"));} + DEBUG_RET(); + return ptr->id; + } + DEBUG_INDEX(("ERROR Not Found\n")); + DEBUG_RET(); + return NULL; } /** * find the id in the descriptor tree rooted at pf->d_head * - * @param pf global pst file pointer - * @param id the id we are looking for + * @param pf global pst file pointer + * @param id the id we are looking for * * @return pointer to the pst_desc_ll node in the descriptor tree */ -pst_desc_ll* _pst_getDptr(pst_file *pf, u_int32_t id) { - pst_desc_ll *ptr = pf->d_head; - DEBUG_ENT("_pst_getDptr"); - while (ptr && (ptr->id != id)) { - if (ptr->child) { - ptr = ptr->child; - continue; - } - while (!ptr->next && ptr->parent) { - ptr = ptr->parent; - } - ptr = ptr->next; - } - DEBUG_RET(); - return ptr; // will be NULL or record we are looking for +pst_desc_ll* _pst_getDptr(pst_file *pf, uint32_t id) { + pst_desc_ll *ptr = pf->d_head; + DEBUG_ENT("_pst_getDptr"); + while (ptr && (ptr->id != id)) { + if (ptr->child) { + ptr = ptr->child; + continue; + } + while (!ptr->next && ptr->parent) { + ptr = ptr->parent; + } + ptr = ptr->next; + } + DEBUG_RET(); + return ptr; // will be NULL or record we are looking for } int32_t _pst_printDptr(pst_file *pf) { - pst_desc_ll *ptr = pf->d_head; - int32_t depth = 0; - char spaces[100]; - DEBUG_ENT("_pst_printDptr"); - memset(spaces, ' ', 99); - spaces[99] = '\0'; - while (ptr) { - DEBUG_INDEX(("%s%#x [%i] desc=%#x, list=%#x\n", &(spaces[(99-depth<0?0:99-depth)]), ptr->id, ptr->no_child, - (ptr->desc==NULL?0:ptr->desc->id), - (ptr->list_index==NULL?0:ptr->list_index->id))); - if (ptr->child) { - depth++; - ptr = ptr->child; - continue; - } - while (!ptr->next && ptr->parent) { - depth--; - ptr = ptr->parent; - } - ptr = ptr->next; - } - DEBUG_RET(); - return 0; + pst_desc_ll *ptr = pf->d_head; + int32_t depth = 0; + char spaces[100]; + DEBUG_ENT("_pst_printDptr"); + memset(spaces, ' ', 99); + spaces[99] = '\0'; + while (ptr) { + DEBUG_INDEX(("%s%#x [%i] desc=%#x, list=%#x\n", &(spaces[(99-depth<0?0:99-depth)]), ptr->id, ptr->no_child, + (ptr->desc==NULL?0:ptr->desc->id), + (ptr->list_index==NULL?0:ptr->list_index->id))); + if (ptr->child) { + depth++; + ptr = ptr->child; + continue; + } + while (!ptr->next && ptr->parent) { + depth--; + ptr = ptr->parent; + } + ptr = ptr->next; + } + DEBUG_RET(); + return 0; } int32_t _pst_printIDptr(pst_file* pf) { - pst_index_ll *ptr = pf->i_head; - DEBUG_ENT("_pst_printIDptr"); - while (ptr) { - DEBUG_INDEX(("%#x offset=%#x size=%#x\n", ptr->id, ptr->offset, ptr->size)); - ptr = ptr->next; - } - DEBUG_RET(); - return 0; + pst_index_ll *ptr = pf->i_head; + DEBUG_ENT("_pst_printIDptr"); + while (ptr) { + DEBUG_INDEX(("%#x offset=%#x size=%#x\n", ptr->id, ptr->offset, ptr->size)); + ptr = ptr->next; + } + DEBUG_RET(); + return 0; } int32_t _pst_printID2ptr(pst_index2_ll *ptr) { - DEBUG_ENT("_pst_printID2ptr"); - while (ptr) { - DEBUG_INDEX(("%#x id=%#x\n", ptr->id2, (ptr->id!=NULL?ptr->id->id:0))); - ptr = ptr->next; - } - DEBUG_RET(); - return 0; + DEBUG_ENT("_pst_printID2ptr"); + while (ptr) { + DEBUG_INDEX(("%#x id=%#x\n", ptr->id2, (ptr->id!=NULL?ptr->id->id:0))); + ptr = ptr->next; + } + DEBUG_RET(); + return 0; } -size_t _pst_read_block(FILE *fp, int32_t offset, void **buf) { - size_t size; - int32_t fpos; - DEBUG_ENT("_pst_read_block"); - DEBUG_READ(("Reading block from %#x\n", offset)); - fpos = ftell(fp); - fseek(fp, offset, SEEK_SET); - fread(&size, sizeof(int16_t), 1, fp); - fseek(fp, offset, SEEK_SET); - DEBUG_READ(("Allocating %i bytes\n", size)); - if (*buf) { - DEBUG_READ(("Freeing old memory\n")); - free(*buf); - } - *buf = (void*)xmalloc(size); - size = fread(*buf, 1, size, fp); - fseek(fp, fpos, SEEK_SET); - DEBUG_RET(); - return size; +size_t _pst_read_block(FILE *fp, off_t offset, void **buf) { + int16_t size16; + size_t size; + off_t fpos; + DEBUG_ENT("_pst_read_block"); + DEBUG_READ(("Reading block from %#x\n", offset)); + fpos = ftell(fp); + fseek(fp, offset, SEEK_SET); + fread(&size16, sizeof(int16_t), 1, fp); + LE16_CPU(size16); + size = size16; + fseek(fp, offset, SEEK_SET); + DEBUG_READ(("Allocating %i bytes\n", size)); + if (*buf) { + DEBUG_READ(("Freeing old memory\n")); + free(*buf); + } + *buf = (void*)xmalloc(size); + size = fread(*buf, 1, size, fp); + fseek(fp, fpos, SEEK_SET); + DEBUG_RET(); + return size; } // when the first byte of the block being read is 01, then we can assume // that it is a list of further ids to read and we will follow those ids // recursively calling this function until we have all the data // we could do decryption of the encrypted PST files here -size_t _pst_read_block_size(pst_file *pf, int32_t offset, size_t size, char ** buf, int32_t do_enc, unsigned char is_index) { - u_int32_t fpos, x; - int16_t count, y; - char *buf2 = NULL, *buf3 = NULL; - unsigned char fdepth; - pst_index_ll *ptr = NULL; - size_t rsize, z; - - DEBUG_ENT("_pst_read_block_size"); - DEBUG_READ(("Reading block from %#x, %i bytes\n", offset, size)); - - fpos = ftell(pf->fp); - fseek(pf->fp, offset, SEEK_SET); - if (*buf) { - DEBUG_READ(("Freeing old memory\n")); - free(*buf); - } - - *buf = (void*) xmalloc(size+1); //plus one so that we can NUL terminate it later - rsize = fread(*buf, 1, size, pf->fp); - if (rsize != size) { - DEBUG_WARN(("Didn't read all that I could. fread returned less [%i instead of %i]\n", rsize, size)); - if (feof(pf->fp)) { - DEBUG_WARN(("We tried to read past the end of the file at [offset %#x, size %#x]\n", offset, size)); - } else if (ferror(pf->fp)) { - DEBUG_WARN(("Error is set on file stream.\n")); - } else { - DEBUG_WARN(("I can't tell why it failed\n")); - } - size = rsize; - } - - // DEBUG_HEXDUMP(*buf, size); - - /* if (is_index) { - DEBUG_READ(("_pst_read_block_size: ODD_BLOCK should be here\n")); - DEBUG_READ(("\t: byte 0-1: %#x %#x\n", (*buf)[0], (*buf)[1])); - }*/ - - if ((*buf)[0] == 0x01 && (*buf)[1] != 0x00 && is_index) { - //don't do this recursion if we should be at a leaf node - memcpy(&count, &((*buf)[2]), sizeof(int16_t)); - LE16_CPU(count); - memcpy(&fdepth, &((*buf)[1]), sizeof(fdepth)); - DEBUG_READ(("Seen indexes to blocks. Depth is %i\n", fdepth)); - // do fancy stuff! :) - DEBUG_READ(("There are %i ids\n", count)); - // if first 2 blocks are 01 01 then index to blocks - size = 0; - y = 0; - while (y < count) { - memcpy(&x, &(*buf)[0x08+(y*4)], sizeof(int32_t)); - LE32_CPU(x); - if ((ptr = _pst_getID(pf, x)) == NULL) { - WARN(("Error. Cannot find ID [%#x] during multi-block read\n", x)); - buf3 = (char*) realloc(buf3, size+1); - buf3[size] = '\0'; - *buf = buf3; - fseek(pf->fp, fpos, SEEK_SET); - DEBUG_RET(); - return size; - } - if ((z = _pst_read_block_size(pf, ptr->offset, ptr->size, &buf2, do_enc, fdepth-1)) < ptr->size) { - buf3 = (char*) realloc(buf3, size+1); - buf3[size] = '\0'; - *buf = buf3; - fseek(pf->fp, fpos, SEEK_SET); - DEBUG_RET(); - return size; - } - DEBUG_READ(("Melding newley retrieved block with bigger one. New size is %i\n", size+z)); - buf3 = (char*) realloc(buf3, size+z+1); //plus one so that we can null terminate it later - DEBUG_READ(("Doing copy. Start pos is %i, length is %i\n", size, z)); - memcpy(&(buf3[size]), buf2, z); - size += z; - y++; - } - free(*buf); - if (buf2) free(buf2); - if (!buf3) { - // this can happen if count == 0. We should create an empty buffer so we don't - // confuse any clients - buf3 = (char*) xmalloc(1); - } - *buf = buf3; - } else if (do_enc && pf->encryption) - _pst_decrypt(*buf, size, pf->encryption); - - (*buf)[size] = '\0'; //should be byte after last one read - fseek(pf->fp, fpos, SEEK_SET); - DEBUG_RET(); - return size; +size_t _pst_read_block_size(pst_file *pf, off_t offset, size_t size, char **buf, int32_t do_enc, unsigned char is_index) { + off_t fpos; + int32_t x; + int16_t count, y; + char *buf2 = NULL, *buf3 = NULL; + unsigned char fdepth; + pst_index_ll *ptr = NULL; + size_t rsize, z; + + DEBUG_ENT("_pst_read_block_size"); + DEBUG_READ(("Reading block from %#x, %i bytes\n", offset, size)); + + fpos = ftell(pf->fp); + fseek(pf->fp, offset, SEEK_SET); + if (*buf) { + DEBUG_READ(("Freeing old memory\n")); + free(*buf); + } + + *buf = (void*) xmalloc(size+1); //plus one so that we can NUL terminate it later + rsize = fread(*buf, 1, size, pf->fp); + if (rsize != size) { + DEBUG_WARN(("Didn't read all that I could. fread returned less [%i instead of %i]\n", rsize, size)); + if (feof(pf->fp)) { + DEBUG_WARN(("We tried to read past the end of the file at [offset %#x, size %#x]\n", offset, size)); + } else if (ferror(pf->fp)) { + DEBUG_WARN(("Error is set on file stream.\n")); + } else { + DEBUG_WARN(("I can't tell why it failed\n")); + } + size = rsize; + } + + // DEBUG_HEXDUMP(*buf, size); + + /* if (is_index) { + DEBUG_READ(("_pst_read_block_size: ODD_BLOCK should be here\n")); + DEBUG_READ(("\t: byte 0-1: %#x %#x\n", (*buf)[0], (*buf)[1])); + }*/ + + if ((*buf)[0] == 0x01 && (*buf)[1] != 0x00 && is_index) { + //don't do this recursion if we should be at a leaf node + memcpy(&count, &((*buf)[2]), sizeof(int16_t)); + LE16_CPU(count); + memcpy(&fdepth, &((*buf)[1]), sizeof(fdepth)); + DEBUG_READ(("Seen indexes to blocks. Depth is %i\n", fdepth)); + // do fancy stuff! :) + DEBUG_READ(("There are %i ids\n", count)); + // if first 2 blocks are 01 01 then index to blocks + size = 0; + y = 0; + while (y < count) { + memcpy(&x, &(*buf)[0x08+(y*4)], sizeof(int32_t)); + LE32_CPU(x); + if ((ptr = _pst_getID(pf, x)) == NULL) { + WARN(("Error. Cannot find ID [%#x] during multi-block read\n", x)); + buf3 = (char*) realloc(buf3, size+1); + buf3[size] = '\0'; + *buf = buf3; + fseek(pf->fp, fpos, SEEK_SET); + DEBUG_RET(); + return size; + } + if ((z = _pst_read_block_size(pf, ptr->offset, ptr->size, &buf2, do_enc, fdepth-1)) < ptr->size) { + buf3 = (char*) realloc(buf3, size+1); + buf3[size] = '\0'; + *buf = buf3; + fseek(pf->fp, fpos, SEEK_SET); + DEBUG_RET(); + return size; + } + DEBUG_READ(("Melding newley retrieved block with bigger one. New size is %i\n", size+z)); + buf3 = (char*) realloc(buf3, size+z+1); //plus one so that we can null terminate it later + DEBUG_READ(("Doing copy. Start pos is %i, length is %i\n", size, z)); + memcpy(&(buf3[size]), buf2, z); + size += z; + y++; + } + free(*buf); + if (buf2) free(buf2); + if (!buf3) { + // this can happen if count == 0. We should create an empty buffer so we don't + // confuse any clients + buf3 = (char*) xmalloc(1); + } + *buf = buf3; + } else if (do_enc && pf->encryption) + _pst_decrypt(*buf, size, pf->encryption); + + (*buf)[size] = '\0'; //should be byte after last one read + fseek(pf->fp, fpos, SEEK_SET); + DEBUG_RET(); + return size; } int32_t _pst_decrypt(unsigned char *buf, size_t size, int32_t type) { - size_t x = 0; - unsigned char y; - DEBUG_ENT("_pst_decrypt"); - if (!buf) { - DEBUG_RET(); - return -1; - } - - if (type == PST_COMP_ENCRYPT) { - x = 0; - while (x < size) { - y = buf[x]; - DEBUG_DECRYPT(("Transposing %#hhx to %#hhx [%#x]\n", buf[x], comp_enc[y], y)); - buf[x] = comp_enc[y]; // transpose from encrypt array - x++; - } - } else { - WARN(("Unknown encryption: %i. Cannot decrypt\n", type)); - DEBUG_RET(); - return -1; - } - DEBUG_RET(); - return 0; + size_t x = 0; + unsigned char y; + DEBUG_ENT("_pst_decrypt"); + if (!buf) { + DEBUG_RET(); + return -1; + } + + if (type == PST_COMP_ENCRYPT) { + x = 0; + while (x < size) { + y = buf[x]; + DEBUG_DECRYPT(("Transposing %#hhx to %#hhx [%#x]\n", buf[x], comp_enc[y], y)); + buf[x] = comp_enc[y]; // transpose from encrypt array + x++; + } + } else { + WARN(("Unknown encryption: %i. Cannot decrypt\n", type)); + DEBUG_RET(); + return -1; + } + DEBUG_RET(); + return 0; } -int32_t _pst_getAtPos(FILE *fp, int32_t pos, void* buf, u_int32_t size) { - DEBUG_ENT("_pst_getAtPos"); - if (fseek(fp, pos, SEEK_SET) == -1) { - DEBUG_RET(); - return 1; - } +int64_t _getIntAt(char *buf) { + int64_t buf64; + int32_t buf32; + if (do_read64) { + memcpy(&buf64, buf, sizeof(buf64)); + LE64_CPU(buf64); + return buf64; + } + else { + memcpy(&buf32, buf, sizeof(buf32)); + LE32_CPU(buf32); + return buf32; + } +} - if (fread(buf, 1, size, fp) < size) { - DEBUG_RET(); - return 2; - } - DEBUG_RET(); - return 0; + +int64_t _pst_getIntAtPos(FILE *fp, off_t pos ) { + int64_t buf64; + int32_t buf32; + if (do_read64) { + _pst_getAtPos(fp, pos, &buf64, sizeof(buf64)); + LE64_CPU(buf64); + return buf64; + } + else { + _pst_getAtPos(fp, pos, &buf32, sizeof(buf32)); + LE32_CPU(buf32); + return buf32; + } } -int32_t _pst_get (FILE *fp, void *buf, u_int32_t size) { - DEBUG_ENT("_pst_get"); - if (fread(buf, 1, size, fp) < size) { - DEBUG_RET(); - return 1; - } - DEBUG_RET(); - return 0; +int32_t _pst_getAtPos(FILE *fp, off_t pos, void* buf, uint32_t size) { + DEBUG_ENT("_pst_getAtPos"); + if (fseek(fp, pos, SEEK_SET) == -1) { + DEBUG_RET(); + return 1; + } + if (fread(buf, 1, size, fp) < size) { + DEBUG_RET(); + return 2; + } + DEBUG_RET(); + return 0; } -size_t _pst_ff_getIDblock_dec(pst_file *pf, u_int32_t id, unsigned char **b) { - size_t r; - DEBUG_ENT("_pst_ff_getIDblock_dec"); - DEBUG_INDEX(("for id %#x\n", id)); - r = _pst_ff_getIDblock(pf, id, b); - int noenc = (id & 2); // disable encryption - if ((pf->encryption) & !(noenc)) { - _pst_decrypt(*b, r, pf->encryption); - } - DEBUG_HEXDUMPC(*b, r, 16); - DEBUG_RET(); - return r; +int32_t _pst_get (FILE *fp, void *buf, uint32_t size) { + DEBUG_ENT("_pst_get"); + if (fread(buf, 1, size, fp) < size) { + DEBUG_RET(); + return 1; + } + DEBUG_RET(); + return 0; } -size_t _pst_ff_getIDblock(pst_file *pf, u_int32_t id, unsigned char** b) { - pst_index_ll *rec; - size_t rsize = 0;//, re_size=0; - DEBUG_ENT("_pst_ff_getIDblock"); - if ((rec = _pst_getID(pf, id)) == NULL) { - DEBUG_INDEX(("Cannot find ID %#x\n", id)); - DEBUG_RET(); - return 0; - } - fseek(pf->fp, rec->offset, SEEK_SET); - if (*b) { - DEBUG_INDEX(("freeing old memory in b\n")); - free(*b); - } - - DEBUG_INDEX(("id = %#x, record size = %#x, offset = %#x\n", id, rec->size, rec->offset)); - *b = (char*) xmalloc(rec->size+1); - rsize = fread(*b, 1, rec->size, pf->fp); - if (rsize != rec->size) { - DEBUG_WARN(("Didn't read all the size. fread returned less [%i instead of %i]\n", rsize, rec->size)); - if (feof(pf->fp)) { - DEBUG_WARN(("We tried to read past the end of the file [offset %#x, size %#x]\n", rec->offset, rec->size)); - } else if (ferror(pf->fp)) { - DEBUG_WARN(("Some error occured on the file stream\n")); - } else { - DEBUG_WARN(("No error has been set on the file stream\n")); - } - } - DEBUG_RET(); - return rsize; +size_t _pst_ff_getIDblock_dec(pst_file *pf, uint32_t id, unsigned char **b) { + size_t r; + DEBUG_ENT("_pst_ff_getIDblock_dec"); + DEBUG_INDEX(("for id %#x\n", id)); + r = _pst_ff_getIDblock(pf, id, b); + int noenc = (id & 2); // disable encryption + if ((pf->encryption) & !(noenc)) { + _pst_decrypt(*b, r, pf->encryption); + } + DEBUG_HEXDUMPC(*b, r, 16); + DEBUG_RET(); + return r; +} + + +size_t _pst_ff_getIDblock(pst_file *pf, uint32_t id, unsigned char** b) { + pst_index_ll *rec; + size_t rsize = 0;//, re_size=0; + DEBUG_ENT("_pst_ff_getIDblock"); + if ((rec = _pst_getID(pf, id)) == NULL) { + DEBUG_INDEX(("Cannot find ID %#x\n", id)); + DEBUG_RET(); + return 0; + } + fseek(pf->fp, rec->offset, SEEK_SET); + if (*b) { + DEBUG_INDEX(("freeing old memory in b\n")); + free(*b); + } + + DEBUG_INDEX(("id = %#x, record size = %#x, offset = %#x\n", id, rec->size, rec->offset)); + *b = (char*) xmalloc(rec->size+1); + rsize = fread(*b, 1, rec->size, pf->fp); + if (rsize != rec->size) { + DEBUG_WARN(("Didn't read all the size. fread returned less [%i instead of %i]\n", rsize, rec->size)); + if (feof(pf->fp)) { + DEBUG_WARN(("We tried to read past the end of the file [offset %#x, size %#x]\n", rec->offset, rec->size)); + } else if (ferror(pf->fp)) { + DEBUG_WARN(("Some error occured on the file stream\n")); + } else { + DEBUG_WARN(("No error has been set on the file stream\n")); + } + } + DEBUG_RET(); + return rsize; } #define PST_PTR_BLOCK_SIZE 0x120 -size_t _pst_ff_getID2block(pst_file *pf, u_int32_t id2, pst_index2_ll *id2_head, unsigned char** buf) { - pst_index_ll* ptr; - // size_t ret; - struct holder h = {buf, NULL, 0, "", 0}; - DEBUG_ENT("_pst_ff_getID2block"); - ptr = _pst_getID2(id2_head, id2); - - if (!ptr) { - DEBUG_INDEX(("Cannot find id2 value %#x\n", id2)); - DEBUG_RET(); - return 0; - } - DEBUG_RET(); - return _pst_ff_getID2data(pf, ptr, &h); +size_t _pst_ff_getID2block(pst_file *pf, uint32_t id2, pst_index2_ll *id2_head, unsigned char** buf) { + pst_index_ll* ptr; + // size_t ret; + struct holder h = {buf, NULL, 0, "", 0}; + DEBUG_ENT("_pst_ff_getID2block"); + ptr = _pst_getID2(id2_head, id2); + + if (!ptr) { + DEBUG_INDEX(("Cannot find id2 value %#x\n", id2)); + DEBUG_RET(); + return 0; + } + DEBUG_RET(); + return _pst_ff_getID2data(pf, ptr, &h); } size_t _pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, struct holder *h) { - int32_t ret; - unsigned char *b = NULL, *t; - DEBUG_ENT("_pst_ff_getID2data"); - if (!(ptr->id & 0x02)) { - ret = _pst_ff_getIDblock_dec(pf, ptr->id, &b); - if (h->buf) { - *(h->buf) = b; - } else if ((h->base64 == 1) && h->fp) { - t = base64_encode(b, ret); - if (t) { - pst_fwrite(t, 1, strlen(t), h->fp); - free(t); // caught by valgrind - } - free(b); - } else if (h->fp) { - pst_fwrite(b, 1, ret, h->fp); - free(b); - } - } else { - // here we will assume it is a block that points to others - DEBUG_READ(("Assuming it is a multi-block record because of it's id\n")); - ret = _pst_ff_compile_ID(pf, ptr->id, h, 0); - } - if (h->buf && *h->buf) - (*(h->buf))[ret]='\0'; - DEBUG_RET(); - return ret; + int32_t ret; + unsigned char *b = NULL, *t; + DEBUG_ENT("_pst_ff_getID2data"); + if (!(ptr->id & 0x02)) { + ret = _pst_ff_getIDblock_dec(pf, ptr->id, &b); + if (h->buf) { + *(h->buf) = b; + } else if ((h->base64 == 1) && h->fp) { + t = base64_encode(b, ret); + if (t) { + pst_fwrite(t, 1, strlen(t), h->fp); + free(t); // caught by valgrind + } + free(b); + } else if (h->fp) { + pst_fwrite(b, 1, ret, h->fp); + free(b); + } + } else { + // here we will assume it is a block that points to others + DEBUG_READ(("Assuming it is a multi-block record because of it's id\n")); + ret = _pst_ff_compile_ID(pf, ptr->id, h, 0); + } + if (h->buf && *h->buf) + (*(h->buf))[ret]='\0'; + DEBUG_RET(); + return ret; } -size_t _pst_ff_compile_ID(pst_file *pf, u_int32_t id, struct holder *h, int32_t size) { - size_t z, a; - u_int16_t count, y; - u_int32_t x, b; - unsigned char * buf3 = NULL, *buf2 = NULL, *t; - unsigned char fdepth; - - DEBUG_ENT("_pst_ff_compile_ID"); - a = _pst_ff_getIDblock(pf, id, &buf3); - if (!a) { - if (buf3) free(buf3); - return 0; - } - if ((buf3[0] != 0x1)) { // if bit 8 is set) { - // if ((buf3)[0] != 0x1 && (buf3)[1] > 4) { - DEBUG_WARN(("WARNING: buffer doesn't start with 0x1, but I expected it to or doesn't have it's two-bit set!\n")); - DEBUG_WARN(("Treating as normal buffer\n")); - if (pf->encryption) _pst_decrypt(buf3, a, pf->encryption); - if (h->buf) - *(h->buf) = buf3; - else if (h->base64 == 1 && h->fp) { - t = base64_encode(buf3, a); - if (t) { - pst_fwrite(t, 1, strlen(t), h->fp); - free(t); // caught by valgrind - } - free(buf3); - } else if (h->fp) { - pst_fwrite(buf3, 1, a, h->fp); - free(buf3); - } - DEBUG_RET(); - return a; - } - memcpy (&count, &(buf3[2]), sizeof(int16_t)); - LE16_CPU(count); - memcpy (&fdepth, &(buf3[1]), sizeof(char)); - DEBUG_READ(("Seen index to blocks. Depth is %i\n", fdepth)); - DEBUG_READ(("There are %i ids here\n", count)); - - y = 0; - while (y < count) { - memcpy(&x, &buf3[0x08+(y*4)], sizeof(int32_t)); - LE32_CPU(x); - if (fdepth == 0x1) { - if ((z = _pst_ff_getIDblock(pf, x, &buf2)) == 0) { - DEBUG_WARN(("call to getIDblock returned zero %i\n", z)); - if (buf2) free(buf2); - free(buf3); - return z; - } - if (pf->encryption) _pst_decrypt(buf2, z, pf->encryption); - if (h->buf) { - *(h->buf) = realloc(*(h->buf), size+z+1); - DEBUG_READ(("appending read data of size %i onto main buffer from pos %i\n", z, size)); - memcpy(&((*(h->buf))[size]), buf2, z); - } - else if ((h->base64 == 1) && h->fp) { - // include any byte left over from the last one encoding - buf2 = (char*)realloc(buf2, z+h->base64_extra); - memmove(buf2+h->base64_extra, buf2, z); - memcpy(buf2, h->base64_extra_chars, h->base64_extra); - z+= h->base64_extra; - - b = z % 3; // find out how many bytes will be left over after the encoding. - // and save them - memcpy(h->base64_extra_chars, &(buf2[z-b]), b); - h->base64_extra = b; - t = base64_encode(buf2, z-b); - if (t) { - DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size)); - pst_fwrite(t, 1, strlen(t), h->fp); - free(t); // caught by valgrind - } - } - else if (h->fp) { - DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size)); - pst_fwrite(buf2, 1, z, h->fp); - } - size += z; - y++; - } - else { - if ((z = _pst_ff_compile_ID(pf, x, h, size)) == 0) { - DEBUG_WARN(("recursive called returned zero %i\n", z)); - free(buf3); - DEBUG_RET(); - return z; - } - size = z; - y++; - } - } - free(buf3); - if (buf2) free(buf2); - DEBUG_RET(); - return size; +size_t _pst_ff_compile_ID(pst_file *pf, uint32_t id, struct holder *h, int32_t size) { + size_t z, a; + uint16_t count, y; + uint32_t x, b; + unsigned char * buf3 = NULL, *buf2 = NULL, *t; + unsigned char fdepth; + + DEBUG_ENT("_pst_ff_compile_ID"); + a = _pst_ff_getIDblock(pf, id, &buf3); + if (!a) { + if (buf3) free(buf3); + return 0; + } + if ((buf3[0] != 0x1)) { // if bit 8 is set) { + // if ((buf3)[0] != 0x1 && (buf3)[1] > 4) { + DEBUG_WARN(("WARNING: buffer doesn't start with 0x1, but I expected it to or doesn't have it's two-bit set!\n")); + DEBUG_WARN(("Treating as normal buffer\n")); + if (pf->encryption) _pst_decrypt(buf3, a, pf->encryption); + if (h->buf) + *(h->buf) = buf3; + else if (h->base64 == 1 && h->fp) { + t = base64_encode(buf3, a); + if (t) { + pst_fwrite(t, 1, strlen(t), h->fp); + free(t); // caught by valgrind + } + free(buf3); + } else if (h->fp) { + pst_fwrite(buf3, 1, a, h->fp); + free(buf3); + } + DEBUG_RET(); + return a; + } + memcpy (&count, &(buf3[2]), sizeof(int16_t)); + LE16_CPU(count); + memcpy (&fdepth, &(buf3[1]), sizeof(char)); + DEBUG_READ(("Seen index to blocks. Depth is %i\n", fdepth)); + DEBUG_READ(("There are %i ids here\n", count)); + + y = 0; + while (y < count) { + memcpy(&x, &buf3[0x08+(y*4)], sizeof(int32_t)); + LE32_CPU(x); + if (fdepth == 0x1) { + if ((z = _pst_ff_getIDblock(pf, x, &buf2)) == 0) { + DEBUG_WARN(("call to getIDblock returned zero %i\n", z)); + if (buf2) free(buf2); + free(buf3); + return z; + } + if (pf->encryption) _pst_decrypt(buf2, z, pf->encryption); + if (h->buf) { + *(h->buf) = realloc(*(h->buf), size+z+1); + DEBUG_READ(("appending read data of size %i onto main buffer from pos %i\n", z, size)); + memcpy(&((*(h->buf))[size]), buf2, z); + } + else if ((h->base64 == 1) && h->fp) { + // include any byte left over from the last one encoding + buf2 = (char*)realloc(buf2, z+h->base64_extra); + memmove(buf2+h->base64_extra, buf2, z); + memcpy(buf2, h->base64_extra_chars, h->base64_extra); + z+= h->base64_extra; + + b = z % 3; // find out how many bytes will be left over after the encoding. + // and save them + memcpy(h->base64_extra_chars, &(buf2[z-b]), b); + h->base64_extra = b; + t = base64_encode(buf2, z-b); + if (t) { + DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size)); + pst_fwrite(t, 1, strlen(t), h->fp); + free(t); // caught by valgrind + } + } + else if (h->fp) { + DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size)); + pst_fwrite(buf2, 1, z, h->fp); + } + size += z; + y++; + } + else { + if ((z = _pst_ff_compile_ID(pf, x, h, size)) == 0) { + DEBUG_WARN(("recursive called returned zero %i\n", z)); + free(buf3); + DEBUG_RET(); + return z; + } + size = z; + y++; + } + } + free(buf3); + if (buf2) free(buf2); + DEBUG_RET(); + return size; } #ifdef _MSC_VER char * fileTimeToAscii(const FILETIME* filetime) { - time_t t; - DEBUG_ENT("fileTimeToAscii"); - t = fileTimeToUnixTime(filetime, 0); - if (t == -1) - DEBUG_WARN(("ERROR time_t varible that was produced, is -1\n")); - DEBUG_RET(); - return ctime(&t); + time_t t; + DEBUG_ENT("fileTimeToAscii"); + t = fileTimeToUnixTime(filetime, 0); + if (t == -1) + DEBUG_WARN(("ERROR time_t varible that was produced, is -1\n")); + DEBUG_RET(); + return ctime(&t); } time_t fileTimeToUnixTime(const FILETIME* filetime, DWORD *x) { - SYSTEMTIME s; - struct tm t; - DEBUG_ENT("fileTimeToUnixTime"); - memset (&t, 0, sizeof(struct tm)); - FileTimeToSystemTime(filetime, &s); - t.tm_year = s.wYear-1900; // this is what is required - t.tm_mon = s.wMonth-1; // also required! It made me a bit confused - t.tm_mday = s.wDay; - t.tm_hour = s.wHour; - t.tm_min = s.wMinute; - t.tm_sec = s.wSecond; - DEBUG_RET(); - return mktime(&t); + SYSTEMTIME s; + struct tm t; + DEBUG_ENT("fileTimeToUnixTime"); + memset (&t, 0, sizeof(struct tm)); + FileTimeToSystemTime(filetime, &s); + t.tm_year = s.wYear-1900; // this is what is required + t.tm_mon = s.wMonth-1; // also required! It made me a bit confused + t.tm_mday = s.wDay; + t.tm_hour = s.wHour; + t.tm_min = s.wMinute; + t.tm_sec = s.wSecond; + DEBUG_RET(); + return mktime(&t); } struct tm * fileTimeToStructTM (const FILETIME *filetime) { - time_t t1; - t1 = fileTimeToUnixTime(filetime, 0); - return gmtime(&t1); + time_t t1; + t1 = fileTimeToUnixTime(filetime, 0); + return gmtime(&t1); } #endif //_MSC_VER int32_t pst_stricmp(char *a, char *b) { - // compare strings case-insensitive. - // returns -1 if a < b, 0 if a==b, 1 if a > b - while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) { - a++; b++; - } - if (toupper(*a) == toupper(*b)) - return 0; - else if (toupper(*a) < toupper(*b)) - return -1; - else - return 1; + // compare strings case-insensitive. + // returns -1 if a < b, 0 if a==b, 1 if a > b + while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) { + a++; b++; + } + if (toupper(*a) == toupper(*b)) + return 0; + else if (toupper(*a) < toupper(*b)) + return -1; + else + return 1; } int32_t pst_strincmp(char *a, char *b, int32_t x) { - // compare upto x chars in string a and b case-insensitively - // returns -1 if a < b, 0 if a==b, 1 if a > b - int32_t y = 0; - while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) { - a++; b++; y++; - } - // if we have reached the end of either string, or a and b still match - if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b)) - return 0; - else if (toupper(*a) < toupper(*b)) - return -1; - else - return 1; + // compare upto x chars in string a and b case-insensitively + // returns -1 if a < b, 0 if a==b, 1 if a > b + int32_t y = 0; + while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) { + a++; b++; y++; + } + // if we have reached the end of either string, or a and b still match + if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b)) + return 0; + else if (toupper(*a) < toupper(*b)) + return -1; + else + return 1; } size_t pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream) { - size_t r; - DEBUG_ENT("pst_fwrite"); - if (ptr) - r = fwrite(ptr, size, nmemb, stream); - else { - r = 0; - DEBUG_WARN(("An attempt to write a NULL Pointer was made\n")); - } - DEBUG_RET(); - return r; + size_t r; + DEBUG_ENT("pst_fwrite"); + if (ptr) + r = fwrite(ptr, size, nmemb, stream); + else { + r = 0; + DEBUG_WARN(("An attempt to write a NULL Pointer was made\n")); + } + DEBUG_RET(); + return r; } char * _pst_wide_to_single(char *wt, int32_t size) { - // returns the first byte of each wide char. the size is the number of bytes in source - char *x, *y; - DEBUG_ENT("_pst_wide_to_single"); - x = xmalloc((size/2)+1); - y = x; - while (size != 0 && *wt != '\0') { - *y = *wt; - wt+=2; - size -= 2; - y++; - } - *y = '\0'; - DEBUG_RET(); - return x; + // returns the first byte of each wide char. the size is the number of bytes in source + char *x, *y; + DEBUG_ENT("_pst_wide_to_single"); + x = xmalloc((size/2)+1); + y = x; + while (size != 0 && *wt != '\0') { + *y = *wt; + wt+=2; + size -= 2; + y++; + } + *y = '\0'; + DEBUG_RET(); + return x; } + +char *pst_rfc2426_escape(char *str) { + static char* buf = NULL; + char *ret, *a, *b; + int x = 0, y, z; + DEBUG_ENT("rfc2426_escape"); + if (!str) + ret = str; + else { + + // calculate space required to escape all the following characters + y = pst_chr_count(str, ',') + + pst_chr_count(str, '\\') + + pst_chr_count(str, ';') + + pst_chr_count(str, '\n'); + z = pst_chr_count(str, '\r'); + if (y == 0 && z == 0) + // there isn't any extra space required + ret = str; + else { + x = strlen(str) + y - z + 1; // don't forget room for the NUL + buf = (char*) realloc(buf, x); + a = str; + b = buf; + while (*a != '\0') { + switch (*a) { + case ',' : + case '\\': + case ';' : + *(b++) = '\\'; + *b = *a; + break; + case '\n': // newlines are encoded as "\n" + *(b++) = '\\'; + *b = 'n'; + break; + case '\r': // skip cr + b--; + break; + default: + *b=*a; + } + b++; + a++; + } + *b = '\0'; // NUL-terminate the string (buf) + ret = buf; + } + } + DEBUG_RET(); + return ret; +} + + +int pst_chr_count(char *str, char x) { + int r = 0; + while (*str != '\0') { + if (*str == x) + r++; + str++; + } + return r; +} + + +char *pst_rfc2425_datetime_format(FILETIME *ft) { + static char* buffer = NULL; + struct tm *stm = NULL; + DEBUG_ENT("rfc2425_datetime_format"); + if (!buffer) buffer = malloc(30); // should be enough for the date as defined below + stm = fileTimeToStructTM(ft); + if (strftime(buffer, 30, "%Y-%m-%dT%H:%M:%SZ", stm)==0) { + DEBUG_INFO(("Problem occured formatting date\n")); + } + DEBUG_RET(); + return buffer; +} + + +char *pst_rfc2445_datetime_format(FILETIME *ft) { + static char* buffer = NULL; + struct tm *stm = NULL; + DEBUG_ENT("rfc2445_datetime_format"); + if (!buffer) buffer = malloc(30); // should be enough for the date as defined below + stm = fileTimeToStructTM(ft); + if (strftime(buffer, 30, "%Y%m%dT%H%M%SZ", stm)==0) { + DEBUG_INFO(("Problem occured formatting date\n")); + } + DEBUG_RET(); + return buffer; +} + + diff --git a/src/libpst.h b/src/libpst.h index 78fd57f..8677859 100644 --- a/src/libpst.h +++ b/src/libpst.h @@ -1,516 +1,551 @@ /*** * libpst.h * Part of LibPST project * Written by David Smith * dave.s@earthcorp.com */ // LibPST - Library for Accessing Outlook .pst files // Dave Smith - davesmith@users.sourceforge.net #ifndef LIBPST_H #define LIBPST_H +#include + #ifndef _MSC_VER #ifndef FILETIME_DEFINED #define FILETIME_DEFINED //Win32 Filetime struct - copied from WINE typedef struct { - u_int32_t dwLowDateTime; - u_int32_t dwHighDateTime; + uint32_t dwLowDateTime; + uint32_t dwHighDateTime; } FILETIME; #endif //ifndef FILETIME_DEFINED #endif //ifndef _MSC_VER -// define the INT32_MAX here cause it isn't normally defined -#ifndef INT32_MAX -# define INT32_MAX INT_MAX -#endif - // According to Jan Wolter, sys/param.h is the most portable source of endian // information on UNIX systems. see http://www.unixpapa.com/incnote/byteorder.html #ifdef _MSC_VER #define BYTE_ORDER LITTLE_ENDIAN #else #include #endif // defined _MSC_VER #if BYTE_ORDER == BIG_ENDIAN # define LE64_CPU(x) \ x = ((((x) & 0xff00000000000000) >> 56) | \ (((x) & 0x00ff000000000000) >> 40) | \ (((x) & 0x0000ff0000000000) >> 24) | \ (((x) & 0x000000ff00000000) >> 8 ) | \ (((x) & 0x00000000ff000000) << 8 ) | \ (((x) & 0x0000000000ff0000) << 24) | \ (((x) & 0x000000000000ff00) << 40) | \ (((x) & 0x00000000000000ff) << 56)); # define LE32_CPU(x) \ x = ((((x) & 0xff000000) >> 24) | \ (((x) & 0x00ff0000) >> 8 ) | \ (((x) & 0x0000ff00) << 8 ) | \ (((x) & 0x000000ff) << 24)); # define LE16_CPU(x) \ x = ((((x) & 0xff00) >> 8) | \ (((x) & 0x00ff) << 8)); #elif BYTE_ORDER == LITTLE_ENDIAN # define LE64_CPU(x) {} # define LE32_CPU(x) {} # define LE16_CPU(x) {} #else # error "Byte order not supported by this library" #endif // BYTE_ORDER #ifdef _MSC_VER #include "windows.h" #define int32_t int -#define u_int32_t unsigned int +#define uint32_t unsigned int #define int16_t short int -#define u_int16_t unsigned short int +#define uint16_t unsigned short int #endif // _MSC_VER #define PST_TYPE_NOTE 1 #define PST_TYPE_APPOINTMENT 8 #define PST_TYPE_CONTACT 9 #define PST_TYPE_JOURNAL 10 #define PST_TYPE_STICKYNOTE 11 #define PST_TYPE_TASK 12 #define PST_TYPE_OTHER 13 #define PST_TYPE_REPORT 14 // defines whether decryption is done on this bit of data #define PST_NO_ENC 0 #define PST_ENC 1 // defines types of possible encryption #define PST_NO_ENCRYPT 0 #define PST_COMP_ENCRYPT 1 #define PST_ENCRYPT 2 // defines different types of mappings #define PST_MAP_ATTRIB 1 #define PST_MAP_HEADER 2 // define my custom email attributes. #define PST_ATTRIB_HEADER -1 // defines types of free/busy values for appointment->showas #define PST_FREEBUSY_FREE 0 #define PST_FREEBUSY_TENTATIVE 1 #define PST_FREEBUSY_BUSY 2 #define PST_FREEBUSY_OUT_OF_OFFICE 3 // defines labels for appointment->label #define PST_APP_LABEL_NONE 0 // None #define PST_APP_LABEL_IMPORTANT 1 // Important #define PST_APP_LABEL_BUSINESS 2 // Business #define PST_APP_LABEL_PERSONAL 3 // Personal #define PST_APP_LABEL_VACATION 4 // Vacation #define PST_APP_LABEL_MUST_ATTEND 5 // Must Attend #define PST_APP_LABEL_TRAVEL_REQ 6 // Travel Required #define PST_APP_LABEL_NEEDS_PREP 7 // Needs Preparation #define PST_APP_LABEL_BIRTHDAY 8 // Birthday #define PST_APP_LABEL_ANNIVERSARY 9 // Anniversary #define PST_APP_LABEL_PHONE_CALL 10// Phone Call +extern int do_read64; + typedef struct _pst_misc_6_struct { int32_t i1; int32_t i2; int32_t i3; int32_t i4; int32_t i5; int32_t i6; } pst_misc_6; typedef struct _pst_entryid_struct { int32_t u1; char entryid[16]; - u_int32_t id; + uint32_t id; } pst_entryid; -typedef struct _pst_desc_struct { - u_int32_t d_id; - u_int32_t desc_id; - u_int32_t list_id; - u_int32_t parent_id; -} pst_desc; - -typedef struct _pst_index_struct{ - u_int32_t id; - int32_t offset; - u_int16_t size; - int16_t u1; +typedef struct _pst_desc_struct32 { + uint32_t d_id; + uint32_t desc_id; + uint32_t list_id; + uint32_t parent_id; +} pst_desc32; + +typedef struct _pst_desc_structn { + uint64_t d_id; + uint64_t desc_id; + uint64_t list_id; + uint32_t parent_id; // not 64 bit ?? + uint32_t u1; // padding +} pst_descn; + +typedef struct _pst_index_struct32 { + uint32_t id; + int32_t offset; + uint16_t size; + int16_t u1; +} pst_index32; + +typedef struct _pst_index_struct { + uint64_t id; + int64_t offset; + uint16_t size; + int16_t u0; + int32_t u1; } pst_index; +typedef struct _pst_index_tree32 { + uint32_t id; + int32_t offset; + int32_t size; + int32_t u1; + struct _pst_index_tree * next; +} pst_index_ll32; + typedef struct _pst_index_tree { - u_int32_t id; - int32_t offset; - size_t size; - int32_t u1; + uint64_t id; + int64_t offset; + int64_t size; + int64_t u1; struct _pst_index_tree * next; } pst_index_ll; typedef struct _pst_index2_tree { - u_int32_t id2; + uint32_t id2; pst_index_ll *id; struct _pst_index2_tree * next; } pst_index2_ll; typedef struct _pst_desc_tree { - u_int32_t id; + uint32_t id; pst_index_ll * list_index; pst_index_ll * desc; int32_t no_child; struct _pst_desc_tree * prev; struct _pst_desc_tree * next; struct _pst_desc_tree * parent; struct _pst_desc_tree * child; struct _pst_desc_tree * child_tail; } pst_desc_ll; typedef struct _pst_item_email_subject { int32_t off1; int32_t off2; - char *subj; + char *subj; } pst_item_email_subject; typedef struct _pst_item_email { FILETIME *arrival_date; int32_t autoforward; // 1 = true, 0 = not set, -1 = false char *body; char *cc_address; char *common_name; int32_t conv_index; int32_t conversion_prohib; int32_t delete_after_submit; // 1 = true, 0 = false int32_t delivery_report; // 1 = true, 0 = false char *encrypted_body; int32_t encrypted_body_size; char *encrypted_htmlbody; int32_t encrypted_htmlbody_size; int32_t flag; char *header; char *htmlbody; int32_t importance; char *in_reply_to; int32_t message_cc_me; // 1 = true, 0 = false int32_t message_recip_me; // 1 = true, 0 = false int32_t message_to_me; // 1 = true, 0 = false char *messageid; int32_t orig_sensitivity; char *outlook_recipient; char *outlook_recipient2; char *outlook_sender; char *outlook_sender_name; char *outlook_sender2; int32_t priority; char *proc_subject; int32_t read_receipt; char *recip_access; char *recip_address; char *recip2_access; char *recip2_address; int32_t reply_requested; char *reply_to; char *return_path_address; int32_t rtf_body_char_count; int32_t rtf_body_crc; char *rtf_body_tag; char *rtf_compressed; - u_int32_t rtf_compressed_size; + uint32_t rtf_compressed_size; int32_t rtf_in_sync; // 1 = true, 0 = doesn't exist, -1 = false int32_t rtf_ws_prefix_count; int32_t rtf_ws_trailing_count; char *sender_access; char *sender_address; char *sender2_access; char *sender2_address; int32_t sensitivity; FILETIME *sent_date; pst_entryid *sentmail_folder; char *sentto_address; pst_item_email_subject *subject; } pst_item_email; typedef struct _pst_item_folder { int32_t email_count; int32_t unseen_email_count; int32_t assoc_count; char subfolder; } pst_item_folder; typedef struct _pst_item_message_store { pst_entryid *deleted_items_folder; pst_entryid *search_root_folder; pst_entryid *top_of_personal_folder; pst_entryid *top_of_folder; int32_t valid_mask; // what folders the message store contains int32_t pwd_chksum; } pst_item_message_store; typedef struct _pst_item_contact { char *access_method; char *account_name; char *address1; char *address1a; char *address1_desc; char *address1_transport; char *address2; char *address2a; char *address2_desc; char *address2_transport; char *address3; char *address3a; char *address3_desc; char *address3_transport; char *assistant_name; char *assistant_phone; char *billing_information; FILETIME *birthday; char *business_address; char *business_city; char *business_country; char *business_fax; char *business_homepage; char *business_phone; char *business_phone2; char *business_po_box; char *business_postal_code; char *business_state; char *business_street; char *callback_phone; char *car_phone; char *company_main_phone; char *company_name; char *computer_name; char *customer_id; char *def_postal_address; char *department; char *display_name_prefix; char *first_name; char *followup; char *free_busy_address; char *ftp_site; char *fullname; int32_t gender; char *gov_id; char *hobbies; char *home_address; char *home_city; char *home_country; char *home_fax; char *home_phone; char *home_phone2; char *home_po_box; char *home_postal_code; char *home_state; char *home_street; char *initials; char *isdn_phone; char *job_title; char *keyword; char *language; char *location; int32_t mail_permission; char *manager_name; char *middle_name; char *mileage; char *mobile_phone; char *nickname; char *office_loc; char *org_id; char *other_address; char *other_city; char *other_country; char *other_phone; char *other_po_box; char *other_postal_code; char *other_state; char *other_street; char *pager_phone; char *personal_homepage; char *pref_name; char *primary_fax; char *primary_phone; char *profession; char *radio_phone; int32_t rich_text; char *spouse_name; char *suffix; char *surname; char *telex; char *transmittable_display_name; char *ttytdd_phone; FILETIME *wedding_anniversary; } pst_item_contact; typedef struct _pst_item_attach { char *filename1; char *filename2; char *mimetype; char *data; size_t size; int32_t id2_val; int32_t id_val; // calculated from id2_val during creation of record int32_t method; int32_t position; int32_t sequence; struct _pst_item_attach *next; } pst_item_attach; typedef struct _pst_item_extra_field { char *field_name; char *value; struct _pst_item_extra_field *next; } pst_item_extra_field; typedef struct _pst_item_journal { FILETIME *end; FILETIME *start; char *type; } pst_item_journal; typedef struct _pst_item_appointment { FILETIME *end; char *location; FILETIME *reminder; FILETIME *start; char *timezonestring; int32_t showas; int32_t label; int32_t all_day; } pst_item_appointment; typedef struct _pst_item { - struct _pst_item_email *email; // data reffering to email - struct _pst_item_folder *folder; // data reffering to folder - struct _pst_item_contact *contact; // data reffering to contact - struct _pst_item_attach *attach; // linked list of attachments - struct _pst_item_message_store * message_store; // data referring to the message store - struct _pst_item_extra_field *extra_fields; // linked list of extra headers and such - struct _pst_item_journal *journal; // data reffering to a journal entry - struct _pst_item_appointment *appointment; // data reffering to a calendar entry - int32_t type; - char *ascii_type; - char *file_as; - char *comment; - int32_t message_size; - char *outlook_version; - char *record_key; // probably 16 bytes long. - size_t record_key_size; - int32_t response_requested; + struct _pst_item_email *email; // data reffering to email + struct _pst_item_folder *folder; // data reffering to folder + struct _pst_item_contact *contact; // data reffering to contact + struct _pst_item_attach *attach; // linked list of attachments + struct _pst_item_message_store *message_store; // data referring to the message store + struct _pst_item_extra_field *extra_fields; // linked list of extra headers and such + struct _pst_item_journal *journal; // data reffering to a journal entry + struct _pst_item_appointment *appointment; // data reffering to a calendar entry + int32_t type; + char *ascii_type; + char *file_as; + char *comment; + int32_t message_size; + char *outlook_version; + char *record_key; // probably 16 bytes long. + size_t record_key_size; + int32_t response_requested; FILETIME *create_date; FILETIME *modify_date; - int32_t private_member; + int32_t private_member; } pst_item; typedef struct _pst_x_attrib_ll { int32_t type; int32_t mytype; int32_t map; void *data; struct _pst_x_attrib_ll *next; } pst_x_attrib_ll; typedef struct _pst_file { pst_index_ll *i_head, *i_tail; pst_index2_ll *i2_head; pst_desc_ll *d_head, *d_tail; pst_x_attrib_ll *x_head; int32_t index1; int32_t index1_count; int32_t index2; int32_t index2_count; + int64_t index1_64; + int64_t index1_count_64; + int64_t index2_64; + int64_t index2_count_64; FILE * fp; // file pointer to opened PST file size_t size; // pst file size unsigned char encryption; // pst encryption setting unsigned char ind_type; // pst index type } pst_file; typedef struct _pst_block_offset { int16_t from; int16_t to; } pst_block_offset; typedef struct _pst_block_offset_pointer { unsigned char *from; unsigned char *to; int needfree; } pst_block_offset_pointer; struct _pst_num_item { - u_int32_t id; + uint32_t id; unsigned char *data; int32_t type; size_t size; char *extra; }; typedef struct _pst_num_array { int32_t count_item; int32_t orig_count; int32_t count_array; struct _pst_num_item ** items; struct _pst_num_array *next; } pst_num_array; struct holder { unsigned char **buf; FILE * fp; int32_t base64; char base64_extra_chars[3]; int32_t base64_extra; }; // prototypes +void set_read64(); int32_t pst_open(pst_file *pf, char *name, char *mode); int32_t pst_close(pst_file *pf); pst_desc_ll * pst_getTopOfFolders(pst_file *pf, pst_item *root); int32_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, unsigned char **b); int32_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp); int32_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp); int32_t pst_load_index (pst_file *pf); pst_desc_ll* pst_getNextDptr(pst_desc_ll* d); int32_t pst_load_extended_attributes(pst_file *pf); -int32_t _pst_build_id_ptr(pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t start_val, u_int32_t end_val); -int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t linku1, u_int32_t *high_id, u_int32_t start_id, u_int32_t end_val); +int32_t _pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, int64_t linku1, uint64_t start_val, uint64_t end_val); +int32_t _pst_build_desc_ptr (pst_file *pf, off_t offset, int32_t depth, int64_t linku1, uint64_t *high_id, uint64_t start_id, uint64_t end_val); pst_item* _pst_getItem(pst_file *pf, pst_desc_ll *d_ptr); void * _pst_parse_item (pst_file *pf, pst_desc_ll *d_ptr); -pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head); +pst_num_array * _pst_parse_block(pst_file *pf, uint32_t block_id, pst_index2_ll *i2_head); int32_t _pst_process(pst_num_array *list, pst_item *item, pst_item_attach *attach); int32_t _pst_free_list(pst_num_array *list); void _pst_freeItem(pst_item *item); int32_t _pst_free_id2(pst_index2_ll * head); int32_t _pst_free_id (pst_index_ll *head); int32_t _pst_free_desc (pst_desc_ll *head); int32_t _pst_free_xattrib(pst_x_attrib_ll *x); int32_t _pst_getBlockOffsetPointer(pst_file *pf, pst_index2_ll *i2_head, unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset_pointer *p); int32_t _pst_getBlockOffset(unsigned char *buf, int32_t read_size, int32_t i_offset, int32_t offset, pst_block_offset *p); pst_index2_ll * _pst_build_id2(pst_file *pf, pst_index_ll* list, pst_index2_ll* head_ptr); -pst_index_ll * _pst_getID(pst_file* pf, u_int32_t id); -pst_index_ll * _pst_getID2(pst_index2_ll * ptr, u_int32_t id); -pst_desc_ll * _pst_getDptr(pst_file *pf, u_int32_t id); -size_t _pst_read_block_size(pst_file *pf, int32_t offset, size_t size, char ** buf, int32_t do_enc, - unsigned char is_index); +pst_index_ll * _pst_getID(pst_file* pf, uint64_t id); +pst_index_ll * _pst_getID2(pst_index2_ll * ptr, uint32_t id); +pst_desc_ll * _pst_getDptr(pst_file *pf, uint32_t id); +size_t _pst_read_block_size(pst_file *pf, off_t offset, size_t size, char **buf, int32_t do_enc, unsigned char is_index); int32_t _pst_decrypt(unsigned char *buf, size_t size, int32_t type); -int32_t _pst_getAtPos(FILE *fp, int32_t pos, void* buf, u_int32_t size); -int32_t _pst_get (FILE *fp, void *buf, u_int32_t size); -size_t _pst_ff_getIDblock_dec(pst_file *pf, u_int32_t id, unsigned char **b); -size_t _pst_ff_getIDblock(pst_file *pf, u_int32_t id, unsigned char** b); -size_t _pst_ff_getID2block(pst_file *pf, u_int32_t id2, pst_index2_ll *id2_head, unsigned char** buf); +int64_t _getIntAt(char *buf); +int64_t _pst_getIntAtPos(FILE *fp, off_t pos); +int32_t _pst_getAtPos(FILE *fp, off_t pos, void* buf, uint32_t size); +int32_t _pst_get (FILE *fp, void *buf, uint32_t size); +size_t _pst_ff_getIDblock_dec(pst_file *pf, uint32_t id, unsigned char **b); +size_t _pst_ff_getIDblock(pst_file *pf, uint32_t id, unsigned char** b); +size_t _pst_ff_getID2block(pst_file *pf, uint32_t id2, pst_index2_ll *id2_head, unsigned char** buf); size_t _pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, struct holder *h); -size_t _pst_ff_compile_ID(pst_file *pf, u_int32_t id, struct holder *h, int32_t size); +size_t _pst_ff_compile_ID(pst_file *pf, uint32_t id, struct holder *h, int32_t size); int32_t pst_strincmp(char *a, char *b, int32_t x); int32_t pst_stricmp(char *a, char *b); -size_t pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream); +size_t pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream); char * _pst_wide_to_single(char *wt, int32_t size); + +char *pst_rfc2426_escape(char *str); +int pst_chr_count(char *str, char x); +char *pst_rfc2425_datetime_format(FILETIME *ft); +char *pst_rfc2445_datetime_format(FILETIME *ft); + // DEBUG functions int32_t _pst_printDptr(pst_file *pf); int32_t _pst_printIDptr(pst_file* pf); int32_t _pst_printID2ptr(pst_index2_ll *ptr); void * xmalloc(size_t size); #endif // defined LIBPST_H diff --git a/src/libstrfunc.c b/src/libstrfunc.c index 38fe57a..ca84545 100644 --- a/src/libstrfunc.c +++ b/src/libstrfunc.c @@ -1,63 +1,80 @@ /* Taken from LibStrfunc v7.3 */ #include #include #include #include "libstrfunc.h" static unsigned char _sf_uc_ib[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=="; -char * -base64_encode(void *data, size_t size) { - char *output; - register char *ou; - register unsigned char *p=(unsigned char *)data; -#ifdef __LINUX__ - register void * dte = ((char*)data + size); -#endif - -#ifndef __LINUX__ - register void * dte = (void*)((char*)data + size); -#endif - //register void *dte=data + size; - register int nc=0; - - if ( data == NULL || size == 0 ) - return NULL; - - ou=output=(char *)malloc(size / 3 * 4 + (size / 57) + 5); - if(!output) - return NULL; - - while((char *)dte - (char *)p >= 3) { - unsigned char x = p[0]; - unsigned char y = p[1]; - unsigned char z = p[2]; - ou[0] = _sf_uc_ib[ x >> 2 ]; - ou[1] = _sf_uc_ib[ ((x & 0x03) << 4) | (y >> 4) ]; - ou[2] = _sf_uc_ib[ ((y & 0x0F) << 2) | (z >> 6) ]; - ou[3] = _sf_uc_ib[ z & 0x3F ]; - p+=3; - ou+=4; - nc+=4; - if(!(nc % 76)) *ou++='\n'; - }; - if((char *)dte - (char *)p == 2) { - *ou++ = _sf_uc_ib[ *p >> 2 ]; - *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ]; - *ou++ = _sf_uc_ib[ ((p[1] & 0x0F) << 2) ]; - *ou++ = '='; - } else if((char *)dte - (char *)p == 1) { - *ou++ = _sf_uc_ib[ *p >> 2 ]; - *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) ]; - *ou++ = '='; - *ou++ = '='; - }; - - *ou=0; - - return output; +char *base64_encode(void *data, size_t size) { + char *output; + register char *ou; + register unsigned char *p=(unsigned char *)data; + register void * dte = (void*)((char*)data + size); + register int nc=0; + + if ( data == NULL || size == 0 ) return NULL; + + ou = output = (char *)malloc(size / 3 * 4 + (size / 57) + 5); + if(!output) return NULL; + + while((char *)dte - (char *)p >= 3) { + unsigned char x = p[0]; + unsigned char y = p[1]; + unsigned char z = p[2]; + ou[0] = _sf_uc_ib[ x >> 2 ]; + ou[1] = _sf_uc_ib[ ((x & 0x03) << 4) | (y >> 4) ]; + ou[2] = _sf_uc_ib[ ((y & 0x0F) << 2) | (z >> 6) ]; + ou[3] = _sf_uc_ib[ z & 0x3F ]; + p+=3; + ou+=4; + nc+=4; + if(!(nc % 76)) *ou++='\n'; + }; + if ((char *)dte - (char *)p == 2) { + *ou++ = _sf_uc_ib[ *p >> 2 ]; + *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ]; + *ou++ = _sf_uc_ib[ ((p[1] & 0x0F) << 2) ]; + *ou++ = '='; + } else if((char *)dte - (char *)p == 1) { + *ou++ = _sf_uc_ib[ *p >> 2 ]; + *ou++ = _sf_uc_ib[ ((*p & 0x03) << 4) ]; + *ou++ = '='; + *ou++ = '='; + }; + + *ou=0; + + return output; }; + +void hexdump(char *hbuf, int start, int stop, int ascii) /* {{{ HexDump all or a part of some buffer */ +{ + char c; + int diff,i; + + while (start < stop ) { + diff = stop - start; + if (diff > 16) diff = 16; + + fprintf(stderr, ":%08X ",start); + + for (i = 0; i < diff; i++) { + if( 8 == i ) fprintf( stderr, " " ); + fprintf(stderr, "%02X ",(unsigned char)*(hbuf+start+i)); + } + if (ascii) { + for (i = diff; i < 16; i++) fprintf(stderr, " "); + for (i = 0; i < diff; i++) { + c = *(hbuf+start+i); + fprintf(stderr, "%c", isprint(c) ? c : '.'); + } + } + fprintf(stderr, "\n"); + start += 16; + } +} diff --git a/src/libstrfunc.h b/src/libstrfunc.h index 04091d7..a8fb06d 100644 --- a/src/libstrfunc.h +++ b/src/libstrfunc.h @@ -1,2 +1,3 @@ char * base64_encode(void *data, size_t size); +void hexdump(char *hbuf, int start, int stop, int ascii); diff --git a/src/lspst.c b/src/lspst.c index 50a2158..466f5dc 100644 --- a/src/lspst.c +++ b/src/lspst.c @@ -1,431 +1,262 @@ /*** * lspst.c * Part of the LibPST project * Author: Joe Nahmias * Based on readpst.c by by David Smith * */ -// header file includes {{{1 +// header file includes #include #include #include #include #include #include #include "libpst.h" #include "define.h" #include "timeconv.h" -// }}}1 -// struct file_ll {{{1 + struct file_ll { - char *name; - char *dname; - FILE * output; - int32_t stored_count; - int32_t email_count; - int32_t skip_count; - int32_t type; - struct file_ll *next; + char *dname; + int32_t stored_count; + int32_t email_count; + int32_t skip_count; + int32_t type; }; -// }}}1 -// Function Declarations {{{1 + + void canonicalize_filename(char *fname); -int chr_count(char *str, char x); void debug_print(char *fmt, ...); -char *rfc2426_escape(char *str); -char *rfc2445_datetime_format(FILETIME *ft); -// }}}1 -#ifndef LSPST_DEBUG_MAIN - #define LSPST_DEBUG_MAIN(x) debug_print x; -#endif -// int main(int argc, char** argv) {{{1 -int main(int argc, char** argv) { - // declarations {{{2 - pst_item *item = NULL; - pst_file pstfile; - pst_desc_ll *d_ptr; - char *temp = NULL; //temporary char pointer - int skip_child = 0; - struct file_ll *f = NULL, *head = NULL; - // }}}2 - - if (argc <= 1) - DIE(("Missing PST filename.\n")); - - // Open PST file - if ( pst_open(&pstfile, argv[1], "r") ) - DIE(("Error opening File\n")); - // Load PST index - if ( pst_load_index(&pstfile) ) - DIE(("Index Error\n")); - pst_load_extended_attributes(&pstfile); - - d_ptr = pstfile.d_head; // first record is main record - if ((item = _pst_parse_item(&pstfile, d_ptr)) == NULL || item->message_store == NULL) { - DIE(("main: Could not get root record\n")); - } - - // default the file_as to the same as the main filename if it doesn't exist - if (item->file_as == NULL) { - if ((temp = strrchr(argv[1], '/')) == NULL) - if ((temp = strrchr(argv[1], '\\')) == NULL) - temp = argv[1]; - else - temp++; // get past the "\\" - else - temp++; // get past the "/" - item->file_as = (char*)xmalloc(strlen(temp)+1); - strcpy(item->file_as, temp); - } - fprintf(stderr, "item->file_as = '%s'.\n", item->file_as); - - // setup head file_ll - head = (struct file_ll*) malloc(sizeof(struct file_ll)); - memset(head, 0, sizeof(struct file_ll)); - head->email_count = 0; - head->skip_count = 0; - head->next = NULL; - head->name = "mbox"; - head->dname = (char*) malloc(strlen(item->file_as)+1); - strcpy(head->dname, item->file_as); - head->type = item->type; - LSPST_DEBUG_MAIN(("head @ %p: name = '%s', dname = '%s', next = %p.\n", head, head->name, head->dname, head->next)); - - if ((d_ptr = pst_getTopOfFolders(&pstfile, item)) == NULL) { - DIE(("Top of folders record not found. Cannot continue\n")); - } - LSPST_DEBUG_MAIN(("d_ptr(TOF) = %p.\n", d_ptr)); - - if (item){ - _pst_freeItem(item); - item = NULL; - } - - d_ptr = d_ptr->child; // do the children of TOPF - LSPST_DEBUG_MAIN(("d_ptr(TOF->child) = %p.\n", d_ptr)); - - LSPST_DEBUG_MAIN(("main: About to do email stuff\n")); - while (d_ptr != NULL) { - // Process d_ptr {{{2 - LSPST_DEBUG_MAIN(("main: New item record, d_ptr = %p.\n", d_ptr)); - if (d_ptr->desc == NULL) { - DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); - f->skip_count++; - goto check_parent; - } - LSPST_DEBUG_MAIN(("main: Desc Email ID %x [d_ptr->id = %x]\n", d_ptr->desc->id, d_ptr->id)); - - item = _pst_parse_item(&pstfile, d_ptr); - LSPST_DEBUG_MAIN(("main: About to process item @ %p.\n", item)); - if (item != NULL) { - - // there should only be one message_store, and we have already - // done it - if (item->message_store != NULL) { - DIE(("ERROR(main): A second message_store has been found.\n")); - } - - if (item->folder != NULL) { - // Process Folder item {{{3 - // if this is a folder, we want to recurse into it - printf("Folder"); - if (item->file_as != NULL) - printf("\t%s/", item->file_as); - printf("\n"); - - LSPST_DEBUG_MAIN(("main: I think I may try to go into folder \"%s\"\n", item->file_as)); - f = (struct file_ll*) malloc(sizeof(struct file_ll)); - memset(f, 0, sizeof(struct file_ll)); - f->next = head; - f->email_count = 0; - f->type = item->type; - f->stored_count = item->folder->email_count; - head = f; - f->name = "mbox"; - f->dname = (char*) xmalloc(strlen(item->file_as)+1); - strcpy(f->dname, item->file_as); - - LSPST_DEBUG_MAIN(("main: f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); - canonicalize_filename(f->name); - - if (d_ptr->child != NULL) { - d_ptr = d_ptr->child; - skip_child = 1; - } else { - LSPST_DEBUG_MAIN(("main: Folder has NO children. Creating directory, and closing again\n")); - // printf("\tNo items to process in folder \"%s\", should have been %i\n", f->dname, f->stored_count); - head = f->next; - if (f->output != NULL) - fclose(f->output); - free(f->dname); - free(f->name); - free(f); - - f = head; - } - _pst_freeItem(item); - item = NULL; // just for the odd situations! - goto check_parent; - // }}}3 - } else if (item->contact != NULL) { - // Process Contact item {{{3 - if (f->type != PST_TYPE_CONTACT) { - LSPST_DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. " - "Will process anyway\n")); - } - if (item->type != PST_TYPE_CONTACT) { - LSPST_DEBUG_MAIN(("main: I have an item that has contact info, but doesn't say that" - " it is a contact. Type is \"%s\"\n", item->ascii_type)); - LSPST_DEBUG_MAIN(("main: Processing anyway\n")); - } - - printf("Contact"); - if (item->contact->fullname != NULL) - printf("\t%s", rfc2426_escape(item->contact->fullname)); - printf("\n"); - // }}}3 - } else if (item->email != NULL && - (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { - // Process Email item {{{3 - printf("Email"); - if (item->email->outlook_sender_name != NULL) - printf("\tFrom: %s", item->email->outlook_sender_name); - if (item->email->subject->subj != NULL) - printf("\tSubject: %s", item->email->subject->subj); - printf("\n"); - // }}}3 - } else if (item->type == PST_TYPE_JOURNAL) { - // Process Journal item {{{3 - if (f->type != PST_TYPE_JOURNAL) { - LSPST_DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); - } - - printf("Journal\t%s\n", rfc2426_escape(item->email->subject->subj)); - // }}}3 - } else if (item->type == PST_TYPE_APPOINTMENT) { - // Process Calendar Appointment item {{{3 - // deal with Calendar appointments - - LSPST_DEBUG_MAIN(("main: Processing Appointment Entry\n")); - if (f->type != PST_TYPE_APPOINTMENT) { - LSPST_DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); - } - - printf("Appointment"); - if (item->email != NULL && item->email->subject != NULL) - printf("\tSUMMARY: %s", rfc2426_escape(item->email->subject->subj)); - if (item->appointment != NULL) { - if (item->appointment->start != NULL) - printf("\tSTART: %s", rfc2445_datetime_format(item->appointment->start)); - if (item->appointment->end != NULL) - printf("\tEND: %s", rfc2445_datetime_format(item->appointment->end)); - printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); - } - printf("\n"); - - // }}}3 - } else { - f->skip_count++; - LSPST_DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", \ - item->type, item->ascii_type)); - } - } else { - f->skip_count++; - LSPST_DEBUG_MAIN(("main: A NULL item was seen\n")); - } - - check_parent: - // _pst_freeItem(item); - while (!skip_child && d_ptr->next == NULL && d_ptr->parent != NULL) { - LSPST_DEBUG_MAIN(("main: Going to Parent\n")); - head = f->next; - if (f->output != NULL) - fclose(f->output); - LSPST_DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count)); - /* - printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n", \ - f->dname, f->email_count, f->skip_count, f->stored_count); - */ - - free(f->name); - free(f->dname); - free(f); - f = head; - if (head == NULL) { //we can't go higher. Must be at start? - LSPST_DEBUG_MAIN(("main: We are now trying to go above the highest level. We must be finished\n")); - break; //from main while loop - } - d_ptr = d_ptr->parent; - skip_child = 0; - } - - if (item != NULL) { - LSPST_DEBUG_MAIN(("main: Freeing memory used by item\n")); - _pst_freeItem(item); - item = NULL; - } - - if (!skip_child) - d_ptr = d_ptr->next; - else - skip_child = 0; - - if (d_ptr == NULL) { LSPST_DEBUG_MAIN(("main: d_ptr is now NULL\n")); } - - // }}}2 - } // end while(d_ptr != NULL) - LSPST_DEBUG_MAIN(("main: Finished.\n")); - - // Cleanup {{{2 - pst_close(&pstfile); - while (f != NULL) { - if (f->output != NULL) - fclose(f->output); - free(f->name); - free(f->dname); - - head = f->next; - free(f); - f = head; - } - DEBUG_RET(); - // }}}2 - - return 0; +// global settings +pst_file pstfile; + + +void create_enter_dir(struct file_ll* f, pst_item *item) +{ + f->email_count = 0; + f->skip_count = 0; + f->type = item->type; + f->stored_count = (item->folder) ? item->folder->email_count : 0; + f->dname = (char*) xmalloc(strlen(item->file_as)+1); + strcpy(f->dname, item->file_as); } -// }}}1 -// void canonicalize_filename(char *fname) {{{1 -// This function will make sure that a filename is in cannonical form. That -// is, it will replace any slashes, backslashes, or colons with underscores. -void canonicalize_filename(char *fname) { - DEBUG_ENT("canonicalize_filename"); - if (fname == NULL) { - DEBUG_RET(); - return; - } - while ((fname = strpbrk(fname, "/\\:")) != NULL) - *fname = '_'; - DEBUG_RET(); + + +void close_enter_dir(struct file_ll *f) +{ + free(f->dname); } -// }}}1 -// int chr_count(char *str, char x) {{{1 -int chr_count(char *str, char x) { - int r = 0; - if (str == NULL) return 0; - while (*str != '\0') { - if (*str == x) - r++; - str++; - } - return r; + + +void process(pst_item *outeritem, pst_desc_ll *d_ptr) +{ + struct file_ll ff; + pst_item *item = NULL; + + DEBUG_ENT("process"); + memset(&ff, 0, sizeof(ff)); + create_enter_dir(&ff, outeritem); + + while (d_ptr) { + DEBUG_MAIN(("main: New item record, d_ptr = %p.\n", d_ptr)); + if (!d_ptr->desc) { + DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); + ff.skip_count++; + } + else { + DEBUG_MAIN(("main: Desc Email ID %x [d_ptr->id = %x]\n", d_ptr->desc->id, d_ptr->id)); + + item = _pst_parse_item(&pstfile, d_ptr); + DEBUG_MAIN(("main: About to process item @ %p.\n", item)); + if (item) { + if (item->message_store) { + // there should only be one message_store, and we have already done it + DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); + } + + if (item->folder && d_ptr->child) { + // if this is a folder, we want to recurse into it + printf("Folder \"%s\"\n", item->file_as); + process(item, d_ptr->child); + + } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { + // Process Contact item + if (ff.type != PST_TYPE_CONTACT) { + DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n")); + } + printf("Contact"); + if (item->contact->fullname != NULL) + printf("\t%s", pst_rfc2426_escape(item->contact->fullname)); + printf("\n"); + + } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { + // Process Email item + if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { + DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); + } + printf("Email"); + if (item->email->outlook_sender_name != NULL) + printf("\tFrom: %s", item->email->outlook_sender_name); + if (item->email->subject->subj != NULL) + printf("\tSubject: %s", item->email->subject->subj); + printf("\n"); + + } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { + // Process Journal item + if (ff.type != PST_TYPE_JOURNAL) { + DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); + } + printf("Journal\t%s\n", pst_rfc2426_escape(item->email->subject->subj)); + + } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { + // Process Calendar Appointment item + DEBUG_MAIN(("main: Processing Appointment Entry\n")); + if (ff.type != PST_TYPE_APPOINTMENT) { + DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); + } + printf("Appointment"); + if (item->email != NULL && item->email->subject != NULL) + printf("\tSUMMARY: %s", pst_rfc2426_escape(item->email->subject->subj)); + if (item->appointment != NULL) { + if (item->appointment->start != NULL) + printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start)); + if (item->appointment->end != NULL) + printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end)); + printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); + } + printf("\n"); + + } else { + ff.skip_count++; + DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", + item->type, item->ascii_type)); + } + _pst_freeItem(item); + } else { + ff.skip_count++; + DEBUG_MAIN(("main: A NULL item was seen\n")); + } + d_ptr = d_ptr->next; + } + } + close_enter_dir(&ff); } -// }}}1 -// void debug_print(char *fmt, ...) {{{1 -void debug_print(char *fmt, ...) { - // shamlessly stolen from minprintf() in K&R pg. 156 - va_list ap; - char *p, *sval; - void *pval; - int ival; - double dval; - FILE *fp = stderr; - - va_start(ap, fmt); - for(p = fmt; *p; p++) { - if (*p != '%') { - fputc(*p, fp); - continue; - } - switch (tolower(*++p)) { - case 'd': case 'i': - ival = va_arg(ap, int); - fprintf(fp, "%d", ival); - break; - case 'f': - dval = va_arg(ap, double); - fprintf(fp, "%f", dval); - break; - case 's': - for (sval = va_arg(ap, char *); *sval; ++sval) - fputc(*sval, fp); - break; - case 'p': - pval = va_arg(ap, void *); - fprintf(fp, "%p", pval); - break; - case 'x': - ival = va_arg(ap, int); - fprintf(fp, "%#010x", ival); - break; - default: - fputc(*p, fp); - break; - } - } - va_end(ap); + + +int main(int argc, char** argv) { + pst_item *item = NULL; + pst_desc_ll *d_ptr; + char *temp = NULL; //temporary char pointer + char *d_log = NULL; + struct file_ll *f = NULL, *head = NULL; + + if (argc <= 1) DIE(("Missing PST filename.\n")); + + DEBUG_INIT(d_log); + DEBUG_REGISTER_CLOSE(); + DEBUG_ENT("main"); + + // Open PST file + if (pst_open(&pstfile, argv[1], "r")) DIE(("Error opening File\n")); + + // Load PST index + if (pst_load_index(&pstfile)) DIE(("Index Error\n")); + + pst_load_extended_attributes(&pstfile); + + d_ptr = pstfile.d_head; // first record is main record + item = _pst_parse_item(&pstfile, d_ptr); + if (!item || !item->message_store) { + DEBUG_RET(); + DIE(("main: Could not get root record\n")); + } + + // default the file_as to the same as the main filename if it doesn't exist + if (!item->file_as) { + if (!(temp = strrchr(argv[1], '/'))) + if (!(temp = strrchr(argv[1], '\\'))) + temp = argv[1]; + else + temp++; // get past the "\\" + else + temp++; // get past the "/" + item->file_as = (char*)xmalloc(strlen(temp)+1); + strcpy(item->file_as, temp); + } + fprintf(stderr, "item->file_as = '%s'.\n", item->file_as); + + d_ptr = pst_getTopOfFolders(&pstfile, item); + if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n")); + DEBUG_MAIN(("d_ptr(TOF) = %p.\n", d_ptr)); + + process(item, d_ptr->child); // do the childred of TOPF + _pst_freeItem(item); + pst_close(&pstfile); + + DEBUG_RET(); + return 0; } -// }}}1 -// char *rfc2426_escape(char *str) {{{1 -char *rfc2426_escape(char *str) { - static char *buf = NULL; - char *a, *b; - int y, z; - - DEBUG_ENT("rfc2426_escape"); - if (str == NULL) { - DEBUG_RET(); - return NULL; - } - - // calculate space required to escape all the commas, semi-colons, backslashes, and newlines - y = chr_count(str, ',') + chr_count(str, '\\') + chr_count(str, ';') + chr_count(str, '\n'); - // count how many carriage-returns we have to skip - z = chr_count(str, '\r'); - - if (y == 0 && z == 0) { - // there isn't any work required - DEBUG_RET(); - return str; - } - - buf = (char *) realloc( buf, strlen(str) + y - z + 1 ); - for (a = str, b = buf; *a != '\0'; ++a, ++b) - switch (*a) { - case ',' : case '\\': case ';' : case '\n': - // insert backslash to escape - *(b++) = '\\'; - *b = *a; - break; - case '\r': - // skip - break; - default: - *b = *a; - } - *b = '\0'; // NUL-terminate the string - - DEBUG_RET(); - return buf; + + +// This function will make sure that a filename is in cannonical form. That +// is, it will replace any slashes, backslashes, or colons with underscores. +void canonicalize_filename(char *fname) { + DEBUG_ENT("canonicalize_filename"); + if (fname == NULL) { + DEBUG_RET(); + return; + } + while ((fname = strpbrk(fname, "/\\:")) != NULL) + *fname = '_'; + DEBUG_RET(); } -// }}}1 -// char *rfc2445_datetime_format(FILETIME *ft) {{{1 -char *rfc2445_datetime_format(FILETIME *ft) { - static char* buffer = NULL; - struct tm *stm = NULL; - DEBUG_ENT("rfc2445_datetime_format"); - if (buffer == NULL) - buffer = malloc(30); // should be enough - stm = fileTimeToStructTM(ft); - if (strftime(buffer, 30, "%Y%m%dT%H%M%SZ", stm)==0) { - DEBUG_INFO(("Problem occured formatting date\n")); - } - DEBUG_RET(); - return buffer; + + +void debug_print(char *fmt, ...) { + // shamlessly stolen from minprintf() in K&R pg. 156 + va_list ap; + char *p, *sval; + void *pval; + int ival; + double dval; + FILE *fp = stderr; + + va_start(ap, fmt); + for(p = fmt; *p; p++) { + if (*p != '%') { + fputc(*p, fp); + continue; + } + switch (tolower(*++p)) { + case 'd': case 'i': + ival = va_arg(ap, int); + fprintf(fp, "%d", ival); + break; + case 'f': + dval = va_arg(ap, double); + fprintf(fp, "%f", dval); + break; + case 's': + for (sval = va_arg(ap, char *); *sval; ++sval) + fputc(*sval, fp); + break; + case 'p': + pval = va_arg(ap, void *); + fprintf(fp, "%p", pval); + break; + case 'x': + ival = va_arg(ap, int); + fprintf(fp, "%#010x", ival); + break; + default: + fputc(*p, fp); + break; + } + } + va_end(ap); } -// }}}1 -// vim:sw=4 ts=4: -// vim600: set foldlevel=0 foldmethod=marker: + diff --git a/src/lzfu.c b/src/lzfu.c index 30a7dac..b762655 100644 --- a/src/lzfu.c +++ b/src/lzfu.c @@ -1,124 +1,124 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "define.h" #include "libpst.h" #include #include #include #include "lzfu.h" #define LZFU_COMPRESSED 0x75465a4c #define LZFU_UNCOMPRESSED 0x414c454d // initital dictionary #define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \ "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \ "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \ "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \ "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \ "\\tx" // initial length of dictionary #define LZFU_INITLENGTH 207 // header for compressed rtf typedef struct _lzfuheader { - u_int32_t cbSize; - u_int32_t cbRawSize; - u_int32_t dwMagic; - u_int32_t dwCRC; + uint32_t cbSize; + uint32_t cbRawSize; + uint32_t dwMagic; + uint32_t dwCRC; } lzfuheader; -unsigned char* lzfu_decompress (unsigned char* rtfcomp, u_int32_t compsize, size_t *size) { +unsigned char* lzfu_decompress (unsigned char* rtfcomp, uint32_t compsize, size_t *size) { // the dictionary buffer unsigned char dict[4096]; // the dictionary pointer unsigned int dict_length=0; // the header of the lzfu block lzfuheader lzfuhdr; // container for the data blocks unsigned char flags; // temp value for determining the bits in the flag unsigned char flag_mask; - u_int32_t i; + uint32_t i; unsigned char *out_buf; - u_int32_t out_ptr = 0; - u_int32_t out_size; - u_int32_t in_ptr; - u_int32_t in_size; + uint32_t out_ptr = 0; + uint32_t out_size; + uint32_t in_ptr; + uint32_t in_size; memcpy(dict, LZFU_INITDICT, LZFU_INITLENGTH); dict_length = LZFU_INITLENGTH; memcpy(&lzfuhdr, rtfcomp, sizeof(lzfuhdr)); LE32_CPU(lzfuhdr.cbSize); LE32_CPU(lzfuhdr.cbRawSize); LE32_CPU(lzfuhdr.dwMagic); LE32_CPU(lzfuhdr.dwCRC); //printf("total size: %d\n", lzfuhdr.cbSize+4); //printf("raw size : %d\n", lzfuhdr.cbRawSize); //printf("compressed: %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no")); //printf("CRC : %#x\n", lzfuhdr.dwCRC); //printf("\n"); out_size = lzfuhdr.cbRawSize + 3; // two braces and a null terminator out_buf = (unsigned char*)xmalloc(out_size); in_ptr = sizeof(lzfuhdr); in_size = (lzfuhdr.cbSize < compsize) ? lzfuhdr.cbSize : compsize; while (in_ptr < in_size) { flags = rtfcomp[in_ptr++]; flag_mask = 1; while (flag_mask) { if (flag_mask & flags) { // two bytes available? if (in_ptr+1 < in_size) { // read 2 bytes from input unsigned short int blkhdr, offset, length; memcpy(&blkhdr, rtfcomp+in_ptr, 2); LE16_CPU(blkhdr); in_ptr += 2; /* swap the upper and lower bytes of blkhdr */ blkhdr = (((blkhdr&0xFF00)>>8)+ ((blkhdr&0x00FF)<<8)); /* the offset is the first 12 bits of the 16 bit value */ offset = (blkhdr&0xFFF0)>>4; /* the length of the dict entry are the last 4 bits */ length = (blkhdr&0x000F)+2; // add the value we are about to print to the dictionary for (i=0; i < length; i++) { unsigned char c1; c1 = dict[(offset+i)%4096]; dict[dict_length]=c1; dict_length = (dict_length+1) % 4096; if (out_ptr < out_size) out_buf[out_ptr++] = c1; } } } else { // one byte available? if (in_ptr < in_size) { // uncompressed chunk (single byte) char c1 = rtfcomp[in_ptr++]; dict[dict_length] = c1; dict_length = (dict_length+1)%4096; if (out_ptr < out_size) out_buf[out_ptr++] = c1; } } flag_mask <<= 1; } } // the compressed version doesn't appear to drop the closing // braces onto the doc, so we do that here. if (out_ptr < out_size) out_buf[out_ptr++] = '}'; if (out_ptr < out_size) out_buf[out_ptr++] = '}'; *size = out_ptr; if (out_ptr < out_size) out_buf[out_ptr++] = '\0'; return out_buf; } diff --git a/src/lzfu.h b/src/lzfu.h index 51f7b39..aa0ae0a 100644 --- a/src/lzfu.h +++ b/src/lzfu.h @@ -1,12 +1,8 @@ #ifndef LZFU_H #define LZFU_H -#ifdef _MSC_VER -#define u_int32_t unsigned int -#else #include -#endif -unsigned char* lzfu_decompress (unsigned char* rtfcomp, u_int32_t compsize, size_t *size); +unsigned char* lzfu_decompress (unsigned char* rtfcomp, uint32_t compsize, size_t *size); #endif diff --git a/src/readpst.c b/src/readpst.c index 66f7c99..c91a831 100644 --- a/src/readpst.c +++ b/src/readpst.c @@ -1,1430 +1,1349 @@ /*** * readpst.c * Part of the LibPST project * Written by David Smith - * dave.s@earthcorp.com + * dave.s@earthcorp.com */ #include #include #include #include #include #include #include +#include "vbuf.h" #ifndef _WIN32 # include # include //mkdir // for reading of directory and clearing in function mk_seperate_dir # include # include #else # include # define chdir _chdir # define int32_t __int32 #endif #ifndef __GNUC__ # include "XGetopt.h" #endif #include "libstrfunc.h" // for base64_encoding #include "version.h" #include "define.h" #include "libpst.h" #include "common.h" #include "timeconv.h" #include "lzfu.h" #define OUTPUT_TEMPLATE "%s" #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory" #define KMAIL_INDEX ".%s.index" #define SEP_MAIL_FILE_TEMPLATE "%i" /* "%09i" */ // max size of the c_time char*. It will store the date of the email #define C_TIME_SIZE 500 #define PERM_DIRS 0777 // macro used for creating directories #ifndef WIN32 #define D_MKDIR(x) mkdir(x, PERM_DIRS) #else #define D_MKDIR(x) mkdir(x) #endif struct file_ll { - char *name; - char *dname; - FILE * output; - int32_t stored_count; - int32_t email_count; - int32_t skip_count; - int32_t type; + char *name; + char *dname; + FILE * output; + int32_t stored_count; + int32_t email_count; + int32_t skip_count; + int32_t type; }; -void process(pst_item *outeritem, pst_desc_ll *d_ptr); -void write_email_body(FILE *f, char *body); -char* removeCR (char *c); -int32_t usage(); -int32_t version(); -char* mk_kmail_dir(char*); -int32_t close_kmail_dir(); -char* mk_recurse_dir(char*); -int32_t close_recurse_dir(); -char* mk_seperate_dir(char *dir); -int32_t close_seperate_dir(); -int32_t mk_seperate_file(struct file_ll *f); -char* my_stristr(char *haystack, char *needle); -void check_filename(char *fname); -char* rfc2426_escape(char *str); -int32_t chr_count(char *str, char x); -char* rfc2425_datetime_format(FILETIME *ft); -char* rfc2445_datetime_format(FILETIME *ft); -char* skip_header_prologue(char *headers); -void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst); -void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst); -void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf); -void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); -void write_appointment(FILE* f_output, pst_item_appointment* appointment, - pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); -void create_enter_dir(struct file_ll* f, pst_item *item); -void close_enter_dir(struct file_ll *f); +void process(pst_item *outeritem, pst_desc_ll *d_ptr); +void write_email_body(FILE *f, char *body); +char* removeCR (char *c); +int usage(); +int version(); +char* mk_kmail_dir(char*); +int close_kmail_dir(); +char* mk_recurse_dir(char*); +int close_recurse_dir(); +char* mk_seperate_dir(char *dir); +int close_seperate_dir(); +int mk_seperate_file(struct file_ll *f); +char* my_stristr(char *haystack, char *needle); +void check_filename(char *fname); +char* skip_header_prologue(char *headers); +void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst); +void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst); +void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf); +void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); +void write_appointment(FILE* f_output, pst_item_appointment* appointment, + pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); +void create_enter_dir(struct file_ll* f, pst_item *item); +void close_enter_dir(struct file_ll *f); char* prog_name; char* output_dir = "."; char* kmail_chdir = NULL; // Normal mode just creates mbox format files in the current directory. Each file is named // the same as the folder's name that it represents #define MODE_NORMAL 0 // KMail mode creates a directory structure suitable for being used directly // by the KMail application #define MODE_KMAIL 1 // recurse mode creates a directory structure like the PST file. Each directory // contains only one file which stores the emails in mbox format. #define MODE_RECURSE 2 // seperate mode is similar directory structure to RECURSE. The emails are stored in // seperate files, numbering from 1 upward. Attachments belonging to the emails are // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip) #define MODE_SEPERATE 3 +// Decrypt the whole file (even the parts that aren't encrypted) and ralph it to stdout +#define MODE_DECSPEW 4 // Output Normal just prints the standard information about what is going on #define OUTPUT_NORMAL 0 // Output Quiet is provided so that only errors are printed #define OUTPUT_QUIET 1 // default mime-type for attachments that have a null mime-type #define MIME_TYPE_DEFAULT "application/octet-stream" // output mode for contacts #define CMODE_VCARD 0 -#define CMODE_LIST 1 +#define CMODE_LIST 1 // output settings for RTF bodies // filename for the attachment #define RTF_ATTACH_NAME "rtf-body.rtf" // mime type for the attachment #define RTF_ATTACH_TYPE "application/rtf" // global settings int mode = MODE_NORMAL; int mode_MH = 0; int output_mode = OUTPUT_NORMAL; int contact_mode = CMODE_VCARD; int overwrite = 0; int save_rtf_body = 1; pst_file pstfile; void process(pst_item *outeritem, pst_desc_ll *d_ptr) { - struct file_ll ff; - pst_item *item = NULL; - - DEBUG_ENT("process"); - memset(&ff, 0, sizeof(ff)); - create_enter_dir(&ff, outeritem); - - while (d_ptr) { - DEBUG_MAIN(("main: New item record\n")); - if (!d_ptr->desc) { - DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); - ff.skip_count++; - } - else { - DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id)); - - item = _pst_parse_item(&pstfile, d_ptr); - DEBUG_MAIN(("main: About to process item\n")); - if (item && item->email && item->email->subject && item->email->subject->subj) { - DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject)); - DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); - } - if (item) { - if (item->message_store) { - // there should only be one message_store, and we have already done it - DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); - } - - if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) { - //if this is a non-empty folder other than deleted items, we want to recurse into it - if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as); - process(item, d_ptr->child); - - } else if (item->contact) { - // deal with a contact - // write them to the file, one per line in this format - // Desc Name \n - if (mode == MODE_SEPERATE) mk_seperate_file(&ff); - ff.email_count++; - DEBUG_MAIN(("main: Processing Contact\n")); - if (ff.type != PST_TYPE_CONTACT) { - DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. " - "Will process anyway\n")); - } - if (item->type != PST_TYPE_CONTACT) { - DEBUG_MAIN(("main: I have an item that has contact info, but doesn't say that" - " it is a contact. Type is \"%s\"\n", item->ascii_type)); - DEBUG_MAIN(("main: Processing anyway\n")); - } - if (!item->contact) { // this is an incorrect situation. Inform user - DEBUG_MAIN(("main: ERROR. This contact has not been fully parsed. one of the pre-requisties is NULL\n")); - } else { - if (contact_mode == CMODE_VCARD) - write_vcard(ff.output, item->contact, item->comment); - else - fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); - } - - } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { - if (mode == MODE_SEPERATE) mk_seperate_file(&ff); - ff.email_count++; - DEBUG_MAIN(("main: seen an email\n")); - write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body); - - } else if (item->type == PST_TYPE_JOURNAL) { - // deal with journal items - if (mode == MODE_SEPERATE) mk_seperate_file(&ff); - ff.email_count++; - - DEBUG_MAIN(("main: Processing Journal Entry\n")); - if (ff.type != PST_TYPE_JOURNAL) { - DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); - } - - /* if (item->type != PST_TYPE_JOURNAL) { - DEBUG_MAIN(("main: I have an item with journal info, but it's type is \"%s\" \n. Processing...\n", - item->ascii_type)); - }*/ - fprintf(ff.output, "BEGIN:VJOURNAL\n"); - if (item->email->subject) - fprintf(ff.output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj)); - if (item->email->body) - fprintf(ff.output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body)); - if (item->journal->start) - fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->journal->start)); - fprintf(ff.output, "END:VJOURNAL\n\n"); - - } else if (item->type == PST_TYPE_APPOINTMENT) { - // deal with Calendar appointments - if (mode == MODE_SEPERATE) mk_seperate_file(&ff); - ff.email_count++; - DEBUG_MAIN(("main: Processing Appointment Entry\n")); - if (ff.type != PST_TYPE_APPOINTMENT) { - DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); - } - write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date); - - } else { - ff.skip_count++; - DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", - item->type, item->ascii_type)); - } - _pst_freeItem(item); - } else { - ff.skip_count++; - DEBUG_MAIN(("main: A NULL item was seen\n")); - } - d_ptr = d_ptr->next; - } - } - close_enter_dir(&ff); - DEBUG_RET(); + struct file_ll ff; + pst_item *item = NULL; + + DEBUG_ENT("process"); + memset(&ff, 0, sizeof(ff)); + create_enter_dir(&ff, outeritem); + + while (d_ptr) { + DEBUG_MAIN(("main: New item record\n")); + if (!d_ptr->desc) { + DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); + ff.skip_count++; + } + else { + DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id)); + + item = _pst_parse_item(&pstfile, d_ptr); + DEBUG_MAIN(("main: About to process item\n")); + if (item && item->email && item->email->subject && item->email->subject->subj) { + DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject)); + DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); + } + if (item) { + if (item->message_store) { + // there should only be one message_store, and we have already done it + DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); + } + + if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) { + //if this is a non-empty folder other than deleted items, we want to recurse into it + if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as); + process(item, d_ptr->child); + + } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { + // deal with a contact + // write them to the file, one per line in this format + // Desc Name \n + if (mode == MODE_SEPERATE) mk_seperate_file(&ff); + ff.email_count++; + DEBUG_MAIN(("main: Processing Contact\n")); + if (ff.type != PST_TYPE_CONTACT) { + DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n")); + } + if (contact_mode == CMODE_VCARD) + write_vcard(ff.output, item->contact, item->comment); + else + fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); + + } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { + if (mode == MODE_SEPERATE) mk_seperate_file(&ff); + ff.email_count++; + DEBUG_MAIN(("main: Processing Email\n")); + if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { + DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); + } + write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body); + + } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { + // deal with journal items + if (mode == MODE_SEPERATE) mk_seperate_file(&ff); + ff.email_count++; + DEBUG_MAIN(("main: Processing Journal Entry\n")); + if (ff.type != PST_TYPE_JOURNAL) { + DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n")); + } + fprintf(ff.output, "BEGIN:VJOURNAL\n"); + if (item->email->subject) + fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj)); + if (item->email->body) + fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body)); + if (item->journal->start) + fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start)); + fprintf(ff.output, "END:VJOURNAL\n\n"); + + } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { + // deal with Calendar appointments + if (mode == MODE_SEPERATE) mk_seperate_file(&ff); + ff.email_count++; + DEBUG_MAIN(("main: Processing Appointment Entry\n")); + if (ff.type != PST_TYPE_APPOINTMENT) { + DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); + } + write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date); + + } else { + ff.skip_count++; + DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", + item->type, item->ascii_type)); + } + _pst_freeItem(item); + } else { + ff.skip_count++; + DEBUG_MAIN(("main: A NULL item was seen\n")); + } + d_ptr = d_ptr->next; + } + } + close_enter_dir(&ff); + DEBUG_RET(); } int main(int argc, char** argv) { - pst_item *item = NULL; - pst_desc_ll *d_ptr; - char * fname = NULL; - char *d_log=NULL; - int c,x; - char *temp = NULL; //temporary char pointer - prog_name = argv[0]; - - // command-line option handling - while ((c = getopt(argc, argv, "bd:hko:qrMSVwc:"))!= -1) { - switch (c) { - case 'b': - save_rtf_body = 0; - break; - case 'c': - if (optarg && optarg[0]=='v') - contact_mode=CMODE_VCARD; - else if (optarg && optarg[0]=='l') - contact_mode=CMODE_LIST; - else { - usage(); - exit(0); - } - break; - case 'd': - d_log = optarg; - break; - case 'h': - usage(); - exit(0); - break; - case 'V': - version(); - exit(0); - break; - case 'k': - mode = MODE_KMAIL; - break; - case 'M': - mode = MODE_SEPERATE; - mode_MH = 1; - break; - case 'o': - output_dir = optarg; - break; - case 'q': - output_mode = OUTPUT_QUIET; - break; - case 'r': - mode = MODE_RECURSE; - break; - case 'S': - mode = MODE_SEPERATE; - break; - case 'w': - overwrite = 1; - break; - default: - usage(); - exit(1); - break; - } - } - - if (argc > optind) { - fname = argv[optind]; - } else { - usage(); - exit(2); - } - - #ifdef DEBUG_ALL - // force a log file - if (!d_log) d_log = "readpst.log"; - #endif // defined DEBUG_ALL - DEBUG_INIT(d_log); - DEBUG_REGISTER_CLOSE(); - DEBUG_ENT("main"); - - if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); - - RET_DERROR(pst_open(&pstfile, fname, "r"), 1, ("Error opening File\n")); - RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); - - pst_load_extended_attributes(&pstfile); - - if (chdir(output_dir)) { - x = errno; - pst_close(&pstfile); - DEBUG_RET(); - DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x))); - } - - if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n"); - - d_ptr = pstfile.d_head; // first record is main record - item = (pst_item*)_pst_parse_item(&pstfile, d_ptr); - if (!item || !item->message_store) { - DEBUG_RET(); - DIE(("main: Could not get root record\n")); - } - - // default the file_as to the same as the main filename if it doesn't exist - if (!item->file_as) { - if (!(temp = strrchr(fname, '/'))) - if (!(temp = strrchr(fname, '\\'))) - temp = fname; - else - temp++; // get past the "\\" - else - temp++; // get past the "/" - item->file_as = (char*)xmalloc(strlen(temp)+1); - strcpy(item->file_as, temp); - DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as)); - } - DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as)); - - d_ptr = pst_getTopOfFolders(&pstfile, item); - if (!d_ptr) { - DEBUG_RET(); - DIE(("Top of folders record not found. Cannot continue\n")); - } - - process(item, d_ptr->child); // do the children of TOPF - _pst_freeItem(item); - pst_close(&pstfile); - - DEBUG_RET(); - return 0; + pst_item *item = NULL; + pst_desc_ll *d_ptr; + char * fname = NULL; + char *d_log=NULL; + int c,x; + char *temp = NULL; //temporary char pointer + prog_name = argv[0]; + + // command-line option handling + while ((c = getopt(argc, argv, "bCc:d:hko:qrSMVw"))!= -1) { + switch (c) { + case 'b': + save_rtf_body = 0; + break; + case 'C': + mode = MODE_DECSPEW; + break; + case 'c': + if (optarg && optarg[0]=='v') + contact_mode=CMODE_VCARD; + else if (optarg && optarg[0]=='l') + contact_mode=CMODE_LIST; + else { + usage(); + exit(0); + } + break; + case 'd': + d_log = optarg; + break; + case 'h': + usage(); + exit(0); + break; + case 'V': + version(); + exit(0); + break; + case 'k': + mode = MODE_KMAIL; + break; + case 'M': + mode = MODE_SEPERATE; + mode_MH = 1; + break; + case 'o': + output_dir = optarg; + break; + case 'q': + output_mode = OUTPUT_QUIET; + break; + case 'r': + mode = MODE_RECURSE; + break; + case 'S': + mode = MODE_SEPERATE; + break; + case 'w': + overwrite = 1; + break; + default: + usage(); + exit(1); + break; + } + } + + if (argc > optind) { + fname = argv[optind]; + } else { + usage(); + exit(2); + } + + unicode_init(); + + #ifdef DEBUG_ALL + // force a log file + if (!d_log) d_log = "readpst.log"; + #endif // defined DEBUG_ALL + DEBUG_INIT(d_log); + DEBUG_REGISTER_CLOSE(); + DEBUG_ENT("main"); + + if (mode == MODE_DECSPEW) { + FILE *fp; + char buf[1024]; + int l=0; + if (NULL == (fp = fopen(fname, "rb"))) { + fprintf(stderr, "Couldn't open file %s\n", fname ); + return 1; + } + + while (0 != ( l = fread( buf, 1, 1024, fp))) { + if (0 != _pst_decrypt( buf, l, PST_COMP_ENCRYPT)) + fprintf(stderr, "_pst_decrypt() failed (I'll try to continue)\n"); + + if (l != fwrite( buf, 1, l, stdout)) { + fprintf(stderr, "Couldn't output to stdout?\n"); + return 1; + } + } + return 0; + } + + if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); + + RET_DERROR(pst_open(&pstfile, fname, "r"), 1, ("Error opening File\n")); + RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); + + pst_load_extended_attributes(&pstfile); + + if (chdir(output_dir)) { + x = errno; + pst_close(&pstfile); + DEBUG_RET(); + DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x))); + } + + if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n"); + + d_ptr = pstfile.d_head; // first record is main record + item = _pst_parse_item(&pstfile, d_ptr); + if (!item || !item->message_store) { + DEBUG_RET(); + DIE(("main: Could not get root record\n")); + } + + // default the file_as to the same as the main filename if it doesn't exist + if (!item->file_as) { + if (!(temp = strrchr(fname, '/'))) + if (!(temp = strrchr(fname, '\\'))) + temp = fname; + else + temp++; // get past the "\\" + else + temp++; // get past the "/" + item->file_as = (char*)xmalloc(strlen(temp)+1); + strcpy(item->file_as, temp); + DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as)); + } + DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as)); + + d_ptr = pst_getTopOfFolders(&pstfile, item); + if (!d_ptr) { + DEBUG_RET(); + DIE(("Top of folders record not found. Cannot continue\n")); + } + + process(item, d_ptr->child); // do the children of TOPF + _pst_freeItem(item); + pst_close(&pstfile); + + DEBUG_RET(); + return 0; } void write_email_body(FILE *f, char *body) { - char *n = body; - // DEBUG_MAIN(("write_email_body(): \"%s\"\n", body)); - DEBUG_ENT("write_email_body"); - while (n) { - if (strncmp(body, "From ", 5) == 0) - fprintf(f, ">"); - if ((n = strchr(body, '\n'))) { - n++; - fwrite(body, n-body, 1, f); //write just a line - - body = n; - } - } - fwrite(body, strlen(body), 1, f); - DEBUG_RET(); + char *n = body; + // DEBUG_MAIN(("write_email_body(): \"%s\"\n", body)); + DEBUG_ENT("write_email_body"); + while (n) { + if (strncmp(body, "From ", 5) == 0) + fprintf(f, ">"); + if ((n = strchr(body, '\n'))) { + n++; + fwrite(body, n-body, 1, f); //write just a line + + body = n; + } + } + fwrite(body, strlen(body), 1, f); + DEBUG_RET(); } char *removeCR (char *c) { - // converts /r/n to /n - char *a, *b; - DEBUG_ENT("removeCR"); - a = b = c; - while (*a != '\0') { - *b = *a; - if (*a != '\r') - b++; - a++; - } - *b = '\0'; - DEBUG_RET(); - return c; + // converts /r/n to /n + char *a, *b; + DEBUG_ENT("removeCR"); + a = b = c; + while (*a != '\0') { + *b = *a; + if (*a != '\r') + b++; + a++; + } + *b = '\0'; + DEBUG_RET(); + return c; } int usage() { - DEBUG_ENT("usage"); - version(); - printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); - printf("OPTIONS:\n"); - printf("\t-b\t- Don't save RTF-Body attachments\n"); - printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n"); - printf("\t-d \t- Debug to file. This is a binary log. Use readlog to print it\n"); - printf("\t-h\t- Help. This screen\n"); - printf("\t-k\t- KMail. Output in kmail format\n"); - printf("\t-M\t- MH. Write emails in the MH format\n"); - printf("\t-o \t- Output Dir. Directory to write files to. CWD is changed *after* opening pst file\n"); - printf("\t-q\t- Quiet. Only print error messages\n"); - printf("\t-r\t- Recursive. Output in a recursive format\n"); - printf("\t-S\t- Seperate. Write emails in the seperate format\n"); - printf("\t-V\t- Version. Display program version\n"); - printf("\t-w\t- Overwrite any output mbox files\n"); - DEBUG_RET(); - return 0; + DEBUG_ENT("usage"); + version(); + printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); + printf("OPTIONS:\n"); + printf("\t-b\t- Don't save RTF-Body attachments\n"); + printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n"); + printf("\t-d \t- Debug to file. This is a binary log. Use readlog to print it\n"); + printf("\t-h\t- Help. This screen\n"); + printf("\t-k\t- KMail. Output in kmail format\n"); + printf("\t-M\t- MH. Write emails in the MH format\n"); + printf("\t-o \t- Output Dir. Directory to write files to. CWD is changed *after* opening pst file\n"); + printf("\t-q\t- Quiet. Only print error messages\n"); + printf("\t-r\t- Recursive. Output in a recursive format\n"); + printf("\t-S\t- Seperate. Write emails in the seperate format\n"); + printf("\t-V\t- Version. Display program version\n"); + printf("\t-w\t- Overwrite any output mbox files\n"); + printf("\t-C\t- Decrypt the entire file and output on stdout (not typically useful)\n"); + DEBUG_RET(); + return 0; } int version() { - DEBUG_ENT("version"); - printf("ReadPST v%s\n", VERSION); + DEBUG_ENT("version"); + printf("ReadPST v%s\n", VERSION); #if BYTE_ORDER == BIG_ENDIAN - printf("Big Endian implementation being used.\n"); + printf("Big Endian implementation being used.\n"); #elif BYTE_ORDER == LITTLE_ENDIAN - printf("Little Endian implementation being used.\n"); + printf("Little Endian implementation being used.\n"); #else # error "Byte order not supported by this library" #endif #ifdef __GNUC__ - printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); + printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); #endif - DEBUG_RET(); - return 0; + DEBUG_RET(); + return 0; } char *mk_kmail_dir(char *fname) { - //change to that directory - //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE - //allocate space for OUTPUT_TEMPLATE and form a char* with fname - //return that value - char *dir, *out_name, *index; - int x; - DEBUG_ENT("mk_kmail_dir"); - if (kmail_chdir && chdir(kmail_chdir)) { - x = errno; - DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x))); - } - dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1); - sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname); - check_filename(dir); - if (D_MKDIR(dir)) { - //error occured - if (errno != EEXIST) { - x = errno; - DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x))); - } - } - kmail_chdir = realloc(kmail_chdir, strlen(dir)+1); - strcpy(kmail_chdir, dir); - free (dir); - - //we should remove any existing indexes created by KMail, cause they might be different now - index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1); - sprintf(index, KMAIL_INDEX, fname); - unlink(index); - free(index); - - out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1); - sprintf(out_name, OUTPUT_TEMPLATE, fname); - DEBUG_RET(); - return out_name; + //change to that directory + //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE + //allocate space for OUTPUT_TEMPLATE and form a char* with fname + //return that value + char *dir, *out_name, *index; + int x; + DEBUG_ENT("mk_kmail_dir"); + if (kmail_chdir && chdir(kmail_chdir)) { + x = errno; + DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x))); + } + dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1); + sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname); + check_filename(dir); + if (D_MKDIR(dir)) { + //error occured + if (errno != EEXIST) { + x = errno; + DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x))); + } + } + kmail_chdir = realloc(kmail_chdir, strlen(dir)+1); + strcpy(kmail_chdir, dir); + free (dir); + + //we should remove any existing indexes created by KMail, cause they might be different now + index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1); + sprintf(index, KMAIL_INDEX, fname); + unlink(index); + free(index); + + out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1); + sprintf(out_name, OUTPUT_TEMPLATE, fname); + DEBUG_RET(); + return out_name; } int close_kmail_dir() { - // change .. - int x; - DEBUG_ENT("close_kmail_dir"); - if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory - free(kmail_chdir); - kmail_chdir = NULL; - } else { - if (chdir("..")) { - x = errno; - DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x))); - } - } - DEBUG_RET(); - return 0; + // change .. + int x; + DEBUG_ENT("close_kmail_dir"); + if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory + free(kmail_chdir); + kmail_chdir = NULL; + } else { + if (chdir("..")) { + x = errno; + DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x))); + } + } + DEBUG_RET(); + return 0; } // this will create a directory by that name, then make an mbox file inside // that dir. any subsequent dirs will be created by name, and they will // contain mbox files char *mk_recurse_dir(char *dir) { - int x; - char *out_name; - DEBUG_ENT("mk_recurse_dir"); - check_filename(dir); - if (D_MKDIR (dir)) { - if (errno != EEXIST) { // not an error because it exists - x = errno; - DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x))); - } - } - if (chdir (dir)) { - x = errno; - DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); - } - out_name = malloc(strlen("mbox")+1); - strcpy(out_name, "mbox"); - DEBUG_RET(); - return out_name; + int x; + char *out_name; + DEBUG_ENT("mk_recurse_dir"); + check_filename(dir); + if (D_MKDIR (dir)) { + if (errno != EEXIST) { // not an error because it exists + x = errno; + DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x))); + } + } + if (chdir (dir)) { + x = errno; + DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); + } + out_name = malloc(strlen("mbox")+1); + strcpy(out_name, "mbox"); + DEBUG_RET(); + return out_name; } int close_recurse_dir() { - int x; - DEBUG_ENT("close_recurse_dir"); - if (chdir("..")) { - x = errno; - DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x))); - } - DEBUG_RET(); - return 0; + int x; + DEBUG_ENT("close_recurse_dir"); + if (chdir("..")) { + x = errno; + DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x))); + } + DEBUG_RET(); + return 0; } char *mk_seperate_dir(char *dir) { - DEBUG_ENT("mk_seperate_dir"); - - size_t dirsize = strlen(dir) + 10; - char dir_name[dirsize]; - int x = 0, y = 0; - - do { - if (y == 0) - snprintf(dir_name, dirsize, "%s", dir); - else - snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y); // enough for 9 digits allocated above - - check_filename(dir_name); - DEBUG_MAIN(("about to try creating %s\n", dir_name)); - if (D_MKDIR(dir_name)) { - if (errno != EEXIST) { // if there is an error, and it doesn't already exist - x = errno; - DIE(("mk_seperate_dir: Cannot create directory %s: %s\n", dir, strerror(x))); - } - } else { - break; - } - y++; - } while (overwrite == 0); - - if (chdir(dir_name)) { - x = errno; - DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); - } - - if (overwrite) { - // we should probably delete all files from this directory + DEBUG_ENT("mk_seperate_dir"); + + size_t dirsize = strlen(dir) + 10; + char dir_name[dirsize]; + int x = 0, y = 0; + + do { + if (y == 0) + snprintf(dir_name, dirsize, "%s", dir); + else + snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y); // enough for 9 digits allocated above + + check_filename(dir_name); + DEBUG_MAIN(("about to try creating %s\n", dir_name)); + if (D_MKDIR(dir_name)) { + if (errno != EEXIST) { // if there is an error, and it doesn't already exist + x = errno; + DIE(("mk_seperate_dir: Cannot create directory %s: %s\n", dir, strerror(x))); + } + } else { + break; + } + y++; + } while (overwrite == 0); + + if (chdir(dir_name)) { + x = errno; + DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); + } + + if (overwrite) { + // we should probably delete all files from this directory #if !defined(WIN32) && !defined(__CYGWIN__) - DIR * sdir = NULL; - struct dirent *dirent = NULL; - struct stat filestat; - if (!(sdir = opendir("./"))) { - WARN(("mk_seperate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./")); - } else { - while ((dirent = readdir(sdir))) { - if (lstat(dirent->d_name, &filestat) != -1) - if (S_ISREG(filestat.st_mode)) { - if (unlink(dirent->d_name)) { - y = errno; - DIE(("mk_seperate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y))); - } - } - } - } + DIR * sdir = NULL; + struct dirent *dirent = NULL; + struct stat filestat; + if (!(sdir = opendir("./"))) { + WARN(("mk_seperate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./")); + } else { + while ((dirent = readdir(sdir))) { + if (lstat(dirent->d_name, &filestat) != -1) + if (S_ISREG(filestat.st_mode)) { + if (unlink(dirent->d_name)) { + y = errno; + DIE(("mk_seperate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y))); + } + } + } + } #endif - } + } - // we don't return a filename here cause it isn't necessary. - DEBUG_RET(); - return NULL; + // we don't return a filename here cause it isn't necessary. + DEBUG_RET(); + return NULL; } int close_seperate_dir() { - int x; - DEBUG_ENT("close_seperate_dir"); - if (chdir("..")) { - x = errno; - DIE(("close_seperate_dir: Cannot go up dir (..): %s\n", strerror(x))); - } - DEBUG_RET(); - return 0; + int x; + DEBUG_ENT("close_seperate_dir"); + if (chdir("..")) { + x = errno; + DIE(("close_seperate_dir: Cannot go up dir (..): %s\n", strerror(x))); + } + DEBUG_RET(); + return 0; } int mk_seperate_file(struct file_ll *f) { - const int name_offset = 1; - DEBUG_ENT("mk_seperate_file"); - DEBUG_MAIN(("opening next file to save email\n")); - if (f->email_count > 999999999) { // bigger than nine 9's - DIE(("mk_seperate_file: The number of emails in this folder has become too high to handle")); - } - sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset); - if (f->output) fclose(f->output); - f->output = NULL; - check_filename(f->name); - if (!(f->output = fopen(f->name, "w"))) { - DIE(("mk_seperate_file: Cannot open file to save email \"%s\"\n", f->name)); - } - DEBUG_RET(); - return 0; + const int name_offset = 1; + DEBUG_ENT("mk_seperate_file"); + DEBUG_MAIN(("opening next file to save email\n")); + if (f->email_count > 999999999) { // bigger than nine 9's + DIE(("mk_seperate_file: The number of emails in this folder has become too high to handle")); + } + sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset); + if (f->output) fclose(f->output); + f->output = NULL; + check_filename(f->name); + if (!(f->output = fopen(f->name, "w"))) { + DIE(("mk_seperate_file: Cannot open file to save email \"%s\"\n", f->name)); + } + DEBUG_RET(); + return 0; } char *my_stristr(char *haystack, char *needle) { - // my_stristr varies from strstr in that its searches are case-insensitive - char *x=haystack, *y=needle, *z = NULL; - DEBUG_ENT("my_stristr"); - if (!haystack || !needle) - return NULL; - while (*y != '\0' && *x != '\0') { - if (tolower(*y) == tolower(*x)) { - // move y on one - y++; - if (!z) { - z = x; // store first position in haystack where a match is made - } - } else { - y = needle; // reset y to the beginning of the needle - z = NULL; // reset the haystack storage point - } - x++; // advance the search in the haystack - } - DEBUG_RET(); - return z; + // my_stristr varies from strstr in that its searches are case-insensitive + char *x=haystack, *y=needle, *z = NULL; + DEBUG_ENT("my_stristr"); + if (!haystack || !needle) + return NULL; + while (*y != '\0' && *x != '\0') { + if (tolower(*y) == tolower(*x)) { + // move y on one + y++; + if (!z) { + z = x; // store first position in haystack where a match is made + } + } else { + y = needle; // reset y to the beginning of the needle + z = NULL; // reset the haystack storage point + } + x++; // advance the search in the haystack + } + DEBUG_RET(); + return z; } void check_filename(char *fname) { - char *t = fname; - DEBUG_ENT("check_filename"); - if (!t) { - DEBUG_RET(); - return fname; - } - while ((t = strpbrk(t, "/\\:"))) { - // while there are characters in the second string that we don't want - *t = '_'; //replace them with an underscore - } - DEBUG_RET(); - return fname; -} - - -char *rfc2426_escape(char *str) { - static char* buf = NULL; - char *ret, *a, *b; - int x = 0, y, z; - DEBUG_ENT("rfc2426_escape"); - if (!str) - ret = str; - else { - - // calculate space required to escape all the following characters - y = chr_count(str, ',') - + chr_count(str, '\\') - + chr_count(str, ';') - + chr_count(str, '\n'); - z = chr_count(str, '\r'); - if (y == 0 && z == 0) - // there isn't any extra space required - ret = str; - else { - x = strlen(str) + y - z + 1; // don't forget room for the NUL - buf = (char*) realloc(buf, x); - a = str; - b = buf; - while (*a != '\0') { - switch (*a) { - case ',' : - case '\\': - case ';' : - *(b++) = '\\'; - *b = *a; - break; - case '\n': // newlines are encoded as "\n" - *(b++) = '\\'; - *b = 'n'; - break; - case '\r': // skip cr - b--; - break; - default: - *b=*a; - } - b++; - a++; - } - *b = '\0'; // NUL-terminate the string (buf) - ret = buf; - } - } - DEBUG_RET(); - return ret; -} - - -int chr_count(char *str, char x) { - int r = 0; - while (*str != '\0') { - if (*str == x) - r++; - str++; - } - return r; -} - - -char *rfc2425_datetime_format(FILETIME *ft) { - static char* buffer = NULL; - struct tm *stm = NULL; - DEBUG_ENT("rfc2425_datetime_format"); - if (!buffer) buffer = malloc(30); // should be enough for the date as defined below - stm = fileTimeToStructTM(ft); - if (strftime(buffer, 30, "%Y-%m-%dT%H:%M:%SZ", stm)==0) { - DEBUG_INFO(("Problem occured formatting date\n")); - } - DEBUG_RET(); - return buffer; -} - - -char *rfc2445_datetime_format(FILETIME *ft) { - static char* buffer = NULL; - struct tm *stm = NULL; - DEBUG_ENT("rfc2445_datetime_format"); - if (!buffer) buffer = malloc(30); // should be enough for the date as defined below - stm = fileTimeToStructTM(ft); - if (strftime(buffer, 30, "%Y%m%dT%H%M%SZ", stm)==0) { - DEBUG_INFO(("Problem occured formatting date\n")); - } - DEBUG_RET(); - return buffer; + char *t = fname; + DEBUG_ENT("check_filename"); + if (!t) { + DEBUG_RET(); + } + while ((t = strpbrk(t, "/\\:"))) { + // while there are characters in the second string that we don't want + *t = '_'; //replace them with an underscore + } + DEBUG_RET(); } // The sole purpose of this function is to bypass the pseudo-header prologue // that Microsoft Outlook inserts at the beginning of the internet email // headers for emails stored in their "Personal Folders" files. char *skip_header_prologue(char *headers) { - const char *bad = "Microsoft Mail Internet Headers"; - if ( strncmp(headers, bad, strlen(bad)) == 0 ) { - // Found the offensive header prologue - char *pc = strchr(headers, '\n'); - return pc + 1; - } - return headers; + const char *bad = "Microsoft Mail Internet Headers"; + if ( strncmp(headers, bad, strlen(bad)) == 0 ) { + // Found the offensive header prologue + char *pc = strchr(headers, '\n'); + return pc + 1; + } + return headers; } void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst) { - DEBUG_ENT("write_separate_attachment"); - FILE *fp = NULL; - int x = 0; - char *temp = NULL; - - // If there is a long filename (filename2) use that, otherwise - // use the 8.3 filename (filename1) - char *attach_filename = (current_attach->filename2) ? current_attach->filename2 - : current_attach->filename1; - - check_filename(f_name); - if (!attach_filename) { - // generate our own (dummy) filename for the attachement - temp = xmalloc(strlen(f_name)+15); - sprintf(temp, "%s-attach%i", f_name, attach_num); - } else { - // have an attachment name, make sure it's unique - temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15); - do { - if (fp) fclose(fp); - if (x == 0) - sprintf(temp, "%s-%s", f_name, attach_filename); - else - sprintf(temp, "%s-%s-%i", f_name, attach_filename, x); - } while ((fp = fopen(temp, "r")) && ++x < 99999999); - if (x > 99999999) { - DIE(("error finding attachment name. exhausted possibilities to %s\n", temp)); - } - } - DEBUG_EMAIL(("Saving attachment to %s\n", temp)); - if (!(fp = fopen(temp, "w"))) { - WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); - } else { - if (current_attach->data) - fwrite(current_attach->data, 1, current_attach->size, fp); - else { - pst_attach_to_file(pst, current_attach, fp); - } - fclose(fp); - } - if (temp) free(temp); - DEBUG_RET(); + DEBUG_ENT("write_separate_attachment"); + FILE *fp = NULL; + int x = 0; + char *temp = NULL; + + // If there is a long filename (filename2) use that, otherwise + // use the 8.3 filename (filename1) + char *attach_filename = (current_attach->filename2) ? current_attach->filename2 + : current_attach->filename1; + + check_filename(f_name); + if (!attach_filename) { + // generate our own (dummy) filename for the attachement + temp = xmalloc(strlen(f_name)+15); + sprintf(temp, "%s-attach%i", f_name, attach_num); + } else { + // have an attachment name, make sure it's unique + temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15); + do { + if (fp) fclose(fp); + if (x == 0) + sprintf(temp, "%s-%s", f_name, attach_filename); + else + sprintf(temp, "%s-%s-%i", f_name, attach_filename, x); + } while ((fp = fopen(temp, "r")) && ++x < 99999999); + if (x > 99999999) { + DIE(("error finding attachment name. exhausted possibilities to %s\n", temp)); + } + } + DEBUG_EMAIL(("Saving attachment to %s\n", temp)); + if (!(fp = fopen(temp, "w"))) { + WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); + } else { + if (current_attach->data) + fwrite(current_attach->data, 1, current_attach->size, fp); + else { + pst_attach_to_file(pst, current_attach, fp); + } + fclose(fp); + } + if (temp) free(temp); + DEBUG_RET(); } void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst) { - DEBUG_ENT("write_inline_attachment"); - char *enc; // base64 encoded attachment - DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size)); - DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data)); - if (current_attach->data) { - enc = base64_encode (current_attach->data, current_attach->size); - if (!enc) { - DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); - return; - } - } - if (boundary) { - char *attach_filename; - fprintf(f_output, "\n--%s\n", boundary); - if (!current_attach->mimetype) { - fprintf(f_output, "Content-type: %s\n", MIME_TYPE_DEFAULT); - } else { - fprintf(f_output, "Content-type: %s\n", current_attach->mimetype); - } - fprintf(f_output, "Content-transfer-encoding: base64\n"); - // If there is a long filename (filename2) use that, otherwise - // use the 8.3 filename (filename1) - if (current_attach->filename2) { - attach_filename = current_attach->filename2; - } else { - attach_filename = current_attach->filename1; - } - if (!attach_filename) { - fprintf(f_output, "Content-Disposition: inline\n\n"); - } else { - fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); - } - } - if (current_attach->data) { - fwrite(enc, 1, strlen(enc), f_output); - DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); - free(enc); // caught by valgrind - } else { - pst_attach_to_file_base64(pst, current_attach, f_output); - } - fprintf(f_output, "\n\n"); - DEBUG_RET(); + DEBUG_ENT("write_inline_attachment"); + char *enc; // base64 encoded attachment + DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size)); + DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data)); + if (current_attach->data) { + enc = base64_encode (current_attach->data, current_attach->size); + if (!enc) { + DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); + return; + } + } + if (boundary) { + char *attach_filename; + fprintf(f_output, "\n--%s\n", boundary); + if (!current_attach->mimetype) { + fprintf(f_output, "Content-type: %s\n", MIME_TYPE_DEFAULT); + } else { + fprintf(f_output, "Content-type: %s\n", current_attach->mimetype); + } + fprintf(f_output, "Content-transfer-encoding: base64\n"); + // If there is a long filename (filename2) use that, otherwise + // use the 8.3 filename (filename1) + if (current_attach->filename2) { + attach_filename = current_attach->filename2; + } else { + attach_filename = current_attach->filename1; + } + if (!attach_filename) { + fprintf(f_output, "Content-Disposition: inline\n\n"); + } else { + fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); + } + } + if (current_attach->data) { + fwrite(enc, 1, strlen(enc), f_output); + DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); + free(enc); // caught by valgrind + } else { + pst_attach_to_file_base64(pst, current_attach, f_output); + } + fprintf(f_output, "\n\n"); + DEBUG_RET(); } void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf) { - DEBUG_ENT("write_normal_email"); - char *boundary = NULL; // the boundary marker between multipart sections - int boundary_created = 0; // we have not (yet) created a new boundary - char *temp = NULL; - int attach_num, base64_body = 0; - time_t em_time; - char *c_time; - pst_item_attach* current_attach; - - // convert the sent date if it exists, or set it to a fixed date - if (item->email->sent_date) { - em_time = fileTimeToUnixTime(item->email->sent_date, 0); - c_time = ctime(&em_time); - if (c_time) - c_time[strlen(c_time)-1] = '\0'; //remove end \n - else - c_time = "Fri Dec 28 12:06:21 2001"; - } else - c_time= "Fri Dec 28 12:06:21 2001"; - - // we will always look at the header to discover some stuff - if (item->email->header ) { - char *b1, *b2; - // see if there is a boundary variable there - // this search MUST be made case insensitive (DONE). - // Also, we should check to find out if we are looking - // at the boundary associated with content-type, and that - // the content type really is multipart - - removeCR(item->email->header); - - if ((b2 = my_stristr(item->email->header, "boundary="))) { - int len; - b2 += strlen("boundary="); // move boundary to first char of marker - - if (*b2 == '"') { - b2++; - b1 = strchr(b2, '"'); // find terminating quote - } else { - b1 = b2; - while (isgraph(*b1)) // find first char that isn't part of boundary - b1++; - } - len = b1 - b2; - boundary = malloc(len+1); //malloc that length - strncpy(boundary, b2, len); // copy boundary to another variable - boundary[len] = '\0'; - b1 = b2 = boundary; - while (*b2 != '\0') { // remove any CRs and Tabs - if (*b2 != '\n' && *b2 != '\r' && *b2 != '\t') { - *b1 = *b2; - b1++; - } - b2++; - } - *b1 = '\0'; - - DEBUG_EMAIL(("Found boundary of - %s\n", boundary)); - } else { - DEBUG_EMAIL(("boundary not found in header\n")); - } - - // also possible to set 7bit encoding detection here. - if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:"))) { - if ((b2 = strchr(b2, ':'))) { - b2++; // skip to the : at the end of the string - - while (*b2 == ' ' || *b2 == '\t') - b2++; - if (pst_strincmp(b2, "base64", 6)==0) { - DEBUG_EMAIL(("body is base64 encoded\n")); - base64_body = 1; - } - } else { - DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n")); - } - } - } - - if (!boundary && (item->attach || (item->email->body && item->email->htmlbody) - || item->email->rtf_compressed || item->email->encrypted_body - || item->email->encrypted_htmlbody)) { - // we need to create a boundary here. - DEBUG_EMAIL(("must create own boundary. oh dear.\n")); - boundary = malloc(50 * sizeof(char)); // allow 50 chars for boundary - boundary[0] = '\0'; - sprintf(boundary, "--boundary-LibPST-iamunique-%i_-_-", rand()); - DEBUG_EMAIL(("created boundary is %s\n", boundary)); - boundary_created = 1; - } - - DEBUG_EMAIL(("About to print Header\n")); - - if (item && item->email && item->email->subject && item->email->subject->subj) { - DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); - } - - if (item->email->header) { - int len; - char *soh = NULL; // real start of headers. - - // some of the headers we get from the file are not properly defined. - // they can contain some email stuff too. We will cut off the header - // when we see a \n\n or \r\n\r\n - removeCR(item->email->header); - temp = strstr(item->email->header, "\n\n"); - - if (temp) { - DEBUG_EMAIL(("Found body text in header\n")); - temp[1] = '\0'; // stop after first \n - } - - // Now, write out the header... - soh = skip_header_prologue(item->email->header); - if (mode != MODE_SEPERATE) { - // don't put rubbish in if we are doing seperate - if (strncmp(soh, "X-From_: ", 9) == 0 ) { - fputs("From ", f_output); - soh += 9; - } else - fprintf(f_output, "From \"%s\" %s\n", item->email->outlook_sender_name, c_time); - } - fprintf(f_output, "%s", soh); - len = strlen(soh); - if (!len || (soh[len-1] != '\n')) fprintf(f_output, "\n"); - - } else { - //make up our own header! - if (mode != MODE_SEPERATE) { - // don't want this first line for this mode - if (item->email->outlook_sender_name) { - temp = item->email->outlook_sender_name; - } else { - temp = "(readpst_null)"; - } - fprintf(f_output, "From \"%s\" %s\n", temp, c_time); - } - - temp = item->email->outlook_sender; - if (!temp) temp = ""; - fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp); - - if (item->email->subject) { - fprintf(f_output, "Subject: %s\n", item->email->subject->subj); - } else { - fprintf(f_output, "Subject: \n"); - } - - fprintf(f_output, "To: %s\n", item->email->sentto_address); - if (item->email->cc_address) { - fprintf(f_output, "Cc: %s\n", item->email->cc_address); - } - - if (item->email->sent_date) { - c_time = (char*) xmalloc(C_TIME_SIZE); - strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); - fprintf(f_output, "Date: %s\n", c_time); - free(c_time); - } - } - - fprintf(f_output, "MIME-Version: 1.0\n"); - if (boundary && boundary_created) { - // if we created the boundary, then it has NOT already been printed - // in the headers above. - if (item->attach) { - // write the boundary stuff if we have attachments - fprintf(f_output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); - } else if (boundary) { - // else if we have multipart/alternative then tell it so - fprintf(f_output, "Content-type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); - } else if (item->email->htmlbody) { - fprintf(f_output, "Content-type: text/html\n"); - } - } - fprintf(f_output, "\n"); // start the body - DEBUG_EMAIL(("About to print Body\n")); - - if (item->email->body) { - if (boundary) { - fprintf(f_output, "\n--%s\n", boundary); - fprintf(f_output, "Content-type: text/plain\n"); - if (base64_body) - fprintf(f_output, "Content-Transfer-Encoding: base64\n"); - fprintf(f_output, "\n"); - } - removeCR(item->email->body); - if (base64_body) { - char *enc = base64_encode(item->email->body, strlen(item->email->body)); - if (enc) { - write_email_body(f_output, enc); - free(enc); - } - } - else { - write_email_body(f_output, item->email->body); - } - } - - if (item->email->htmlbody) { - if (boundary) { - fprintf(f_output, "\n--%s\n", boundary); - fprintf(f_output, "Content-type: text/html\n"); - if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n"); - fprintf(f_output, "\n"); - } - removeCR(item->email->htmlbody); - if (base64_body) { - char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody)); - if (enc) { - write_email_body(f_output, enc); - free(enc); - } - } - else { - write_email_body(f_output, item->email->htmlbody); - } - } - - if (item->email->rtf_compressed && save_rtf) { - //int32_t tester; - DEBUG_EMAIL(("Adding RTF body as attachment\n")); - current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); - memset(current_attach, 0, sizeof(pst_item_attach)); - current_attach->next = item->attach; - item->attach = current_attach; - current_attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, ¤t_attach->size); - current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); - strcpy(current_attach->filename2, RTF_ATTACH_NAME); - current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); - strcpy(current_attach->mimetype, RTF_ATTACH_TYPE); - //memcpy(&tester, item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); - //LE32_CPU(tester); - //printf("lz produced %d bytes, rtf claims %d bytes\n", current_attach->size, tester); - } - - if (item->email->encrypted_body || item->email->encrypted_htmlbody) { - // if either the body or htmlbody is encrypted, add them as attachments - if (item->email->encrypted_body) { - DEBUG_EMAIL(("Adding Encrypted Body as attachment\n")); - current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); - memset(current_attach, 0, sizeof(pst_item_attach)); - current_attach->next = item->attach; - item->attach = current_attach; - current_attach->data = item->email->encrypted_body; - current_attach->size = item->email->encrypted_body_size; - item->email->encrypted_body = NULL; - } - - if (item->email->encrypted_htmlbody) { - DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n")); - current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); - memset(current_attach, 0, sizeof(pst_item_attach)); - current_attach->next = item->attach; - item->attach = current_attach; - current_attach->data = item->email->encrypted_htmlbody; - current_attach->size = item->email->encrypted_htmlbody_size; - item->email->encrypted_htmlbody = NULL; - } - 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"); - } - - // attachments - attach_num = 0; - for (current_attach = item->attach; current_attach; current_attach = current_attach->next) { - DEBUG_EMAIL(("Attempting Attachment encoding\n")); - if (!current_attach->data) { - DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size)); - } - if (mode == MODE_SEPERATE && !mode_MH) - write_separate_attachment(f_name, current_attach, ++attach_num, pst); - else - write_inline_attachment(f_output, current_attach, boundary, pst); - } - if (mode != MODE_SEPERATE) { /* do not add a boundary after the last attachment for mode_MH */ - DEBUG_EMAIL(("Writing buffer between emails\n")); - if (boundary) fprintf(f_output, "\n--%s--\n", boundary); - fprintf(f_output, "\n\n"); - } - if (boundary) free (boundary); - DEBUG_RET(); + DEBUG_ENT("write_normal_email"); + char *boundary = NULL; // the boundary marker between multipart sections + int boundary_created = 0; // we have not (yet) created a new boundary + char *temp = NULL; + int attach_num, base64_body = 0; + time_t em_time; + char *c_time; + pst_item_attach* current_attach; + + // convert the sent date if it exists, or set it to a fixed date + if (item->email->sent_date) { + em_time = fileTimeToUnixTime(item->email->sent_date, 0); + c_time = ctime(&em_time); + if (c_time) + c_time[strlen(c_time)-1] = '\0'; //remove end \n + else + c_time = "Fri Dec 28 12:06:21 2001"; + } else + c_time= "Fri Dec 28 12:06:21 2001"; + + // we will always look at the header to discover some stuff + if (item->email->header ) { + char *b1, *b2; + // see if there is a boundary variable there + // this search MUST be made case insensitive (DONE). + // Also, we should check to find out if we are looking + // at the boundary associated with content-type, and that + // the content type really is multipart + + removeCR(item->email->header); + + if ((b2 = my_stristr(item->email->header, "boundary="))) { + int len; + b2 += strlen("boundary="); // move boundary to first char of marker + + if (*b2 == '"') { + b2++; + b1 = strchr(b2, '"'); // find terminating quote + } else { + b1 = b2; + while (isgraph(*b1)) // find first char that isn't part of boundary + b1++; + } + len = b1 - b2; + boundary = malloc(len+1); //malloc that length + strncpy(boundary, b2, len); // copy boundary to another variable + boundary[len] = '\0'; + b1 = b2 = boundary; + while (*b2 != '\0') { // remove any CRs and Tabs + if (*b2 != '\n' && *b2 != '\r' && *b2 != '\t') { + *b1 = *b2; + b1++; + } + b2++; + } + *b1 = '\0'; + + DEBUG_EMAIL(("Found boundary of - %s\n", boundary)); + } else { + DEBUG_EMAIL(("boundary not found in header\n")); + } + + // also possible to set 7bit encoding detection here. + if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:"))) { + if ((b2 = strchr(b2, ':'))) { + b2++; // skip to the : at the end of the string + + while (*b2 == ' ' || *b2 == '\t') + b2++; + if (pst_strincmp(b2, "base64", 6)==0) { + DEBUG_EMAIL(("body is base64 encoded\n")); + base64_body = 1; + } + } else { + DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n")); + } + } + } + + if (!boundary && (item->attach || (item->email->body && item->email->htmlbody) + || item->email->rtf_compressed || item->email->encrypted_body + || item->email->encrypted_htmlbody)) { + // we need to create a boundary here. + DEBUG_EMAIL(("must create own boundary. oh dear.\n")); + boundary = malloc(50 * sizeof(char)); // allow 50 chars for boundary + boundary[0] = '\0'; + sprintf(boundary, "--boundary-LibPST-iamunique-%i_-_-", rand()); + DEBUG_EMAIL(("created boundary is %s\n", boundary)); + boundary_created = 1; + } + + DEBUG_EMAIL(("About to print Header\n")); + + if (item && item->email && item->email->subject && item->email->subject->subj) { + DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); + } + + if (item->email->header) { + int len; + char *soh = NULL; // real start of headers. + + // some of the headers we get from the file are not properly defined. + // they can contain some email stuff too. We will cut off the header + // when we see a \n\n or \r\n\r\n + removeCR(item->email->header); + temp = strstr(item->email->header, "\n\n"); + + if (temp) { + DEBUG_EMAIL(("Found body text in header\n")); + temp[1] = '\0'; // stop after first \n + } + + // Now, write out the header... + soh = skip_header_prologue(item->email->header); + if (mode != MODE_SEPERATE) { + // don't put rubbish in if we are doing seperate + if (strncmp(soh, "X-From_: ", 9) == 0 ) { + fputs("From ", f_output); + soh += 9; + } else + fprintf(f_output, "From \"%s\" %s\n", item->email->outlook_sender_name, c_time); + } + fprintf(f_output, "%s", soh); + len = strlen(soh); + if (!len || (soh[len-1] != '\n')) fprintf(f_output, "\n"); + + } else { + //make up our own header! + if (mode != MODE_SEPERATE) { + // don't want this first line for this mode + if (item->email->outlook_sender_name) { + temp = item->email->outlook_sender_name; + } else { + temp = "(readpst_null)"; + } + fprintf(f_output, "From \"%s\" %s\n", temp, c_time); + } + + temp = item->email->outlook_sender; + if (!temp) temp = ""; + fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp); + + if (item->email->subject) { + fprintf(f_output, "Subject: %s\n", item->email->subject->subj); + } else { + fprintf(f_output, "Subject: \n"); + } + + fprintf(f_output, "To: %s\n", item->email->sentto_address); + if (item->email->cc_address) { + fprintf(f_output, "Cc: %s\n", item->email->cc_address); + } + + if (item->email->sent_date) { + c_time = (char*) xmalloc(C_TIME_SIZE); + strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); + fprintf(f_output, "Date: %s\n", c_time); + free(c_time); + } + } + + fprintf(f_output, "MIME-Version: 1.0\n"); + if (boundary && boundary_created) { + // if we created the boundary, then it has NOT already been printed + // in the headers above. + if (item->attach) { + // write the boundary stuff if we have attachments + fprintf(f_output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); + } else if (boundary) { + // else if we have multipart/alternative then tell it so + fprintf(f_output, "Content-type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); + } else if (item->email->htmlbody) { + fprintf(f_output, "Content-type: text/html\n"); + } + } + fprintf(f_output, "\n"); // start the body + DEBUG_EMAIL(("About to print Body\n")); + + if (item->email->body) { + if (boundary) { + fprintf(f_output, "\n--%s\n", boundary); + fprintf(f_output, "Content-type: text/plain\n"); + if (base64_body) + fprintf(f_output, "Content-Transfer-Encoding: base64\n"); + fprintf(f_output, "\n"); + } + removeCR(item->email->body); + if (base64_body) { + char *enc = base64_encode(item->email->body, strlen(item->email->body)); + if (enc) { + write_email_body(f_output, enc); + free(enc); + } + } + else { + write_email_body(f_output, item->email->body); + } + } + + if (item->email->htmlbody) { + if (boundary) { + fprintf(f_output, "\n--%s\n", boundary); + fprintf(f_output, "Content-type: text/html\n"); + if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n"); + fprintf(f_output, "\n"); + } + removeCR(item->email->htmlbody); + if (base64_body) { + char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody)); + if (enc) { + write_email_body(f_output, enc); + free(enc); + } + } + else { + write_email_body(f_output, item->email->htmlbody); + } + } + + if (item->email->rtf_compressed && save_rtf) { + //int32_t tester; + DEBUG_EMAIL(("Adding RTF body as attachment\n")); + current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; + current_attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, ¤t_attach->size); + current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); + strcpy(current_attach->filename2, RTF_ATTACH_NAME); + current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); + strcpy(current_attach->mimetype, RTF_ATTACH_TYPE); + //memcpy(&tester, item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); + //LE32_CPU(tester); + //printf("lz produced %d bytes, rtf claims %d bytes\n", current_attach->size, tester); + } + + if (item->email->encrypted_body || item->email->encrypted_htmlbody) { + // if either the body or htmlbody is encrypted, add them as attachments + if (item->email->encrypted_body) { + DEBUG_EMAIL(("Adding Encrypted Body as attachment\n")); + current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; + current_attach->data = item->email->encrypted_body; + current_attach->size = item->email->encrypted_body_size; + item->email->encrypted_body = NULL; + } + + if (item->email->encrypted_htmlbody) { + DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n")); + current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(current_attach, 0, sizeof(pst_item_attach)); + current_attach->next = item->attach; + item->attach = current_attach; + current_attach->data = item->email->encrypted_htmlbody; + current_attach->size = item->email->encrypted_htmlbody_size; + item->email->encrypted_htmlbody = NULL; + } + 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"); + } + + // attachments + attach_num = 0; + for (current_attach = item->attach; current_attach; current_attach = current_attach->next) { + DEBUG_EMAIL(("Attempting Attachment encoding\n")); + if (!current_attach->data) { + DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size)); + } + if (mode == MODE_SEPERATE && !mode_MH) + write_separate_attachment(f_name, current_attach, ++attach_num, pst); + else + write_inline_attachment(f_output, current_attach, boundary, pst); + } + if (mode != MODE_SEPERATE) { /* do not add a boundary after the last attachment for mode_MH */ + DEBUG_EMAIL(("Writing buffer between emails\n")); + if (boundary) fprintf(f_output, "\n--%s--\n", boundary); + fprintf(f_output, "\n\n"); + } + if (boundary) free (boundary); + DEBUG_RET(); } void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]) { - // We can only call rfc escape once per printf, since the second call - // may free the buffer returned by the first call. - // I had tried to place those into a single printf - Carl. - - DEBUG_ENT("write_vcard"); - // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile - fprintf(f_output, "BEGIN:VCARD\n"); - fprintf(f_output, "FN:%s\n", rfc2426_escape(contact->fullname)); - - //fprintf(f_output, "N:%s;%s;%s;%s;%s\n", - fprintf(f_output, "N:%s;", (!contact->surname) ? "" : rfc2426_escape(contact->surname)); - fprintf(f_output, "%s;", (!contact->first_name) ? "" : rfc2426_escape(contact->first_name)); - fprintf(f_output, "%s;", (!contact->middle_name) ? "" : rfc2426_escape(contact->middle_name)); - fprintf(f_output, "%s;", (!contact->display_name_prefix) ? "" : rfc2426_escape(contact->display_name_prefix)); - fprintf(f_output, "%s\n", (!contact->suffix) ? "" : rfc2426_escape(contact->suffix)); - - if (contact->nickname) - fprintf(f_output, "NICKNAME:%s\n", rfc2426_escape(contact->nickname)); - if (contact->address1) - fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address1)); - if (contact->address2) - fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address2)); - if (contact->address3) - fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address3)); - if (contact->birthday) - fprintf(f_output, "BDAY:%s\n", rfc2425_datetime_format(contact->birthday)); - - if (contact->home_address) { - //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n", - fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box) ? "" : rfc2426_escape(contact->home_po_box)); - fprintf(f_output, "%s;", ""); // extended Address - fprintf(f_output, "%s;", (!contact->home_street) ? "" : rfc2426_escape(contact->home_street)); - fprintf(f_output, "%s;", (!contact->home_city) ? "" : rfc2426_escape(contact->home_city)); - fprintf(f_output, "%s;", (!contact->home_state) ? "" : rfc2426_escape(contact->home_state)); - fprintf(f_output, "%s;", (!contact->home_postal_code) ? "" : rfc2426_escape(contact->home_postal_code)); - fprintf(f_output, "%s\n", (!contact->home_country) ? "" : rfc2426_escape(contact->home_country)); - fprintf(f_output, "LABEL;TYPE=home:%s\n", rfc2426_escape(contact->home_address)); - } - - if (contact->business_address) { - //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", - fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box) ? "" : rfc2426_escape(contact->business_po_box)); - fprintf(f_output, "%s;", ""); // extended Address - fprintf(f_output, "%s;", (!contact->business_street) ? "" : rfc2426_escape(contact->business_street)); - fprintf(f_output, "%s;", (!contact->business_city) ? "" : rfc2426_escape(contact->business_city)); - fprintf(f_output, "%s;", (!contact->business_state) ? "" : rfc2426_escape(contact->business_state)); - fprintf(f_output, "%s;", (!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code)); - fprintf(f_output, "%s\n", (!contact->business_country) ? "" : rfc2426_escape(contact->business_country)); - fprintf(f_output, "LABEL;TYPE=work:%s\n", rfc2426_escape(contact->business_address)); - } - - if (contact->other_address) { - //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n", - fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box) ? "" : rfc2426_escape(contact->other_po_box)); - fprintf(f_output, "%s;", ""); // extended Address - fprintf(f_output, "%s;", (!contact->other_street) ? "" : rfc2426_escape(contact->other_street)); - fprintf(f_output, "%s;", (!contact->other_city) ? "" : rfc2426_escape(contact->other_city)); - fprintf(f_output, "%s;", (!contact->other_state) ? "" : rfc2426_escape(contact->other_state)); - fprintf(f_output, "%s;", (!contact->other_postal_code) ? "" : rfc2426_escape(contact->other_postal_code)); - fprintf(f_output, "%s\n", (!contact->other_country) ? "" : rfc2426_escape(contact->other_country)); - fprintf(f_output, "LABEL;TYPE=postal:%s\n", rfc2426_escape(contact->other_address)); - } - - if (contact->business_fax) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", rfc2426_escape(contact->business_fax)); - if (contact->business_phone) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(contact->business_phone)); - if (contact->business_phone2) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(contact->business_phone2)); - if (contact->car_phone) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", rfc2426_escape(contact->car_phone)); - if (contact->home_fax) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", rfc2426_escape(contact->home_fax)); - if (contact->home_phone) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(contact->home_phone)); - if (contact->home_phone2) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(contact->home_phone2)); - if (contact->isdn_phone) fprintf(f_output, "TEL;TYPE=isdn:%s\n", rfc2426_escape(contact->isdn_phone)); - if (contact->mobile_phone) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", rfc2426_escape(contact->mobile_phone)); - if (contact->other_phone) fprintf(f_output, "TEL;TYPE=msg:%s\n", rfc2426_escape(contact->other_phone)); - if (contact->pager_phone) fprintf(f_output, "TEL;TYPE=pager:%s\n", rfc2426_escape(contact->pager_phone)); - if (contact->primary_fax) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", rfc2426_escape(contact->primary_fax)); - if (contact->primary_phone) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", rfc2426_escape(contact->primary_phone)); - if (contact->radio_phone) fprintf(f_output, "TEL;TYPE=pcs:%s\n", rfc2426_escape(contact->radio_phone)); - if (contact->telex) fprintf(f_output, "TEL;TYPE=bbs:%s\n", rfc2426_escape(contact->telex)); - if (contact->job_title) fprintf(f_output, "TITLE:%s\n", rfc2426_escape(contact->job_title)); - if (contact->profession) fprintf(f_output, "ROLE:%s\n", rfc2426_escape(contact->profession)); - if (contact->assistant_name || contact->assistant_phone) { - fprintf(f_output, "AGENT:BEGIN:VCARD\n"); - if (contact->assistant_name) fprintf(f_output, "FN:%s\n", rfc2426_escape(contact->assistant_name)); - if (contact->assistant_phone) fprintf(f_output, "TEL:%s\n", rfc2426_escape(contact->assistant_phone)); - } - if (contact->company_name) fprintf(f_output, "ORG:%s\n", rfc2426_escape(contact->company_name)); - if (comment) fprintf(f_output, "NOTE:%s\n", rfc2426_escape(comment)); - - fprintf(f_output, "VERSION: 3.0\n"); - fprintf(f_output, "END:VCARD\n\n"); - DEBUG_RET(); + // We can only call rfc escape once per printf, since the second call + // may free the buffer returned by the first call. + // I had tried to place those into a single printf - Carl. + + DEBUG_ENT("write_vcard"); + // the specification I am following is (hopefully) PST_RFC2426 vCard Mime Directory Profile + fprintf(f_output, "BEGIN:VCARD\n"); + fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname)); + + //fprintf(f_output, "N:%s;%s;%s;%s;%s\n", + fprintf(f_output, "N:%s;", (!contact->surname) ? "" : pst_rfc2426_escape(contact->surname)); + fprintf(f_output, "%s;", (!contact->first_name) ? "" : pst_rfc2426_escape(contact->first_name)); + fprintf(f_output, "%s;", (!contact->middle_name) ? "" : pst_rfc2426_escape(contact->middle_name)); + fprintf(f_output, "%s;", (!contact->display_name_prefix) ? "" : pst_rfc2426_escape(contact->display_name_prefix)); + fprintf(f_output, "%s\n", (!contact->suffix) ? "" : pst_rfc2426_escape(contact->suffix)); + + if (contact->nickname) + fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname)); + if (contact->address1) + fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1)); + if (contact->address2) + fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2)); + if (contact->address3) + fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3)); + if (contact->birthday) + fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday)); + + if (contact->home_address) { + //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n", + fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box) ? "" : pst_rfc2426_escape(contact->home_po_box)); + fprintf(f_output, "%s;", ""); // extended Address + fprintf(f_output, "%s;", (!contact->home_street) ? "" : pst_rfc2426_escape(contact->home_street)); + fprintf(f_output, "%s;", (!contact->home_city) ? "" : pst_rfc2426_escape(contact->home_city)); + fprintf(f_output, "%s;", (!contact->home_state) ? "" : pst_rfc2426_escape(contact->home_state)); + fprintf(f_output, "%s;", (!contact->home_postal_code) ? "" : pst_rfc2426_escape(contact->home_postal_code)); + fprintf(f_output, "%s\n", (!contact->home_country) ? "" : pst_rfc2426_escape(contact->home_country)); + fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address)); + } + + if (contact->business_address) { + //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", + fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box) ? "" : pst_rfc2426_escape(contact->business_po_box)); + fprintf(f_output, "%s;", ""); // extended Address + fprintf(f_output, "%s;", (!contact->business_street) ? "" : pst_rfc2426_escape(contact->business_street)); + fprintf(f_output, "%s;", (!contact->business_city) ? "" : pst_rfc2426_escape(contact->business_city)); + fprintf(f_output, "%s;", (!contact->business_state) ? "" : pst_rfc2426_escape(contact->business_state)); + fprintf(f_output, "%s;", (!contact->business_postal_code) ? "" : pst_rfc2426_escape(contact->business_postal_code)); + fprintf(f_output, "%s\n", (!contact->business_country) ? "" : pst_rfc2426_escape(contact->business_country)); + fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address)); + } + + if (contact->other_address) { + //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n", + fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box) ? "" : pst_rfc2426_escape(contact->other_po_box)); + fprintf(f_output, "%s;", ""); // extended Address + fprintf(f_output, "%s;", (!contact->other_street) ? "" : pst_rfc2426_escape(contact->other_street)); + fprintf(f_output, "%s;", (!contact->other_city) ? "" : pst_rfc2426_escape(contact->other_city)); + fprintf(f_output, "%s;", (!contact->other_state) ? "" : pst_rfc2426_escape(contact->other_state)); + fprintf(f_output, "%s;", (!contact->other_postal_code) ? "" : pst_rfc2426_escape(contact->other_postal_code)); + fprintf(f_output, "%s\n", (!contact->other_country) ? "" : pst_rfc2426_escape(contact->other_country)); + fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address)); + } + + if (contact->business_fax) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", pst_rfc2426_escape(contact->business_fax)); + if (contact->business_phone) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone)); + if (contact->business_phone2) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone2)); + if (contact->car_phone) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", pst_rfc2426_escape(contact->car_phone)); + if (contact->home_fax) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", pst_rfc2426_escape(contact->home_fax)); + if (contact->home_phone) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone)); + if (contact->home_phone2) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone2)); + if (contact->isdn_phone) fprintf(f_output, "TEL;TYPE=isdn:%s\n", pst_rfc2426_escape(contact->isdn_phone)); + if (contact->mobile_phone) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", pst_rfc2426_escape(contact->mobile_phone)); + if (contact->other_phone) fprintf(f_output, "TEL;TYPE=msg:%s\n", pst_rfc2426_escape(contact->other_phone)); + if (contact->pager_phone) fprintf(f_output, "TEL;TYPE=pager:%s\n", pst_rfc2426_escape(contact->pager_phone)); + if (contact->primary_fax) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", pst_rfc2426_escape(contact->primary_fax)); + if (contact->primary_phone) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", pst_rfc2426_escape(contact->primary_phone)); + if (contact->radio_phone) fprintf(f_output, "TEL;TYPE=pcs:%s\n", pst_rfc2426_escape(contact->radio_phone)); + if (contact->telex) fprintf(f_output, "TEL;TYPE=bbs:%s\n", pst_rfc2426_escape(contact->telex)); + if (contact->job_title) fprintf(f_output, "TITLE:%s\n", pst_rfc2426_escape(contact->job_title)); + if (contact->profession) fprintf(f_output, "ROLE:%s\n", pst_rfc2426_escape(contact->profession)); + if (contact->assistant_name || contact->assistant_phone) { + fprintf(f_output, "AGENT:BEGIN:VCARD\n"); + if (contact->assistant_name) fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->assistant_name)); + if (contact->assistant_phone) fprintf(f_output, "TEL:%s\n", pst_rfc2426_escape(contact->assistant_phone)); + } + if (contact->company_name) fprintf(f_output, "ORG:%s\n", pst_rfc2426_escape(contact->company_name)); + if (comment) fprintf(f_output, "NOTE:%s\n", pst_rfc2426_escape(comment)); + + fprintf(f_output, "VERSION: 3.0\n"); + fprintf(f_output, "END:VCARD\n\n"); + DEBUG_RET(); } void write_appointment(FILE* f_output, pst_item_appointment* appointment, - pst_item_email* email, FILETIME* create_date, FILETIME* modify_date) + pst_item_email* email, FILETIME* create_date, FILETIME* modify_date) { - fprintf(f_output, "BEGIN:VEVENT\n"); - if (create_date) - fprintf(f_output, "CREATED:%s\n", - rfc2445_datetime_format(create_date)); - if (modify_date) - fprintf(f_output, "LAST-MOD:%s\n", - rfc2445_datetime_format(modify_date)); - if (email && email->subject) - fprintf(f_output, "SUMMARY:%s\n", - rfc2426_escape(email->subject->subj)); - if (email && email->body) - fprintf(f_output, "DESCRIPTION:%s\n", - rfc2426_escape(email->body)); - if (appointment && appointment->start) - fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", - rfc2445_datetime_format(appointment->start)); - if (appointment && appointment->end) - fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n", - rfc2445_datetime_format(appointment->end)); - if (appointment && appointment->location) - fprintf(f_output, "LOCATION:%s\n", - rfc2426_escape(appointment->location)); - if (appointment) { - switch (appointment->showas) { - case PST_FREEBUSY_TENTATIVE: - fprintf(f_output, "STATUS:TENTATIVE\n"); - break; - case PST_FREEBUSY_FREE: - // mark as transparent and as confirmed - fprintf(f_output, "TRANSP:TRANSPARENT\n"); - case PST_FREEBUSY_BUSY: - case PST_FREEBUSY_OUT_OF_OFFICE: - fprintf(f_output, "STATUS:CONFIRMED\n"); - break; - } - switch (appointment->label) { - case PST_APP_LABEL_NONE: - fprintf(f_output, "CATEGORIES:NONE\n"); - break; - case PST_APP_LABEL_IMPORTANT: - fprintf(f_output, "CATEGORIES:IMPORTANT\n"); - break; - case PST_APP_LABEL_BUSINESS: - fprintf(f_output, "CATEGORIES:BUSINESS\n"); - break; - case PST_APP_LABEL_PERSONAL: - fprintf(f_output, "CATEGORIES:PERSONAL\n"); - break; - case PST_APP_LABEL_VACATION: - fprintf(f_output, "CATEGORIES:VACATION\n"); - break; - case PST_APP_LABEL_MUST_ATTEND: - fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); - break; - case PST_APP_LABEL_TRAVEL_REQ: - fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); - break; - case PST_APP_LABEL_NEEDS_PREP: - fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); - break; - case PST_APP_LABEL_BIRTHDAY: - fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); - break; - case PST_APP_LABEL_ANNIVERSARY: - fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); - break; - case PST_APP_LABEL_PHONE_CALL: - fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); - break; - } - } - fprintf(f_output, "END:VEVENT\n\n"); + fprintf(f_output, "BEGIN:VEVENT\n"); + if (create_date) + fprintf(f_output, "CREATED:%s\n", + pst_rfc2445_datetime_format(create_date)); + if (modify_date) + fprintf(f_output, "LAST-MOD:%s\n", + pst_rfc2445_datetime_format(modify_date)); + if (email && email->subject) + fprintf(f_output, "SUMMARY:%s\n", + pst_rfc2426_escape(email->subject->subj)); + if (email && email->body) + fprintf(f_output, "DESCRIPTION:%s\n", + pst_rfc2426_escape(email->body)); + if (appointment && appointment->start) + fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", + pst_rfc2445_datetime_format(appointment->start)); + if (appointment && appointment->end) + fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n", + pst_rfc2445_datetime_format(appointment->end)); + if (appointment && appointment->location) + fprintf(f_output, "LOCATION:%s\n", + pst_rfc2426_escape(appointment->location)); + if (appointment) { + switch (appointment->showas) { + case PST_FREEBUSY_TENTATIVE: + fprintf(f_output, "STATUS:TENTATIVE\n"); + break; + case PST_FREEBUSY_FREE: + // mark as transparent and as confirmed + fprintf(f_output, "TRANSP:TRANSPARENT\n"); + case PST_FREEBUSY_BUSY: + case PST_FREEBUSY_OUT_OF_OFFICE: + fprintf(f_output, "STATUS:CONFIRMED\n"); + break; + } + switch (appointment->label) { + case PST_APP_LABEL_NONE: + fprintf(f_output, "CATEGORIES:NONE\n"); + break; + case PST_APP_LABEL_IMPORTANT: + fprintf(f_output, "CATEGORIES:IMPORTANT\n"); + break; + case PST_APP_LABEL_BUSINESS: + fprintf(f_output, "CATEGORIES:BUSINESS\n"); + break; + case PST_APP_LABEL_PERSONAL: + fprintf(f_output, "CATEGORIES:PERSONAL\n"); + break; + case PST_APP_LABEL_VACATION: + fprintf(f_output, "CATEGORIES:VACATION\n"); + break; + case PST_APP_LABEL_MUST_ATTEND: + fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); + break; + case PST_APP_LABEL_TRAVEL_REQ: + fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); + break; + case PST_APP_LABEL_NEEDS_PREP: + fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); + break; + case PST_APP_LABEL_BIRTHDAY: + fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); + break; + case PST_APP_LABEL_ANNIVERSARY: + fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); + break; + case PST_APP_LABEL_PHONE_CALL: + fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); + break; + } + } + fprintf(f_output, "END:VEVENT\n\n"); } void create_enter_dir(struct file_ll* f, pst_item *item) { - f->email_count = 0; - f->skip_count = 0; - f->type = item->type; - f->stored_count = (item->folder) ? item->folder->email_count : 0; - - DEBUG_ENT("create_enter_dir"); - if (mode == MODE_KMAIL) - f->name = mk_kmail_dir(item->file_as); //create directory and form filename - else if (mode == MODE_RECURSE) - f->name = mk_recurse_dir(item->file_as); - else if (mode == MODE_SEPERATE) { - // do similar stuff to recurse here. - mk_seperate_dir(item->file_as); - f->name = (char*) xmalloc(10); - memset(f->name, 0, 10); - // sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count); - } else { - f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1); - sprintf(f->name, OUTPUT_TEMPLATE, item->file_as); - } - - f->dname = (char*) xmalloc(strlen(item->file_as)+1); - strcpy(f->dname, item->file_as); - - if (overwrite != 1) { - int x = 0; - char *temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits - - sprintf(temp, "%s", f->name); - check_filename(temp); - while ((f->output = fopen(temp, "r"))) { - DEBUG_MAIN(("need to increase filename because one already exists with that name\n")); - DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x)); - x++; - sprintf(temp, "%s%08d", f->name, x); - DEBUG_MAIN(("- trying \"%s\"\n", f->name)); - if (x == 99999999) { - DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x)); - } - fclose(f->output); - } - if (x > 0) { //then the f->name should change - free (f->name); - f->name = temp; - } else { - free(temp); - } - } - - DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); - if (mode != MODE_SEPERATE) { - check_filename(f->name); - if (!(f->output = fopen(f->name, "w"))) { - DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name)); - } - } - DEBUG_RET(); + f->email_count = 0; + f->skip_count = 0; + f->type = item->type; + f->stored_count = (item->folder) ? item->folder->email_count : 0; + + DEBUG_ENT("create_enter_dir"); + if (mode == MODE_KMAIL) + f->name = mk_kmail_dir(item->file_as); //create directory and form filename + else if (mode == MODE_RECURSE) + f->name = mk_recurse_dir(item->file_as); + else if (mode == MODE_SEPERATE) { + // do similar stuff to recurse here. + mk_seperate_dir(item->file_as); + f->name = (char*) xmalloc(10); + memset(f->name, 0, 10); + // sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count); + } else { + f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1); + sprintf(f->name, OUTPUT_TEMPLATE, item->file_as); + } + + f->dname = (char*) xmalloc(strlen(item->file_as)+1); + strcpy(f->dname, item->file_as); + + if (overwrite != 1) { + int x = 0; + char *temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits + + sprintf(temp, "%s", f->name); + check_filename(temp); + while ((f->output = fopen(temp, "r"))) { + DEBUG_MAIN(("need to increase filename because one already exists with that name\n")); + DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x)); + x++; + sprintf(temp, "%s%08d", f->name, x); + DEBUG_MAIN(("- trying \"%s\"\n", f->name)); + if (x == 99999999) { + DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x)); + } + fclose(f->output); + } + if (x > 0) { //then the f->name should change + free (f->name); + f->name = temp; + } else { + free(temp); + } + } + + DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); + if (mode != MODE_SEPERATE) { + check_filename(f->name); + if (!(f->output = fopen(f->name, "w"))) { + DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name)); + } + } + DEBUG_RET(); } void close_enter_dir(struct file_ll *f) { - DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count)); - if (output_mode != OUTPUT_QUIET) - printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n", - f->dname, f->email_count, f->skip_count, f->stored_count); - if (f->output) fclose(f->output); - free(f->name); - free(f->dname); - - if (mode == MODE_KMAIL) - close_kmail_dir(); - else if (mode == MODE_RECURSE) - close_recurse_dir(); - else if (mode == MODE_SEPERATE) - close_seperate_dir(); + DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count)); + if (output_mode != OUTPUT_QUIET) + printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n", + f->dname, f->email_count, f->skip_count, f->stored_count); + if (f->output) fclose(f->output); + free(f->name); + free(f->dname); + + if (mode == MODE_KMAIL) + close_kmail_dir(); + else if (mode == MODE_RECURSE) + close_recurse_dir(); + else if (mode == MODE_SEPERATE) + close_seperate_dir(); } diff --git a/src/readpstlog.c b/src/readpstlog.c index 441af04..b5f8fc3 100644 --- a/src/readpstlog.c +++ b/src/readpstlog.c @@ -1,249 +1,249 @@ #include #include #include #ifndef _WIN32 # include #endif #ifndef __GNUC__ # include "XGetopt.h" #endif #include "define.h" #define BUF_SIZE 4096 int usage(); size_t get(void * buf, int size, unsigned int count, FILE *fp); int split_args(char *args, int **targ); int is_in(int a, int *b, int c); int main(int argc, char** argv) { int level = 0; int *i=NULL, x, ptr, stop=0, flag; char *fname, *buf, rec_type; unsigned char version; int *show_type=NULL, show_size=0; int *ex_type=NULL, ex_size=0; unsigned int funcname, filename, text, end, dtype, line, c; FILE *fp; struct _debug_file_rec_m mfile_rec; struct _debug_file_rec_l lfile_rec; char format = 'D'; // default while ((c = getopt(argc, argv, "f:t:x:")) != -1) { switch(c) { case 'f': // change the output format format = toupper(optarg[0]); break; case 't': //change the type of statements shown show_size = split_args(optarg, &show_type); // type = atoi(optarg); break; case 'x': // change the type of statements excluded ex_size = split_args(optarg, &ex_type); break; } } if (argc > optind) { fname = argv[optind++]; } else { usage(); exit(2); } fp = fopen(fname, "rb"); if (fp == NULL) { printf("Error. couldn't open debug file\n"); return 2; } if (get(&version, sizeof(char), 1, fp)==0) { printf("Error. could not read version byte from front of file"); return 3; } if (version > DEBUG_VERSION) { printf("Version number is higher than the format I know about."); return 4; } buf = (char*) xmalloc(BUF_SIZE); while (!stop) { if (fread(&x, sizeof(int), 1, fp)<=0) break; ptr = 0; if (x > 0) { if (i) free(i); - i = (int*)xmalloc(sizeof(int)*(x+1)); + i = (off_t*)xmalloc(sizeof(off_t)*(x+1)); // plus 1 cause we want to read the offset of the next index - if (get(i, sizeof(int), x+1, fp)==0) { + if (get(i, sizeof(off_t), x+1, fp)==0) { // we have reached the end of the debug file printf("oh dear. we must now end\n"); break; } while (ptr < x) { - fseek(fp,i[ptr++], SEEK_SET); + fseek(fp, i[ptr++], SEEK_SET); get(&rec_type, 1, sizeof(char), fp); if (rec_type == 'L') { get(&lfile_rec, sizeof(lfile_rec), 1, fp); funcname=lfile_rec.funcname; filename=lfile_rec.filename; text = lfile_rec.text; end = lfile_rec.end; dtype = lfile_rec.type; line = lfile_rec.line; } else if (rec_type == 'M') { get(&mfile_rec, sizeof(mfile_rec), 1, fp); funcname = mfile_rec.funcname; filename = mfile_rec.filename; text = mfile_rec.text; end = mfile_rec.end; dtype = mfile_rec.type; line = mfile_rec.line; } if (dtype == DEBUG_FUNCENT_NO) level++; if ((show_type == NULL || is_in(dtype, show_type, show_size)) && (ex_type == NULL || !is_in(dtype, ex_type, ex_size))) { c = 0; flag = 0; while (c < end) { int ii = (level-1) * 4; if (ii < 0) ii = 0; if (ii > 64) ii = 64; char indent[ii+1]; memset(indent, ' ', ii); indent[ii] = '\0'; if (c + (BUF_SIZE-1) < end) { get(buf, 1, BUF_SIZE-1, fp); buf[BUF_SIZE-1] = '\0'; c += BUF_SIZE-1; } else { get(buf, 1, end-c, fp); buf[end-c] = '\0'; c = end; } if (flag == 0) { if (format == 'I') { // indented text format char *b = buf+text; printf("%s %s/%s[%d]: ", indent, &buf[filename], &buf[funcname], line); while (b) { char *p = strchr(b, '\n'); if (p) { *p = '\0'; printf("%s\n%s ", b, indent); b = p + 1; } else { printf("%s", b); b = NULL; } } } else if (format == 'T') { // text format printf("%s/%s[%d]: %s", &buf[filename], &buf[funcname], line, &buf[text]); } else { printf("Type: %d\nFile[line]: %s[%d]\nFunction:%s\nText:%s", dtype, &buf[filename], line, &buf[funcname], &buf[text]); } flag = 1; } else { if (format == 'I') { char *b = buf; while (b) { char *p = strchr(b, '\n'); if (p) { *p = '\0'; printf("%s\n%s ", b, indent); b = p + 1; } else { printf("%s", b); b = NULL; } } } else printf("%s", buf); } } printf("\n"); } if (dtype == DEBUG_FUNCRET_NO) level--; } if (fseek(fp, i[ptr], SEEK_SET)==-1) { printf("finished\n"); break; } } else { printf("...no more items\n"); break; } } free(buf); fclose(fp); return 0; } -size_t get(void * buf, int size, unsigned int count, FILE *fp) { +size_t get(void *buf, int size, unsigned int count, FILE *fp) { size_t z; - if ((z=fread(buf,size, count, fp)) < count) { + if ((z=fread(buf, size, count, fp)) < count) { printf("Read Failed! (size=%d, count=%d,z=%ld)\n", size, count, (long)z); exit(1); } return z; } int usage() { printf("readlog -t[show_type] -x[exclude_type] -f[format] filename\n"); printf("\tformat:\n\t\tt: text log format\n"); printf("\t\ti: indented text log format\n"); printf("\tshow_type:\n\t\tcomma separated list of types to show " "[ie, 2,4,1,6]\n"); printf("\texclude_type:\n\t\tcomma separated list of types to exclude " "[ie, 1,5,3,7]\n"); return 0; } int split_args(char *args, int **targ) { int count = 1, *i, x, z; char *tmp = args, *y; if (*targ != NULL) { free(*targ); } // find the number of tokens in the string. Starting // from 1 cause there will always be one while ((tmp = strchr(tmp, ',')) != NULL) { tmp++; count++; } *targ = (int*)xmalloc(count * sizeof(int)); i = *targ; // for convienience tmp = args; z = 0; for (x = 0; x < count; x++) { y = strtok(tmp, ","); tmp = NULL; // must be done after first call if (y != NULL) { i[x] = atoi(y); z++; } } return z; } // checks to see if the first arg is in the array of the second arg, // the size of which is specified with the third arg. If the second // arg is NULL, then it is obvious that it is not there. int is_in(int a, int *b, int c){ int d = 0; if (b == NULL || c == 0) { // no array or no items in array return 0; } while (d < c) { if (a == b[d]) return 1; d++; } return 0; } diff --git a/src/vbuf.c b/src/vbuf.c new file mode 100644 index 0000000..a19f5d5 --- /dev/null +++ b/src/vbuf.c @@ -0,0 +1,932 @@ +// {{{ includes + +#include +//#include "defines.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "vbuf.h" +#include "generic.h" + +#ifdef WITH_DMALLOC +#include +#endif + +// }}} + +int skip_nl( char *s ) // {{{ returns the width of the newline at s[0] +{ + if( s[0] == '\n' ) return 1; + if( s[0] == '\r' && s[1] == '\n' ) return 2; + if( s[0] == '\0' ) return 0; + return -1; +} // }}} +int find_nl( vstr *vs ) // {{{ find newline of type type in b +{ + char *nextr, *nextn; + + nextr = memchr( vs->b, '\r', vs->dlen ); + nextn = memchr( vs->b, '\n', vs->dlen ); + + //case 1: UNIX, we find \n first + if( nextn && (nextr == NULL || nextr > nextn ) ) { + return nextn - vs->b; + } + + //case 2: DOS, we find \r\n + if( NULL != nextr && NULL != nextn && 1 == (char*)nextn - (char*)nextr ) { + return nextr - vs->b; + } + + //case 3: we find nothing + + return -1; +} // }}} + +// {{{ UTF8 <-> UTF16 <-> ISO8859 Character set conversion functions and (ack) their globals + +//TODO: the following should not be +char *wwbuf=NULL; +size_t nwwbuf=0; +static int unicode_up=0; +iconv_t i16to8, i8to16, i8859_1to8, i8toi8859_1; + +void unicode_init() // {{{ +{ + char *wipe = ""; + char dump[4]; + + if( unicode_up ) unicode_close(); + + if( (iconv_t)-1 == (i16to8 = iconv_open( "UTF-8", "UTF-16" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-16 to UTF-8.\n"); + exit( 1 ); + } + + if( (iconv_t)-1 == (i8to16 = iconv_open( "UTF-16", "UTF-8" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to UTF-16.\n"); + exit( 2 ); + } + + //iconv will prefix output with an FF FE (utf-16 start seq), the following dumps that. + memset( dump, 'x', 4 ); + ASSERT( 0 == utf8to16( wipe, 1, dump, 4 ), "unicode_init(): attempt to dump FF FE failed." ); + + if( (iconv_t)-1 == (i8859_1to8 = iconv_open( "UTF-8", "ISO_8859-1" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for ASCII to UTF-8.\n"); + exit( 1 ); + } + + + if( (iconv_t)-1 == (i8toi8859_1 = iconv_open( "ISO_8859-1", "UTF-8" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to ASCII.\n"); + exit( 1 ); + } + + unicode_up = 1; +} +// }}} +void unicode_close() // {{{ +{ + unicode_up = 0; + iconv_close( i8to16 ); + iconv_close( i16to8 ); + iconv_close( i8859_1to8 ); + iconv_close( i8toi8859_1 ); +} +// }}} + +//int utf16_write( FILE* stream, const void *buf, size_t count ) // {{{ write utf-8 or iso_8869-1 to stream after converting it to utf-16 +//{ +// +// //TODO: if anything big comes through here we are sunk, should do it +// //bit-by-bit, not one-big-gulp +// +// size_t inbytesleft, outbytesleft; +// char *inbuf, *outbuf; +// size_t icresult; +// size_t rl; +// +// //do we have enough buffer space? +// if( !wwbuf || nwwbuf < (count * 2 + 2) ) { +// wwbuf = F_REALLOC( wwbuf, count * 2 +2 ); +// +// nwwbuf = count * 2 + 2; +// } +// +// inbytesleft = count; outbytesleft = nwwbuf; +// inbuf = (char*)buf; outbuf = wwbuf; +// +//// fprintf(stderr, "X%s, %dX", (char*)buf, strlen( buf )); +//// fflush(stderr); +// +// if( (rl = strlen( buf ) + 1) != count ) { +// fprintf(stderr, "utf16_write(): reported buffer size (%d) does not match string length (%d)\n", +// count, +// rl); +// +// //hexdump( (char*)buf, 0, count, 1 ); +// +// raise( SIGSEGV ); +// inbytesleft = rl; +// } +// +//// fprintf(stderr, " attempting to convert:\n"); +//// hexdump( (char*)inbuf, 0, count, 1 ); +// +// icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); +// +//// fprintf(stderr, " converted:\n"); +//// hexdump( (char*)buf, 0, count, 1 ); +// +//// fprintf(stderr, " to:\n"); +//// hexdump( (char*)wwbuf, 0, nwwbuf, 1 ); +// +// if( (size_t)-1 == icresult ) { +// fprintf(stderr, "utf16_write(): iconv failure(%d): %s\n", errno, strerror( errno ) ); +// fprintf(stderr, " attempted to convert:\n"); +// hexdump( (char*)inbuf, 0, count, 1 ); +// +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf, 0, count, 1 ); +// +// fprintf(stderr, "I'm going to segfault now.\n"); +// raise( SIGSEGV ); +// exit(1); +// } +// +// if( inbytesleft > 0 ) { +// fprintf(stderr, "utf16_write(): iconv returned a short count.\n"); +// exit(1); +// } +// +// return fwrite( wwbuf, nwwbuf - outbytesleft - 2, 1, stream ); +//} +// }}} + +//char *utf16buf = NULL; +//int utf16buf_len = 0; +// +//int utf16_fprintf( FILE* stream, const char *fmt, ... ) // {{{ +//{ +// int result=0; +// va_list ap; +// +// if( utf16buf == NULL ) { +// utf16buf = (char*)F_MALLOC( SZ_MAX + 1 ); +// +// utf16buf_len = SZ_MAX + 1; +// } +// +// va_start( ap, fmt ); +// +// result = vsnprintf( utf16buf, utf16buf_len, fmt, ap ); +// +// if( result + 1 > utf16buf_len ) { //didn't have space, realloc() and try again +// fprintf(stderr, "utf16_fprintf(): buffer too small (%d), F_MALLOC(%d)\n", utf16buf_len, result); +// free( utf16buf ); +// utf16buf_len = result + 1; +// utf16buf = (char*)F_MALLOC( utf16buf_len ); +// +// result = vsnprintf( utf16buf, utf16buf_len, fmt, ap ); +// } +// +// +// //didn't have space...again...something weird is going on... +// ASSERT( result + 1 <= utf16buf_len, "utf16_fprintf(): Unpossible error!\n"); +// +// if( 1 != utf16_write( stream, utf16buf, result + 1 ) ) +// DIE( "Write error? -> %s or %s\n", strerror( errno ), uerr_str( uerr_get() ) ); +// +// return result; +//} +//// }}} +//int utf16to8( char *inbuf_o, char *outbuf_o, int length ) // {{{ +//{ +// int inbytesleft = length; +// int outbytesleft = length; +// char *inbuf = inbuf_o; +// char *outbuf = outbuf_o; +// int rlen = -1, tlen; +// int icresult = -1; +// +// int i, strlen=-1; +// +// DEBUG( +// fprintf(stderr, " utf16to8(): attempting to convert:\n"); +// //hexdump( (char*)inbuf_o, 0, length, 1 ); +// fflush(stderr); +// ); +// +// for( i=0; i actual string length +// //enum: zero terminated, length valid +// // zero terminated, length short //we won't go beyond length ever, so this is same as NZT case +// // zero terminated, length long +// // not zero terminated +// // TODO: MEMORY BUG HERE! +// for( tlen = 0; tlen <= inbytesleft - 2; tlen+=2 ) { +// if( inbuf_o[tlen] == 0 && inbuf_o[tlen+1] == 0 ){ +// rlen = tlen + 2; +// tlen = rlen; +// break; +// } +// if( tlen == inbytesleft )fprintf(stderr, "Space allocated for string > actual string length. Go windows!\n"); +// } +// +// if( rlen >= 0 ) +// icresult = iconv( i16to8, &inbuf, &rlen, &outbuf, &outbytesleft ); +// +// if( icresult == (size_t)-1 ) { +// fprintf(stderr, "utf16to8(): iconv failure(%d): %s\n", errno, strerror( errno ) ); +// fprintf(stderr, " attempted to convert:\n"); +// hexdump( (char*)inbuf_o, 0, length, 1 ); +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf_o, 0, length, 1 ); +// fprintf(stderr, " MyDirtyOut:\n"); +// for( i=0; ib); + } + + return (-1 == len )?0:1; +} // }}} +int vb_utf16to8( vbuf *dest, char *buf, int len ) // {{{ +{ + int inbytesleft = len; + char *inbuf = buf; + //int rlen = -1, tlen; + int icresult = -1; + VBUF_STATIC( dumpster, 100 ); + + //int i; //, strlen=-1; + int outbytesleft; + char *outbuf; + + ASSERT( unicode_up, "vb_utf16to8() called before unicode started." ); + + if( 2 > dest->blen ) vbresize( dest, 2 ); + dest->dlen = 0; + + //Bad Things can happen if a non-zero-terminated utf16 string comes through here + if( !utf16_is_terminated( buf, len ) ) return -1; + + do { + outbytesleft = dest->blen - dest->dlen; + outbuf = dest->b + dest->dlen; + icresult = iconv( i16to8, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + dest->dlen = outbuf - dest->b; + vbgrow( dest, inbytesleft); + } while( (size_t)-1 == icresult && E2BIG == errno ); + + if( 0 != vb_utf8to16T( dumpster, dest->b, dest->dlen ) ) + DIE("Reverse conversion failed."); + + if( icresult == (size_t)-1 ) { + //TODO: error + //ERR_UNIX( errno, "vb_utf16to8():iconv failure: %s", strerror( errno ) ); + unicode_init(); + return -1; + /* + fprintf(stderr, " attempted to convert:\n"); + hexdump( (char*)cin, 0, inlen, 1 ); + fprintf(stderr, " result:\n"); + hexdump( (char*)bout->b, 0, bout->dlen, 1 ); + fprintf(stderr, " MyDirtyOut:\n"); + for( i=0; i actual string length + //enum: zero terminated, length valid + // zero terminated, length short //we won't go beyond length ever, so this is same as NZT case + // zero terminated, length long + // not zero terminated + // TODO: MEMORY BUG HERE! + // + /* + for( tlen = 0; tlen <= inbytesleft - 2; tlen+=2 ) { + if( inbuf_o[tlen] == 0 && inbuf_o[tlen+1] == 0 ){ + rlen = tlen + 2; + tlen = rlen; + break; + } + if( tlen == inbytesleft )fprintf(stderr, "Space allocated for string > actual string length. Go windows!\n"); + } + */ + + //if( rlen >= 0 ) + icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + + if( icresult == (size_t)-1 ) { + DIE("iconv failure(%d): %s\n", errno, strerror( errno ) ); + //fprintf(stderr, " attempted to convert:\n"); + //hexdump( (char*)inbuf_o, 0, iblen, 1 ); + //fprintf(stderr, " result:\n"); + //hexdump( (char*)outbuf_o, 0, oblen, 1 ); + //fprintf(stderr, " MyDirtyOut:\n"); +// for( i=0; i= 0 ) + int outbytesleft; + char *outbuf; + if( 2 > bout->blen ) vbresize( bout, 2 ); + bout->dlen = 0; + + do { + outbytesleft = bout->blen - bout->dlen; + outbuf = bout->b + bout->dlen; + icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + bout->dlen = outbuf - bout->b; + vbgrow( bout, 20 ); + } while( (size_t)-1 == icresult && E2BIG == errno ); + + if( icresult == (size_t)-1 ) { + WARN("iconv failure: %s", strerror( errno ) ); + //ERR_UNIX( errno, "vb_utf8to16():iconv failure: %s", strerror( errno ) ); + unicode_init(); + return -1; + /* + fprintf(stderr, "vb_utf8to16(): iconv failure(%d == %d?): %s\n", errno, E2BIG, strerror( errno ) ); + fprintf(stderr, " attempted to convert:\n"); + hexdump( (char*)cin, 0, inlen, 1 ); + fprintf(stderr, " result:\n"); + hexdump( (char*)bout->b, 0, bout->dlen, 1 ); + fprintf(stderr, " MyDirtyOut:\n"); + for( i=0; i 0; l -=2) { + *dest = *src; + dest++; src +=2; + } + *dest = 0; +} +// }}} +#endif + +void cheap_ascii2uni(char *src, char *dest, int l) /* {{{ Quick and dirty ascii to unicode */ +{ + for (; l > 0; l--) { + *dest++ = *src++; + *dest++ = 0; + + } +} +// }}} + +// }}} +// {{{ VARBUF Functions +vbuf *vballoc( size_t len ) // {{{ +{ + struct varbuf *result; + + result = F_MALLOC( sizeof( struct varbuf ) ); + + result->dlen = 0; + result->blen = 0; + result->buf = NULL; + + vbresize( result, len ); + + return result; + +} // }}} +void vbcheck( vbuf *vb ) // {{{ +{ + ASSERT( vb->b - vb->buf <= vb->blen, "vbcheck(): vb->b outside of buffer range."); + ASSERT( vb->dlen <= vb->blen, "vbcheck(): data length > buffer length."); + + ASSERT( vb->blen < 1024*1024, "vbcheck(): blen is a bit large...hmmm."); +} // }}} +void vbfree( vbuf *vb ) // {{{ +{ + free( vb->buf ); + free( vb ); +} // }}} +void vbclear( struct varbuf *vb ) // {{{ditch the data, keep the buffer +{ + vbresize( vb, 0 ); +} // }}} +void vbresize( struct varbuf *vb, size_t len ) // {{{ DESTRUCTIVELY grow or shrink buffer +{ + vb->dlen = 0; + + if( vb->blen >= len ) { + vb->b = vb->buf; + return; + } + + vb->buf = F_REALLOC( vb->buf, len ); + vb->b = vb->buf; + vb->blen = len; +} // }}} +int vbavail( vbuf *vb ) // {{{ +{ + return vb->blen - ((char*)vb->b - (char*)vb->buf + vb->dlen); +} // }}} +//void vbdump( vbuf *vb ) // {{{ TODO: to stdout? Yuck +//{ +// printf("vb dump-------------\n"); +// printf("dlen: %d\n", vb->dlen ); +// printf("blen: %d\n", vb->blen ); +// printf("b - buf: %d\n", vb->b - vb->buf ); +// printf("buf:\n"); +// hexdump( vb->buf, 0, vb->blen, 1 ); +// printf("b:\n"); +// hexdump( vb->b, 0, vb->dlen, 1 ); +// printf("^^^^^^^^^^^^^^^^^^^^\n"); +//} // }}} +void vbgrow( struct varbuf *vb, size_t len ) // {{{ out: vbavail(vb) >= len, data are preserved +{ + if( 0 == len ) return; + + if( 0 == vb->blen ) { + vbresize( vb, len ); + return; + } + + if( vb->dlen + len > vb->blen ) { + if( vb->dlen + len < vb->blen * 1.5 ) len = vb->blen * 1.5; + char *nb = F_MALLOC( vb->blen + len ); + //printf("vbgrow() got %p back from malloc(%d)\n", nb, vb->blen + len); + vb->blen = vb->blen + len; + memcpy( nb, vb->b, vb->dlen ); + + //printf("vbgrow() I am going to free %p\n", vb->buf ); + free( vb->buf ); + vb->buf = nb; + vb->b = vb->buf; + } else { + if( vb->b != vb->buf ) + memcpy( vb->buf, vb->b, vb->dlen ); + } + + vb->b = vb->buf; + + ASSERT( vbavail( vb ) >= len, "vbgrow(): I have failed in my mission." ); +} // }}} +void vbset( vbuf *vb, void *b, size_t len ) // {{{ set vbuf b size=len, resize if necessary, relen = how much to over-allocate +{ + vbresize( vb, len ); + + memcpy( vb->b, b, len ); + vb->dlen = len; +} // }}} +void vsskipws( vstr *vs ) // {{{ +{ + char *p = vs->b; + while( p - vs->b < vs->dlen && isspace( p[0] ) ) p++; + + vbskip( (vbuf*)vs, p - vs->b ); +} // }}} +void vbappend( struct varbuf *vb, void *b, size_t len ) // {{{ append len bytes of b to vbuf, resize if necessary +{ + if( 0 == vb->dlen ) { + vbset( vb, b, len ); + return; + } + + vbgrow( vb, len ); + + memcpy( vb->b + vb->dlen, b, len ); + vb->dlen += len; + + //printf("vbappend() end: >%s/%d<\n", vbuf->b, vbuf->dlen ); +} // }}} +void vbskip( struct varbuf *vb, size_t skip ) // {{{ dumps the first skip bytes from vbuf +{ + ASSERT( skip <= vb->dlen, "vbskip(): Attempt to seek past end of buffer." ); + //memmove( vbuf->b, vbuf->b + skip, vbuf->dlen - skip ); + vb->b += skip; + vb->dlen -= skip; +} // }}} +void vboverwrite( struct varbuf *vbdest, struct varbuf *vbsrc ) // {{{ overwrite vbdest with vbsrc +{ + vbresize( vbdest, vbsrc->blen ); + memcpy( vbdest->b, vbsrc->b, vbsrc->dlen ); + vbdest->blen = vbsrc->blen; + vbdest->dlen = vbsrc->dlen; +} // }}} +// }}} +// {{{ VARSTR Functions +vstr *vsalloc( size_t len ) // {{{ +{ + vstr *result = (vstr*)vballoc( len + 1 ); + vsset( result, "" ); + return result; +} // }}} +char *vsstr( vstr *vs ) // {{{ +{ + return vs->b; +} // }}} +size_t vslen( vstr *vs ) // {{{ +{ + return strlen( vsstr( vs )); +} // }}} +void vsfree( vstr *vs ) // {{{ +{ + vbfree( (vbuf*)vs ); +} // }}} +void vscharcat( vstr *vb, int ch ) // {{{ +{ + vbgrow( (vbuf*)vb, 1); + vb->b[vb->dlen-1] = ch; + vb->b[vb->dlen] = '\0'; + vb->dlen++; +} // }}} +void vsnprepend( vstr *vb, char *str, size_t len ) // {{{ prependappend string str to vbuf, vbuf must already contain a valid string +{ + ASSERT( vb->b[vb->dlen-1] == '\0', "vsncat(): attempt to append string to non-string."); + int sl = strlen( str ); + int n = (slb + n, vb->b, vb->dlen - 1 ); + memcpy( vb->b, str, n ); + //strncat( vb->b, str, n ); + + vb->dlen += n; + vb->b[ vb->dlen - 1 ] = '\0'; +} // }}} +void vsskip( vstr *vs, size_t len ) // {{{ len < dlen-1 -> skip len chars, else DIE +{ + ASSERT( len < vs->dlen - 1, "Attempt to skip past end of string" ); + vbskip( (vbuf*)vs, len ); +} // }}} +int vsskipline( vstr *vs ) // {{{ in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" +{ + int nloff = find_nl( vs ); + int nll = skip_nl( vs->b + nloff ); + + if( nloff < 0 ) { + //TODO: error + printf("vb_skipline(): there seems to be no newline here.\n"); + return -1; + } + if( skip_nl < 0 ) { + //TODO: error + printf("vb_skipline(): there seems to be no newline here...except there should be. :P\n"); + return -1; + } + + memmove( vs->b, vs->b + nloff + nll, vs->dlen - nloff - nll ); + + vs->dlen -= nloff + nll; + + return 0; +} // }}} +int vscatprintf( vstr *vs, char *fmt, ... ) // {{{ +{ + int size; + va_list ap; + + /* Guess we need no more than 100 bytes. */ + //vsresize( vb, 100 ); + if(!vs->b || vs->dlen == 0) { + vsset( vs, "" ); + } + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b + vs->dlen - 1, vs->blen - vs->dlen, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen - vs->dlen ) { + vs->dlen += size; + return size; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbgrow( (vbuf*)vs, size+1 ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbgrow( (vbuf*)vs, vs->blen); + } +} // }}} +int vslast( vstr *vs ) // {{{ returns the last character stored in a vstr +{ + if( vs->dlen < 1 ) return -1; + if( vs->b[vs->dlen-1] != '\0' ) return -1; + if( vs->dlen == 1 ) return '\0'; + return vs->b[vs->dlen-2]; +} // }}} +void vs_printf( vstr *vs, char *fmt, ... ) // {{{ print over vb +{ + int size; + va_list ap; + + /* Guess we need no more than 100 bytes. */ + vbresize( (vbuf*)vs, 100 ); + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b, vs->blen, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen) { + vs->dlen = size + 1; + return; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbresize( (vbuf*)vs, size+1 ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbresize( (vbuf*)vs, vs->blen*2); + } +} // }}} +void vs_printfa( vstr *vs, char *fmt, ... ) // {{{ printf append to vs +{ + int size; + va_list ap; + + if( vs->blen - vs->dlen < 50 ) + vbgrow( (vbuf*)vs, 100 ); + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b + vs->dlen - 1, vs->blen - vs->dlen + 1, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen) { + vs->dlen += size; + return; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbgrow( (vbuf*)vs, size+1 - vs->dlen ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbgrow( (vbuf*)vs, size ); + } +} // }}} +void vshexdump( vstr *vs, char *b, size_t start, size_t stop, int ascii ) // {{{ +{ + char c; + int diff,i; + + while (start < stop ) { + diff = stop - start; + if (diff > 16) diff = 16; + + vs_printfa(vs, ":%08X ",start); + + for (i = 0; i < diff; i++) { + if( 8 == i ) vs_printfa( vs, " " ); + vs_printfa(vs, "%02X ",(unsigned char)*(b+start+i)); + } + if (ascii) { + for (i = diff; i < 16; i++) vs_printfa(vs, " "); + for (i = 0; i < diff; i++) { + c = *(b+start+i); + vs_printfa(vs, "%c", isprint(c) ? c : '.'); + } + } + vs_printfa(vs, "\n"); + start += 16; + } +} // }}} +void vsset( vstr *vs, char *s ) // {{{ Store string s in vs +{ + vsnset( vs, s, strlen( s ) ); +} // }}} +void vsnset( vstr *vs, char *s, size_t n ) // {{{ Store string s in vs +{ + vbresize( (vbuf*)vs, n + 1 ); + memcpy( vs->b, s, n); + vs->b[n] = '\0'; + vs->dlen = n+1; +} // }}} +void vsgrow( vstr *vs, size_t len ) // {{{ grow buffer by len bytes, data are preserved +{ + vbgrow( (vbuf*)vs, len ); +} // }}} +size_t vsavail( vstr *vs ) // {{{ +{ + return vbavail( (vbuf*)vs ); +} // }}} +void vsnset16( vstr *vs, char *s, size_t len ) // {{{ Like vbstrnset, but for UTF16 +{ + vbresize( (vbuf*)vs, len+1 ); + memcpy( vs->b, s, len ); + + vs->b[len] = '\0'; + vs->dlen = len+1; + vs->b[len] = '\0'; +} // }}} +void vscat( vstr *vs, char *str ) // {{{ +{ + vsncat( vs, str, strlen(str ) ); +} // }}} +int vscmp( vstr *vs, char *str ) // {{{ +{ + return strcmp( vs->b, str ); +} // }}} +void vsncat( vstr *vs, char *str, size_t len ) // {{{ append string str to vstr, vstr must already contain a valid string +{ + ASSERT( vs->b[vs->dlen-1] == '\0', "vsncat(): attempt to append string to non-string."); + int sl = strlen( str ); + int n = (slb + vs->dlen - 1, str, n ); + //strncat( vs->b, str, n ); + + vs->dlen += n; + vs->b[ vs->dlen - 1 ] = '\0'; +} // }}} +void vstrunc( vstr *v, int off ) // {{{ Drop chars [off..dlen] +{ + if( off >= v->dlen - 1 ) return; //nothing to do + v->b[off] = '\0'; + v->dlen = off + 1; +} +// }}} +// }}} +// {{{ User input +// TODO: not sure how useful this stuff is here +int fmyinput(char *prmpt, char *ibuf, int maxlen) /* {{{ get user input */ +{ + printf("%s",prmpt); + + fgets(ibuf,maxlen+1,stdin); + + ibuf[strlen(ibuf)-1] = 0; + + return(strlen(ibuf)); +} +// }}} +//}}} +// +// +//{{{ String formatting and output to FILE *stream or just stdout, etc +// TODO: a lot of old, unused stuff in here +void vswinhex8(vstr *vs, unsigned char *hbuf, int start, int stop, int loff ) // {{{ Produce regedit-style hex output */ +{ + int i; + int lineflag=0; + + for( i=start; i= 77) { + lineflag=1; + loff=0; + vscatprintf( vs, "\\%s ", STUPID_CR ); + } + break; + case 1: + if( loff >= 75 ) { + loff=0; + vscatprintf( vs, "\\%s ", STUPID_CR ); + } + break; + } + // if( 24 < i || 0 == (i - 17) % 25 ) fprintf( stream, "\\\n " ); + } + } + + // fprintf( stream, "\n" ); +} // }}} diff --git a/src/vbuf.h b/src/vbuf.h new file mode 100644 index 0000000..8abe4a7 --- /dev/null +++ b/src/vbuf.h @@ -0,0 +1,142 @@ +/* {{{ vbuf.h - variable length buffer functions + * + * Functions that try to make dealing with buffers easier. + * + * vbuf + * + * vstr + * - should always contain a valid string + * + * }}} */ + +#ifndef VBUF_H +#define VBUF_H +#define SZ_MAX 4096 +#include +#include +#include +/***************************************************/ + +// {{{ Tokenizer const TOK_EMPTY, TOK_ELEMENT, DELIM +#define DELIM '\\' + +#define TOK_EMPTY 0 +#define TOK_DELIM 1 +#define TOK_PARENT 2 +#define TOK_CURRENT 3 +#define TOK_ELEMENT 4 + +#define TOK_ERROR 10 +#define TOK_BUF_SMALL 11 +// }}} + + +// Variable-length buffers +struct varbuf { // {{{ + size_t dlen; //length of data stored in buffer + size_t blen; //length of buffer + char *buf; //buffer + char *b; //start of stored data +}; // }}} + + +// The exact same thing as a varbuf but should always contain at least '\0' +struct varstr { // {{{ + size_t dlen; //length of data stored in buffer + size_t blen; //length of buffer + char *buf; //buffer + char *b; //start of stored data +}; // }}} + + +typedef struct varbuf vbuf; +typedef struct varstr vstr; + +#define VBUF_STATIC(x,y) static vbuf *x = NULL; if(!x) x = vballoc(y); +#define VSTR_STATIC(x,y) static vstr *x = NULL; if(!x) x = vsalloc(y); + +// vbuf functions +struct varbuf *vballoc( size_t len ); +void vbfree( vbuf *vb ); +void vbclear( vbuf *vb ); //ditch the data, keep the buffer +void vbresize( vbuf *vb, size_t len ); +int vbavail( vbuf *vb ); +void vbdump( vbuf *vb ); +void vbgrow( vbuf *vb, size_t len ); // grow buffer by len bytes, data are preserved +void vbset( vbuf *vb, void *data, size_t len ); +void vbskipws( vbuf *vb ); +void vbappend( vbuf *vb, void *data, size_t length ); +void vbskip( vbuf *vb, size_t skip ); +void vboverwrite( vbuf *vbdest, vbuf *vbsrc ); + +// vstr functions +vstr *vsalloc( size_t len ); +char *vsb( vstr *vs ); +size_t vslen( vstr *vs ); //strlen +void vsfree( vstr *vs ); +void vsset( vstr *vs, char *s ); // Store string s in vb +void vsnset( vstr *vs, char *s, size_t n ); // Store string s in vb +void vsgrow( vstr *vs, size_t len ); // grow buffer by len bytes, data are preserved +size_t vsavail( vstr *vs ); +void vscat( vstr *vs, char *str ); +void vsncat( vstr *vs, char *str, size_t len ); +void vsnprepend( vstr *vs, char *str, size_t len ) ; +void vsskip( vstr *vs, size_t len ); +int vscmp( vstr *vs, char *str ); +void vsskipws( vstr *vs ); +void vs_printf( vstr *vs, char *fmt, ... ); +void vs_printfa( vstr *vs, char *fmt, ... ); +void vshexdump( vstr *vs, char *b, size_t start, size_t stop, int ascii ); +int vscatprintf( vstr *vs, char *fmt, ... ); +void vsvprintf( vstr *vs, char *fmt, va_list ap ); +void vstrunc( vstr *vs, int off ); // Drop chars [off..dlen] +int vslast( vstr *vs ); // returns the last character stored in a vstr string +void vscharcat( vstr *vs, int ch ); +int vsutf16( vstr *vs, vbuf *in ); //in: in=zero-terminated utf16; out: vs=utf8; returns: 0 on success, else on fail + +int vs_parse_escaped_string( vstr *vs, char *str, size_t len ); + + +/* + * Windows unicode output trash - this stuff sucks + * TODO: most of this should not be here + */ + +void unicode_init(); +void unicode_close(); +int utf16_write( FILE* stream, const void *buf, size_t count ); +int utf16_fprintf( FILE* stream, const char *fmt, ... ); +int utf16to8( char *inbuf_o, char *outbuf_o, int length ); +int utf8to16( char *inbuf_o, int iblen, char *outbuf_o, int oblen); +int vb_utf8to16T( vbuf *bout, char *cin, int inlen ); +int vb_utf16to8( vbuf *dest, char *buf, int len ); +int iso8859_1to8( char *inbuf_o, char *outbuf_o, int length ); +int utf8toascii( const char *inbuf_o, char *outbuf_o, int length ); + +/* dump ascii hex in windoze format */ +void winhex(FILE* stream, unsigned char *hbuf, int start, int stop, int loff); +void winhex8(FILE *stream, unsigned char *hbuf, int start, int stop, int loff ); + +void vbwinhex8(vbuf *vb, unsigned char *hbuf, int start, int stop, int loff ); + +/* general search routine, find something in something else */ +int find_in_buf(char *buf, char *what, int sz, int len, int start); + +/* Get INTEGER from memory. This is probably low-endian specific? */ +int get_int( char *array ); + +int find_nl( vstr *vs ); // find newline of type type in b +int skip_nl( char *s ); // returns the width of the newline at s[0] +//int vb_readline( struct varbuf *vb, int *ctype, FILE *in ); // read *AT LEAST* one full line of data from in +int vb_skipline( struct varbuf *vb ); // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" +/* Get a string of HEX bytes (space separated), + * or if first char is ' get an ASCII string instead. */ +int gethexorstr(char **c, char *wb); +char *esc_index( char *s, int c ); // just like index(3), but works on strings with escape sequences +char *esc_rindex( char *s, int c ); // just like rindex(3), but works on strings with escape sequences + +char *tok_esc_char( char *s, int *is_esc, int *c ); +int vb_path_token( vbuf *tok, char **path ); // returns things like TOK_EMPTY, TOK_ERROR, complete list at top + +int gettoken( char *tok, int len, char **path, char delim ); // Path tokenizer: increments path, dumps token in tok +#endif diff --git a/xml/libpst.in b/xml/libpst.in index 3b19ba9..691823b 100644 --- a/xml/libpst.in +++ b/xml/libpst.in @@ -1,1362 +1,1443 @@ @PACKAGE@ Utilities - Version @VERSION@ Packages This is a fork of the libpst project at SourceForge. Another fork is located at http://alioth.debian.org/projects/libpst/ The various source and binary packages are available at http://www.five-ten-sg.com/@PACKAGE@/packages/ The most recent documentation is available at http://www.five-ten-sg.com/@PACKAGE@/ - 2007-07-10 + 2008-01-06 readpst 1 readpst @VERSION@ readpst convert PST (MS Outlook Personal Folders) files to mbox format Synopsis readpst + - files + pstfile Description readpst is a program that can read an Outlook PST (Personal Folders) file and convert it into an mbox file, a format suitable for KMail, a recursive mbox structure, or separate emails. Options -b Do not save the attachments for the RTF format of the email body. + + -C + + Decrypt the entire pst file and dump it to stdout. + + -c format Set the Contact output mode. Use -cv for vcard format or -cl for an email list. -d debug-file Specify name of debug log file. The log file is not an ascii file, it is a binary file readable by readpstlog. -h Show summary of options and exit. -k Changes the output format to KMail. -o output-directory Specifies the output directory. The directory must already exist, and is entered after the PST file is opened, but before any processing of files commences. -q Changes to silent mode. No feedback is printed to the screen, except for error messages. -r Changes the output format to Recursive. This will create folders as named in the PST file, and will put all emails in a file called "mbox" inside each folder. These files are then compatible with all mbox-compatible email clients. -S Output messages into separate files. This will create folders as named in the PST file, and will put each email in its own file. These files will be numbered from 1 increasing in intervals of 1 (ie 1, 2, 3, ...). Any attachments are saved alongside each email as XXXXXXXXX-attach1, XXXXXXXXX-attach2 and so on, or with the name of the attachment if one is present. -M Output messages in MH format as separate files. This will create folders as named in the PST file, and will put each email together with any attachments into its own file. These files will be numbered from 1 to n with no leading zeros. -V Show program version and exit. -w Overwrite any previous output files. Beware: When used with the -S switch, this will remove all files from the target folder before writing. This is to keep the count of emails and attachments correct. See Also readpstlog 1 Author This manual page was originally written by Dave Smith <dave.s@earthcorp.com>, and updated by Joe Nahmias <joe@nahmias.net> for the Debian GNU/Linux system (but may be used by others). It was subsequently updated by Brad Hards <bradh@frogmouth.net>, and converted to xml format by Carl Byington <carl@five-ten-sg.com>. Copyright Copyright (C) 2002 by David Smith <dave.s@earthcorp.com>. XML version Copyright (C) 2006 by 510 Software Group <carl@five-ten-sg.com>. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, please write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. CVS Version $Id$ + + + 2008-01-06 + + + + lspst + 1 + lspst @VERSION@ + + + + lspst + list PST (MS Outlook Personal Folders) file data + + + + Synopsis + + lspst + pstfile + + + + + Description + lspst is a program that can read an Outlook + PST (Personal Folders) file and produce a simple listing of the + data (contacts, email subjects, etc). + + + + + See Also + + readpstlog 1 + + + + + Author + + lspst was written by Joe Nahmias <joe@nahmias.net> based on readpst. + This man page was written by 510 Software Group <carl@five-ten-sg.com>. + + + + + Copyright + + Copyright (C) 2004 by Joe Nahmias <joe@nahmias.net>. + + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + + You should have received a copy of the GNU General Public License along + with this program; see the file COPYING. If not, please write to the + Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + + + + CVS Version + + $Id$ + + + + + - 2007-07-10 + 2008-01-06 readpstlog 1 readpstlog @VERSION@ readpstlog convert a readpst logfile to text format Synopsis readpstlog logfile Description readpstlog is a program that converts the binary logfile generated by readpst to a more desirable text format. Options -f format Sets the format of the text log output. Currently, the only valid output formats are T, for single line text, D for the default default multi line format, and I for an indented style with single line text. -t include-types Print only the specified types of log messages. Types are specified in a comma-delimited list (e.g. 3,10,5,6). -x exclude-types Exclude the specified types of log messages. Types are specified in a comma-delimited list (e.g. 3,10,5,6). Message Types readpstlog understands the following types of log messages: 1 File accesses 2 Index accesses 3 New email found 4 Warnings 5 Read accesses 6 Informational messages 7 Main function calls 8 Decrypting calls 9 Function entries 10 Function exits 11 HexDump calls Author This manual page was written by Joe Nahmias <joe@nahmias.net> for the Debian GNU/Linux system (but may be used by others). It was converted to xml format by Carl Byington <carl@five-ten-sg.com>. Copyright Copyright (C) 2002 by David Smith <dave.s@earthcorp.com>. XML version Copyright (C) 2005 by 510 Software Group <carl@five-ten-sg.com>. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, please write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. CVS Version $Id$ - 2007-07-10 + 2008-01-06 pst2ldif 1 pst2ldif @VERSION@ pst2ldif extract contacts from a MS Outlook .pst file in .ldif format Synopsis pst2ldif pstfilename Options -h Show summary of options. Subsequent options are then ignored. -V include-types Show program version. Subsequent options are then ignored. -b ldap-base Sets the ldap base value used in the dn records. You probably want to use something like "o=organization, c=US". -c class Sets the objectClass values for the contact items. This class needs to be defined in the schema used by your LDAP server, and at a minimum it must contain the ldap attributes given below. -d debug-file Specify name of debug log file. The log file is not an ascii file, it is a binary file readable by readpstlog. Description pst2ldif reads the contact information from a MS Outlook .pst file and produces a .ldif file that may be used to import those contacts into an LDAP database. The following ldap attributes are generated: cn givenName sn personalTitle company mail postalAddress l st postalCode c homePhone telephoneNumber facsimileTelephoneNumber mobile description Copyright Copyright (C) 2006 by 510 Software Group <carl@five-ten-sg.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, please write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. CVS Version $Id$ - 2007-07-10 + 2008-01-06 outlook.pst 5 outlook.pst format of MS Outlook .pst file Synopsis outlook.pst Overview Each item in a .pst file is identified by two id values ID1 and ID2. There are two separate b-trees indexed by these ID1 and ID2 values. File Header The file header is located at offset 0 in the .pst file. We only support index type 0x0E and encryption type 0x01. offsetIndex1 is the file offset of the root of the index1 b-tree, which contains (ID1, offset, size, unknown) tuples for each item in the file. backPointer1 is the value that should appear in the parent pointer of that root node. offsetIndex2 is the file offset of the root of the index2 b-tree, which contains (ID2, DESC-ID1, LIST-ID1, PARENT-ID2) tuples for each item in the file. backPointer2 is the value that should appear in the parent pointer of that root node. Index 1 Node The index1 b-tree nodes are 516 byte blocks with the following format. The itemCount specifies the number of 12 byte records that are active. The nodeLevel is non-zero for this style of nodes. The leaf nodes have a different format. The backPointer must match the backPointer from the triple that pointed to this node. Each item in this node is a triple of (ID1, backPointer, offset) where the offset points to the next deeper node in the tree, the backPointer value must match the backPointer in that deeper node, and ID1 is the lowest ID1 value in the subtree. Index 1 Leaf Node The index1 b-tree leaf nodes are 516 byte blocks with the following format. The itemCount specifies the number of 12 byte records that are active. The nodeLevel is zero for these leaf nodes. The backPointer must match the backPointer from the triple that pointed to this node. Each item in this node is a tuple of (ID1, offset, size, unknown) The two low order bits of the ID1 value seem to be flags. I have never seen a case with bit zero set. Bit one indicates that the item is not encrypted. Note that references to these ID1 values elsewhere may have the low order bit set (and I don't know what that means), but when we do the search in this tree we need to clear that bit so that we can find the correct item. Index 2 Node The index2 b-tree nodes are 516 byte blocks with the following format. The itemCount specifies the number of 12 byte records that are active. The nodeLevel is non-zero for this style of nodes. The leaf nodes have a different format. The backPointer must match the backPointer from the triple that pointed to this node. Each item in this node is a triple of (ID2, backPointer, offset) where the offset points to the next deeper node in the tree, the backPointer value must match the backPointer in that deeper node, and ID2 is the lowest ID2 value in the subtree. Index 2 Leaf Node The index2 b-tree leaf nodes are 516 byte blocks with the following format. The itemCount specifies the number of 16 byte records that are active. The nodeLevel is zero for these leaf nodes. The backPointer must match the backPointer from the triple that pointed to this node. Each item in this node is a tuple of (ID2, DESC-ID1, LIST-ID1, PARENT-ID2) Associated List Item Contains associations between id1 and id2 for the items controlled by the record. In the above leaf node, we have a tuple of (0x61, 0x02a82c, 0x02a836, 0) 0x02a836 is the ID1 of the associated list, and we can lookup that ID1 value in the index1 b-tree to find the (offset,size) of the data in the .pst file. Associated Descriptor Item 0xbcec Contains information about the item, which may be email, contact, or other outlook types. In the above leaf node, we have a tuple of (0x21, 0x00e638, 0, 0) 0x00e638 is the ID1 of the associated descriptor, and we can lookup that ID1 value in the index1 b-tree to find the (offset,size) of the data in the .pst file. Note the signature of 0xbcec. There are other descriptor block formats with other signatures. Note the indexOffset of 0x013c - starting at that position in the descriptor block, we have an array of two byte integers. The first integer (0x000b) is a (count-1) of the number of overlapping pairs following the count. The first pair is (0, 0xc), the next pair is (0xc, 0x14) and the last (12th) pair is (0x123, 0x13b). These pairs are (start,end+1) offsets of items in this block. So we have count+2 integers following the count value. Note the b5offset of 0x0020, which is a type that I will call an index reference. Such index references have at least two different forms, and may point to data either in this block, or in some other block. External pointer references have the low order 4 bits all set, and are ID2 values that can be used to fetch data. This value of 0x0020 is an internal pointer reference, which needs to be right shifted by 4 bits to become 0x0002, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0xc, 0x14) pair. Finally, we have the offset and size of the "b5" block located at offset 0xc with a size of 8 bytes in this descriptor block. The "b5" block has the following format: Note the descoffset of 0x0040, which again is an index reference. In this case, it is an internal pointer reference, which needs to be right shifted by 4 bits to become 0x0004, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0x14, 0x7c) pair. We now have the offset 0x14 of the descriptor array, composed of 8 byte entries. Each descriptor entry has the following format: For some reference types (2, 3, 0xb) the value is used directly. Otherwise, the value is an index reference, which is either an ID2 value, or an offset, to be right shifted by 4 bits and used to fetch a pair from the index table to find the offset and size of the item in this descriptor block. The following reference types are known, but not all of these are implemented in the code yet. The following item types are known, but not all of these are implemented in the code yet. Note: it appears that some types can have a IPOS value or a ID2 value depending on the size of the field in question. It is safer to check every field than for me to say what the "usually" contain. Absolute values though, are generally going to be constant. Associated Descriptor Item 0x7cec This style of descriptor block is similar to the 0xbcec format. Note the signature of 0x7cec. There are other descriptor block formats with other signatures. Note the indexOffset of 0x017a - starting at that position in the descriptor block, we have an array of two byte integers. The first integer (0x0006) is a (count-1) of the number of overlapping pairs following the count. The first pair is (0, 0xc), the next pair is (0xc, 0x14) and the last (7th) pair is (0x160, 0x179). These pairs are (start,end+1) offsets of items in this block. So we have count+2 integers following the count value. Note the 7coffset of 0x0040, which is an index reference. In this case, it is an internal reference pointer, which needs to be right shifted by 4 bits to become 0x0004, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0x14, 0xea) pair. We have the offset and size of the "7c" block located at offset 0x14 with a size of 214 bytes in this case. The "7c" block starts with a header with the following format: Note the b5Offset of 0x0020, which is an index reference. In this case, it is an internal reference pointer, which needs to be right shifted by 4 bits to become 0x0002, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0xc, 0x14) pair. Finally, we have the offset and size of the "b5" block located at offset 0xc with a size of 8 bytes in this descriptor block. The "b5" block has the following format: Note the descoffset of 0x0060, which again is an index reference. In this case, it is an internal pointer reference, which needs to be right shifted by 4 bits to become 0x0006, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0xea, 0xf0) pair. That gives us (0xf0 - 0xea)/6 = 1, so we have a recordCount of one. The actual data between 0xea and 0xf0 is unknown and unused here. Note the index2Offset above of 0x0080, which again is an index reference. In this case, it is an internal pointer reference, which needs to be right shifted by 4 bits to become 0x0008, which is then a byte offset to be added to the above indexOffset plus two (to skip the count), so it points to the (0xf0, 0x155) pair. This is an array of tables of four byte integers. We will call these the IND2 tables. The size of each of these tables is specified by the recordSize field of the "7c" header. The number of these tables is the above recordCount value derived from the "b5" block. Now the remaining data in the "7c" block after the header starts at offset 0x2a. There should be itemCount 8 byte items here, with the following format: The ind2Offset is a byte offset into the current IND2 table of some value. If that is a four byte integer value, then once we fetch that, we have the same triple (item type, reference type, value) as we find in the 0xbcec style descriptor blocks. If not, then this value is used directly. These 8 byte descriptors are processed recordCount times, each time using the next IND2 table. The item and reference types are as described above for the 0xbcec format descriptor block. Associated Descriptor Item 0x0002 This style of descriptor block is almost unknown here. It seems to contain a list of ID1 values.