# HG changeset patch # User carl # Date 1089383176 25200 # Node ID 6b1b602514dbe4404870ab410b0dbd9cd2f4fb09 Initial revision diff -r 000000000000 -r 6b1b602514db AUTHORS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AUTHORS Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,1 @@ +Dave Smith \ No newline at end of file diff -r 000000000000 -r 6b1b602514db COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff -r 000000000000 -r 6b1b602514db COPYING.rtf Binary file COPYING.rtf has changed diff -r 000000000000 -r 6b1b602514db COPYING.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING.txt Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff -r 000000000000 -r 6b1b602514db CREDITS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CREDITS Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,4 @@ +First and foremost I owe this accomplishment to the one true +God, the one who is called "I am" - He has not got an email address +yet + diff -r 000000000000 -r 6b1b602514db FILE-FORMAT --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FILE-FORMAT Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,170 @@ +File format for Outlook pst files +================================= + +Basically, we work on two indexes. One index associates an ID with each item, and the second index associates a second ID with the original ID. I see no real purpose for this yet. + +0x00 - Signature [4 bytes] (0x4E444221) +0xA8 - File Size [4 bytes] +0xC4 - Pointer to Index of all Items in File, associating the first ID [4 bytes] +0xBC - Pointer to Index of controlling Items in File [4 bytes] + +First All Items Index: - constists of a table of offsets pointing to the table of items. +====================== +repeating: +0x0 - First id in this table [4 bytes] +0x04 - Unknown [4 bytes] +0x08 - Offset of table [4 bytes] + +until "First id in this table" is zero + +Table Of Items: - Pointed to by above records. +=============== +repeating: +0x0 - Id1 of this item [4 bytes] +0x04 - Offset of this item [4 bytes] +0x08 - Size of data stored there [2 bytes] +0x0A - Unknown [2 bytes] + +until "Id1 of this item" is zero. When this is reached, you return to the above table and read the next record + +Second All Items Index: - Contains the descriptors for emails, and other items +======================= +repeating: +0x0 - First id2 of this table [4 bytes] +0x04 - Unknown [4 bytes] +0x08 - Offset of table [4 bytes] + +until "First id2 of this table" is zero + +Second Table of Items: - Pointed to by above records +====================== +repeats 0x1F times +0x0 - Id2 of this item [4 bytes] +0x04 - Id1 of the descriptor item [4 bytes] +0x08 - Id1 of the associated list [4 bytes] (this contains a list of id1 and id2 that are to with this controlling item) +0x0C - Id2 of parent [4 bytes] + + +Associated List: - pointed to by the above record. Contains associations between id1 and id2 for the items controlled by the record +================ +0x0 - Constant [2 bytes] (0x0002) +0x02 - Count [2 bytes] (the number of items that are about to follow) + +repeating +0x0 - Id2 of record [4 bytes] +0x04 - Id of record [4 bytes] - This is an association between the two +0x08 - Unknown [4 bytes] +until you have reached the "Count" + + +Descriptor Item: - Referenced from "Second Table of Items" - contains information about the item (email, contact...) +================ +0x0 - Block Offset to Block Index [2 bytes] +0x02 - Constant [2 bytes] (0xBCEC) +0x04 - Index Pos of Section1 [4 bytes] + +NOTE: An index pos can be shifted left 4 times [ i_pos << 4 ] to get an index offset (ie, an offset from the start of the block index) + + +Block Index: - contains offsets to points in the current block +============ +0x0 - Count of offsets minus one. [2 bytes] (In effect, each offset must be taken with the following one so that the start and end of the referenced item can be established. Therefore there is one extra to show the end of the last item.) + +repeating +0x0 - Block Offset [2 bytes] +until you have one extra than the "Count" + + +Section1: - Referenced from "Descriptor Item" - contains not much +========= +0x0 - Constant? [4 bytes] (0x0602B5) +0x04 - Index Pos of Descriptor fields [4 bytes] + + +Descriptor Fields: - Contain the information needed to access the details of the email +================== +repeats +0x0 - Item type [2 bytes] (subject, from, to ...) +0x02 - Reference type [2 bytes] (how to interpret the value) +0x04 - Value [4 bytes] +until the alloted size of the record has been read. (The following Block Offset from the Index has been reached) + +Reference Types: - I don't know if I have interpreted this field correctly. It might have a completely different purpose +=============== +0x0002 - +0x0003 - Value following is a value in it's own right +0x000B - +0x001E - (STRING) Value following is a Index Position (must be shifted left 4 times) +0x0040 - (DATE) " " " " " +0x0048 - +0x0102 - (STRUCTURE) " " " " " +0x1003 - +0x101E - (ARRAY OF STRING) +0x1102 - + +Value: +====== +When the value is of type Index Position, you can left shift the value 4 times to get an offset into the Block Index. Some descriptor types can have Id2 values. This is recognised by using a bitwise AND with the number. ie val & 0x0000000F. if the result is 0xF, it is likely to be a Id2 reference. + + +Descriptor Types: - Types that are in "Descriptor Fields" +================= + +All Values are Hex + +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. + +Type Ref Type Value Desc +---- -------- ----- ---- +001A [REF] IPM Context. What type of message is this +0037 001E [REF] Email Subject. The referenced item is of type "Subject Type" +0039 [REF] Date. This is likely to be the arrival date +003B [REF] Outlook Address of Sender +003F [REF] Outlook structure describing the recipient +0040 [REF] Name of the Outlook recipient structure +0041 [REF] Outlook structure describing the sender +0042 [REF] Name of the Outlook sender structure +0043 [REF] Another structure describing the recipient +0044 [REF] Name of the second recipient structure +004F [REF] Reply-To Outlook Structure +0050 [REF] Name of the Reply-To structure +0051 [REF] Outlook Name of recipient +0052 [REF] Second Outlook name of recipient +0064 [REF] Sender's Address access method (SMTP, EX) +0065 [REF] Sender's Address +0070 [REF] Processed Subject (with Fwd:, Re, ... removed) +0071 [REF] Date. Another date +0075 [REF] Recipient Address Access Method (SMTP, EX) +0076 [REF] Recipient's Address +0077 [REF] Second Recipient Access Method (SMTP, EX) +0078 [REF] Second Recipient Address +007D 001E [REF] Email Header. This is the header that was attached to the email +0C19 [REF] Second sender struct +0C1A [REF] Name of second sender struct +0C1D [REF] Second outlook name of sender +0C1E [REF] Second sender access method (SMTP, EX) +0C1F [REF] Second Sender Address +0E03 [REF] CC Address? +0E04 [REF] SentTo Address +0E06 [REF] Date. +0E07 [REF] Flag - contains IsSeen value +0FF9 [REF] binary record header +1000 001E [REF] Plain Text Email Body. Does not exist if the email doesn't have a plain text version +1013 001E [REF] HTML Email Body. Does not exist if the email doesn't have a HTML version +1035 [REF] Message ID +1042 [REF] In-Reply-To or Parent's Message ID +1046 [REF] Return Path +3001 [REF] Folder Name? I have seen this value used for the contacts record aswell +3007 [REF] Date. +3008 [REF] Date. +300B [REF] binary record header +35E0 [REF] binary record found in first item. Contains the reference to "Top of Personal Folder" item +35E3 [REF] binary record with a reference to "Deleted Items" item +35E7 [REF] binary record with a refernece to "Search Root" item +3602 [REF] the number of emails stored in a folder +3603 [REF] the number of unread emails in a folder +3613 [REF] the folder content description +8000- Contain extra bits of information that have been taken from the email's header. I call them extra lines + +Key: +[REF] = Can be either Index Position, or an Id2 Reference diff -r 000000000000 -r 6b1b602514db FILE-FORMAT.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FILE-FORMAT.html Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,69 @@ + +File Format for Outlook PST files +

Header

+
+        00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+0x00    xx xx xx xx 00 00 00 00 00 00 00 00 00 00 00 00
+...
+0xA0    00 00 00 00 00 00 00 00 xx xx xx xx 00 00 00 00
+0xB0    00 00 00 00 00 00 00 00 00 00 00 00 xx xx xx xx
+0xC0    00 00 00 00 xx xx xx xx 00 00 00 00 00 00 00 00
+
+
+ + +

Signature in Header

+

The first 4 bytes of the PST file should be 0x21 0x42 0x44 0x4E, or as an int 0x4E444221. This is the only signature I have come across and will probably work in nearly all situations.

+ +

Size of current PST file

+

This is the size of the file. If I understand correctly, then Outlook would appear to have a 2GB, or 4GB file limit. Actually, I am not sure that the whole file format could take more than 1GB.

+ +

Pointer to Index of Controlling Items

+

This is what is reffered to as the second index, or Descriptive index. These records contain pointers to the item description and a table of extra ids. These records also contain the id2# of its parent.

+

Table pointing to further tables

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx xx xx 00 00 00 00 xx xx xx xx
+
+

Leaf node table (Actual Records)

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
+
+ +

Pointer to index of ID Offsets

+

This is what is reffered to as an ID. These just basically point to offsets in the file. The do not describe what they point to. Each ID2 record that needs data not stored in it, will have an ID value that is a pointer to some data.

+

Table pointing to further tables

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx xx xx 00 00 00 00 xx xx xx xx
+
+

Leaf node table (Actual Records)

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx xx xx xx xx xx xx xx xx 00 00 
+
+ +

Association Table

+

This is a simple record associating the ID records with the ID2 records. It is nearly always the case that an item record will refer to an ID2 value. This list, which should be pre-read, will allow the ID2 values to point to file offsets. We must keep a full list of ID values in memory so that we can lookup the file offsets when required.

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    02 00 xx xx[xx xx xx xx xx xx xx xx 00 00 00 00]...
+
+ +

Description Record

+

This is a record that lists attributes of an item together with the attribute's data. It is the main place where data is stored. All data in a PST file is stored as items - from emails, to contacts, to the layout of a folder.

+ +

Block Header

+
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx EC BC xx xx xx xx
+
+OR +
+    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+    xx xx EC 7C xx xx xx xx
+
+ + + \ No newline at end of file diff -r 000000000000 -r 6b1b602514db Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,47 @@ +GCC_FLAGS=-g ${CFLAGS} + +all: readpst getidblock readpstlog dumpblocks + +libpst.o: libpst.c libpst.h define.h + gcc ${GCC_FLAGS} -c libpst.c -o libpst.o + +libstrfunc.o: libstrfunc.c libstrfunc.h + gcc ${GCC_FLAGS} -c libstrfunc.c -o libstrfunc.o + +debug.o: debug.c define.h + gcc ${GCC_FLAGS} -c debug.c -o debug.o + +lzfu.o: lzfu.c define.h + gcc ${GCC_FLAGS} -c lzfu.c -o lzfu.o + +readpst: readpst.c define.h libpst.o timeconv.o libstrfunc.o common.h debug.o lzfu.o +# ccmalloc gcc -Wall -Werror readpst.c -g -o readpst libpst.o timeconv.o libstrfunc.o debug.o +# gcc -Wall -Werror readpst.c -g -o readpst libpst.o timeconv.o libstrfunc.o debug.o lzfu.o -lefence + gcc ${GCC_FLAGS} readpst.c -o readpst libpst.o timeconv.o libstrfunc.o debug.o lzfu.o + +timeconv.o: timeconv.c timeconv.h common.h + gcc ${GCC_FLAGS} -c timeconv.c -o timeconv.o + +getidblock: getidblock.c define.h libpst.o common.h debug.o libstrfunc.o + gcc ${GCC_FLAGS} getidblock.c -o getidblock libpst.o debug.o timeconv.o libstrfunc.o + +testdebug: testdebug.c define.h debug.o + gcc ${GCC_FLAGS} testdebug.c -o testdebug debug.o libstrfunc.o + +readpstlog: readpstlog.c define.h debug.o + gcc ${GCC_FLAGS} readpstlog.c -g -o readpstlog debug.o libstrfunc.o + +dumpblocks: dumpblocks.c define.h libpst.o debug.o + gcc ${GCC_FLAGS} dumpblocks.c -o dumpblocks libpst.o debug.o libstrfunc.o timeconv.o + +clean: + rm -f core readpst libpst.o timeconv.o libstrfunc.o debug.o getidblock readpstlog testdebug dumpblocks lzfu.o *~ + +rebuild: clean all + +install: all + cp readpst /usr/local/bin + cp readpstlog /usr/local/bin/readpstlog +uninstall: + rm -f /usr/local/bin/readpst + rm -f /usr/local/bin/readpstlog diff -r 000000000000 -r 6b1b602514db README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,327 @@ +RFC reference: +RFC 1341 - base64 Mime encoding and layout of mime headers +RFC 2183 - Content-Disposition for describing email attachments +RFC 2426 - vCard definition (for saving contacts) + +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. + +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 diff -r 000000000000 -r 6b1b602514db README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,330 @@ +RFC reference: +RFC 1341 - base64 Mime encoding and layout of mime headers +RFC 2183 - Content-Disposition for describing email attachments +RFC 2426 - vCard definition (for saving contacts) + +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 diff -r 000000000000 -r 6b1b602514db Setup1.vdproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Setup1.vdproj Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,1052 @@ +"DeployProject" +{ +"VSVersion" = "3:700" +"ProjectType" = "8:{5443560c-dbb4-11d2-8724-00a0c9a8b90c}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:LibPST" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + "Entry" + { + "MsmKey" = "8:_266DA9FD3BE7441AB9E4C076D65E406A" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\AUTHORS" + } + "Entry" + { + "MsmKey" = "8:_2DA6FA8DBEA14B8381CC55D6BC6995AB" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\COPYING.RTF" + } + "Entry" + { + "MsmKey" = "8:_340CC0B2B28145F3992BF62C2A281345" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\FILE-FORMAT.HTML" + } + "Entry" + { + "MsmKey" = "8:_3F8282D501424D669B52768ED1EA6EF2" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\TODO" + } + "Entry" + { + "MsmKey" = "8:_4C206382456343BEA91EC4A76C2CA773" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\COPYING.TXT" + } + "Entry" + { + "MsmKey" = "8:_7DE8FC201860495D91028E21669FFBD0" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\FILE-FORMAT" + } + "Entry" + { + "MsmKey" = "8:_7F461C98D65D40089911C85F1A4AA613" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\RELEASE\\READLOG.EXE" + } + "Entry" + { + "MsmKey" = "8:_BAB8D23ACFC94A7A9D5B00CAA9B99898" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\RELEASE\\READPST.EXE" + } + "Entry" + { + "MsmKey" = "8:_D728B43BE8024217ACCADE69476AE4B0" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\CREDITS" + } + "Entry" + { + "MsmKey" = "8:_DF924B5495224B6FB5A02EEBFA4ABB59" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:\\\\BLESSING\\SRC\\LIBPST\\README.TXT" + } + } + "Configurations" + { + "Debug" + { + "DisplayName" = "8:Debug" + "IsDebugOnly" = "11:TRUE" + "IsReleaseOnly" = "11:FALSE" + "OutputFilename" = "8:Debug\\Setup1.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + } + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:setup\\LibPST.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + } + } + "Deployable" + { + "CustomAction" + { + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "Feature" + { + } + "File" + { + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_266DA9FD3BE7441AB9E4C076D65E406A" + { + "SourcePath" = "8:AUTHORS" + "TargetName" = "8:AUTHORS.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_2DA6FA8DBEA14B8381CC55D6BC6995AB" + { + "SourcePath" = "8:COPYING.rtf" + "TargetName" = "8:COPYING.rtf" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_340CC0B2B28145F3992BF62C2A281345" + { + "SourcePath" = "8:FILE-FORMAT.html" + "TargetName" = "8:FILE-FORMAT.html" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_3F8282D501424D669B52768ED1EA6EF2" + { + "SourcePath" = "8:TODO" + "TargetName" = "8:TODO.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_4C206382456343BEA91EC4A76C2CA773" + { + "SourcePath" = "8:COPYING.txt" + "TargetName" = "8:COPYING.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_7DE8FC201860495D91028E21669FFBD0" + { + "SourcePath" = "8:FILE-FORMAT" + "TargetName" = "8:FILE-FORMAT.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_D728B43BE8024217ACCADE69476AE4B0" + { + "SourcePath" = "8:CREDITS" + "TargetName" = "8:CREDITS.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{54DA9790-1474-11D3-8E00-00C04F6837D0}:_DF924B5495224B6FB5A02EEBFA4ABB59" + { + "SourcePath" = "8:README.txt" + "TargetName" = "8:README.txt" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + } + "FileType" + { + } + "Folder" + { + "{EE62640D-12F2-11D3-8D6C-00A0C9CFCEE6}:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + { + "DefaultLocation" = "8:[ProgramFilesFolder]\\[ProductName]" + "Name" = "8:#1925" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + } + } + "{777C097F-0ED8-11D3-8D6C-00A0C9CFCEE6}:_964BAED9D14B417FA1F1220CC3097FC4" + { + "Name" = "8:#1919" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:ProgramMenuFolder" + "Folders" + { + "{461E96AF-1495-11D3-8D6C-00A0C9CFCEE6}:_F29DF218DC6A4FB69D74598BA9E10A04" + { + "Name" = "8:LibPST" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:_C122D79760AC41F9A8E705C23A19C12D" + "Folders" + { + } + } + } + } + "{777C097F-0ED8-11D3-8D6C-00A0C9CFCEE6}:_9ADAEB5873A141F5B3CB8A3E034C6CA2" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "Shortcut" + { + "{D0C99CFE-1238-11D3-8E00-00C04F6837D0}:_58BF5F3112104CE09F31C1615D469BD3" + { + "Name" = "8:COPYING" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_2DA6FA8DBEA14B8381CC55D6BC6995AB" + "Folder" = "8:_F29DF218DC6A4FB69D74598BA9E10A04" + "WorkingFolder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Icon" = "8:" + "Feature" = "8:" + } + "{D0C99CFE-1238-11D3-8E00-00C04F6837D0}:_888B00DFF8D14174A092BCD8EFC42462" + { + "Name" = "8:Libpst Executable" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_BAB8D23ACFC94A7A9D5B00CAA9B99898" + "Folder" = "8:_F29DF218DC6A4FB69D74598BA9E10A04" + "WorkingFolder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Icon" = "8:" + "Feature" = "8:" + } + "{D0C99CFE-1238-11D3-8E00-00C04F6837D0}:_E27938998715411F870EA27ADBD07301" + { + "Name" = "8:README" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_DF924B5495224B6FB5A02EEBFA4ABB59" + "Folder" = "8:_F29DF218DC6A4FB69D74598BA9E10A04" + "WorkingFolder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Icon" = "8:" + "Feature" = "8:" + } + } + "Sequences" + { + } + "Registry" + { + "HKLM" + { + "Keys" + { + "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_995E61C8F0B346D396C71E896B18D35E" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_928E99957DFA460ABF76327134CBDD9D" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCU" + { + "Keys" + { + "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_A560F4ACAEEA4DD4BE301B08846171FD" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{7DF0CD0A-FF27-11D2-8D6B-00A0C9CFCEE6}:_F838B287CF714A46A450E9B0F023D234" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "ProjectOutput" + { + "{B1E2BB22-187D-11D3-8E02-00C04F6837D0}:_7F461C98D65D40089911C85F1A4AA613" + { + "SourcePath" = "8:Release\\readlog.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:Release|Win32" + "OutputGroupCanonicalName" = "8:Built" + "OutputProjectCanonicalName" = "8:readlog.vcproj" + "OutputProjectGuid" = "8:{DC5B4944-D652-4761-AF88-9FC2AC321FA1}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + "{B1E2BB22-187D-11D3-8E02-00C04F6837D0}:_BAB8D23ACFC94A7A9D5B00CAA9B99898" + { + "SourcePath" = "8:Release\\readpst.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_02D7B7E47B1945E2A60FC9B30A3DB4EC" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:Release|Win32" + "OutputGroupCanonicalName" = "8:Built" + "OutputProjectCanonicalName" = "8:w32pst.vcproj" + "OutputProjectGuid" = "8:{7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:LibPST 0.4.2" + "ProductCode" = "8:{051CC073-1088-45CE-B6B4-6A818D1A0C4C}" + "PackageCode" = "8:{EB46674A-D12E-4709-A10E-26AF5DA5FC2F}" + "UpgradeCode" = "8:{26048EE7-3ACA-4238-8160-9A388FF0BE0F}" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:FALSE" + "DetectNewerInstalledVersion" = "11:FALSE" + "ProductVersion" = "8:0.4.2" + "Manufacturer" = "8:LibPST" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:www.sf.net/projects/ol2mbox" + "Title" = "8:LibPST 0.4.2" + "Subject" = "8:" + "ARPCONTACT" = "8:Dave Smith" + "Keywords" = "8:" + "ARPCOMMENTS" = "8:Convert PST files to mbox files" + "ARPURLINFOABOUT" = "8:www.sf.net/projects/ol2mbox" + "ARPPRODUCTICON" = "8:" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + } + "MergeModule" + { + } + "UserInterface" + { + "{E4ECAB26-4AB7-11D3-8D78-00A0C9CFCEE6}:_022695AADC7645C6AD4D996A924BADB0" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + "ModuleSignature" = "8:VsdUserInterface.524F4245_5254_5341_4C45_534153783400" + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_4D31ADFC1DDC4E8DB34CFC315F68CE34" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_6F5F0C0A1AEA4E7BBE611CEEA4CDD96B" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "ModuleSignature" = "8:VsdDialogs.2DED2424_5429_4616_A1AD_4D62837C2ADA" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_7965A4F2A58F45878A12917BA74B747A" + { + "Sequence" = "3:110" + "DisplayName" = "8:License Agreement" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminLicenseDlg.wid" + "ModuleSignature" = "8:VsdDialogs.836CEFDB_3154_4E4C_84F8_DC115871E5E1" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "EulaText" + { + "Name" = "8:EulaText" + "DisplayName" = "8:#1008" + "Description" = "8:#1108" + "Type" = "3:6" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:_2DA6FA8DBEA14B8381CC55D6BC6995AB" + "UsePlugInResources" = "11:TRUE" + } + "Sunken" + { + "Name" = "8:Sunken" + "DisplayName" = "8:#1007" + "Description" = "8:#1107" + "Type" = "3:5" + "ContextData" = "8:4;True=4;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:4" + "DefaultValue" = "3:4" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_903D207433054D92BFD487087BBD066A" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "ModuleSignature" = "8:VsdDialogs.FA58E60A_A1E8_4876_95FC_2AC3B5AAA5F8" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_A4A1C5B85FAB4F92A3B4EEC34BBBD96D" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "ModuleSignature" = "8:VsdDialogs.E35A0E2C_F131_4B57_B946_59A1A2A8F45F" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8: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." + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_4F5559A7DEAB4DE2925C542BBB3A9F85" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_B1E07CF844E3483E82198DD9386DA673" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "ModuleSignature" = "8:VsdDialogs.EE9A1AFA_41DD_4514_B727_DF0ACA1D7389" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_7A173552C86C4E688960FE54E12232EA" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_37E4508ABFDD42BDB58BAE10301345DA" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "ModuleSignature" = "8:VsdDialogs.6DBC9783_3677_4D68_8BF5_D749558A0AC1" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_413518D7364F4D138DC324363B89A71F" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "ModuleSignature" = "8:VsdDialogs.68F69290_BB7C_474E_A153_6679845F3DDF" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8: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." + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_7562C9CDD20B4E789E62146FD5A2F988" + { + "Sequence" = "3:110" + "DisplayName" = "8:License Agreement" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdLicenseDlg.wid" + "ModuleSignature" = "8:VsdDialogs.8FA7D956_B864_4FF4_92F0_FB2799B33176" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "EulaText" + { + "Name" = "8:EulaText" + "DisplayName" = "8:#1008" + "Description" = "8:#1108" + "Type" = "3:6" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:_2DA6FA8DBEA14B8381CC55D6BC6995AB" + "UsePlugInResources" = "11:TRUE" + } + "Sunken" + { + "Name" = "8:Sunken" + "DisplayName" = "8:#1007" + "Description" = "8:#1107" + "Type" = "3:5" + "ContextData" = "8:4;True=4;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:4" + "DefaultValue" = "3:4" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_EF43D4AB2DFD477E91C34CC588F44083" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "ModuleSignature" = "8:VsdDialogs.C113BC36_2532_4D45_8099_4818B1133B2F" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_835654FC087041D3B4610A66F9E340AF" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_33A87B3E5EB64385A6C24862B4F1E9C6" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "ModuleSignature" = "8:VsdDialogs.83D22742_1B79_46f6_9A99_DF0F2BD4C077" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{E4ECAB26-4AB7-11D3-8D78-00A0C9CFCEE6}:_8CA4D8B70C5A4D2498C79F9B7CA0C023" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + "ModuleSignature" = "8:VsdDialogs.CE4B864F_F1C1_4B85_98D4_2A2BF5FFB12B" + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_AB25D6EB5E7140B397000436C87D1D5E" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_12DABCAD3D524B38A88CFDB189826E73" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "ModuleSignature" = "8:VsdDialogs.4FB12620_0D15_42D0_8677_2766FFA6923F" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{7DFFC192-4ABE-11D3-8D78-00A0C9CFCEE6}:_E64115E41D964A25BA1E40221BA371AE" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{E4ECAB24-4AB7-11D3-8D78-00A0C9CFCEE6}:_3D878C0BB5664F24B73D17D0D0C4F1AA" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "ModuleSignature" = "8:VsdDialogs.1DB77F5A_BA5C_4470_89B6_0B0EC07E3A10" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + } +} diff -r 000000000000 -r 6b1b602514db TODO diff -r 000000000000 -r 6b1b602514db XGetopt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XGetopt.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,199 @@ +// XGetopt.cpp Version 1.1 +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// +// Modified: David Smith +// dave.s@earthcorp.com +// Moved two char declarations from body of function so +// that it can compile as a C function. +// Thanks so much Hans +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "XGetopt.h" + +/////////////////////////////////////////////////////////////////////////////// +// +// X G e t o p t . c p p +// +// +// NAME +// getopt -- parse command line options +// +// SYNOPSIS +// int getopt(int argc, char *argv[], char *optstring) +// +// extern char *optarg; +// extern int optind; +// +// DESCRIPTION +// The getopt() function parses the command line arguments. Its +// arguments argc and argv are the argument count and array as +// passed into the application on program invocation. In the case +// of Visual C++ programs, argc and argv are available via the +// variables __argc and __argv (double underscores), respectively. +// getopt returns the next option letter in argv that matches a +// letter in optstring. +// +// optstring is a string of recognized option letters; if a letter +// is followed by a colon, the option is expected to have an argument +// that may or may not be separated from it by white space. optarg +// is set to point to the start of the option argument on return from +// getopt. +// +// Option letters may be combined, e.g., "-ab" is equivalent to +// "-a -b". Option letters are case sensitive. +// +// getopt places in the external variable optind the argv index +// of the next argument to be processed. optind is initialized +// to 0 before the first call to getopt. +// +// When all options have been processed (i.e., up to the first +// non-option argument), getopt returns EOF, optarg will point +// to the argument, and optind will be set to the argv index of +// the argument. If there are no non-option arguments, optarg +// will be set to NULL. +// +// The special option "--" may be used to delimit the end of the +// options; EOF will be returned, and "--" (and everything after it) +// will be skipped. +// +// RETURN VALUE +// For option letters contained in the string optstring, getopt +// will return the option letter. getopt returns a question mark (?) +// when it encounters an option letter not included in optstring. +// EOF is returned when processing is finished. +// +// BUGS +// 1) Long options are not supported. +// 2) The GNU double-colon extension is not supported. +// 3) The environment variable POSIXLY_CORRECT is not supported. +// 4) The + syntax is not supported. +// 5) The automatic permutation of arguments is not supported. +// 6) This implementation of getopt() returns EOF if an error is +// encountered, instead of -1 as the latest standard requires. +// +// EXAMPLE +// BOOL CMyApp::ProcessCommandLine(int argc, char *argv[]) +// { +// int c; +// +// while ((c = getopt(argc, argv, "aBn:")) != EOF) +// { +// switch (c) +// { +// case 'a': +// TRACE(_T("option a\n")); +// // +// // set some flag here +// // +// break; +// +// case 'B': +// TRACE( _T("option B\n")); +// // +// // set some other flag here +// // +// break; +// +// case 'n': +// TRACE(_T("option n: value=%d\n"), atoi(optarg)); +// // +// // do something with value here +// // +// break; +// +// case '?': +// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); +// return FALSE; +// break; +// +// default: +// TRACE(_T("WARNING: no handler for option %c\n"), c); +// return FALSE; +// break; +// } +// } +// // +// // check for non-option args here +// // +// return TRUE; +// } +// +/////////////////////////////////////////////////////////////////////////////// + +char *optarg; // global argument pointer +int optind = 0; // global argv index + +int getopt(int argc, char *argv[], char *optstring) +{ + static char *next = NULL; + char c, *cp; + if (optind == 0) + next = NULL; + + optarg = NULL; + + if (next == NULL || *next == '\0') + { + if (optind == 0) + optind++; + + if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') + { + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + if (strcmp(argv[optind], "--") == 0) + { + optind++; + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + next = argv[optind]+1; + optind++; + } + + c = *next++; + cp = strchr(optstring, c); + + if (cp == NULL || c == ':') + return '?'; + + cp++; + if (*cp == ':') + { + if (*next != '\0') + { + optarg = next; + next = NULL; + } + else if (optind < argc) + { + optarg = argv[optind]; + optind++; + } + else + { + return '?'; + } + } + + return c; +} diff -r 000000000000 -r 6b1b602514db XGetopt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XGetopt.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,23 @@ +// XGetopt.h +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XGETOPT_H +#define XGETOPT_H + +extern int optind, opterr; +extern char *optarg; + +int getopt(int argc, char *argv[], char *optstring); + +#endif //XGETOPT_H diff -r 000000000000 -r 6b1b602514db common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,22 @@ + +#ifndef __COMMON_H +#define __COMMON_H + +#ifndef _WIN32 + typedef unsigned int DWORD; + typedef unsigned short int WORD; + typedef unsigned char BYTE; + typedef unsigned int UINT32; + +# pragma pack (1) + +# ifndef FILETIME_DEFINED +# define FILETIME_DEFINED + /*Win32 Filetime struct - copied from WINE*/ + typedef struct { + unsigned int dwLowDateTime; + unsigned int dwHighDateTime; + } FILETIME; +# endif +#endif // _WIN32 +#endif // __COMMON_H diff -r 000000000000 -r 6b1b602514db debug.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,443 @@ +/* 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_init(char *fname); +void _debug_msg_info (int line, char *file, int type); +void _debug_msg(char* fmt, ...); +void _debug_hexdump(char *x, int y, int cols); +void _debug_func(char *function); +void _debug_func_ret(); +void _debug_close(); +void _debug_write(); +void _debug_write_msg(struct _debug_item *item, char *fmt, va_list *ap, int size); +void _debug_write_hex(struct _debug_item *item, 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 off = 0, toff; + int count = 0; + + if (col == -1) { + col = NUM_COL; + } + fprintf(out, "\n"); + while (off < size) { + fprintf(out, "%X\t:", off); + 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"); +} + +void _pst_debug_hexprint(char *data, int size) { + int i = 0; + while (i < size) { + fprintf(stderr, "%02hhX", data[i]); + i++; + } +} + +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 != NULL) + _debug_close(); + 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 == NULL) { + fprintf(stderr, "debug_fp is NULL\n"); + return; + } + 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 == NULL) + return; + va_start(ap, fmt); + // get the record off of the temp_list + info_ptr = temp_list; + if (info_ptr != NULL) + 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 + + if (f > 0 && f < MAX_MESSAGE_SIZE) { + info_ptr->text = (char*) xmalloc(f+1); + 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); + } + 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; + _debug_write_msg(info_ptr, fmt, &ap, f); + 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"; + } + va_end(ap); + + if (item_head == NULL) + item_head = info_ptr; + + info_ptr->next = NULL; + if (item_tail != NULL) + 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(char *x, int y, int cols) { + struct _debug_item *temp; + if (debug_fp == NULL) + return; + info_ptr = temp_list; + if (info_ptr != NULL) + 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 != NULL) { + 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 != NULL) { + func_ptr = func_head; + func_head = func_head->next; + free(func_ptr->name); + free(func_ptr); + } + + if (debug_fp != NULL) + fclose(debug_fp); + debug_fp = NULL; + + if (func_head != NULL) + while (func_head != NULL) { + printf("function '%s' still on stack\n", func_head->name); + func_head = func_head->next; + } +} + +void _debug_write() { + size_t size, ptr, funcname, filename, text, end; + char *buf, rec_type; + long index_pos = ftell (debug_fp), 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_ptr = 0; + struct _debug_file_rec_m mfile_rec; + struct _debug_file_rec_l lfile_rec; + + if (curr_items == 0) + // no items to write. + return; + index = (int*) xmalloc(index_size); + 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 != NULL) { + 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 + 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); + 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); +} + +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 = malloc(index_size); + int index_pos, file_pos; + char zero='\0'; + unsigned int end; + 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); + // that should do it... +} + +void _debug_write_hex(struct _debug_item *item, 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 = malloc(index_size); + int index_pos, file_pos; + char zero='\0'; + index[0] = 1; // only one item in this index run + 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.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); + + 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); + fwrite(&zero, 1, 1, debug_fp); + 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 == NULL) { + fprintf(stderr, "xMalloc: Out Of memory [req: %ld]\n", (long)size); + exit(1); + } + return mem; +} + diff -r 000000000000 -r 6b1b602514db define.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/define.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,201 @@ +/*** + * define.h + * Part of the LibPST project + * Written by David Smith + * dave.s@earthcorp.com + */ + +//#define DEBUG_ALL +#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 +//#define DEBUG_MODE_DECRYPT +#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_FUNC_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); +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(char *x, int y, int cols); +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);} +#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);} +#define DEBUG_HEXDUMPC(x, s, c)\ + {_debug_msg_info(__LINE__, __FILE__, DEBUG_HEXDUMP_NO);\ + _debug_hexdump(x, s, c);} +#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) \ + {MESSAGEPRINT(("Entering function %s\n",x),DEBUG_FUNC_NO);\ + _debug_func(x);} +# define DEBUG_RET() {MESSAGEPRINT(("Leaving function\n"),DEBUG_FUNC_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 -r 000000000000 -r 6b1b602514db dumpblocks.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dumpblocks.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,85 @@ +#include +#include +#include +#include "libpst.h" +#include "define.h" + +#define OUT_BUF 20 +int main(int argc, char **argv) { + pst_file pstfile; + pst_index_ll *ptr; + char *outdir=NULL, *file=NULL, *outname=NULL; + unsigned char *buf=NULL; + int c; + FILE *fp; + + while ((c=getopt(argc, argv, "o:"))!=-1) { + switch(c) { + case 'o': + outdir=optarg; + break; + default: + printf("Unknown switch %c\n", c); + } + } + if (optind < argc) { + file = argv[optind]; + } else { + printf("Usage: dumpblocks [options] pstfile\n"); + printf("\tcopies the datablocks from the pst file into seperate files\n"); + printf("Options: \n"); + printf("\t-o target\tSpecify the output directory\n"); + exit(1); + } + DEBUG_INIT("dumpblocks.log"); + DEBUG_REGISTER_CLOSE(); + DEBUG_ENT("main"); + + printf("Opening file %s\n",file); + if (pst_open(&pstfile, file, "r")) { + printf("Failed to open file %s\n", file); + exit(1); + } + + printf("Reading Indexes\n"); + if (pst_load_index(&pstfile)) { + printf("Failed to load indexes in file %s\n", argv[1]); + exit(1); + } + + if (outdir != NULL) + if (chdir(outdir)) { + printf("Failed to change into directory %s\n", outdir); + exit(1); + } + + ptr = pstfile.i_head; + outname = (char*) xmalloc(OUT_BUF); + printf("Saving blocks\n"); + while (ptr != NULL) { + /* if (pstfile.encryption == PST_ENC) { + c = _pst_ff_getIDblock_dec(&pstfile, ptr->id, buf); + } else {*/ + if ((ptr->id & 0x02)==0 && pstfile.encryption == PST_ENC) { + c = _pst_ff_getIDblock_dec(&pstfile, ptr->id, &buf); + } else { + c = _pst_ff_getIDblock(&pstfile, ptr->id, &buf); + } + + if (c > 0) { + snprintf(outname, OUT_BUF, "%x", ptr->id); + if ((fp = fopen(outname, "wb")) == NULL) { + printf("Failed to open file %s\n", outname); + continue; + } + fwrite(buf, 1, c, fp); + fclose(fp); + } else { + printf("Failed to read block id %#x\n", ptr->id); + } + ptr = ptr->next; + } + pst_close(&pstfile); + DEBUG_RET(); + return 0; +} diff -r 000000000000 -r 6b1b602514db getidblock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/getidblock.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,139 @@ +#include +#include + +#ifndef __GNUC__ +# include "XGetopt.h" +#endif + +#ifndef _WIN32 +# include +#endif + +#include "define.h" +#include "libpst.h" + +static void usage(); + +int main(int argc, char ** argv) { + // pass the id number to display on the command line + char *fname, *sid; + pst_file pstfile; + unsigned int id; + int decrypt = 0, process = 0, binary = 0, c; + unsigned char *buf = NULL; + size_t readSize; + pst_item *item; + pst_desc_ll* ptr; + + DEBUG_INIT("getidblock.log"); + DEBUG_REGISTER_CLOSE(); + DEBUG_ENT("main"); + + while ((c = getopt(argc, argv, "bdp")) != -1) { + switch (c) { + case 'b': + // enable binary output + binary = 1; + break; + case 'd': + //enable decrypt + decrypt = 1; + break; + case 'p': + // enable procesing of block + process = 1; + break; + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (optind+1 >= argc) { + // no more items on the cmd + usage(); + exit(EXIT_FAILURE); + } + fname = argv[optind]; + sid = argv[optind+1]; + id = (unsigned int)strtol(sid, NULL, 0); + + DEBUG_MAIN(("Opening file\n")); + memset(&pstfile, 0, sizeof(pstfile)); + if (pst_open(&pstfile, fname, "r")!=0) { + DIE(("Error opening file\n")); + } + + DEBUG_MAIN(("Loading Index\n")); + if (pst_load_index(&pstfile) != 0) { + DIE(("Error loading file index\n")); + } + + // if ((ptr = _pst_getID(&pstfile, id)) == NULL) { + // DIE(("id not found [%#x]\n", id)); + // } + + DEBUG_MAIN(("Loading block\n")); + + if ((readSize = _pst_ff_getIDblock(&pstfile, id, &buf)) <= 0 || buf == NULL) { + // if ((readSize = _pst_read_block_size(&pstfile, ptr->offset, ptr->size, &buf, 1, 1)) < ptr->size) { + DIE(("Error loading block\n")); + } + if (binary==0) printf("Block %#x, size %#x[%i]\n",id, (unsigned int)readSize, (int) readSize); + + if (decrypt!=0) + if (_pst_decrypt(buf, readSize, (int)pstfile.encryption) != 0) { + DIE(("Error decrypting block\n")); + } + + DEBUG_MAIN(("Printing block... [id %#x, size %#x]\n", id, readSize)); + if (binary==0) { + _pst_debug_hexdump(stdout, buf, readSize, 0x10); + } else { + if (fwrite(buf, 1, readSize, stdout) != 0) { + DIE(("Error occured during writing of buf to stdout\n")); + } + } + free(buf); + + if (process!=0) { + DEBUG_MAIN(("Parsing block...\n")); + ptr = pstfile.d_head; + while(ptr != NULL) { + if (ptr->list_index != NULL && ptr->list_index->id == id) + break; + if (ptr->desc != NULL && ptr->desc->id == id) + break; + ptr = pst_getNextDptr(ptr); + } + if (ptr == NULL) { + ptr = (pst_desc_ll*)xmalloc(sizeof(pst_desc_ll)); + ptr->desc = _pst_getID(&pstfile, id); + ptr->list_index = NULL; + } + if (ptr != NULL) { + if ((item = _pst_parse_item(&pstfile, ptr)) != NULL) + _pst_freeItem(item); + } else { + DEBUG_MAIN(("item not found with this ID\n")); + printf("Cannot find the owning Record of this ID. Cannot parse\n"); + } + } + + if(pst_close(&pstfile)!=0) { + DIE(("pst_close failed\n")); + } + + DEBUG_RET(); + return 0; +} + +void usage() { + printf("usage: getidblock [options] filename id\n"); + printf("\tfilename - name of the file to access\n"); + printf("\tid - ID of the block to fetch - can begin with 0x for hex\n"); + printf("\toptions\n"); + printf("\t\t-d\tDecrypt the block before printing\n"); + printf("\t\t-p\tProcess the block before finishing.\n"); + printf("\t\t\tView the debug log for information\n"); +} diff -r 000000000000 -r 6b1b602514db libpst.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpst.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,4250 @@ +/*** + * libpst.c + * Part of the LibPST project + * Written by David Smith + * dave.s@earthcorp.com + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include //mkdir +#include // for Win32 definition of _O_BINARY +#include "define.h" +#include "libstrfunc.h" + +#ifdef _MSC_VER +# include +#else +# include +#endif //ifdef _MSC_VER + +//#include +//#include + +#include "libpst.h" +#include "timeconv.h" + +//#ifdef _MSC_VER +//#include "windows.h" +//#define WARN printf +//#define DEBUG_INFO printf +//#define DEBUG_EMAIL printf +//#define DEBUG_READ printf +//#define DEBUG_DECRYPT printf +//#define DEBUG_CODE printf +//#define DEBUG_INDEX printf +//#define DEBUG_WARN printf +//#define DEBUG printf +// +//#define LE32_CPU(x) {} +//#define LE16_CPU(x) {} +//#endif // _MSC_VER + +#define FILE_SIZE_POINTER 0xA8 +#define INDEX_POINTER 0xC4 +#define SECOND_POINTER 0xBC +#define INDEX_DEPTH 0x4C +#define SECOND_DEPTH 0x5C +// 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 PST_SIGNATURE 0x4E444221 + +struct _pst_table_ptr_struct{ + int32_t start; + int32_t u1; + int32_t offset; +}; + +typedef struct _pst_block_header { + int16_t type; + int16_t count; +} pst_block_header; + +typedef struct _pst_id2_assoc { + int32_t id2; + int32_t id; + int32_t table2; +} pst_id2_assoc; + +// this is an array of the un-encrypted values. the un-encrypyed 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 +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*/ + +int32_t pst_open(pst_file *pf, char *name, char *mode) { + u_int32_t sig; + // unsigned char ind_type; + + DEBUG_ENT("pst_open"); +#ifdef _MSC_VER + // set the default open mode for windows + _fmode = _O_BINARY; +#endif //_MSC_VER + + if (pf == NULL) { + WARN (("cannot be passed a NULL pst_file\n")); + DEBUG_RET(); + return -1; + } + memset(pf, 0, sizeof(pst_file)); + + if ((pf->fp = fopen(name, mode)) == NULL) { + WARN(("cannot open PST file. Error\n")); + DEBUG_RET(); + return -1; + } + 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; + } + + // architecture independant byte-swapping (little, big, pdp) + 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; + } + _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; + } + + _pst_getAtPos(pf->fp, ENC_OFFSET, &(pf->encryption), sizeof(unsigned char)); + DEBUG_INFO(("encrypt = %i\n", pf->encryption)); + // pf->encryption = encrypt; + + _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); + + _pst_getAtPos(pf->fp, FILE_SIZE_POINTER, &(pf->size), sizeof(pf->size)); + LE32_CPU(pf->size); + + // very tempting to leave these values set way too high and let the exploration of the tables set them... + pf->index1_depth = pf->index2_depth = 255; + + DEBUG_INFO(("Pointer2 is %#X, count %i[%#x], depth %#x\n", + pf->index2, pf->index2_count, pf->index2_count, pf->index2_depth)); + _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], depth %#x\n", + pf->index1, pf->index1_count, pf->index1_count, pf->index1_depth)); + pf->id_depth_ok = 0; + pf->desc_depth_ok = 0; + DEBUG_RET(); + return 0; +} + +int32_t pst_close(pst_file *pf) { + DEBUG_ENT("pst_close"); + if (pf->fp == NULL) { + 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; + // pst_item *i; + // char *a, *b; + // int x,z; + DEBUG_ENT("pst_getTopOfFolders"); + if (root == NULL || root->message_store == NULL + /* || (root->message_store->top_of_personal_folder == NULL + && root->message_store->top_of_folder == NULL)*/) { + DEBUG_INDEX(("There isn't a top of folder record here.\n")); + ret = NULL; + } else if (root->message_store->top_of_personal_folder == NULL) { + // 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 != NULL) { + size = _pst_ff_getID2data(pf,ptr, &h); + } else { + DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n")); + } + attach->size = size; // may aswell 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 != NULL) { + size = _pst_ff_getID2data(pf, ptr, &h); + } else { + DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n")); + } + 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 != NULL) { + 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); + pst_fwrite(c, 1, strlen(c), fp); + } else { + DEBUG_WARN (("Couldn't find ID pointer. Cannot save attachement to Base64\n")); + } + attach->size = size; + } else { + // encode the attachment to the file + c = base64_encode(attach->data, attach->size); + pst_fwrite(c, 1, strlen(c), fp); + size = attach->size; + } + DEBUG_RET(); + return 1; +} + +int32_t pst_load_index (pst_file *pf) { + int32_t x,y; + DEBUG_ENT("pst_load_index"); + if (pf == NULL) { + WARN(("Cannot load index for a NULL pst_file\n")); + DEBUG_RET(); + return -1; + } + + x = _pst_build_id_ptr(pf, pf->index1, 0, -1, INT32_MAX); + if (x == -1 || x == 4) { + if (x == -1) + pf->index1_depth = 0; //only do this for -1 + DEBUG_INDEX(("Re-calling _pst_build_id_ptr cause we started with too grand an idea!!!\n")); + if (_pst_build_id_ptr(pf, pf->index1, 0, 0x4, INT32_MAX) == -1) { + //we must call twice for testing the depth of the index + DEBUG_RET(); + return -1; + } + } + + DEBUG_INDEX(("Second Table\n")); + y = -1; + x = _pst_build_desc_ptr(pf, pf->index2, 0, &y, 0x21, INT32_MAX); + if (x == -1 || x == 4) { + if (x == -1) + pf->index2_depth = 0; //only if -1 is return val + + if (_pst_build_desc_ptr(pf, pf->index2, 0, &y, 0x21, INT32_MAX) == -1) { + // we must call twice for testing the depth of the index + DEBUG_RET(); + return -1; + } + } + + 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 != NULL) { + if ((r = d->child) == NULL) { + while(d->next == NULL && d->parent != NULL) + 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; +} 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_index_ll *list; + pst_index2_ll *list2;//, *t; + 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; + char *wt; + + 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->list_index != NULL) { + list2 = _pst_build_id2(pf, p->list_index, NULL); + } + if (p->desc == NULL) { + DEBUG_WARN(("desc is NULL for item 0x61. Cannot load Extended Attributes\n")); + DEBUG_RET(); + return 0; + } + if ((na = _pst_parse_block(pf, p->desc->id, list2)) == NULL) { + DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n")); + 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 == NULL) { + 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) { + // 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); + 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 != NULL && ptr->map > p_sh->map) { + p_sh2 = p_sh; + p_sh = p_sh->next; + } + if (p_sh2 == NULL) { + // 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 (buffer) + free(buffer); + if (headerbuffer) + free(headerbuffer); + pf->x_head = p_head; + DEBUG_RET(); + return 1; +} + +#define BLOCK_SIZE 516 + +int32_t _pst_build_id_ptr(pst_file *pf, int32_t offset, int32_t depth, int32_t start_val, int32_t end_val) { + struct _pst_table_ptr_struct table, table2; + pst_index_ll *i_ptr=NULL; + pst_index index; + // int fpos = ftell(pf->fp); + int32_t x, ret; + int32_t old = start_val; + char *buf = NULL, *bptr = NULL; + + DEBUG_ENT("_pst_build_id_ptr"); + if (pf->index1_depth - depth == 0) { + // we must be at a leaf table. These are index items + DEBUG_INDEX(("Reading Items\n")); + // fseek(pf->fp, offset, SEEK_SET); + x = 0; + + if (_pst_read_block_size(pf, offset, BLOCK_SIZE, &buf, 0, 0) < BLOCK_SIZE) { + DEBUG_WARN(("Not read the full block size of the index. There is a problem\n")); + DEBUG_RET(); + return -1; + } + bptr = buf; + // DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); + memcpy(&index, bptr, sizeof(index)); + LE32_CPU(index.id); + LE32_CPU(index.offset); + LE16_CPU(index.size); + LE16_CPU(index.u1); + bptr += sizeof(index); + + while(index.id != 0 && x < 42 && bptr < buf+BLOCK_SIZE && index.id < end_val) { + 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 (start_val != -1 && index.id != start_val) { + DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n")); + DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); + // fseek(pf->fp, fpos, SEEK_SET); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } else { + start_val = -1; + pf->id_depth_ok = 1; + } + // u1 could be a flag. if bit 0x2 is not set, it might be deleted + // if (index.u1 & 0x2 || index.u1 & 0x4) { + // ignore the above condition. it doesn't appear to hold + if (old > index.id) { // then we have back-slid on the new values + DEBUG_INDEX(("Back slider detected - Old value [%#x] greater than new [%#x]. Progressing to next table\n", old, index.id)); + DEBUG_RET(); + return 2; + } + old = index.id; + 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 != NULL) + pf->i_tail->next = i_ptr; + if (pf->i_head == NULL) + pf->i_head = i_ptr; + pf->i_tail = i_ptr; + memcpy(&index, bptr, sizeof(index)); + LE32_CPU(index.id); + LE32_CPU(index.offset); + LE16_CPU(index.size); + LE16_CPU(index.u1); + bptr += sizeof(index); + } + // fseek(pf->fp, fpos, SEEK_SET); + if (x < 42) { // we have stopped prematurley. Why? + if (index.id == 0) { + DEBUG_INDEX(("Found index.id == 0\n")); + } else if (!(bptr < buf+BLOCK_SIZE)) { + DEBUG_INDEX(("Read past end of buffer\n")); + } else if (index.id >= end_val) { + DEBUG_INDEX(("index.id[%x] > end_val[%x]\n", + index.id, end_val)); + } else { + DEBUG_INDEX(("Stopped for unknown reason\n")); + } + } + if (buf) free (buf); + DEBUG_RET(); + return 2; + } else { + // this is then probably a table of offsets to more tables. + DEBUG_INDEX(("Reading Table Items\n")); + + x = 0; + ret = 0; + + if (_pst_read_block_size(pf, offset, BLOCK_SIZE, &buf, 0, 0) < BLOCK_SIZE) { + DEBUG_WARN(("Not read the full block size of the index. There is a problem\n")); + DEBUG_RET(); + return -1; + } + bptr = buf; + // DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); + + memcpy(&table, bptr, sizeof(table)); + LE32_CPU(table.start); + LE32_CPU(table.u1); + LE32_CPU(table.offset); + bptr += sizeof(table); + memcpy(&table2, bptr, sizeof(table)); + LE32_CPU(table2.start); + LE32_CPU(table2.u1); + LE32_CPU(table2.offset); + + if (start_val != -1 && table.start != start_val) { + DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); + DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } + + while (table.start != 0 && bptr < buf+BLOCK_SIZE && table.start < end_val) { + DEBUG_INDEX(("[%i] %i Table [start id = %#x, u1 = %#x, offset = %#x]\n", depth, ++x, table.start, table.u1, table.offset)); + + if (table2.start <= table.start) + // this should only be the case when we come to the end of the table + // and table2.start == 0 + table2.start = end_val; + + if ((ret = _pst_build_id_ptr(pf, table.offset, depth+1, table.start, table2.start)) == -1 && pf->id_depth_ok == 0) { + // it would appear that if the table below us isn't a table, but data, then we are actually the table. hmmm + DEBUG_INDEX(("Setting max depth to %i\n", depth)); + pf->index1_depth = depth; //set max depth to this level + if (buf) free (buf); + // fseek(pf->fp, fpos, SEEK_SET); + DEBUG_RET(); + return 4; // this will indicate that we want to be called again with the same parameters + } else if (ret == 4) { + //we shan't bother with checking return value? + DEBUG_INDEX(("Seen that a max depth has been set. Calling build again\n")); + _pst_build_id_ptr(pf, table.offset, depth+1, table.start, table2.start); + } else if (ret == 2) { + DEBUG_INDEX(("child returned successfully\n")); + } else { + DEBUG_INDEX(("child has returned without a known error [%i]\n", ret)); + } + memcpy(&table, bptr, sizeof(table)); + LE32_CPU(table.start); + LE32_CPU(table.u1); + LE32_CPU(table.offset); + bptr += sizeof(table); + memcpy(&table2, bptr, sizeof(table)); + LE32_CPU(table2.start); + LE32_CPU(table2.u1); + LE32_CPU(table2.offset); + } + + if (table.start == 0) { + DEBUG_INDEX(("Table.start == 0\n")); + } else if (bptr >= buf+BLOCK_SIZE) { + DEBUG_INDEX(("Read past end of buffer\n")); + } else if (table.start >= end_val) { + DEBUG_INDEX(("Table.start[%x] > end_val[%x]\n", + table.start, end_val)); + } else { + DEBUG_INDEX(("Table reading stopped for an unknown reason\n")); + } + + if (buf) free (buf); + DEBUG_INDEX(("End of table of pointers\n")); + DEBUG_RET(); + return 3; + } + DEBUG_WARN(("ERROR ** Shouldn't be here!\n")); + + DEBUG_RET(); + return 1; +} + +#define DESC_BLOCK_SIZE 520 +int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t *high_id, int32_t start_id, + int32_t end_val) { + struct _pst_table_ptr_struct table, table2; + pst_desc desc_rec; + pst_desc_ll *d_ptr=NULL, *d_par=NULL; + int32_t i = 0, y, prev_id=-1; + char *buf = NULL, *bptr; + + struct _pst_d_ptr_ll { + pst_desc_ll * ptr; + int32_t parent; // used for lost and found lists + struct _pst_d_ptr_ll * next; + struct _pst_d_ptr_ll * prev; + } *d_ptr_head=NULL, *d_ptr_tail=NULL, *d_ptr_ptr=NULL, *lf_ptr=NULL, *lf_head=NULL, *lf_shd=NULL, *lf_tmp; + // lf_ptr and lf_head are used for the lost/found list. If the parent isn't found yet, put it on this + // list and check it each time you read a new item + + int32_t d_ptr_count = 0; + DEBUG_ENT("_pst_build_desc_ptr"); + if (pf->index2_depth-depth == 0) { + // leaf node + if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { + DEBUG_WARN(("I didn't get all the index that I wanted. _pst_read_block_size returned less than requested\n")); + DEBUG_RET(); + return -1; + } + bptr = buf; + + //DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); + + 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); + + if (end_val <= start_id) { + DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#x, end:%#x]\n", + start_id, end_val)); + } + + while (i < 0x1F && desc_rec.d_id < end_val && (prev_id == -1 || desc_rec.d_id > prev_id)) { + DEBUG_INDEX(("[%i] Item(%#x) = [d_id = %#x, desc_id = %#x, " + "list_id = %#x, parent_id = %#x]\n", depth, i, desc_rec.d_id, + desc_rec.desc_id, desc_rec.list_id, desc_rec.parent_id)); + i++; + + if (start_id != -1 && desc_rec.d_id != start_id) { + DEBUG_INDEX(("Error: This table appears to be corrupt. Perhaps" + " we are looking too deep!\n")); + if (buf) free(buf); + DEBUG_RET(); + return -1; + } else { + start_id = -1; + pf->desc_depth_ok = 1; + } + + if (desc_rec.d_id == 0) { + 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); + continue; + } + prev_id = desc_rec.d_id; + + // 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)) != NULL) { + 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 != NULL && 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 != NULL) + d_ptr->prev->next = d_ptr->next; + else if (d_ptr->parent != NULL) + d_ptr->parent->child = d_ptr->next; + else + pf->d_head = d_ptr->next; + + if (d_ptr->next != NULL) + d_ptr->next->prev = d_ptr->prev; + else if (d_ptr->parent != NULL) + 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; + + // ok, now place in correct place + DEBUG_INDEX(("Searching for parent\n")); + if (desc_rec.parent_id == 0) { + DEBUG_INDEX(("No Parent\n")); + if (pf->d_tail != NULL) + pf->d_tail->next = d_ptr; + if (pf->d_head == NULL) + pf->d_head = d_ptr; + d_ptr->prev = pf->d_tail; + pf->d_tail = d_ptr; + } else { + // check in the quick list + d_ptr_ptr = d_ptr_head; + while (d_ptr_ptr != NULL && d_ptr_ptr->ptr->id != desc_rec.parent_id) { + d_ptr_ptr = d_ptr_ptr->next; + } + + if (d_ptr_ptr == NULL && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) { + // check in the lost/found list + lf_ptr = lf_head; + while (lf_ptr != NULL && lf_ptr->ptr->id != desc_rec.parent_id) { + lf_ptr = lf_ptr->next; + } + if (lf_ptr == NULL) { + DEBUG_WARN(("ERROR -- not found parent with id %#x. Adding to lost/found\n", desc_rec.parent_id)); + lf_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll)); + lf_ptr->prev = NULL; + lf_ptr->next = lf_head; + lf_ptr->parent = desc_rec.parent_id; + lf_ptr->ptr = d_ptr; + lf_head = lf_ptr; + } else { + d_par = lf_ptr->ptr; + DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", d_par->id)); + } + } + + if (d_ptr_ptr != NULL || d_par != NULL) { + if (d_ptr_ptr != NULL) + d_par = d_ptr_ptr->ptr; + else { + //add the d_par to the cache + DEBUG_INDEX(("Update - Cache addition\n")); + d_ptr_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll)); + d_ptr_ptr->prev = NULL; + d_ptr_ptr->next = d_ptr_head; + d_ptr_ptr->ptr = d_par; + d_ptr_head = d_ptr_ptr; + if (d_ptr_tail == NULL) + d_ptr_tail = d_ptr_ptr; + d_ptr_count++; + if (d_ptr_count > 100) { + //remove on from the end + d_ptr_ptr = d_ptr_tail; + d_ptr_tail = d_ptr_ptr->prev; + free (d_ptr_ptr); + d_ptr_count--; + } + } + DEBUG_INDEX(("Found a parent\n")); + d_par->no_child++; + d_ptr->parent = d_par; + if (d_par->child_tail != NULL) + d_par->child_tail->next = d_ptr; + if (d_par->child == NULL) + d_par->child = d_ptr; + d_ptr->prev = d_par->child_tail; + d_par->child_tail = d_ptr; + } + } + } + + } 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)); + // DEBUG_INDEX(("Item pointer is %p\n", d_ptr)); + 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; + + DEBUG_INDEX(("Searching for parent\n")); + if (desc_rec.parent_id == 0 || desc_rec.parent_id == desc_rec.d_id) { + if (desc_rec.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 != NULL) + pf->d_tail->next = d_ptr; + if (pf->d_head == NULL) + pf->d_head = d_ptr; + d_ptr->prev = pf->d_tail; + pf->d_tail = d_ptr; + } else { + d_ptr_ptr = d_ptr_head; + while (d_ptr_ptr != NULL && d_ptr_ptr->ptr->id != desc_rec.parent_id) { + d_ptr_ptr = d_ptr_ptr->next; + } + + if (d_ptr_ptr == NULL && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) { + // check in the lost/found list + lf_ptr = lf_head; + while (lf_ptr != NULL && lf_ptr->ptr->id != desc_rec.parent_id) { + lf_ptr = lf_ptr->next; + } + if (lf_ptr == NULL) { + DEBUG_WARN(("ERROR -- not found parent with id %#x. Adding to lost/found\n", desc_rec.parent_id)); + lf_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll)); + lf_ptr->prev = NULL; + lf_ptr->next = lf_head; + lf_ptr->parent = desc_rec.parent_id; + lf_ptr->ptr = d_ptr; + lf_head = lf_ptr; + } else { + d_par = lf_ptr->ptr; + DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", d_par->id)); + } + } + + if (d_ptr_ptr != NULL || d_par != NULL) { + if (d_ptr_ptr != NULL) + d_par = d_ptr_ptr->ptr; + else { + //add the d_par to the cache + DEBUG_INDEX(("Normal - Cache addition\n")); + d_ptr_ptr = (struct _pst_d_ptr_ll*) xmalloc(sizeof(struct _pst_d_ptr_ll)); + d_ptr_ptr->prev = NULL; + d_ptr_ptr->next = d_ptr_head; + d_ptr_ptr->ptr = d_par; + d_ptr_head = d_ptr_ptr; + if (d_ptr_tail == NULL) + d_ptr_tail = d_ptr_ptr; + d_ptr_count++; + if (d_ptr_count > 100) { + //remove one from the end + d_ptr_ptr = d_ptr_tail; + d_ptr_tail = d_ptr_ptr->prev; + free (d_ptr_ptr); + d_ptr_count--; + } + } + + DEBUG_INDEX(("Found a parent\n")); + d_par->no_child++; + d_ptr->parent = d_par; + if (d_par->child_tail != NULL) + d_par->child_tail->next = d_ptr; + if (d_par->child == NULL) + d_par->child = d_ptr; + d_ptr->prev = d_par->child_tail; + d_par->child_tail = d_ptr; + } + } + } + // check here to see if d_ptr is the parent of any of the items in the lost / found list + lf_ptr = lf_head; lf_shd = NULL; + while (lf_ptr != NULL) { + if (lf_ptr->parent == d_ptr->id) { + DEBUG_INDEX(("Found a child (%#x) of the current record. Joining to main structure.\n", lf_ptr->ptr->id)); + d_par = d_ptr; + d_ptr = lf_ptr->ptr; + + d_par->no_child++; + d_ptr->parent = d_par; + if (d_par->child_tail != NULL) + d_par->child_tail->next = d_ptr; + if (d_par->child == NULL) + d_par->child = d_ptr; + d_ptr->prev = d_par->child_tail; + d_par->child_tail = d_ptr; + if (lf_shd == NULL) + lf_head = lf_ptr->next; + else + lf_shd->next = lf_ptr->next; + lf_tmp = lf_ptr->next; + free(lf_ptr); + lf_ptr = lf_tmp; + } else { + lf_shd = lf_ptr; + lf_ptr = lf_ptr->next; + } + } + 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); + } + // fseek(pf->fp, fpos, SEEK_SET); + } else { + // hopefully a table of offsets to more tables + if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { + DEBUG_WARN(("didn't read enough desc index. _pst_read_block_size returned less than requested\n")); + DEBUG_RET(); + return -1; + } + bptr = buf; + // DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 12); + + memcpy(&table, bptr, sizeof(table)); + LE32_CPU(table.start); + LE32_CPU(table.u1); + LE32_CPU(table.offset); + bptr+=sizeof(table); + memcpy(&table2, bptr, sizeof(table)); + LE32_CPU(table2.start); + LE32_CPU(table2.u1); + LE32_CPU(table2.offset); + + if (start_id != -1 && table.start != start_id) { + DEBUG_WARN(("This table isn't right. Perhaps we are too deep, or corruption\n")); + if (buf) free (buf); + DEBUG_RET(); + return -1; + } + + y = 0; + while(table.start != 0 /*&& y < 0x1F && table.start < end_val*/) { + DEBUG_INDEX(("[%i] %i Pointer Table = [start = %#x, u1 = %#x, offset = %#x]\n", + depth, ++y, table.start, table.u1, table.offset)); + + + if (table2.start <= table.start) { + // for the end of our table, table2.start may equal 0 + DEBUG_WARN(("2nd value in index table is less than current value. Setting to higher value [%#x, %#x, %#x]\n", + table.start, table2.start, INT32_MAX)); + table2.start = INT32_MAX; + } + + if ((i = _pst_build_desc_ptr(pf, table.offset, depth+1, high_id, table.start, table2.start)) == -1 && pf->desc_depth_ok == 0) { //the table beneath isn't a table + pf->index2_depth = depth; //set the max depth to this level + if (buf) free(buf); + DEBUG_RET(); + return 4; + } else if (i == 4) { //repeat with last tried values, but lower depth + _pst_build_desc_ptr(pf, table.offset, depth+1, high_id, table.start, table2.start); + } + + memcpy(&table, bptr, sizeof(table)); + LE32_CPU(table.start); + LE32_CPU(table.u1); + LE32_CPU(table.offset); + bptr+=sizeof(table); + memcpy(&table2, bptr, sizeof(table)); + LE32_CPU(table2.start); + LE32_CPU(table2.u1); + LE32_CPU(table2.offset); + } + if (buf) free(buf); + DEBUG_RET(); + return 3; + } + // ok, lets try freeing the d_ptr_head cache here + while (d_ptr_head != NULL) { + d_ptr_ptr = d_ptr_head->next; + free(d_ptr_head); + d_ptr_head = d_ptr_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 == NULL) { + DEBUG_WARN(("you cannot pass me a NULL! I don't want it!\n")); + DEBUG_RET(); + return NULL; + } + + if (d_ptr->list_index != NULL) { + 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")); + // } + + if (d_ptr->desc == NULL) { + 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 ((list = _pst_parse_block(pf, d_ptr->desc->id, id2_head)) == NULL) { + DEBUG_WARN(("_pst_parse_block() returned an error for d_ptr->desc->id [%#x]\n", d_ptr->desc->id)); + DEBUG_RET(); + return NULL; + } + + item = (pst_item*) xmalloc(sizeof(pst_item)); + memset(item, 0, sizeof(pst_item)); + + if (_pst_process(list, item)) { + DEBUG_WARN(("_pst_process() returned non-zero value. That is an error\n")); + _pst_free_list(list); + DEBUG_RET(); + return NULL; + } else { + _pst_free_list(list); + list = NULL; //_pst_process will free the items in the list + } + + if ((id_ptr = _pst_getID2(id2_head, 0x671)) != NULL) { + // attachements exist - so we will process them + while (item->attach != NULL) { + attach = item->attach->next; + free(item->attach); + item->attach = attach; + } + + DEBUG_EMAIL(("ATTACHEMENT processing attachement\n")); + if ((list = _pst_parse_block(pf, id_ptr->id, id2_head)) == NULL) { + DEBUG_WARN(("ERROR error processing main attachment record\n")); + DEBUG_RET(); + return NULL; + } + 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++; + } + item->current_attach = item->attach; + + if (_pst_process(list, item)) { + DEBUG_WARN(("ERROR _pst_process() failed with attachments\n")); + _pst_free_list(list); + DEBUG_RET(); + return NULL; + } + _pst_free_list(list); + + // 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 != NULL) { + if ((id_ptr = _pst_getID2(id2_head, attach->id2_val)) != NULL) { + // 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; + } + item->current_attach = attach; + if (_pst_process(list, item)) { + DEBUG_WARN(("ERROR _pst_process() failed with an attachment\n")); + _pst_free_list(list); + attach = attach->next; + continue; + } + _pst_free_list(list); + if ((id_ptr = _pst_getID2(id2_head, attach->id2_val)) != NULL) { + // 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; + } + item->current_attach = item->attach; //reset back to first + } + + _pst_free_id2(id2_head); + + + DEBUG_RET(); + return item; +} + +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 block_offset; + // pst_index_ll *rec = NULL; + u_int32_t size = 0, t_ptr = 0, fr_ptr = 0, to_ptr = 0, ind_ptr = 0, x = 0, stop = 0; + u_int32_t num_recs = 0, count_rec = 0, ind2_ptr = 0, list_start = 0, num_list = 0, cur_list = 0; + int32_t block_type, rec_size; + 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 ("BC") blocks + struct { + u_int16_t ref_type; + u_int16_t type; + u_int16_t ind2_off; + u_int16_t u1; + } table2_rec; //for type 2 ("7C") blocks + struct { + u_int16_t index_offset; + u_int16_t type; + u_int16_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_int16_t b_five_offset; + u_int16_t u5; + u_int16_t ind2_offset; + u_int16_t u6; + 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 (block == NULL) { + DEBUG_EMAIL(("block == NULL. Cannot continue with this block\n")); + DEBUG_RET(); + return NULL; + }*/ + + // DEBUG_EMAIL(("About to read %i bytes from offset %#x\n", block->size, block->offset)); + + if ((read_size = _pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { + // if (_pst_read_block_size(pf, block->offset, block->size, &buf, PST_ENC, 0) < block->size) { + WARN(("Error reading block id %#x\n", block_id)); + if (buf) free (buf); + DEBUG_RET(); + return NULL; + } + DEBUG_EMAIL(("pointer to buf is %p\n", buf)); + + memcpy(&block_hdr, &(buf[0]), sizeof(block_hdr)); + LE16_CPU(block_hdr.index_offset); + LE16_CPU(block_hdr.type); + LE16_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; + + _pst_getBlockOffset(buf, ind_ptr, block_hdr.offset, &block_offset); + fr_ptr = block_offset.from; + + memcpy(&table_rec, &(buf[fr_ptr]), 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); + if (buf) free (buf); + DEBUG_RET(); + return NULL; + } + + _pst_getBlockOffset(buf, ind_ptr, table_rec.value, &block_offset); + list_start = fr_ptr = block_offset.from; + to_ptr = block_offset.to; + num_list = (to_ptr - fr_ptr)/sizeof(table_rec); + num_recs = 1; // only going to one object in these blocks + rec_size = 0; // doesn't matter cause there is only one object + } else if (block_hdr.type == 0x7CEC) { //type 2 + block_type = 2; + + _pst_getBlockOffset(buf, ind_ptr, block_hdr.offset, &block_offset); + fr_ptr = block_offset.from; //now got pointer to "7C block" + memset(&seven_c_blk, 0, sizeof(seven_c_blk)); + memcpy(&seven_c_blk, &(buf[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); + LE16_CPU(seven_c_blk.b_five_offset); + LE16_CPU(seven_c_blk.u5); + LE16_CPU(seven_c_blk.ind2_offset); + LE16_CPU(seven_c_blk.u6); + 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")); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + + rec_size = seven_c_blk.rec_size; + num_list = seven_c_blk.item_count; + DEBUG_EMAIL(("b5 offset = %#x\n", seven_c_blk.b_five_offset)); + + _pst_getBlockOffset(buf, ind_ptr, seven_c_blk.b_five_offset, &block_offset); + fr_ptr = block_offset.from; + memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec)); + DEBUG_EMAIL(("before convert %#x\n", table_rec.type)); + LE16_CPU(table_rec.type); + DEBUG_EMAIL(("after convert %#x\n", 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)); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + + if (table_rec.value == 0) { // this is for the 2nd index offset + WARN(("reference to second index block is zero. ERROR\n")); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + + _pst_getBlockOffset(buf, ind_ptr, table_rec.value, &block_offset); + num_recs = (block_offset.to - block_offset.from) / 6; // this will give the number of records in this block + + _pst_getBlockOffset(buf, ind_ptr, seven_c_blk.ind2_offset, &block_offset); + ind2_ptr = block_offset.from; + } else { + WARN(("ERROR: Unknown block constant - %#X for id %#x\n", block_hdr.type, block_id)); + DEBUG_HEXDUMPC(buf, read_size,0x10); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + + DEBUG_EMAIL(("Mallocing number of items %i\n", num_recs)); + while (count_rec < num_recs) { + na_ptr = (pst_num_array*) xmalloc(sizeof(pst_num_array)); + memset(na_ptr, 0, sizeof(pst_num_array)); + if (na_head == NULL) { + na_head = na_ptr; + na_ptr->next = NULL; + } + else { + na_ptr->next = 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->count_array = num_recs; // each record will have a record of the total number of records + x = 0; + + DEBUG_EMAIL(("going to read %i (%#x) items\n", na_ptr->count_item, na_ptr->count_item)); + + fr_ptr = list_start; // init fr_ptr to the start of the list. + cur_list = 0; + stop = 0; + while (!stop && cur_list < num_list) { //we will increase fr_ptr as we progress through index + if (block_type == 1) { + memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec)); + LE16_CPU(table_rec.type); + LE16_CPU(table_rec.ref_type); + fr_ptr += sizeof(table_rec); + } else if (block_type == 2) { + // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code + memcpy(&table2_rec, &(buf[fr_ptr]), sizeof(table2_rec)); + LE16_CPU(table2_rec.ref_type); + LE16_CPU(table2_rec.type); + LE16_CPU(table2_rec.ind2_off); + LE16_CPU(table2_rec.u1); + + // table_rec and table2_rec are arranged differently, so assign the values across + table_rec.type = table2_rec.type; + table_rec.ref_type = table2_rec.ref_type; + if (ind2_ptr+table2_rec.ind2_off > 0 && + ind2_ptr+table2_rec.ind2_off < read_size-sizeof(table_rec.value)) + memcpy(&(table_rec.value), &(buf[ind2_ptr+table2_rec.ind2_off]), sizeof(table_rec.value)); + else { + DEBUG_WARN (("trying to read more than blocks size. Size=%#x, Req.=%#x," + " Req Size=%#x\n", read_size, ind2_ptr+table2_rec.ind2_off, + sizeof(table_rec.value))); + } + + fr_ptr += sizeof(table2_rec); + } else { + WARN(("Missing code for block_type %i\n", block_type)); + if (buf) free(buf); + DEBUG_RET(); + return NULL; + } + cur_list++; // get ready to read next bit from list + DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n", + x, table_rec.type, table_rec.ref_type, table_rec.value)); + + na_ptr->items[x] = (struct _pst_num_item*) xmalloc(sizeof(struct _pst_num_item)); + // DEBUG_EMAIL(("_pst_parse_block: record address = %p\n", na_ptr->items[x])); + 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 != NULL && mapptr->map < table_rec.type) + mapptr = mapptr->next; + if (mapptr != NULL && 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 + + 2 - 0x0002 - Signed 16bit value + 3 - 0x0003 - Signed 32bit value + 4 - 0x0004 - 4-byte floating point + 5 - 0x0005 - Floating point double + 6 - 0x0006 - Signed 64-bit int + 7 - 0x0007 - Application Time + 10 - 0x000A - 32-bit error value + 11 - 0x000B - Boolean (non-zero = true) + 13 - 0x000D - Embedded Object + 20 - 0x0014 - 8-byte signed integer (64-bit) + 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 + - 0x1014 - Array of 64bit values + - 0x101E - Array of Strings + - 0x1102 - Array of Binary data + */ + + if (table_rec.ref_type == 0x0003 || table_rec.ref_type == 0x000b + || table_rec.ref_type == 0x0002) { //contains data + na_ptr->items[x]->data = xmalloc(sizeof(int32_t)); + memcpy(na_ptr->items[x]->data, &(table_rec.value), sizeof(int32_t)); + + na_ptr->items[x]->size = sizeof(int32_t); + na_ptr->items[x]->type = table_rec.ref_type; + + } else if (table_rec.ref_type == 0x0005 || table_rec.ref_type == 0x000D + || table_rec.ref_type == 0x1003 || table_rec.ref_type == 0x0014 + || table_rec.ref_type == 0x001E || table_rec.ref_type == 0x0102 + || table_rec.ref_type == 0x0040 || table_rec.ref_type == 0x101E + || table_rec.ref_type == 0x0048 || table_rec.ref_type == 0x1102 + || table_rec.ref_type == 0x1014) { + //contains index_ref to data + LE32_CPU(table_rec.value); + if ((table_rec.value & 0x0000000F) == 0xF) { + // if value ends in 'F' then this should be an id2 value + DEBUG_EMAIL(("Found id2 [%#x] value. Will follow it\n", + table_rec.value)); + if ((na_ptr->items[x]->size = _pst_ff_getID2block(pf, table_rec.value, i2_head, + &(na_ptr->items[x]->data)))==0) { + DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", + table_rec.value)); + na_ptr->items[x]->size = 0; + na_ptr->items[x]->data = NULL; + na_ptr->items[x]->type = table_rec.value; + } + DEBUG_EMAIL(("Read %i bytes to a buffer at %p\n", + na_ptr->items[x]->size, na_ptr->items[x]->data)); + } else if (table_rec.value != 0) { + if ((table_rec.value >> 4)+ind_ptr > read_size) { + // check that we will not be outside the buffer we have read + DEBUG_WARN(("table_rec.value [%#x] is outside of block [%#x]\n", + table_rec.value, read_size)); + na_ptr->count_item --; + continue; + } + if (_pst_getBlockOffset(buf, ind_ptr, table_rec.value, &block_offset)) { + 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; + } + t_ptr = block_offset.from; + if (t_ptr <= block_offset.to) { + na_ptr->items[x]->size = size = block_offset.to - t_ptr; + } else { + DEBUG_WARN(("I don't want to malloc less than zero sized block. from=%#x, to=%#x." + "Will change to 1 byte\n", block_offset.from, block_offset.to)); + na_ptr->items[x]->size = size = 0; // the malloc statement will add one to this + } + + // plus one for good luck (and strings) we will null terminate all reads + na_ptr->items[x]->data = (char*) xmalloc(size+1); + memcpy(na_ptr->items[x]->data, &(buf[t_ptr]), size); + na_ptr->items[x]->data[size] = '\0'; // null terminate buffer + + 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); + if ((na_ptr->items[x]->size = + _pst_ff_getID2block(pf, type_d_rec->id, i2_head, + &(na_ptr->items[x]->data)))==0){ + DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", + type_d_rec->id)); + na_ptr->items[x]->size = 0; + na_ptr->items[x]->data = NULL; + na_ptr->items[x]->type = type_d_rec->id; + } + DEBUG_EMAIL(("Read %i bytes into a buffer at %p\n", + na_ptr->items[x]->size, na_ptr->items[x]->data)); + // } + } + } else { + DEBUG_EMAIL(("Ignoring 0 value in offset\n")); + if (na_ptr->items[x]->data) + free (na_ptr->items[x]->data); + na_ptr->items[x]->data = NULL; + + free(na_ptr->items[x]); + + na_ptr->count_item--; // remove this item from the destination list + continue; + } + if (na_ptr->items[x]->type == 0) //it can be used to convey information + // to later functions + na_ptr->items[x]->type = table_rec.ref_type; + } else { + WARN(("ERROR Unknown ref_type %#x\n", table_rec.ref_type)); + 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; + count_rec++; + } + if (buf != NULL) + free(buf); + DEBUG_RET(); + return na_head; +} + +// check if item->email is NULL, and init if so +#define MALLOC_EMAIL(x) { if (x->email == NULL) { 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 == NULL) { 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 == NULL) { 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 == NULL) { 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 == NULL) { 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 == NULL) { 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 -- plus one on the size for good luck (and string termination) +#define LIST_COPY(targ, type) { \ + targ = type realloc(targ, list->items[x]->size+1); \ + memset(targ, 0, list->items[x]->size+1); \ + memcpy(targ, list->items[x]->data, list->items[x]->size); \ +} + +/* free(list->items[x]->data); \ + list->items[x]->data=NULL; \*/ + +//#define INC_CHECK_X() { if (++x >= list->count_item) break; } +#define NULL_CHECK(x) { if (x == NULL) { DEBUG_EMAIL(("NULL_CHECK: Null Found\n")); break;} } + +#define MOVE_NEXT(targ) { \ + if (next){\ + if ((char*)targ == NULL) {\ + DEBUG_EMAIL(("MOVE_NEXT: Target is NULL. Will stop processing this option\n"));\ + break;\ + }\ + targ = targ->next;\ + if ((char*)targ == NULL) {\ + 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) { + int32_t x, t; + int32_t next = 0; + pst_item_attach *attach; + pst_item_extra_field *ef; + + DEBUG_ENT("_pst_process"); + if (item == NULL) { + DEBUG_EMAIL(("item cannot be NULL.\n")); + DEBUG_RET(); + return -1; + } + + attach = item->current_attach; // a working variable + + while (list != NULL) { + 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; + } + // INC_CHECK_X(); + 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)); + // INC_CHECK_X(); + 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)); + // INC_CHECK_X(); //increment x here so that the next if statement has a chance of matching the next item + 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; + } + // INC_CHECK_X(); + 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)); + // INC_CHECK_X(); + 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; + } + // INC_CHECK_X(); + 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 = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->private = 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)); + // INC_CHECK_X(); + 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)); + // INC_CHECK_X(); + 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; + // INC_CHECK_X(); + 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))); + // INC_CHECK_X(); + 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)); + // INC_CHECK_X(); + break; + case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient + DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n")); + // INC_CHECK_X(); + break; + case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure + DEBUG_EMAIL(("Received By Name 1 -- NOT HANDLED\n")); + //INC_CHECK_X(); + break; + case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender + DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + break; + case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2 + DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n")); + //INC_CHECK_X(); + break; + case 0x0044: // PR_RCVD_REPRESENTING_NAME Name of Recipient Structure 2 + DEBUG_EMAIL(("Received on behalf of Structure Name -- NOT HANDLED\n")); + //INC_CHECK_X(); + break; + case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure + DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + break; + case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2 + DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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))); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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(item->email->rtf_compressed, (char*)); + // DEBUG_EMAIL(("Pointer: %p\n", item->email->rtf_compressed)); + DEBUG_EMAIL(("NOT PRINTED\n")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + break; + case 0x3004: // PR_COMMENT Comment for item - usually folders + DEBUG_EMAIL(("Comment - ")); + LIST_COPY(item->comment, (char*)); + DEBUG_EMAIL(("%s\n", item->comment)); + //INC_CHECK_X(); + 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))); + //INC_CHECK_X(); + 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))); + //INC_CHECK_X(); + break; + case 0x300B: // PR_SEARCH_KEY Record Header 2 + DEBUG_EMAIL(("Record Search 2 -- NOT HANDLED\n")); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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; + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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 == NULL) { //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")); + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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(("Attachement 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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); + //INC_CHECK_X(); + break; + case 0x67F2: // ID2 value of the attachments proper record + DEBUG_EMAIL(("Attachment ID2 value - ")); + if (attach != NULL){ + 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)); + } + //INC_CHECK_X(); + 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)); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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")); + //INC_CHECK_X(); + 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); + //INC_CHECK_X(); + 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 - NOT PROCESSED\n")); + 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 - NOT PROCESSED\n")); + 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 - NOT PROCESSED\n")); + 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 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: + /* 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 != NULL) { + free(list->items[x]->data); + list->items[x]->data = NULL; + } + //INC_CHECK_X(); + } + x++; + } + x = 0; + list = list->next; + next = 1; + } + DEBUG_RET(); + return 0; +} + +int32_t _pst_free_list(pst_num_array *list) { + int32_t x = 0; + pst_num_array *l; + DEBUG_ENT("_pst_free_list"); + while (list != NULL) { + while (x < list->count_item) { + if (list->items[x]->data != NULL) { + free (list->items[x]->data); + } + if (list->items[x] != NULL) { + free (list->items[x]); + } + x++; + } + if (list->items != NULL) { + free(list->items); + } + l = list; + list = list->next; + free (l); + x = 0; + } + DEBUG_RET(); + return 1; +} + +int32_t _pst_free_id2(pst_index2_ll * head) { + pst_index2_ll *t; + DEBUG_ENT("_pst_free_id2"); + while (head != NULL) { + 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 != NULL) { + 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 != NULL) { + while (head->child != NULL) { + head = head->child; + } + + // point t to the next item + t = head->next; + if (t == NULL && head->parent != NULL) { + t = head->parent; + t->child = NULL; // set the child to NULL so we don't come back here again! + } + + if (head != NULL) + 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 != NULL) { + 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 != NULL) { + head = head_ptr; + while (head_ptr != NULL) + 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)); + DEBUG_RET(); + return NULL; + } + + memcpy(&block_head, &(buf[0]), 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)); + 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 + //check it doesn't exist already first + /* i2_ptr = head; + while(i2_ptr != NULL) { + if (i2_ptr->id2 == id2_rec.id2) + break; + i2_ptr = i2_ptr->next; + }*/ + + // if (i2_ptr == NULL) { + 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 == NULL) + head = i2_ptr; + if (tail != NULL) + tail->next = i2_ptr; + tail = i2_ptr; + /* } else { + // if it does already exist + DEBUG_INDEX(("_pst_build_id2(): \t\t%#x already exists. Updating ID to %#x\n", + id2_rec.id2, i_ptr->id)); + i2_ptr->id = i_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)) != NULL) { + /*DEBUG_INDEX(("_pst_build_id2(): \t\tAdding new list onto end of current\n")); + if (head == NULL) + head = i2_ptr; + if (tail != NULL) + tail->next = i2_ptr; + while (i2_ptr->next != NULL) + i2_ptr = i2_ptr->next; + tail = i2_ptr;*/ + } + // need to re-establish tail + DEBUG_INDEX(("Returned from depth\n")); + if (tail != NULL) { + while (tail->next != NULL) + tail = tail->next; + } + } + } + } + x++; + } + if (buf != NULL) { + free (buf); + } + DEBUG_RET(); + return head; +} + +// This version of free does NULL check first +#define SAFE_FREE(x) {if (x != NULL) free(x);} + +void _pst_freeItem(pst_item *item) { + pst_item_attach *t; + pst_item_extra_field *et; + + DEBUG_ENT("_pst_freeItem"); + if (item != NULL) { + 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 != NULL) + 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->address1_desc); + SAFE_FREE(item->contact->address1_transport); + SAFE_FREE(item->contact->address2); + SAFE_FREE(item->contact->address2_desc); + SAFE_FREE(item->contact->address2_transport); + SAFE_FREE(item->contact->address3); + 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 != NULL) { + 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 != NULL) { + 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(); +} + +int32_t _pst_getBlockOffset(char *buf, int32_t i_offset, int32_t offset, pst_block_offset *p) { + int32_t of1; + DEBUG_ENT("_pst_getBlockOffset"); + if (p == NULL || buf == NULL || offset == 0) { + DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 (%p, %p, %#x)\n", p, buf, offset)); + DEBUG_RET(); + return -1; + } + of1 = offset>>4; + 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_RET(); + return 0; +} + +pst_index_ll * _pst_getID(pst_file* pf, u_int32_t id) { + // static pst_index_ll *old_val = NULL; //this should make it quicker + pst_index_ll *ptr = NULL; + DEBUG_ENT("_pst_getID"); + if (id == 0) { + DEBUG_RET(); + return NULL; + } + + /* if (id & 0x3) { // if either of the last two bits on the id are set + DEBUG_INDEX(("ODD_INDEX (not even) is this a pointer to a table?\n")); + }*/ + // Dave: I don't think I should do this. next bit. I really think it doesn't work + // it isn't based on sound principles either. + // update: seems that the last two sig bits are flags. u tell me! + id &= 0xFFFFFFFE; // remove least sig. bit. seems that it might work if I do this + + DEBUG_INDEX(("Trying to find %#x\n", id)); + + if (ptr == NULL) + ptr = pf->i_head; + while (ptr->id != id) { + ptr = ptr->next; + if (ptr == NULL) { + break; + } + } + if (ptr == NULL) { + DEBUG_INDEX(("ERROR: Value not found\n")); + } else { + DEBUG_INDEX(("Found Value %#x\n", ptr->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 != NULL && ptr->id2 != id) { + ptr = ptr->next; + } + if (ptr != NULL) { + if (ptr->id != NULL) { + 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_desc_ll * _pst_getDptr(pst_file *pf, u_int32_t id) { + pst_desc_ll *ptr = pf->d_head; + DEBUG_ENT("_pst_getDptr"); + while(ptr != NULL && ptr->id != id) { + if (ptr->child != NULL) { + ptr = ptr->child; + continue; + } + while (ptr->next == NULL && ptr->parent != NULL) { + 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 != NULL) { + 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 != NULL) { + depth++; + ptr = ptr->child; + continue; + } + while (ptr->next == NULL && ptr->parent != NULL) { + 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 != NULL) { + 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 != NULL) { + 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 != NULL) { + 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 != NULL) { + DEBUG_READ(("Freeing old memory\n")); + free(*buf); + } + + *buf = (void*) xmalloc(size+1); //plus one so that we can NULL 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 != NULL) + free(buf2); + if (buf3 == NULL) { + // 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 == NULL) { + 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; + } + + if (fread(buf, 1, size, fp) < size) { + DEBUG_RET(); + return 2; + } + DEBUG_RET(); + return 0; +} + +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; +} + +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"); + r = _pst_ff_getIDblock(pf, id, b); + if (pf->encryption) + _pst_decrypt(*b, r, pf->encryption); + DEBUG_RET(); + return r; +} + +/** the get ID function for the default file format that I am working with + ie the one in the PST files */ +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 != NULL) { + DEBUG_INDEX(("freeing old memory in b\n")); + free(*b); + } + + DEBUG_INDEX(("record size = %#x, estimated size = %#x\n", rec->size, rec->size)); + *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}; + DEBUG_ENT("_pst_ff_getID2block"); + ptr = _pst_getID2(id2_head, id2); + + if (ptr == NULL) { + 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) { + // if the attachment begins with 01 01, <= 256 bytes, it is stored in the record + 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 != NULL) { + *(h->buf) = b; + } else if (h->base64 == 1 && h->fp != NULL) { + t = base64_encode(b, ret); + pst_fwrite(t, 1, strlen(t), h->fp); + free(b); + } else if (h->fp != NULL) { + pst_fwrite(b, 1, ret, h->fp); + free(b); + } + // if ((*buf)[0] == 0x1) { +// DEBUG_WARN(("WARNING: buffer starts with 0x1, but I didn't expect it to!\n")); +// } + } 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 != NULL && *h->buf != NULL) + (*(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"); + if ((a = _pst_ff_getIDblock(pf, id, &buf3))==0) + 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 != NULL) + *(h->buf) = buf3; + else if (h->base64 == 1 && h->fp != NULL) { + t = base64_encode(buf3, a); + pst_fwrite(t, 1, strlen(t), h->fp); + free(buf3); + } else if (h->fp != NULL) { + 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 != NULL) + free(buf2); + free(buf3); + return z; + } + if (pf->encryption) + _pst_decrypt(buf2, z, pf->encryption); + if (h->buf != NULL) { + *(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 != NULL) { + // 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); + pst_fwrite(t, 1, strlen(t), h->fp); + DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", + z, strlen(t), size)); + } else if (h->fp != NULL) { + 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 != NULL) + 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 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); +} + +struct tm * fileTimeToStructTM (const FILETIME *filetime) { + 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; +} + +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; +} + +size_t pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream) { + size_t r; + DEBUG_ENT("pst_fwrite"); + if (ptr != NULL) + 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; +} + diff -r 000000000000 -r 6b1b602514db libpst.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpst.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,507 @@ +/*** + * 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 + +#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; +} 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 +#include + +#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 int16_t short int +#define u_int16_t unsigned short int +#endif // _MSC_VER + + +#define PST_VERSION "0.5" + +#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 + +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]; + int32_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; +} pst_index; + +typedef struct _pst_index_tree { + u_int32_t id; + int32_t offset; + size_t size; + int32_t u1; + struct _pst_index_tree * next; +} pst_index_ll; + +typedef struct _pst_index2_tree { + int32_t id2; + pst_index_ll *id; + struct _pst_index2_tree * next; +} pst_index2_ll; + +typedef struct _pst_desc_tree { + u_int32_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; +} 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; + 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 *address1_desc; + char *address1_transport; + char *address2; + char *address2_desc; + char *address2_transport; + char *address3; + 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; +} 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_attach *current_attach; // pointer to current attachment + 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; +} 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; + FILE * fp; + size_t size; + unsigned char index1_depth; + unsigned char index2_depth; + unsigned char encryption; + unsigned char id_depth_ok; + unsigned char desc_depth_ok; + unsigned char ind_type; +} pst_file; + +typedef struct _pst_block_offset { + int16_t from; + int16_t to; +} pst_block_offset; + +struct _pst_num_item { + int32_t id; + unsigned char *data; + int32_t type; + size_t size; + char *extra; +}; + +typedef struct _pst_num_array { + int32_t count_item; + 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 +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 start_val, int32_t end_val); +int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t *high_id, + int32_t start_id, int32_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); +int32_t _pst_process(pst_num_array *list, pst_item *item); +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_getBlockOffset(char *buf, 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); +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); +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); + +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); +char * _pst_wide_to_single(char *wt, int32_t size); +// 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 diff -r 000000000000 -r 6b1b602514db libstrfunc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libstrfunc.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,68 @@ + +/* Taken from LibStrfunc v7.3 */ + +#include +#include +#include + +char *_sf_b64_buf=NULL; +size_t _sf_b64_len=0; + + +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) + return NULL; + + ou=output=(char *)malloc(size / 3 * 4 + (size / 50) + 5); + if(!output) + return NULL; + + while((char *)dte - (char *)p >= 3) { + *ou = _sf_uc_ib[ *p >> 2 ]; + ou[1] = _sf_uc_ib[ ((*p & 0x03) << 4) | (p[1] >> 4) ]; + ou[2] = _sf_uc_ib[ ((p[1] & 0x0F) << 2) | (p[2] >> 6) ]; + ou[3] = _sf_uc_ib[ p[2] & 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; + + _sf_b64_len = (ou - output); + + if(_sf_b64_buf) + free(_sf_b64_buf); + return _sf_b64_buf=output; +}; + diff -r 000000000000 -r 6b1b602514db libstrfunc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libstrfunc.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,2 @@ + +char * base64_encode(void *data, size_t size); diff -r 000000000000 -r 6b1b602514db lzfu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lzfu.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,125 @@ + /* + 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 + +#ifndef _MSC_VER +#include +#endif + +#ifdef _MSC_VER +#define uint32_t unsigned int +#endif + +#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 { + uint32_t cbSize; + uint32_t cbRawSize; + uint32_t dwMagic; + uint32_t dwCRC; +} lzfuheader; + + +/** + We always need to add 0x10 to the buffer offset because we need to skip past the header info +*/ + +unsigned char* lzfu_decompress (unsigned char* rtfcomp) { + // 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; + unsigned int i, in_size; + unsigned char *out_buf; + unsigned int out_ptr = 0; + + 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_buf = (unsigned char*)xmalloc(lzfuhdr.cbRawSize+20); //plus 4 cause we have 2x'}' and a \0 + in_size = 0; + // we add plus one here cause when referencing an array, the index is always one less + // (ie, when accessing 2 element array, highest index is [1]) + while (in_size+0x11 < lzfuhdr.cbSize) { + memcpy(&flags, &(rtfcomp[in_size+0x10]), 1); + in_size += 1; + + flag_mask = 1; + while (flag_mask != 0 && in_size+0x11 < lzfuhdr.cbSize) { + if (flag_mask & flags) { + // read 2 bytes from input + unsigned short int blkhdr, offset, length; + memcpy(&blkhdr, &(rtfcomp[in_size+0x10]), 2); + LE16_CPU(blkhdr); + in_size += 2; + /* swap the upper and lower bytes of blkhdr */ + blkhdr = (((blkhdr&0xFF00)>>8)+ + ((blkhdr&0x00FF)<<8)); + /* the offset is the first 24 bits of the 32 bit value */ + offset = (blkhdr&0xFFF0)>>4; + /* the length of the dict entry are the last 8 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; + out_buf[out_ptr++] = c1; + } + } else { + // uncompressed chunk (single byte) + char c1 = rtfcomp[in_size+0x10]; + in_size ++; + dict[dict_length] = c1; + dict_length = (dict_length+1)%4096; + out_buf[out_ptr++] = c1; + } + flag_mask <<= 1; + } + } + // the compressed version doesn't appear to drop the closing braces onto the doc. + // we should do that + out_buf[out_ptr++] = '}'; + out_buf[out_ptr++] = '}'; + out_buf[out_ptr++] = '\0'; + return out_buf; +} diff -r 000000000000 -r 6b1b602514db lzfu.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lzfu.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,4 @@ +#ifndef LZFU_H +#define LZFU_H +unsigned char* lzfu_decompress (unsigned char* rtfcomp); +#endif diff -r 000000000000 -r 6b1b602514db readlog.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readlog.vcproj Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 000000000000 -r 6b1b602514db readpst.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readpst.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,1434 @@ +/*** + * readpst.c + * Part of the LibPST project + * Written by David Smith + * dave.s@earthcorp.com + */ +#include +#include +#include +#include +#include +#include +#include + +#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 "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 VERSION "0.5" +// 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; + struct file_ll *next; +}; + + +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, int overwrite); +int32_t close_seperate_dir(); +int32_t mk_seperate_file(struct file_ll *f); +char *my_stristr(char *haystack, char *needle); +char *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 *prog_name; +char *output_dir = "."; + +// 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 + + +// 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 + +// 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" + +int main(int argc, char** argv) { + pst_item *item = NULL; + pst_file pstfile; + pst_desc_ll *d_ptr; + char * fname = NULL; + time_t em_time; + char * c_time, *d_log=NULL; + int c,x; + int mode = MODE_NORMAL; + int output_mode = OUTPUT_NORMAL; + int contact_mode = CMODE_VCARD; + int overwrite = 0; + int base64_body = 0; + // int encrypt = 0; + FILE *fp; + char *enc; // base64 encoded attachment + char *boundary = NULL, *b1, *b2; // the boundary marker between multipart sections + char *temp = NULL; //temporary char pointer + int attach_num = 0; + int skip_child = 0; + struct file_ll *f, *head; + prog_name = argv[0]; + + while ((c = getopt(argc, argv, "d:hko:qrSVwc:"))!= -1) { + switch (c) { + case 'c': + if (optarg!=NULL && optarg[0]=='v') + contact_mode=CMODE_VCARD; + else if (optarg!=NULL && 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 '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 (d_log == NULL) + d_log = "readpst.log"; + DEBUG_INIT(d_log); + DEBUG_REGISTER_CLOSE(); + DEBUG_ENT("main"); + + if (argc > optind) { + fname = argv[optind]; + } else { + usage(); + exit(2); + } + + if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); + + DEBUG_MAIN(("main: Opening PST file '%s'\n", fname)); + RET_DERROR(pst_open(&pstfile, fname, "r"), 1, ("Error opening File\n")); + DEBUG_MAIN(("main: Loading Indexes\n")); + RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); + DEBUG_MAIN(("processing file items\n")); + + pst_load_extended_attributes(&pstfile); + + if (chdir(output_dir)) { + x = errno; + pst_close(&pstfile); + 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 + 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(fname, '/')) == NULL) + if ((temp = strrchr(fname, '\\')) == NULL) + 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)); + + + f = (struct file_ll*) malloc(sizeof(struct file_ll)); + memset(f, 0, sizeof(struct file_ll)); + f->email_count = 0; + f->skip_count = 0; + f->next = NULL; + head = f; + if (mode == MODE_KMAIL) + f->name = mk_kmail_dir(item->file_as); + 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, overwrite); + f->name = (char*) xmalloc(10); + sprintf(f->name, "%09i", f->email_count); + } else { + f->name = (char*) malloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1); + sprintf(f->name, OUTPUT_TEMPLATE, item->file_as); + } + + f->dname = (char*) malloc(strlen(item->file_as)+1); + strcpy(f->dname, item->file_as); + + if (overwrite != 1 && mode != MODE_SEPERATE) { + // if overwrite is set to 1 we keep the existing name and don't modify anything + // we don't want to go changing the file name of the SEPERATE items + temp = (char*) malloc (strlen(f->name)+10); //enough room for 10 digits + sprintf(temp, "%s", f->name); + temp = check_filename(temp); + x = 0; + while ((f->output = fopen(temp, "r")) != NULL) { + DEBUG_MAIN(("main: need to increase filename cause one already exists with that name\n")); + DEBUG_MAIN(("main: - increasing it to %s%d\n", f->name, x)); + x++; + sprintf(temp, "%s%08d", f->name, x); + DEBUG_MAIN(("main: - trying \"%s\"\n", temp)); + if (x == 99999999) { + DIE(("main: 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); + } + } + if (mode != MODE_SEPERATE) { + f->name = check_filename(f->name); + if ((f->output = fopen(f->name, "w")) == NULL) { + DIE(("main: Could not open file \"%s\" for write\n", f->name)); + } + } + f->type = item->type; + + if ((d_ptr = pst_getTopOfFolders(&pstfile, item)) == NULL) { + DIE(("Top of folders record not found. Cannot continue\n")); + } + + if (item){ + _pst_freeItem(item); + item = NULL; + } + + /* if ((item = _pst_parse_item(&pstfile, d_ptr)) == NULL || item->folder == NULL) { + DEBUG_MAIN(("main: Could not get \"Top Of Personal Folder\" record\n")); + return -2; + }*/ + d_ptr = d_ptr->child; // do the children of TOPF + + if (output_mode != OUTPUT_QUIET) printf("Processing items...\n"); + + DEBUG_MAIN(("main: About to do email stuff\n")); + while (d_ptr != NULL) { + DEBUG_MAIN(("main: New item record\n")); + if (d_ptr->desc == NULL) { + DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); + f->skip_count++; + goto check_parent; + } + 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 != NULL && item->email != NULL && item->email->subject != NULL && + item->email->subject->subj != NULL) { + // DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject)); + // DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); + } + if (item != NULL) { + if (item->message_store != NULL) { + // 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 != NULL) { //if this is a folder, we want to recurse into it + if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as); + // f->email_count++; + 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; + + temp = item->file_as; + temp = check_filename(temp); + + 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, overwrite); + f->name = (char*) xmalloc(10); + memset(f->name, 0, 10); + // sprintf(f->name, "%09i", 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) { + temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits + sprintf(temp, "%s", f->name); + x = 0; + temp = check_filename(temp); + while ((f->output = fopen(temp, "r")) != NULL) { + DEBUG_MAIN(("main: need to increase filename cause one already exists with that name\n")); + DEBUG_MAIN(("main: - increasing it to %s%d\n", f->name, x)); + x++; + sprintf(temp, "%s%08d", f->name, x); + DEBUG_MAIN(("main: - trying \"%s\"\n", f->name)); + if (x == 99999999) { + DIE(("main: 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(("main: f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); + if (mode != MODE_SEPERATE) { + f->name = check_filename(f->name); + if ((f->output = fopen(f->name, "w")) == NULL) { + DIE(("main: Could not open file \"%s\" for write\n", f->name)); + } + } + if (d_ptr->child != NULL) { + d_ptr = d_ptr->child; + skip_child = 1; + } else { + DEBUG_MAIN(("main: Folder has NO children. Creating directory, and closing again\n")); + if (output_mode != OUTPUT_QUIET) + 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); + if (mode == MODE_KMAIL) + close_kmail_dir(); + else if (mode == MODE_RECURSE) + close_recurse_dir(); + else if (mode == MODE_SEPERATE) + close_seperate_dir(); + free(f->dname); + free(f->name); + free(f); + + f = head; + } + _pst_freeItem(item); + item = NULL; // just for the odd situations! + goto check_parent; + } else if (item->contact != NULL) { + // 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(f); + } + f->email_count++; + + DEBUG_MAIN(("main: Processing Contact\n")); + if (f->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 == NULL) { // 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) { + // 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(item->contact->fullname)); + fprintf(f->output, "N:%s;%s;%s;%s;%s\n", + rfc2426_escape((item->contact->surname==NULL?"":item->contact->surname)), + rfc2426_escape((item->contact->first_name==NULL?"":item->contact->first_name)), + rfc2426_escape((item->contact->middle_name==NULL?"":item->contact->middle_name)), + rfc2426_escape((item->contact->display_name_prefix==NULL?"":item->contact->display_name_prefix)), + rfc2426_escape((item->contact->suffix==NULL?"":item->contact->suffix))); + if (item->contact->nickname != NULL) + fprintf(f->output, "NICKNAME:%s\n", rfc2426_escape(item->contact->nickname)); + if (item->contact->address1 != NULL) + fprintf(f->output, "EMAIL:%s\n", rfc2426_escape(item->contact->address1)); + if (item->contact->address2 != NULL) + fprintf(f->output, "EMAIL:%s\n", rfc2426_escape(item->contact->address2)); + if (item->contact->address3 != NULL) + fprintf(f->output, "EMAIL:%s\n", rfc2426_escape(item->contact->address3)); + if (item->contact->birthday != NULL) + fprintf(f->output, "BDAY:%s\n", rfc2425_datetime_format(item->contact->birthday)); + if (item->contact->home_address != NULL) { + fprintf(f->output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n", + rfc2426_escape((item->contact->home_po_box!=NULL?item->contact->home_po_box:"")), + "", // extended Address + rfc2426_escape((item->contact->home_street!=NULL?item->contact->home_street:"")), + rfc2426_escape((item->contact->home_city!=NULL?item->contact->home_city:"")), + rfc2426_escape((item->contact->home_state!=NULL?item->contact->home_state:"")), + rfc2426_escape((item->contact->home_postal_code!=NULL?item->contact->home_postal_code:"")), + rfc2426_escape((item->contact->home_country!=NULL?item->contact->home_country:""))); + fprintf(f->output, "LABEL;TYPE=home:%s\n", rfc2426_escape(item->contact->home_address)); + } + if (item->contact->business_address != NULL) { + fprintf(f->output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", + rfc2426_escape((item->contact->business_po_box!=NULL?item->contact->business_po_box:"")), + "", // extended Address + rfc2426_escape((item->contact->business_street!=NULL?item->contact->business_street:"")), + rfc2426_escape((item->contact->business_city!=NULL?item->contact->business_city:"")), + rfc2426_escape((item->contact->business_state!=NULL?item->contact->business_state:"")), + rfc2426_escape((item->contact->business_postal_code!=NULL?item->contact->business_postal_code:"")), + rfc2426_escape((item->contact->business_country!=NULL?item->contact->business_country:""))); + fprintf(f->output, "LABEL;TYPE=work:%s\n", rfc2426_escape(item->contact->business_address)); + } + if (item->contact->other_address != NULL) { + fprintf(f->output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n", + rfc2426_escape((item->contact->other_po_box!=NULL?item->contact->business_po_box:"")), + "", // extended Address + rfc2426_escape((item->contact->other_street!=NULL?item->contact->other_street:"")), + rfc2426_escape((item->contact->other_city!=NULL?item->contact->other_city:"")), + rfc2426_escape((item->contact->other_state!=NULL?item->contact->other_state:"")), + rfc2426_escape((item->contact->other_postal_code!=NULL?item->contact->other_postal_code:"")), + rfc2426_escape((item->contact->other_country!=NULL?item->contact->other_country:""))); + fprintf(f->output, "ADR;TYPE=postal:%s\n", rfc2426_escape(item->contact->other_address)); + } + if (item->contact->business_fax != NULL) + fprintf(f->output, "TEL;TYPE=work,fax:%s\n", rfc2426_escape(item->contact->business_fax)); + if (item->contact->business_phone != NULL) + fprintf(f->output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(item->contact->business_phone)); + if (item->contact->business_phone2 != NULL) + fprintf(f->output, "TEL;TYPE=work,voice:%s\n", rfc2426_escape(item->contact->business_phone2)); + if (item->contact->car_phone != NULL) + fprintf(f->output, "TEL;TYPE=car,voice:%s\n", rfc2426_escape(item->contact->car_phone)); + if (item->contact->home_fax != NULL) + fprintf(f->output, "TEL;TYPE=home,fax:%s\n", rfc2426_escape(item->contact->home_fax)); + if (item->contact->home_phone != NULL) + fprintf(f->output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(item->contact->home_phone)); + if (item->contact->home_phone2 != NULL) + fprintf(f->output, "TEL;TYPE=home,voice:%s\n", rfc2426_escape(item->contact->home_phone2)); + if (item->contact->isdn_phone != NULL) + fprintf(f->output, "TEL;TYPE=isdn:%s\n", rfc2426_escape(item->contact->isdn_phone)); + if (item->contact->mobile_phone != NULL) + fprintf(f->output, "TEL;TYPE=cell,voice:%s\n", rfc2426_escape(item->contact->mobile_phone)); + if (item->contact->other_phone != NULL) + fprintf(f->output, "TEL;TYPE=msg:%s\n", rfc2426_escape(item->contact->other_phone)); + if (item->contact->pager_phone != NULL) + fprintf(f->output, "TEL;TYPE=pager:%s\n", rfc2426_escape(item->contact->pager_phone)); + if (item->contact->primary_fax != NULL) + fprintf(f->output, "TEL;TYPE=fax,pref:%s\n", rfc2426_escape(item->contact->primary_fax)); + if (item->contact->primary_phone != NULL) + fprintf(f->output, "TEL;TYPE=phone,pref:%s\n", rfc2426_escape(item->contact->primary_phone)); + if (item->contact->radio_phone != NULL) + fprintf(f->output, "TEL;TYPE=pcs:%s\n", rfc2426_escape(item->contact->radio_phone)); + if (item->contact->telex != NULL) + fprintf(f->output, "TEL;TYPE=bbs:%s\n", rfc2426_escape(item->contact->telex)); + if (item->contact->job_title != NULL) + fprintf(f->output, "TITLE:%s\n", rfc2426_escape(item->contact->job_title)); + if (item->contact->profession != NULL) + fprintf(f->output, "ROLE:%s\n", rfc2426_escape(item->contact->profession)); + if (item->contact->assistant_name != NULL || item->contact->assistant_phone != NULL) { + fprintf(f->output, "AGENT:BEGIN:VCARD\\n"); + if (item->contact->assistant_name != NULL) + fprintf(f->output, "FN:%s\\n", rfc2426_escape(item->contact->assistant_name)); + if (item->contact->assistant_phone != NULL) + fprintf(f->output, "TEL:%s\\n", rfc2426_escape(item->contact->assistant_phone)); + fprintf(f->output, "END:VCARD\\n\n"); + } + if (item->contact->company_name != NULL) + fprintf(f->output, "ORG:%s\n", rfc2426_escape(item->contact->company_name)); + if (item->comment != NULL) + fprintf(f->output, "NOTE:%s\n", rfc2426_escape(item->comment)); + + fprintf(f->output, "VERSION: 3.0\n"); + fprintf(f->output, "END:VCARD\n\n"); + } else { + fprintf(f->output, "%s <%s>\n", item->contact->fullname, item->contact->address1); + } + } + } else if (item->email != NULL && + (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { + if (mode == MODE_SEPERATE) { + mk_seperate_file(f); + } + + f->email_count++; + + DEBUG_MAIN(("main: seen an email\n")); + + // convert the sent date if it exists, or set it to a fixed date + if (item->email->sent_date != NULL) { + em_time = fileTimeToUnixTime(item->email->sent_date, 0); + c_time = ctime(&em_time); + if (c_time != NULL) + 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"; + + // if the boundary is still set from the previous run, then free it + if (boundary != NULL) { + free (boundary); + boundary = NULL; + } + + // we will always look at the header to discover some stuff + if (item->email->header != NULL ) { + // see if there is a boundary variable there + // this search MUST be made case insensitive (DONE). + // Also, some check to find out if we + // are looking at the boundary associated with content-type, and that the content + // type really is "multipart" + if ((b2 = my_stristr(item->email->header, "boundary=")) != NULL) { + 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++; + } + + boundary = malloc ((b1-b2)+1); //malloc that length + memset (boundary, 0, (b1-b2)+1); // blank it + strncpy(boundary, b2, b1-b2); // copy boundary to another variable + 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_MAIN(("main: Found boundary of - %s\n", boundary)); + } else { + + DEBUG_MAIN(("main: boundary not found in header\n")); + } + + // also possible to set 7bit encoding detection here. + if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:")) != NULL) { + if ((b2 = strchr(b2, ':')) != NULL) { + b2++; // skip to the : at the end of the string + + while (*b2 == ' ' || *b2 == '\t') + b2++; + if (pst_strincmp(b2, "base64", 6)==0) { + DEBUG_MAIN(("body is base64 encoded\n")); + base64_body = 1; + } + } else { + DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n")); + } + } + + } + if (boundary == NULL && (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(("main: 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(("main: created boundary is %s\n", boundary)); + } + + DEBUG_MAIN(("main: About to print Header\n")); + + if (item != NULL && item->email != NULL && item->email->subject != NULL && + item->email->subject->subj != NULL) { + DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); + } + if (item->email->header != NULL) { + // 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 != NULL) { + DEBUG_MAIN(("main: Found body text in header\n")); + temp += 2; // get past the \n\n + *temp = '\0'; + } + + if (mode != MODE_SEPERATE) { + // don't put rubbish in if we are doing seperate + fprintf(f->output, "From \"%s\" %s\n%s\n", + item->email->outlook_sender_name, c_time, item->email->header); + fprintf(f->output, "\n"); + } else { + fprintf(f->output, "%s\n", item->email->header); + } + } 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 != NULL) { + temp = item->email->outlook_sender_name; + } else { + temp = "(readpst_null)"; + } + fprintf(f->output, "From \"%s\" %s\n", temp, c_time); + } + if ((temp = item->email->outlook_sender) == NULL) + temp = ""; + fprintf(f->output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp); + if (item->email->subject != NULL) { + 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 != NULL) { + fprintf(f->output, "CC: %s\n", item->email->cc_address); + } + if (item->email->sent_date != NULL) { + 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 (item->attach != NULL) { + // write the boundary stuff if we have attachments + fprintf(f->output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", + boundary); + } else if (item->email->htmlbody && item->email->body) { + // else if we have an html and text body then tell it so + fprintf(f->output, "Content-type: multipart/alternate;\n\tboundary=\"%s\"\n", + boundary); + } else if (item->email->htmlbody) { + fprintf(f->output, "Content-type: text/html\n"); + } + fprintf(f->output, "\n"); + } + + + DEBUG_MAIN(("main: About to print Body\n")); + + if (item->email->body != NULL) { + if (boundary) { + fprintf(f->output, "\n--%s\n", boundary); + fprintf(f->output, "Content-type: text/plain\n\n"); + if (base64_body) + fprintf(f->output, "Content-Transfer-Encoding: base64\n"); + } + removeCR(item->email->body); + if (base64_body) + write_email_body(f->output, base64_encode(item->email->body, + strlen(item->email->body))); + else + write_email_body(f->output, item->email->body); + } + + if (item->email->htmlbody != NULL) { + if (boundary) { + fprintf(f->output, "\n--%s\n", boundary); + fprintf(f->output, "Content-type: text/html\n\n"); + if (base64_body) + fprintf(f->output, "Content-Transfer-Encoding: base64\n"); + } + removeCR(item->email->htmlbody); + if (base64_body) + write_email_body(f->output, base64_encode(item->email->htmlbody, + strlen(item->email->htmlbody))); + else + write_email_body(f->output, item->email->htmlbody); + } + + attach_num = 0; + + if (item->email->rtf_compressed != NULL) { + DEBUG_MAIN(("Adding RTF body as attachment\n")); + item->current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); + memset(item->current_attach, 0, sizeof(pst_item_attach)); + item->current_attach->next = item->attach; + item->attach = item->current_attach; + item->current_attach->data = lzfu_decompress(item->email->rtf_compressed); + item->current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); + strcpy(item->current_attach->filename2, RTF_ATTACH_NAME); + item->current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); + strcpy(item->current_attach->mimetype, RTF_ATTACH_TYPE); + memcpy(&(item->current_attach->size), item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); + LE32_CPU(item->current_attach->size); + // item->email->rtf_compressed = ; + // attach_num++; + } + 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_MAIN(("Adding Encrypted Body as attachment\n")); + item->current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(item->current_attach, 0, sizeof(pst_item_attach)); + item->current_attach->next = item->attach; + item->attach = item->current_attach; + + item->current_attach->data = item->email->encrypted_body; + item->current_attach->size = item->email->encrypted_body_size; + item->email->encrypted_body = NULL; + } + if (item->email->encrypted_htmlbody) { + DEBUG_MAIN(("Adding encrypted HTML body as attachment\n")); + item->current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); + memset(item->current_attach, 0, sizeof(pst_item_attach)); + item->current_attach->next = item->attach; + item->attach = item->current_attach; + + item->current_attach->data = item->email->encrypted_htmlbody; + item->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"); + } + base64_body = 0; + // attachments + item->current_attach = item->attach; + while (item->current_attach != NULL) { + DEBUG_MAIN(("main: Attempting Attachment encoding\n")); + if (item->current_attach->data == NULL) { + DEBUG_MAIN(("main: Data of attachment is NULL!. Size is supposed to be %i\n", item->current_attach->size)); + } + if (mode == MODE_SEPERATE) { + f->name = check_filename(f->name); + if (item->current_attach->filename2 == NULL) { + temp = xmalloc(strlen(f->name)+15); + sprintf(temp, "%s-attach%i", f->name, attach_num); + } else { + temp = xmalloc(strlen(f->name)+strlen(item->current_attach->filename2)+15); + fp = NULL; x=0; + do { + if (fp != NULL) fclose(fp); + if (x == 0) + sprintf(temp, "%s-%s", f->name, item->current_attach->filename2); + else + sprintf(temp, "%s-%s-%i", f->name, item->current_attach->filename2, x); + } while ((fp = fopen(temp, "r"))!=NULL && ++x < 99999999); + if (x > 99999999) { + DIE(("error finding attachment name. exhausted possibilities to %s\n", temp)); + } + } + DEBUG_MAIN(("main: Saving attachment to %s\n", temp)); + if ((fp = fopen(temp, "w")) == NULL) { + WARN(("main: Cannot open attachment save file \"%s\"\n", temp)); + } else { + if (item->current_attach->data != NULL) + fwrite(item->current_attach->data, 1, item->current_attach->size, fp); + else { + pst_attach_to_file(&pstfile, item->current_attach, fp); + } + fclose(fp); + } + } else { + DEBUG_MAIN(("main: Attachment Size is %i\n", item->current_attach->size)); + DEBUG_MAIN(("main: Attachment Pointer is %p\n", item->current_attach->data)); + if (item->current_attach->data != NULL) { + if ((enc = base64_encode (item->current_attach->data, item->current_attach->size)) == NULL) { + DEBUG_MAIN(("main: ERROR base64_encode returned NULL. Must have failed\n")); + item->current_attach = item->current_attach->next; + continue; + } + } + if (boundary) { + fprintf(f->output, "\n--%s\n", boundary); + if (item->current_attach->mimetype == NULL) { + fprintf(f->output, "Content-type: %s\n", MIME_TYPE_DEFAULT); + } else { + fprintf(f->output, "Content-type: %s\n", item->current_attach->mimetype); + } + fprintf(f->output, "Content-transfer-encoding: base64\n"); + if (item->current_attach->filename2 == NULL) { + fprintf(f->output, "Content-Disposition: inline\n\n"); + } else { + fprintf(f->output, "Content-Disposition: attachment; filename=\"%s\"\n\n", + item->current_attach->filename2); + } + } + if (item->current_attach->data != NULL) { + fwrite(enc, 1, strlen(enc), f->output); + DEBUG_MAIN(("Attachment Size after encoding is %i\n", strlen(enc))); + } else { + pst_attach_to_file_base64(&pstfile, item->current_attach, f->output); + } + fprintf(f->output, "\n\n"); + } + item->current_attach = item->current_attach->next; + attach_num++; + } + if (mode != MODE_SEPERATE) { + DEBUG_MAIN(("main: Writing buffer between emails\n")); + if (boundary) + fprintf(f->output, "\n--%s--\n", boundary); + fprintf(f->output, "\n\n"); + } + } else if (item->type == PST_TYPE_JOURNAL) { + // deal with journal items + if (mode == MODE_SEPERATE) { + mk_seperate_file(f); + } + f->email_count++; + + DEBUG_MAIN(("main: Processing Journal Entry\n")); + if (f->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(f->output, "BEGIN:VJOURNAL\n"); + if (item->email->subject != NULL) + fprintf(f->output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj)); + if (item->email->body != NULL) + fprintf(f->output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body)); + if (item->journal->start != NULL) + fprintf(f->output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->journal->start)); + fprintf(f->output, "END:VJOURNAL\n\n"); + } else if (item->type == PST_TYPE_APPOINTMENT) { + // deal with Calendar appointments + if (mode == MODE_SEPERATE) { + mk_seperate_file(f); + } + f->email_count++; + + DEBUG_MAIN(("main: Processing Appointment Entry\n")); + if (f->type != PST_TYPE_APPOINTMENT) { + DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); + } + fprintf(f->output, "BEGIN:VEVENT\n"); + if (item->create_date != NULL) + fprintf(f->output, "CREATED:%s\n", rfc2445_datetime_format(item->create_date)); + if (item->modify_date != NULL) + fprintf(f->output, "LAST-MOD:%s\n", rfc2445_datetime_format(item->modify_date)); + if (item->email != NULL && item->email->subject != NULL) + fprintf(f->output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj)); + if (item->email != NULL && item->email->body != NULL) + fprintf(f->output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body)); + if (item->appointment != NULL && item->appointment->start != NULL) + fprintf(f->output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->appointment->start)); + if (item->appointment != NULL && item->appointment->end != NULL) + fprintf(f->output, "DTEND;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->appointment->end)); + if (item->appointment != NULL && item->appointment->location != NULL) + fprintf(f->output, "LOCATION:%s\n", rfc2426_escape(item->appointment->location)); + if (item->appointment != NULL) { + switch (item->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 (item->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"); + } else { + f->skip_count++; + DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", + item->type, item->ascii_type)); + } + } else { + f->skip_count++; + DEBUG_MAIN(("main: A NULL item was seen\n")); + } + DEBUG_MAIN(("main: Going to next d_ptr\n")); + if (boundary) { + free(boundary); + boundary = NULL; + } + check_parent: + // _pst_freeItem(item); + while (!skip_child && d_ptr->next == NULL && d_ptr->parent != NULL) { + DEBUG_MAIN(("main: Going to Parent\n")); + head = f->next; + if (f->output != NULL) + fclose(f->output); + 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 (mode == MODE_KMAIL) + close_kmail_dir(); + else if (mode == MODE_RECURSE) + close_recurse_dir(); + else if (mode == MODE_SEPERATE) + close_seperate_dir(); + free(f->name); + free(f->dname); + free(f); + f = head; + if (head == NULL) { //we can't go higher. Must be at start? + 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) { + 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) { + DEBUG_MAIN(("main: d_ptr is now NULL\n")); + } + } + if (output_mode != OUTPUT_QUIET) printf("Finished.\n"); + + DEBUG_MAIN(("main: Finished.\n")); + pst_close(&pstfile); + // fclose(pstfile.fp); + while (f != NULL) { + if (f->output != NULL) + 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) + // DO SOMETHING HERE + ; + head = f->next; + free (f); + f = head; + } + + 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 != NULL) { + 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; +} + +int usage() { + DEBUG_ENT("usage"); + version(); + printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); + printf("OPTIONS:\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-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; +} + +int version() { + DEBUG_ENT("version"); + printf("ReadPST v%s implementing LibPST v%s\n", VERSION, PST_VERSION); +#if BYTE_ORDER == BIG_ENDIAN + printf("Big Endian implementation being used.\n"); +#elif BYTE_ORDER == LITTLE_ENDIAN + 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__); +#endif + DEBUG_RET(); + return 0; +} + +char *kmail_chdir = NULL; + +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 != NULL && 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); + dir = 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 != NULL) { //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; +} + +char* mk_recurse_dir(char *dir) { + // 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 + int x; + char *out_name; + DEBUG_ENT("mk_recurse_dir"); + 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; +} + +char* mk_seperate_dir(char *dir, int overwrite) { +#if !defined(WIN32) && !defined(__CYGWIN__) + DIR * sdir = NULL; + struct dirent *dirent = NULL; + struct stat *filestat = xmalloc(sizeof(struct stat)); +#endif + + char *dir_name = NULL; + int x = 0, y = 0; + DEBUG_ENT("mk_seperate_dir"); + /*#if defined(WIN32) || defined(__CYGWIN__) + DIE(("mk_seperate_dir: Win32 applications cannot use this function yet.\n")); + #endif*/ + + dir_name = xmalloc(strlen(dir)+10); + + do { + if (y == 0) + sprintf(dir_name, "%s", dir); + else + sprintf(dir_name, "%s%09i", dir, y); // enough for 9 digits allocated above + + dir_name = check_filename(dir_name); + DEBUG_MAIN(("mk_seperate_dir: 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__) + if ((sdir = opendir("./")) == NULL) { + WARN(("mk_seperate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./")); + } else { + while ((dirent = readdir(sdir)) != NULL) { + 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 + } + + // overwrite will never change during this function, it is just there so that + // if overwrite is set, we only go through this loop once. + + // 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 mk_seperate_file(struct file_ll *f) { + DEBUG_ENT("mk_seperate_file"); + DEBUG_MAIN(("mk_seperate_file: 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, "%09i", f->email_count); + if (f->output != NULL) + fclose(f->output); + f->output = NULL; + f->name = check_filename(f->name); + if ((f->output = fopen(f->name, "w")) == NULL) { + DIE(("mk_seperate_file: Cannot open file to save email \"%s\"\n", f->name)); + } + DEBUG_RET(); + return 0; +} + +// my_stristr varies from strstr in that its searches are case-insensitive +char * my_stristr(char *haystack, char *needle) { + char *x=haystack, *y=needle, *z = NULL; + DEBUG_ENT("my_stristr"); + if (haystack == NULL || needle == NULL) + return NULL; + while (*y != '\0' && *x != '\0') { + if (tolower(*y) == tolower(*x)) { + // move y on one + y++; + if (z == NULL) { + 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; +} + +char *check_filename(char *fname) { + char *t = fname; + DEBUG_ENT("check_filename"); + if (t == NULL) { + DEBUG_RET(); + return fname; + } + while ((t = strpbrk(t, "/\\:")) != NULL) { + // 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 == NULL) + ret = str; + else { + + // calculate space required to escape all the following characters + x = strlen(str) +(y=(chr_count(str, ',')*2) + (chr_count(str, '\\')*2) + (chr_count(str, ';')*2) + (chr_count(str, '\n')*2)); + z = chr_count(str, '\r'); + if (y == 0 && z == 0) + // there isn't any extra space required + ret = str; + else { + buf = (char*) realloc(buf, x+1); + a = str; + b = buf; + while (*a != '\0') { + switch(*a) { + case ',' : + case '\\': + case ';' : + case '\n': + *(b++)='\\'; + *b=*a; + break; + case '\r': + break; + default: + *b=*a; + } + b++; + a++; + } + *b = '\0'; + 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 == NULL) + buffer = malloc(30); // should be enough for the date as defined below + + stm = fileTimeToStructTM(ft); + //Year[4]-Month[2]-Day[2] Hour[2]:Min[2]:Sec[2] + 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 == 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; +} diff -r 000000000000 -r 6b1b602514db readpstlog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readpstlog.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,210 @@ +#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 *i=NULL, x, ptr, stop=0, flag; + char *fname, *buf, format, 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; + + 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 != NULL) + free(i); + i = (int*)xmalloc(sizeof(int)*(x+1)); + // plus 1 cause we want to read the offset of the next index + if (get(i, sizeof(int), 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); + 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 ((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) { + 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=='T') { // text format + printf("%s[%d]: %s", &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 { + printf("%s", buf); + } + } + printf("\n"); + } + } + 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 z; + 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("\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 ain't 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 -r 000000000000 -r 6b1b602514db testdebug.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdebug.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,23 @@ +#include +#include +#include "define.h" + +#define BUF_SIZE 100000 +int main() { + char *x = xmalloc(BUF_SIZE); // 10k + memset(x, '.', BUF_SIZE-1); + x[BUF_SIZE-2]='P'; + x[BUF_SIZE-1]='\0'; + + DEBUG_INIT("libpst.log"); + DEBUG_REGISTER_CLOSE(); + + DEBUG_ENT("main"); + + DEBUG_FILE(("%s", x)); + DEBUG_FILE(("This is an error %d\n", 4)); + + DEBUG_RET(); + return 0; +} + diff -r 000000000000 -r 6b1b602514db timeconv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timeconv.c Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,126 @@ +/*********************************************************************** + * + * Borrowed from WINE sources!! (http://www.winehq.com) + * Converts a Win32 FILETIME structure to a UNIX time_t value + */ + +/*** WARNING **** + * This file is not to be incluided in a Visual C++ Project + * It will make the whole project fail to compile + * There are functions in libpst.c to handle the dates + * Do not use this one + */ + +#include +#include "common.h" + +time_t fileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ); +char * fileTimeToAscii (const FILETIME *filetime); + +char * fileTimeToAscii (const FILETIME *filetime) { + time_t t1; + + t1 = fileTimeToUnixTime(filetime,0); + return ctime(&t1); +} + +struct tm * fileTimeToStructTM (const FILETIME *filetime) { + time_t t1; + t1 = fileTimeToUnixTime(filetime, 0); + return gmtime(&t1); +} + +/*********************************************************************** + * DOSFS_FileTimeToUnixTime + * + * Convert a FILETIME format to Unix time. + * If not NULL, 'remainder' contains the fractional part of the filetime, + * in the range of [0..9999999] (even if time_t is negative). + */ +time_t fileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ) +{ + /* Read the comment in the function DOSFS_UnixTimeToFileTime. */ +#if USE_LONG_LONG + + long long int t = filetime->dwHighDateTime; + t <<= 32; + t += (UINT32)filetime->dwLowDateTime; + t -= 116444736000000000LL; + if (t < 0) + { + if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; + return -1 - ((-t - 1) / 10000000); + } + else + { + if (remainder) *remainder = t % 10000000; + return t / 10000000; + } + +#else /* ISO version */ + + UINT32 a0; /* 16 bit, low bits */ + UINT32 a1; /* 16 bit, medium bits */ + UINT32 a2; /* 32 bit, high bits */ + UINT32 r; /* remainder of division */ + unsigned int carry; /* carry bit for subtraction */ + int negative; /* whether a represents a negative value */ + + /* Copy the time values to a2/a1/a0 */ + a2 = (UINT32)filetime->dwHighDateTime; + a1 = ((UINT32)filetime->dwLowDateTime ) >> 16; + a0 = ((UINT32)filetime->dwLowDateTime ) & 0xffff; + + /* Subtract the time difference */ + if (a0 >= 32768 ) a0 -= 32768 , carry = 0; + else a0 += (1 << 16) - 32768 , carry = 1; + + if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0; + else a1 += (1 << 16) - 54590 - carry, carry = 1; + + a2 -= 27111902 + carry; + + /* If a is negative, replace a by (-1-a) */ + negative = (a2 >= ((UINT32)1) << 31); + if (negative) + { + /* Set a to -a - 1 (a is a2/a1/a0) */ + a0 = 0xffff - a0; + a1 = 0xffff - a1; + a2 = ~a2; + } + + /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r. + Split the divisor into 10000 * 1000 which are both less than 0xffff. */ + a1 += (a2 % 10000) << 16; + a2 /= 10000; + a0 += (a1 % 10000) << 16; + a1 /= 10000; + r = a0 % 10000; + a0 /= 10000; + + a1 += (a2 % 1000) << 16; + a2 /= 1000; + a0 += (a1 % 1000) << 16; + a1 /= 1000; + r += (a0 % 1000) * 10000; + a0 /= 1000; + + /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */ + if (negative) + { + /* Set a to -a - 1 (a is a2/a1/a0) */ + a0 = 0xffff - a0; + a1 = 0xffff - a1; + a2 = ~a2; + + r = 9999999 - r; + } + + if (remainder) *remainder = r; + + /* Do not replace this by << 32, it gives a compiler warning and it does + not work. */ + return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0; +#endif +} diff -r 000000000000 -r 6b1b602514db timeconv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/timeconv.h Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,21 @@ +#ifndef __TIMECONV_H +#define __TIMECONV_H + +#include "common.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + time_t fileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ); + + char * fileTimeToAscii (const FILETIME *filetime); + + struct tm * fileTimeToStructTM (const FILETIME *filetime); + +#ifdef __cplusplus +} +#endif + +#endif diff -r 000000000000 -r 6b1b602514db w32pst.sln --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w32pst.sln Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "w32pst", "w32pst.vcproj", "{7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "readlog", "readlog.vcproj", "{DC5B4944-D652-4761-AF88-9FC2AC321FA1}" +EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "LibPST", "Setup1.vdproj", "{F3CFFE7E-DA2E-4CDF-8BA7-D32C7A5F148A}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}.Debug.ActiveCfg = Debug|Win32 + {7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}.Debug.Build.0 = Debug|Win32 + {7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}.Release.ActiveCfg = Release|Win32 + {7ABFA22F-27B6-4771-A63A-F3BD9BB5E819}.Release.Build.0 = Release|Win32 + {DC5B4944-D652-4761-AF88-9FC2AC321FA1}.Debug.ActiveCfg = Debug|Win32 + {DC5B4944-D652-4761-AF88-9FC2AC321FA1}.Debug.Build.0 = Debug|Win32 + {DC5B4944-D652-4761-AF88-9FC2AC321FA1}.Release.ActiveCfg = Release|Win32 + {DC5B4944-D652-4761-AF88-9FC2AC321FA1}.Release.Build.0 = Release|Win32 + {F3CFFE7E-DA2E-4CDF-8BA7-D32C7A5F148A}.Debug.ActiveCfg = Debug + {F3CFFE7E-DA2E-4CDF-8BA7-D32C7A5F148A}.Release.ActiveCfg = Release + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff -r 000000000000 -r 6b1b602514db w32pst.vcproj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/w32pst.vcproj Fri Jul 09 07:26:16 2004 -0700 @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +