dbxunit.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:42k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit dbxunit;
  2. interface
  3. uses Windows;
  4. type
  5.   int1 = char;
  6.   int2 = word;
  7.   int4 = longword;
  8.   paint4 = ^taint4;
  9.   taint4 = array[0..1] of int4;
  10.   paint1 = ^taint1;
  11.   taint1 = array[0..1] of int1;
  12.   dtDateTime = array[0..1] of int4;
  13. const
  14.   // Message flags (TDbxMessageInfo.Flags)
  15.   MF_MESSAGE_BODY = $00000001;
  16.   MF_IN_WORK      = $00000008;
  17.   MF_MARKED       = $00000020;
  18.   MF_READ         = $00000080;
  19.   MF_MARKED_FOR_DOWNLOAD = $00000100;
  20.   MF_NEWS_POSTING        = $00000800;
  21.   MF_DIGITAL_SIGNED      = $00001000;
  22.   MF_WITH_ATTACHMENT     = $00004000;
  23.   MF_REPLIED             = $00080000;
  24.   MF_FORWARDED           = $00100000;
  25.   MF_THREAD_IS_WATCHED   = $00400000;
  26.   MF_THREAD_IS_IGNORED   = $00800000;
  27.   // Folder flags (TDbxFolderInfo.Flags)
  28.   FF_ACTIVE_FOLDER = $00000001;
  29.   FF_IN_OE         = $00000080;
  30.   FF_ALL_WITH_SUBFOLDERS = $00000100;
  31.   CLSID_MessageDatabase = #$c5#$fd#$74#$6f;
  32.   CLSID_FolderDatabase = #$c6#$fd#$74#$6f;
  33.   CLSID_Pop3uidlDatabase = #$c7#$fd#$74#$6f;
  34.   CLSID_OfflineDatabase = #$30#$9d#$fe#$26;
  35. type
  36.   // The first sector is used for the _file_header_ and the _file_info_.
  37.   // The shortest dbx files I found only consists of a _file_header_ and nothing else.
  38.   TDbxFileHeader = record
  39.       // 0x0000
  40.       // must be "cf ad 12 fe"
  41.       reserved0 : array[0..3] of int1;
  42.       // 0x0004
  43.       // m : "c5 fd 74 6f" CLSID_MessageDatabase
  44.       // f : "c6 fd 74 6f" CLSID_FolderDatabase
  45.       // p : "c7 fd 74 6f" Pop3uidl
  46.       // o : "30 9d fe 26" Offline
  47.       dbxtype : array[0..3] of int1;
  48.       // 0x0008
  49.       // must be "66 e3 d1 11 9a 4e 00 c0 4f a3 09 d4 05 00 00 00 05 00 00 00"
  50.       reserved1 : array[0..19] of int1;
  51.       // 0x001c
  52.       // The Length of _file_info_ object
  53.       FileInfoLength : int4;
  54.       // 0x0024
  55.       // pointer to the last variable segment
  56.       LastVariableSegment : int4;
  57.       // 0x0028
  58.       // Length of a variable segment (0xc000)
  59.       VariableSegmentLength : int4;
  60.       // 0x002c
  61.       // Used space for the last variable segment
  62.       VariableSegmentSpace : int4;
  63.       // 0x0030
  64.       // Pointer to the last _tree_ segment
  65.       LastTreeSegment : int4;
  66.       // 0x0034
  67.       // Length of the last _tree_ segment (0x3e1c)
  68.       TreeSegmentLength : int4;
  69.       // 0x0038
  70.       // Used space for the last _tree_ segment
  71.       TreeSegmentSpace : int4;
  72.       // 0x003c
  73.       // m : Pointer to the last _message_ segment
  74.       LastMessage : int4;
  75.       // 0x0040
  76.       // m : Length of a _message_ segment (0xf780)
  77.       MessageSegmentLength : int4;
  78.       // 0x0044
  79.       // m : Used space for the last _message_ segment
  80.       MessageSegmentSpace : int4;
  81.       // 0x0048
  82.       // m : Root pointer to the deleted message list
  83.       DeletedMessageList : int4;
  84.       // 0x004c
  85.       // Root pointer to the deleted tree list
  86.       DeletedTreeList : int4;
  87.       // 0x0054
  88.       // Used space in the middle sector of the file
  89.       MiddleSectorSpace : int4;
  90.       // 0x0058
  91.       // Reusable space in the middle sector of the file
  92.       ReuseMiddleSectorSpace : int4;
  93.       // 0x005c
  94.       // Index of the last entry in the _tree_
  95.       LastTreeEntry : int4;
  96.       // 0x0064
  97.       // must be "01 00 00 00"
  98.       reserved2 : array[0..3] of int1;
  99.       // 0x0068
  100.       // f : "01 00 00 00"
  101.       reserved3 : array[0..3] of int1;
  102.       // 0x006c
  103.       // f : pointer to the first _folder_list_node_
  104.       FirstFolderListNode : int4;
  105.       // 0x0070
  106.       // f : pointer to the last _folder_list_node_
  107.       LastFolderListNode : int4;
  108.       // 0x0074
  109.       // f : "03 00 00 00"
  110.       reserved4 : array[0..3] of int1;
  111.       // 0x0078
  112.       // f : "02 00 00 00"
  113.       reserved5 : array[0..3] of int1;
  114.       // 0x007c
  115.       // Used space of the file. (Length of the first and middle sector)
  116.       UsedFileSpace : int4;
  117.       // 0x0080
  118.       // f : "02 00 00 00"
  119.       // m : "03 00 00 00"
  120.       reserved6 : array[0..3] of int1;
  121.       // 0x0088
  122.       // m :  Pointer to _message_conditions_ object
  123.       MessageConditions : int4;
  124.       // 0x008c
  125.       // f : Pointer to _folder_conditions_ object
  126.       FolderConditions : int4;
  127.       // 0x00c4
  128.       // Entries in tree (SortTreeRootNode)
  129.       SortTreeEntries : int4;
  130.       // 0x00c8
  131.       // Entries in tree (TreeRootNode)
  132.       TreeRootEntries : int4;
  133.       // 0x00cc
  134.       // f : Entries in tree (ActiveFolders)
  135.       ActiveTreeEntries : int4;
  136.       // 0x00e4
  137.       // Pointer to the root node of a tree all entries are sorted by there index
  138.       // m : Points to all message info objects
  139.       // f : Points to all folder info objects
  140.       SortTreeRootNode : int4;
  141.       // 0x00e8
  142.       // Pointer to the root node of a tree
  143.       // m : Points to all watched or ignored message info objects
  144.       // f : Points to the same folder info objects like (39) sorted by there
  145.       //     parent folders index followed by there name
  146.       TreeRootNode : int4;
  147.       // 0x00ec
  148.       // f : Pointer to the root node of a tree. points to all activ subfolders
  149.       //     of "Outlook Express". this are the folders you can see in OE on the
  150.       //     folders pane. sorted like the tree in (TreeRootNode)
  151.       ActiveFolders : int4;
  152.       // 0x0108
  153.       // must be "01 00 00 00"
  154.       reserved7 : array[0..3] of int1;
  155.       // 0x010c
  156.       // f : "02 00 00 00"
  157.       reserved8 : array[0..3] of int1;
  158.       // 0x027c
  159.       // Used space for _indexed_info_ objects
  160.       // m : _message_info_
  161.       // f : _folder_info_
  162.       IndexedInfoSpace : int4;
  163.       // 0x0280
  164.       // Used space for _conditions_ objects
  165.       // m : 0x50 _message_conditions_
  166.       // f : 0x2c _folder_conditions_
  167.       ConditionsSpace : int4;
  168.       // 0x0288
  169.       // f : used space for _folder_list_ objects
  170.       FolderListSpace : int4;
  171.       // 0x028c
  172.       // used space for _tree_ objects
  173.       TreeSpace : int4;
  174.       // 0x0290
  175.       // m : used space for _message_ objects
  176.       MessageSpace : int4;
  177.       // (MiddleSectorSpace) - (ReuseMiddleSectorSpace) =
  178.       //            (IndexedInfoSpace) + (ConditionsSpace) + (FolderListSpace) +
  179.       //            (TreeSpace) + (MessageSpace)
  180.       // 0x22bc
  181.       // must be "01 00 00 00"
  182.       reserved9 : array[0..3] of int1;
  183.       // 0x22ec
  184.       // must be "00 00 02 00"
  185.       reserved10 : array[0..3] of int1;
  186.       // 0x22f0
  187.       // m : "07 00 00 00"
  188.       // f : "01 00 00 00 00 00 02 05"
  189.       reserved11 : array[0..7] of int1;
  190.       // 0x2320
  191.       // f : "02 00 01 00 .. .. .. .. 02 05 00 00"
  192.       reserved12 : array[0..299] of int1;
  193.       // 0x244c
  194.       // must be "68 00 00 00"
  195.       reserved13 : array[0..3] of int1;
  196.     end;
  197.   TDbxMessageFileInfo = record
  198.       // Starts from 0x24bc
  199.       // 0x0000
  200.       // must be "01 00 00 00"
  201.       reserved0 : array[0..3] of int1;
  202.       // 0x0004
  203.       // Source type (3 - Local store, 0 - News)
  204.       SourceType : int1;
  205.       // 0x0005
  206.       // Registry key of the account
  207.       AccountRegistryKey : array[0..255] of int1;
  208.       // 0x0105
  209.       // Folder name used in Outlook Express
  210.       FolderName : array[0..266] of int1;
  211.       // 0x0210
  212.       // A small value (3 or 4 or ...)
  213.       SmallValue : int4;
  214.       // 0x0214
  215.       // must be "01 00 00 00 00 00 00 00 fa 0f 00 00"
  216.       reserved1 : array[0..11] of int1;
  217.       // 0x0220
  218.       // OE session number file last changed
  219.       SessionNumber : int4;
  220.       // 0x0224
  221.       // ??
  222.       reserved2 : int4;
  223.       // 0x0348
  224.       // must be "01 00 01 00"
  225.       reserved3 : array[0..3] of int1;
  226.     end;
  227.   TDbxFolderFileInfo = record
  228.       // Starts from 0x24bc
  229.       // 0x0000
  230.       // Win32 filetime - date/time creation foldres.dbx
  231.       CreationTime : dtDateTime;
  232.       // 0x0008
  233.       // must be "01 00 00 00"
  234.       reserved0 : array[0..3] of int1;
  235.     end;
  236.   // The middle sector is used to store all other objects. The first value of
  237.   // each object in this sector is the address of the object(object marker).
  238.   // This sector is divided up into segments. I found three different types of segments :
  239.   //   * The variable segments are used to store objects of different type and
  240.   //     size. This segments are used because objects of the same type don't
  241.   //     have the same size (_indexed_info_ objects) or there are only a few
  242.   //     objects of a special type (_conditions_ or _folder_list_ objects).
  243.   //   * The tree segments are used to store the _tree_node_ objects. Each object
  244.   //     has a size of 0x27c bytes.
  245.   //   * The message segments are used to store the _message_ objects. Each object
  246.   //     has a size of 0x210 bytes. This segments are only used in the message dbx files.
  247.   TDbxIndexedInfo = record
  248.       // Object marker
  249.       ObjectMarker : int4;
  250.       // Length of the following _indexed_info_ object
  251.       IndexedInfoBodyLength : int4;
  252.       // Length of this _indexed_info_ object. (Not always set)
  253.       IndexedInfoObjectLength : int2;
  254.       // Entries in the following index field
  255.       Entries : int1;
  256.       // Counts the changes on this _indexed_info_ object
  257.       ChangesCount : int1;
  258.       data : paint1;
  259.       BeginIndex, LengthIndex : array[0..$1f] of int4;
  260.     end;
  261.   TDbxConditions = record
  262.       // Object marker
  263.       ObjectMarker : int4;
  264.       // Length of the following text
  265.       TextLength : int4;
  266.       // 0x00 is terminated C-string
  267.       text : pointer;
  268.       // In the message dbx files is a message conditions object used.
  269.       // A pointer to this object is stored in (MessageConditions) in the TDbxFileHeader.
  270.       // In the folders.dbx file is a folder conditions object used.
  271.       // A pointer to this object is stored at (FolderConditions) in the TDbxFileHeader.
  272.     end;
  273.     TDbxTreeNode = record
  274.         // The tree stores int4 values. In the dbx files the int4 values are pointers
  275.         // to indexed info objects. The nodes of the tree are the tree nodes. The
  276.         // tree node is the basic part of the tree. Each node object is 0x27c bytes
  277.         // long. 0x18 bytes for the header and 0x264 bytes for the body.
  278.         // Object marker
  279.         ObjectMarker : int4;
  280.         // --- unused
  281.         reserved0 : int4;
  282.         // Pointer to child node
  283.         ChildNode : int4;
  284.         // Pointer to parent node
  285.         ParentNode : int4;
  286.         // Node ID
  287.         NodeID : int1;
  288.         // Entries in the body of this node
  289.         EntriesCount : int1;
  290.         // --- unused
  291.         reserved1 : int2;
  292.         // Stored values in the child tree (ChildNode)
  293.         Values : int4;
  294.       end;
  295.     // The body of a tree node contains (EntriesCount) entries.
  296.     // Each entry consists of 3 int4 values :
  297.     TDbxTreeEntry = record
  298.         // Value
  299.         Value : int4;
  300.         // Pointer to child node
  301.         ChildNode : int4;
  302.         // Stored values in the child tree (ChildNode)
  303.         Values : int4;
  304.       end;
  305.     PDbxTreeEntryArray = ^TDbxTreeEntryArray;
  306.     TDbxTreeEntryArray = array[0..1] of TDbxTreeEntry;
  307.     TDbxTree = record
  308.         Node : TDbxTreeNode;
  309.         Entries : paint4;
  310.         Count : int4;
  311.       end;
  312.     // * Because of the size of 0x264 for the body, (TDbxTreeNode.EntriesCount)
  313.     //   can be up to 0x33.
  314.     // * The root node of the tree has no parent, so (TDbxTreeNode.ParentNode)
  315.     //   is set to 0.
  316.     // * The leafs have no child nodes, so (TDbxTreeNode.ChildNode),
  317.     //   (TDbxTreeNode.VAlues), (TDbxTreeEntry.ChildNode) and
  318.     //   (TDbxTreeEntry.Values) are set to 0.
  319.     // * The child node (TDbxTreeNode.ChildNode) has a node id(TDbxTreeNode.NodeID)
  320.     //   of 0. The other child nodes (TDbxTreeEntry.ChildNode) have node id's from 0 to
  321.     //   (TDbxTreeNode.EntriesCount) -1.
  322.     // In the message dbx files are two trees used.
  323.     // They are used to store pointers to _message_info_ objects.
  324.     //  * This first one is used to store pointers to 'all' _message_info_ objects.
  325.     //  * The second tree is used to store pointers to all watched or ignored
  326.     //    _message_info_ objects.
  327.     // In the folders.dbx file are three trees.
  328.     // They are used to store pointers to _folder_info_ objects.
  329.     //   * The first one is used to store pointers to all _folder_info_ objects,
  330.     //     sorted by there index.
  331.     //   * The second one is used to store pointers to all _folder_info_ objects,
  332.     //     sorted by there parent folders index followed by there name.
  333.     //   * The third one is used to store all pointers to _folder_info_ objects
  334.     //     which are active subfolders of "Outlook Express", sorted by there
  335.     //     parent folders index followed by there name. This are the folders
  336.     //     you can see in OE on the folders pane.
  337.     // This object is only used in the message dbx files.
  338.     // The message is separated in several objects which are organized in
  339.     // a single linked list. The pointer to the first one can be retrieved
  340.     // from the corresponding _message_info_ object. To get the whole message
  341.     // text you have to walk along the links and put the text segments together.
  342.     TDbxMessage = record
  343.         // Object Marker
  344.         ObjectMarker : int4;
  345.         // Length of the body
  346.         BodyLength : int4;
  347.         // Text. The lenght of this text segment is stored in TDbxMessageHeader.BodyTextSegmentLength
  348.         Text : paint1;
  349.       end;
  350.     // All message objects have a size of 0x210 bytes. 0x10 bytes for the header
  351.     // and 0x200 bytes for the text segment. Even if the text is shorter
  352.     // the whole space is reserved, but (TDbxMessageHeader.BodyTextSegmentLength) provides the real length.
  353.     // OE stores the message text with 0x0d 0x0a at the end of each line and no terminating 0x00.
  354.     // This object is only used in the message dbx files.
  355.     // The message info object stores information about a corresponding _message_ object.
  356.     // The data structure of the message info object is the _indexed_info_.
  357.     // The pointers to the message info objects are stored in the _tree_.
  358.     TDbxMessageInfo = record
  359.         // 00
  360.         // Index
  361.         Index : int4;
  362.         // 01
  363.         // Flags
  364.         Flags : int4;
  365.         // 02
  366.         // (Win32 Filetime) Time when message was created/sent
  367.         CreateTime : dtDateTime;
  368.         // 03
  369.         // if set, number of the lines in the message body
  370.         LinesCount : int4;
  371.         // 04
  372.         // Pointer to the corresponding 'message'
  373.         MessagePointer : int4;
  374.         // 05
  375.         // Original subject (without any "re:")
  376.         OriginalSubject : string;
  377.         // 06
  378.         // (Win32 Filetime) time when message was saved in this folder
  379.         SavedTime : dtDateTime;
  380.         // 07
  381.         // Message ID
  382.         MessageID : string;
  383.         // 08
  384.         // Subject of the message
  385.         Subject : string;
  386.         // 09
  387.         // Sender mail address and name
  388.         Sender : string;
  389.         // 0A
  390.         // Answered to message id
  391.         Answered : string;
  392.         // 0B
  393.         // Server / Newsgroup / Message number (list)
  394.         ServerList : string;
  395.         // 0C
  396.         // Server
  397.         Server : string;
  398.         // 0D
  399.         // Sender name
  400.         SenderName : string;
  401.         // 0E
  402.         // Sender mail address
  403.         SenderAddress : string;
  404.         // 0F
  405.         // unused ???
  406.         // 10
  407.         // Priority of the email (1 high, 3 normal, 5 low)
  408.         Priority : int4;
  409.         // 11
  410.         // Length of the 'message' text(header and body)
  411.         // !!! this value can be wrong !!!
  412.         TextLength : int4;
  413.         // 12
  414.         // (Win32 FILETIME) time message created/received
  415.         ReceivedTime : dtDateTime;
  416.         // 13
  417.         // Receiver name
  418.         ReceiverName : string;
  419.         // 14
  420.         // Receiver mail address
  421.         ReceiverAddress : string;
  422.         // 15
  423.         // not used ???
  424.         // 16
  425.         // When used always : lengt = 1 / values = 0x00
  426.         reserved0 : int4;
  427.         // 17
  428.         // not used ???
  429.         // 18
  430.         // When used always : lengt = 1 / values = 0x00
  431.         reserved1 : int4;
  432.         // 19
  433.         // When used always : lengt = 1 / values = 0x00
  434.         reserved2 : int4;
  435.         // 1A
  436.         // OE mail or news account name
  437.         AccountName : string;
  438.         // 1B
  439.         // Registry key for mail or news account (like "00000008")
  440.         RegistryKey : string;
  441.         // 1C
  442.         // message text structure. this data is constructed, when a message
  443.         // is read the first time.
  444.  //       Data : pointer;
  445.         // 23
  446.         // This index is used for the Hotmail Http email accounts and stores
  447.         // a message id ("MSG982493141.24"). I don't know if other Http email
  448.         // accounts are using this index too.
  449.         IndexID : string;
  450.       end;
  451.     TDbxFolderInfo = record
  452.         // 00
  453.         // Index (for the root folder "Outlook Express" default 0)
  454.         Index : int4;
  455.         // 01
  456.         // Index of the parent folder (for the root folder "Outlook Express" : 0xffffffff (-1))
  457.         ParentIndex : int4;
  458.         // 02
  459.         // Folder name (newsgroup name)
  460.         FolderName : string;
  461.         // 03
  462.         // dbx filename
  463.         DBXFileName : string;
  464.         // 04
  465.         reserved0 : int4;
  466.         // 05
  467.         // Registry key of the account
  468.         RegistryKey : string;
  469.         // 06
  470.         // Flags
  471.         Flags : int4;
  472.         // 07
  473.         // Number of messages in the folder
  474.         MessagesCount : int4;
  475.         // 08
  476.         // Number of unread messages in the folder
  477.         UnreadCount : int4;
  478.         // 09
  479.         // all OE subfolders of 'local folders' have a unique index
  480.         // int4
  481.         // 0A
  482.         // set for 'local folders' and all subfolders if set, always set to 0x03
  483.         // int4
  484.         // 0B
  485.         // unused ???
  486.         // 0C
  487.         // unused ???
  488.         // 0D
  489.         // maximal message index on the server
  490.         MaxIndexOnServer : int4;
  491.         // 0E
  492.         // minimal message index on the server
  493.         MinIndexOnServer : int4;
  494.         // 10
  495.         // maximal message index local
  496.         MaxIndexLocal : int4;
  497.         // 11
  498.         // minimal message index local
  499.         MinIndexLocal : int4;
  500.         // 12
  501.         // Messages to download ((0D) - (10))
  502.         DownloadCount : int4;
  503.         // 13
  504.         // data
  505.         // 14
  506.         // unused ???
  507.         // 15
  508.         // data
  509.         // 16
  510.         // unused ???
  511.         // 17
  512.         // unused ???
  513.         // 18
  514.         // unused ???
  515.         // 19
  516.         // unused ???
  517.         // 1a
  518.         // int4
  519.         // 1b
  520.         // unused ???
  521.         // 1c
  522.         // watched messages
  523.         Watched : int4;
  524.       end;
  525.     // Each deleted object in the middle sector of the file gets a new header.
  526.     // deleted objects are organized in a single linked list.
  527.     // Deleted message und tree objects always have the same size. They are easy
  528.     // to reuse. Only on single linked list is needed for each. You can find the
  529.     // pointers to the roots at position (12) and (13) in the file header.
  530.     // All other deleted objects (indexed info, conditions, folder list) from the
  531.     // variable segments have no unique length. They are organized in several single
  532.     // linked lists. For each length one. You can find the pointers to the roots
  533.     // at position (a7) and following in the file header.
  534.     TDbxDeleted = record
  535.         // Object marker
  536.         ObjectMarker : int4;
  537.         // Length of field (FreeSpace)
  538.         FieldLength : int4;
  539.         // Length of this object, (FieldLength) + 0x14
  540.         ObjectLength : int4;
  541.         // not used, not cleared
  542.         reserved : int4;
  543.         // Pointer to the next deleted object
  544.         Next : int4;
  545.         // Free space, not cleared, length (FieldLength)
  546.       end;
  547.     PDbxFoldersList = ^TDbxFoldersList;
  548.     TDbxFoldersList = record
  549.         info : TDbxFolderInfo;
  550.         next : PDbxFoldersList;
  551.       end;
  552.     TOEFolder = class
  553.         ParentFolder : TOEFolder;
  554.         ChildFolders : array of TDbxFolderInfo;
  555.         NextFolder : TOEFolder;
  556.         constructor Create;
  557.       end;
  558.     TOEMessage = class
  559.       end;
  560.     TOEIdentity = class
  561.         UserID : string; // IID
  562.         Username : string; // e.g. Main Identrity
  563.         StoreRoot : string; // path to dbx files
  564.         version : string;
  565.       end;
  566.     // if function returns true, then getting messages will be continue
  567.     TFGetMessageInfo = function (MessageInfo : TDbxMessageInfo) : boolean of object;
  568.     // Class for importing messages and folders from Outlook Express database files
  569.     TOEImport = class
  570.         // Folders tree
  571.         FoldersTree : TOEFolder;
  572.         // List of OE identities
  573.         Identities : array of TOEIdentity;
  574.         // Main Identity
  575.         MainIdentity : TOEIdentity;
  576.         constructor Create;
  577.         // Sets up Identities and MainIdentity;
  578.         procedure GetIdentities;
  579.         procedure LoadFileHeader(var f : file; var FileHeader : TDbxFileHeader);
  580.         procedure LoadFolderFileInfo(var f : file; var FileInfo : TDbxFolderFileInfo);
  581.         procedure LoadFolderInfo(var f : file; Address : int4; var FolderInfo : TDbxFolderInfo);
  582.         procedure LoadIndexedInfo(var f : file; Address : int4; var IndexedInfo : TDbxIndexedInfo);
  583.         procedure LoadMessageFileInfo(var f : file; var FileInfo : TDbxMessageFileInfo);
  584.         procedure LoadMessageInfo(var f : file; Address : int4; var MessageInfo : TDbxMessageInfo);
  585.         procedure LoadTree(var f : file; Address, Entries : int4; var Tree : TDbxTree);
  586.         function GetIndexedValue(IndexedInfo : TDbxIndexedInfo; index : byte) : int4;
  587.         
  588.         function GetIndexedDateTime(IndexedInfo : TDbxIndexedInfo; index : byte) : dtDateTime;
  589.         function GetIndexedString(IndexedInfo : TDbxIndexedInfo; index : byte) : string;
  590.         procedure LoadMessagesList(filename : string; Func : TFGetMessageInfo);
  591.         procedure LoadMessage(var f : file; address : int4; var Message : TDbxMessage);
  592.         // Imports folders tree;
  593.         procedure ImportFoldersTree(Identity : TOEIdentity);
  594.         destructor Destroy; override;
  595.       end;
  596. implementation
  597. uses SysUtils;
  598. constructor TOEImport.Create;
  599. begin
  600.   Identities := nil;
  601.   FoldersTree := TOEFolder.Create;
  602.   MainIdentity := nil;
  603.   GetIdentities;
  604. end;
  605. function GetFullPath(path : pchar) : string;
  606. var
  607.   f, p : pchar;
  608.   resPath, srcPath, s, VarName : string;
  609.   i : integer;
  610. begin
  611.   srcPath := AnsiUpperCase(path);
  612.   resPath := path;
  613.   while (length(respath) > 0) and (pos(#0, respath) > 0) do
  614.     delete(respath, pos(#0, respath), 1);
  615.   p := GetEnvironmentStrings;
  616.   f := p;
  617.   while p^ <> #0 do
  618.   begin
  619.     s := UpperCase(String(p));
  620.     if s <> '' then OEMToChar(PChar(s), PChar(s));
  621.     VarName := copy(s, 1, pos('=', s) - 1);
  622.     i := pos('%' + VarName + '%', srcPath);
  623.     delete(s, 1, pos('=', s));
  624.     if i > 0 then
  625.     begin
  626.       Delete(srcPath, i, 2 + length(VarName));
  627.       insert(s, srcpath, i);
  628.       Delete(resPath, i, 2 + length(VarName));
  629.       insert(s, respath, i);
  630.     end;
  631.     inc(p, lStrLen(p) + 1);
  632.   end;
  633.   FreeEnvironmentStrings(f);
  634.   if Length(resPath) > 0 then
  635.     if resPath[Length(resPath)] <> '' then
  636.       resPath := resPath + '';
  637.   result := resPath;
  638. end;
  639. procedure TOEImport.GetIdentities;
  640. var
  641.   Reg : HKey;
  642.   k, keys : PStrList;
  643.   i, j : integer;
  644.   identity : TOEIdentity;
  645. begin
  646.   SetLength(Identities, 0);
  647.   try
  648.     Reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities');
  649.     keys := NewStrList;
  650.     k := NewStrList;
  651.     RegKeyGetSubKeys(Reg, keys); 
  652.     RegKeyClose(reg);
  653.     for i := 0 to Keys.Count - 1 do
  654.     begin
  655.       Reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i] + 'SoftwareMicrosoftOutlook Express');
  656.       RegKeyGetSubKeys(Reg, k);
  657.       RegKeyClose(reg);
  658.       for j := 0 to k.Count - 1 do
  659.       begin
  660.         identity := TOEIdentity.Create;
  661.         identity.version := k.Items[j];
  662.         identity.UserID := keys.Items[i];
  663.         reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i] + 'SoftwareMicrosoftOutlook Express' + k.Items[j]);
  664.         identity.StoreRoot := GetFullPath(PChar(RegKeyGetStrEx(reg, 'Store Root')));
  665.         RegKeyClose(reg);
  666.         reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i]);
  667.         identity.Username := RegKeyGetStr(reg, 'Username');
  668.         if identity.Username = 'Main Identity' then
  669.           MainIdentity := identity;
  670.         SetLength(Identities, length(Identities) + 1);
  671.         Identities[length(Identities) - 1] := identity;
  672.         RegKeyClose(reg);
  673.       end;
  674.     end;
  675.     keys.Free;
  676.     k.Free;
  677.   finally
  678.   end;
  679. end;
  680. destructor TOEImport.Destroy;
  681. var
  682.   i : integer;
  683. begin
  684.   FoldersTree.Free;
  685.   for i := 0 to length(identities) - 1 do
  686.   begin
  687.     identities[i].Free;
  688.   end;
  689.   SetLength(Identities, 0);
  690.   inherited;
  691. end;
  692. procedure TOEImport.LoadFileHeader(var f : file; var FileHeader : TDbxFileHeader);
  693. begin
  694.   FillChar(FileHeader, sizeof(FileHeader), 0);
  695.   try
  696.       BlockRead(f, FileHeader.reserved0, sizeof(FileHeader.reserved0));
  697.       BlockRead(f, FileHeader.dbxtype, sizeof(FileHeader.dbxtype));
  698.       BlockRead(f, FileHeader.reserved1, sizeof(FileHeader.reserved1));
  699.       BlockRead(f, FileHeader.FileInfoLength, sizeof(FileHeader.FileInfoLength));
  700.       Seek(f, $024);
  701.       BlockRead(f, FileHeader.LastVariableSegment, sizeof(FileHeader.LastVariableSegment));
  702.       BlockRead(f, FileHeader.VariableSegmentLength, sizeof(FileHeader.VariableSegmentLength));
  703.       BlockRead(f, FileHeader.VariableSegmentSpace, sizeof(FileHeader.VariableSegmentSpace));
  704.       BlockRead(f, FileHeader.LastTreeSegment, sizeof(FileHeader.LastTreeSegment));
  705.       BlockRead(f, FileHeader.TreeSegmentLength, sizeof(FileHeader.TreeSegmentLength));
  706.       BlockRead(f, FileHeader.TreeSegmentSpace, sizeof(FileHeader.TreeSegmentSpace));
  707.       BlockRead(f, FileHeader.LastMessage, sizeof(FileHeader.LastMessage));
  708.       Seek(f, $040);
  709.       BlockRead(f, FileHeader.MessageSegmentLength, sizeof(FileHeader.MessageSegmentLength));
  710.       BlockRead(f, FileHeader.MessageSegmentSpace, sizeof(FileHeader.MessageSegmentSpace));
  711.       BlockRead(f, FileHeader.DeletedMessageList, sizeof(FileHeader.DeletedMessageList));
  712.       BlockRead(f, FileHeader.DeletedTreeList, sizeof(FileHeader.DeletedTreeList));
  713.       Seek(f, $054);
  714.       BlockRead(f, FileHeader.MiddleSectorSpace, sizeof(FileHeader.MiddleSectorSpace));
  715.       BlockRead(f, FileHeader.ReuseMiddleSectorSpace, sizeof(FileHeader.ReuseMiddleSectorSpace));
  716.       BlockRead(f, FileHeader.LastTreeEntry, sizeof(FileHeader.LastTreeEntry));
  717.       Seek(f, $064);
  718.       BlockRead(f, FileHeader.reserved2, sizeof(FileHeader.reserved2));
  719.       BlockRead(f, FileHeader.reserved3, sizeof(FileHeader.reserved3));
  720.       BlockRead(f, FileHeader.FirstFolderListNode, sizeof(FileHeader.FirstFolderListNode));
  721.       BlockRead(f, FileHeader.LastFolderListNode, sizeof(FileHeader.LastFolderListNode));
  722.       BlockRead(f, FileHeader.reserved4, sizeof(FileHeader.reserved4));
  723.       BlockRead(f, FileHeader.reserved5, sizeof(FileHeader.reserved5));
  724.       BlockRead(f, FileHeader.UsedFileSpace, sizeof(FileHeader.UsedFileSpace));
  725.       BlockRead(f, FileHeader.reserved6, sizeof(FileHeader.reserved6));
  726.       Seek(f, $088);
  727.       BlockRead(f, FileHeader.MessageConditions, sizeof(FileHeader.MessageConditions));
  728.       BlockRead(f, FileHeader.FolderConditions, sizeof(FileHeader.FolderConditions));
  729.       Seek(f, $0c4);
  730.       BlockRead(f, FileHeader.SortTreeEntries, sizeof(FileHeader.SortTreeEntries));
  731.       BlockRead(f, FileHeader.TreeRootEntries, sizeof(FileHeader.TreeRootEntries));
  732.       BlockRead(f, FileHeader.ActiveTreeEntries, sizeof(FileHeader.ActiveTreeEntries));
  733.       Seek(f, $0e4);
  734.       BlockRead(f, FileHeader.SortTreeRootNode, sizeof(FileHeader.SortTreeRootNode));
  735.       BlockRead(f, FileHeader.TreeRootNode, sizeof(FileHeader.TreeRootNode));
  736.       BlockRead(f, FileHeader.ActiveFolders, sizeof(FileHeader.ActiveFolders));
  737.       Seek(f, $108);
  738.       BlockRead(f, FileHeader.reserved7, sizeof(FileHeader.reserved7));
  739.       BlockRead(f, FileHeader.reserved8, sizeof(FileHeader.reserved8));
  740.       Seek(f, $27c);
  741.       BlockRead(f, FileHeader.IndexedInfoSpace, sizeof(FileHeader.IndexedInfoSpace));
  742.       BlockRead(f, FileHeader.ConditionsSpace, sizeof(FileHeader.ConditionsSpace));
  743.       Seek(f, $288);
  744.       BlockRead(f, FileHeader.FolderListSpace, sizeof(FileHeader.FolderListSpace));
  745.       BlockRead(f, FileHeader.TreeSpace, sizeof(FileHeader.TreeSpace));
  746.       BlockRead(f, FileHeader.MessageSpace, sizeof(FileHeader.MessageSpace));
  747.   finally
  748.   end;
  749. end;
  750. procedure TOEImport.LoadFolderInfo(var f : file; Address : int4; var FolderInfo : TDbxFolderInfo);
  751. var
  752.   IndexedInfo : TDbxIndexedInfo;
  753. begin
  754.   try
  755.     FillChar(FolderInfo, sizeof(FolderInfo), 0);
  756.     IndexedInfo.data := nil;
  757.     LoadIndexedInfo(f, Address, IndexedInfo);
  758.     FolderInfo.Index := GetIndexedValue(IndexedInfo, 0);
  759.     FolderInfo.ParentIndex := GetIndexedValue(IndexedInfo, 1);
  760.     FolderInfo.FolderName := GetIndexedString(IndexedInfo, 2);
  761.     FolderInfo.DBXFileName := GetIndexedString(IndexedInfo, 3);
  762.     FolderInfo.RegistryKey := GetIndexedString(IndexedInfo, 5);
  763.     FolderInfo.Flags := GetIndexedValue(IndexedInfo, 6);
  764.     FolderInfo.MessagesCount := GetIndexedValue(IndexedInfo, 7);
  765.     FolderInfo.UnreadCount := GetIndexedValue(IndexedInfo, 8);
  766.     FolderInfo.MaxIndexOnServer := GetIndexedValue(IndexedInfo, $0d);
  767.     FolderInfo.MinIndexOnServer := GetIndexedValue(IndexedInfo, $0e);
  768.     FolderInfo.MaxIndexLocal := GetIndexedValue(IndexedInfo, $10);
  769.     FolderInfo.MinIndexLocal := GetIndexedValue(IndexedInfo, $11);
  770.     FolderInfo.DownloadCount := GetIndexedValue(IndexedInfo, $12);
  771.     FolderInfo.Watched := GetIndexedValue(IndexedInfo, $1c);
  772.     FreeMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
  773.   finally
  774.   end;
  775. end;
  776. procedure TOEImport.LoadMessageInfo(var f : file; Address : int4; var MessageInfo : TDbxMessageInfo);
  777. var
  778.   IndexedInfo : TDbxIndexedInfo;
  779. begin
  780.   try
  781.     FillChar(MessageInfo, sizeof(MessageInfo), 0);
  782.     LoadIndexedInfo(f, Address, IndexedInfo);
  783.     MessageInfo.Index := GetIndexedValue(IndexedInfo, 0);
  784.     MessageInfo.Flags := GetIndexedValue(IndexedInfo, 1);
  785.     MessageInfo.CreateTime := GetIndexedDateTime(IndexedInfo, 2);
  786.     MessageInfo.LinesCount := GetIndexedValue(IndexedInfo, 3);
  787.     MessageInfo.MessagePointer := GetIndexedValue(IndexedInfo, 4);
  788.     MessageInfo.OriginalSubject := GetIndexedString(IndexedInfo, 5);
  789.     MessageInfo.SavedTime := GetIndexedDateTime(IndexedInfo, 6);
  790.     MessageInfo.MessageID := GetIndexedString(IndexedInfo, 7);
  791.     MessageInfo.Subject := GetIndexedString(IndexedInfo, 8);
  792.     MessageInfo.Sender := GetIndexedString(IndexedInfo, 9);
  793.     MessageInfo.Answered := GetIndexedString(IndexedInfo, $0a);
  794.     MessageInfo.ServerList := GetIndexedString(IndexedInfo, $0b);
  795.     MessageInfo.Server := GetIndexedString(IndexedInfo, $0c);
  796.     MessageInfo.SenderName := GetIndexedString(IndexedInfo, $0d);
  797.     MessageInfo.SenderAddress := GetIndexedString(IndexedInfo, $0e);
  798.     MessageInfo.Priority := GetIndexedValue(IndexedInfo, $10);
  799.     MessageInfo.TextLength := GetIndexedValue(IndexedInfo, $11);
  800.     MessageInfo.ReceivedTime := GetIndexedDateTime(IndexedInfo, $12);
  801.     MessageInfo.ReceiverName := GetIndexedString(IndexedInfo, $13);
  802.     MessageInfo.ReceiverAddress := GetIndexedString(IndexedInfo, $14);
  803.     MessageInfo.AccountName := GetIndexedString(IndexedInfo, $1a);
  804.     MessageInfo.RegistryKey := GetIndexedString(IndexedInfo, $1b);
  805.     MessageInfo.IndexID := GetIndexedString(IndexedInfo, $23);
  806.     FreeMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
  807.   finally
  808.   end;
  809. end;
  810. procedure TOEImport.LoadIndexedInfo(var f : file; Address : int4; var IndexedInfo : TDbxIndexedInfo);
  811. var
  812.   lastIndirect, data, index, i, value : int4;
  813.   isIndirect, isDirect : boolean;
  814. begin
  815.     FillChar(IndexedInfo, sizeof(IndexedInfo), 0);
  816.     Seek(f, Address);
  817.     BlockRead(f, IndexedInfo.ObjectMarker, sizeof(IndexedInfo.ObjectMarker));
  818.     BlockRead(f, IndexedInfo.IndexedInfoBodyLength, sizeof(IndexedInfo.IndexedInfoBodyLength));
  819.     BlockRead(f, IndexedInfo.IndexedInfoObjectLength, sizeof(IndexedInfo.IndexedInfoObjectLength));
  820.     BlockRead(f, IndexedInfo.Entries, sizeof(IndexedInfo.Entries));
  821.     BlockRead(f, IndexedInfo.ChangesCount, sizeof(IndexedInfo.ChangesCount));
  822.     GetMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
  823.     BlockRead(f, IndexedInfo.data^, IndexedInfo.IndexedInfoBodyLength);
  824.     isIndirect := false;
  825.     lastIndirect := 0;
  826.     data := byte(IndexedInfo.entries) shl 2;
  827.     for i := 0 to byte(IndexedInfo.Entries) - 1 do
  828.     if i * 4 + 3 < IndexedInfo.IndexedInfoBodyLength then
  829.     begin
  830.       value := byte(IndexedInfo.data^[i * 4]) + byte(IndexedInfo.data^[i * 4 + 1]) * $100 +
  831.                byte(IndexedInfo.data^[i * 4 + 2]) * $10000 + byte(IndexedInfo.data^[i * 4 + 3]) * $1000000;
  832.       isDirect := (value and $80) = $80;
  833.       index := byte(value and $7f);
  834.       value := value shr 8;
  835.       if isDirect then
  836.       begin
  837.         IndexedInfo.BeginIndex[index] := i shl 2 + 1;
  838.         IndexedInfo.LengthIndex[index] := 3;
  839.       end else
  840.       begin
  841.         IndexedInfo.BeginIndex[index] := data + value;
  842.         IndexedInfo.LengthIndex[index] := 0;
  843.         if isIndirect then
  844.           IndexedInfo.LengthIndex[lastIndirect] := data+value - IndexedInfo.BeginIndex[lastIndirect];
  845.         isIndirect := true;
  846.         lastIndirect := index;
  847.       end;
  848.     end;
  849.     if isIndirect then
  850.      IndexedInfo.LengthIndex[LastIndirect] := IndexedInfo.IndexedInfoBodyLength - IndexedInfo.BeginIndex[lastIndirect];
  851. end;
  852. function TOEImport.GetIndexedValue(IndexedInfo : TDbxIndexedInfo; index : byte) : int4;
  853. var
  854.   value : int4;
  855. begin
  856.   if IndexedInfo.BeginIndex[index] = 0 then
  857.   begin
  858.     result := 0;
  859.     exit;
  860.   end;
  861.   value := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index]]) +
  862.            byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 1]) * $100 +
  863.            byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 2]) * $10000 +
  864.            byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 3]) * $1000000;
  865.   if IndexedInfo.LengthIndex[index] < 4 then
  866.     value := value and ((1 shl (IndexedInfo.LengthIndex[index] shl 3)) - 1);
  867.   result := value;
  868. end;
  869. function TOEImport.GetIndexedDateTime(IndexedInfo : TDbxIndexedInfo; index : byte) : dtDateTime;
  870. var
  871.   value : dtDateTime;
  872. begin
  873.   value[0] := 0;
  874.   value[1] := 0;
  875.   result := value;
  876.   if IndexedInfo.BeginIndex[index] = 0 then exit;
  877.   value[0] := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index]]) +
  878.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 1]) * $100 +
  879.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 2]) * $10000 +
  880.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 3]) * $1000000;
  881.   value[1] := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 4]) +
  882.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 5]) * $100 +
  883.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 6]) * $10000 +
  884.               byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 7]) * $1000000;
  885.   result := value;
  886. end;
  887. function TOEImport.GetIndexedString(IndexedInfo : TDbxIndexedInfo; index : byte) : string;
  888. var
  889.   i : int4;
  890.   s : string;
  891. begin
  892.   s := '';
  893.   if IndexedInfo.BeginIndex[index] <> 0 then
  894.   begin
  895. //    SetLength(s, IndexedInfo.LengthIndex[index] - 1);
  896.       for i := 0 to IndexedInfo.LengthIndex[index] - 2 do
  897.        if IndexedInfo.data^[IndexedInfo.BeginIndex[index] + i] = #0 then break else
  898.          s := s + char(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + i]);
  899.   end;
  900.   result := s;
  901. //  result := StrPas(@IndexedInfo.data^[IndexedInfo.BeginIndex[index]]);
  902. end;
  903. procedure TOEImport.LoadFolderFileInfo(var f : file; var FileInfo : TDbxFolderFileInfo);
  904. begin
  905.   try
  906.     FillChar(FileInfo, sizeof(FileInfo), 0);
  907.     Seek(f, $24bc);
  908.     BlockRead(f, FileInfo.CreationTime, sizeof(FileInfo.CreationTime));
  909.   finally
  910.   end;
  911. end;
  912. procedure TOEImport.LoadMessageFileInfo(var f : file; var FileInfo: TDbxMessageFileInfo);
  913. begin
  914.   try
  915.     FillChar(FileInfo, sizeof(FileInfo), 0);
  916.     Seek(f, $24bc);
  917.     BlockRead(f, FileInfo.reserved0, sizeof(FileInfo.reserved0));
  918.     BlockRead(f, FileInfo.SourceType, sizeof(FileInfo.SourceType));
  919.     BlockRead(f, FileInfo.AccountRegistryKey, sizeof(FileInfo.AccountRegistryKey));
  920.     Seek(f, $24bc + $105);
  921.     BlockRead(f, FileInfo.FolderName, sizeof(FileInfo.FolderName));
  922.     Seek(f, $24bc + $210);
  923.     BlockRead(f, FileInfo.SmallValue, sizeof(FileInfo.SmallValue));
  924.     BlockRead(f, FileInfo.reserved1, sizeof(FileInfo.reserved1));
  925.     BlockRead(f, FileInfo.SessionNumber, sizeof(FileInfo.SessionNumber));
  926.   finally
  927.   end;
  928. end;
  929. procedure TOEImport.LoadTree(var f : file; Address, Entries : int4; var Tree : TDbxTree);
  930. procedure readValues(parent : int4; address : int4; position : int4; values : int4);
  931. var
  932.   buffer : array[0..($027c div 4)] of int4;
  933.   n : int4;
  934.   entr : byte;
  935.   i : integer;
  936.   pos : int4;
  937.   val : int4;
  938. begin
  939.   n := 0;
  940.   if Address = 0 then exit;
  941.   Seek(f, Address);
  942.   BlockRead(f, buffer, $027c);
  943.   entr := (buffer[4] shr 8) and $ff;
  944.   if buffer[2] <> 0 then
  945.   begin
  946.     readValues(address, buffer[2], position, buffer[5]);
  947.     inc(n, buffer[5]);
  948.   end;
  949.   for i := 0 to entr - 1 do
  950.   begin
  951.     pos := 6 + i * 3;
  952.     if buffer[pos] <> 0 then
  953.     begin
  954.       inc(n);
  955.       val := position + n;
  956.       paint4(tree.Entries)^[val - 1] := buffer[pos];
  957.     end;
  958.     if buffer[pos + 1] <> 0 then
  959.     begin
  960.       readValues(address, buffer[pos + 1], position + n, buffer[pos + 2]);
  961.       inc(n, buffer[pos + 2]);
  962.     end;
  963.   end;
  964. end;
  965. begin
  966.   FillChar(Tree.Node, sizeof(Tree.Node), 0);
  967.   tree.Count := Entries;
  968.   GetMem(tree.Entries, sizeof(int4) * Entries);
  969.   readValues(0, address, 0, Entries);
  970. end;
  971. procedure TOEImport.ImportFoldersTree(Identity : TOEIdentity);
  972. var
  973.   f : file;
  974.   FileHeader : TDbxFileHeader;
  975.   FolderFileInfo : TDbxFolderFileInfo;
  976.   folderfile : boolean;
  977.   Tree : TDbxTree;
  978.   i, j : integer;
  979.   info : TDbxFolderInfo;
  980. begin
  981.   try
  982.     SetLength(FoldersTree.ChildFolders, 0);
  983.     if not fileexists(Identity.StoreRoot + 'folders.dbx') then exit;
  984.     AssignFile(f, Identity.StoreRoot + 'folders.dbx');
  985.     Reset(f, 1);
  986.     FillChar(FolderFileInfo, sizeof(FolderFileInfo), 0);
  987.     LoadFileHeader(f, FileHeader);
  988.     FolderFile := FileHeader.dbxtype = CLSID_FolderDatabase;
  989.     if FolderFile then
  990.     begin
  991.       LoadFolderFileInfo(f, FolderFileInfo);
  992.       LoadTree(f, FileHeader.ActiveFolders, FileHeader.ActiveTreeEntries, Tree);
  993.       for i := 0 to Tree.Count - 1 do
  994.       begin
  995.         j := length(FoldersTree.ChildFolders);
  996.         setlength(FoldersTree.ChildFolders, j + 1);
  997.         LoadFolderInfo(f, tree.Entries^[i], FoldersTree.ChildFolders[j]);
  998.       end;
  999.       FreeMem(tree.Entries, sizeof(int4) * FileHeader.ActiveTreeEntries);
  1000.     end;
  1001.     CloseFile(f);
  1002.   finally
  1003.   end;
  1004. end;
  1005. procedure TOEImport.LoadMessagesList(FileName : string; Func : TFGetMessageInfo);
  1006. var
  1007.   f : file;
  1008.   MessageFileInfo : TDbxMessageFileInfo;
  1009.   FileHeader : TDbxFileHeader;
  1010.   MessageFile : boolean;
  1011.   Tree : TDbxTree;
  1012.   i : integer;
  1013.   info : TDbxMessageInfo;
  1014. begin
  1015.   try
  1016.     {$i-}
  1017.     AssignFile(f, FileName);
  1018.     Reset(f, 1);
  1019.     if ioresult <> 0 then exit;
  1020.     {$i+}
  1021.     LoadFileHeader(f, FileHeader);
  1022.     MessageFile := FileHeader.dbxtype = CLSID_MessageDatabase;
  1023.     if MessageFile then
  1024.     begin
  1025.       LoadMessageFileInfo(f, MessageFileInfo);
  1026.       Tree.Entries := nil;
  1027.       LoadTree(f, FileHeader.SortTreeRootNode, FileHeader.SortTreeEntries, Tree);
  1028.       for i := 0 to Tree.Count - 1 do
  1029.       begin
  1030.         LoadMessageInfo(f, tree.Entries^[i], info);
  1031.         if @Func <> nil then if not Func(info) then break;
  1032.         setlength(info.OriginalSubject, 0);
  1033.         setlength(info.MessageID, 0);
  1034.         setlength(info.Subject, 0);
  1035.         setlength(info.Sender, 0);
  1036.         setlength(info.Answered, 0);
  1037.         setlength(info.ServerList, 0);
  1038.         setlength(info.Server, 0);
  1039.         setlength(info.SenderName, 0);
  1040.         setlength(info.SenderAddress, 0);
  1041.         setlength(info.ReceiverName, 0);
  1042.         setlength(info.ReceiverAddress, 0);
  1043.         setlength(info.AccountName, 0);
  1044.         setlength(info.RegistryKey, 0);
  1045.         setlength(info.IndexID, 0);
  1046.       end;
  1047.       FreeMem(tree.Entries, sizeof(int4) * FileHeader.SortTreeEntries);
  1048.     end;
  1049.     CloseFile(f);
  1050.   finally
  1051.   end;
  1052. end;
  1053. procedure TOEImport.LoadMessage(var f : file; Address : int4; var Message : TDbxMessage);
  1054. var
  1055.   addr : int4;
  1056.   header : array[0..3] of int4;
  1057.   pos : integer;
  1058.   length : integer;
  1059. begin
  1060.   try
  1061.     addr := address;
  1062.     length := 0;
  1063.     Message.ObjectMarker := address;
  1064.     while (addr > 0) do
  1065.     begin
  1066.       Seek(f, addr);
  1067.       BlockRead(f, header, $10);
  1068.       inc(length, header[2]);
  1069.       addr := header[3];
  1070.     end;
  1071.     Message.BodyLength := length;
  1072.     if length > 20000000 then MsgOK('too big');
  1073.     GetMem(message.Text, length + 1);
  1074.     pos := 0;
  1075.     addr := Address;
  1076.     while (addr > 0) do
  1077.     begin
  1078.       Seek(f, addr);
  1079.       BlockRead(f, header, $10);
  1080.       BlockRead(f, message.Text[pos], header[2]);
  1081.       addr := header[3];
  1082.       inc(pos, header[2]);
  1083.     end;
  1084.     message.Text[pos] := #0;
  1085.   finally
  1086.   end;
  1087. end;
  1088. constructor TOEFolder.Create;
  1089. begin
  1090.   ParentFolder := nil;
  1091.   SetLength(ChildFolders, 0);
  1092.   NextFolder := nil;
  1093. end;
  1094. end.