dbxunit.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:42k
- unit dbxunit;
- interface
- uses Windows;
- type
- int1 = char;
- int2 = word;
- int4 = longword;
- paint4 = ^taint4;
- taint4 = array[0..1] of int4;
- paint1 = ^taint1;
- taint1 = array[0..1] of int1;
- dtDateTime = array[0..1] of int4;
- const
- // Message flags (TDbxMessageInfo.Flags)
- MF_MESSAGE_BODY = $00000001;
- MF_IN_WORK = $00000008;
- MF_MARKED = $00000020;
- MF_READ = $00000080;
- MF_MARKED_FOR_DOWNLOAD = $00000100;
- MF_NEWS_POSTING = $00000800;
- MF_DIGITAL_SIGNED = $00001000;
- MF_WITH_ATTACHMENT = $00004000;
- MF_REPLIED = $00080000;
- MF_FORWARDED = $00100000;
- MF_THREAD_IS_WATCHED = $00400000;
- MF_THREAD_IS_IGNORED = $00800000;
- // Folder flags (TDbxFolderInfo.Flags)
- FF_ACTIVE_FOLDER = $00000001;
- FF_IN_OE = $00000080;
- FF_ALL_WITH_SUBFOLDERS = $00000100;
- CLSID_MessageDatabase = #$c5#$fd#$74#$6f;
- CLSID_FolderDatabase = #$c6#$fd#$74#$6f;
- CLSID_Pop3uidlDatabase = #$c7#$fd#$74#$6f;
- CLSID_OfflineDatabase = #$30#$9d#$fe#$26;
- type
- // The first sector is used for the _file_header_ and the _file_info_.
- // The shortest dbx files I found only consists of a _file_header_ and nothing else.
- TDbxFileHeader = record
- // 0x0000
- // must be "cf ad 12 fe"
- reserved0 : array[0..3] of int1;
- // 0x0004
- // m : "c5 fd 74 6f" CLSID_MessageDatabase
- // f : "c6 fd 74 6f" CLSID_FolderDatabase
- // p : "c7 fd 74 6f" Pop3uidl
- // o : "30 9d fe 26" Offline
- dbxtype : array[0..3] of int1;
- // 0x0008
- // must be "66 e3 d1 11 9a 4e 00 c0 4f a3 09 d4 05 00 00 00 05 00 00 00"
- reserved1 : array[0..19] of int1;
- // 0x001c
- // The Length of _file_info_ object
- FileInfoLength : int4;
- // 0x0024
- // pointer to the last variable segment
- LastVariableSegment : int4;
- // 0x0028
- // Length of a variable segment (0xc000)
- VariableSegmentLength : int4;
- // 0x002c
- // Used space for the last variable segment
- VariableSegmentSpace : int4;
- // 0x0030
- // Pointer to the last _tree_ segment
- LastTreeSegment : int4;
- // 0x0034
- // Length of the last _tree_ segment (0x3e1c)
- TreeSegmentLength : int4;
- // 0x0038
- // Used space for the last _tree_ segment
- TreeSegmentSpace : int4;
- // 0x003c
- // m : Pointer to the last _message_ segment
- LastMessage : int4;
- // 0x0040
- // m : Length of a _message_ segment (0xf780)
- MessageSegmentLength : int4;
- // 0x0044
- // m : Used space for the last _message_ segment
- MessageSegmentSpace : int4;
- // 0x0048
- // m : Root pointer to the deleted message list
- DeletedMessageList : int4;
- // 0x004c
- // Root pointer to the deleted tree list
- DeletedTreeList : int4;
- // 0x0054
- // Used space in the middle sector of the file
- MiddleSectorSpace : int4;
- // 0x0058
- // Reusable space in the middle sector of the file
- ReuseMiddleSectorSpace : int4;
- // 0x005c
- // Index of the last entry in the _tree_
- LastTreeEntry : int4;
- // 0x0064
- // must be "01 00 00 00"
- reserved2 : array[0..3] of int1;
- // 0x0068
- // f : "01 00 00 00"
- reserved3 : array[0..3] of int1;
- // 0x006c
- // f : pointer to the first _folder_list_node_
- FirstFolderListNode : int4;
- // 0x0070
- // f : pointer to the last _folder_list_node_
- LastFolderListNode : int4;
- // 0x0074
- // f : "03 00 00 00"
- reserved4 : array[0..3] of int1;
- // 0x0078
- // f : "02 00 00 00"
- reserved5 : array[0..3] of int1;
- // 0x007c
- // Used space of the file. (Length of the first and middle sector)
- UsedFileSpace : int4;
- // 0x0080
- // f : "02 00 00 00"
- // m : "03 00 00 00"
- reserved6 : array[0..3] of int1;
- // 0x0088
- // m : Pointer to _message_conditions_ object
- MessageConditions : int4;
- // 0x008c
- // f : Pointer to _folder_conditions_ object
- FolderConditions : int4;
- // 0x00c4
- // Entries in tree (SortTreeRootNode)
- SortTreeEntries : int4;
- // 0x00c8
- // Entries in tree (TreeRootNode)
- TreeRootEntries : int4;
- // 0x00cc
- // f : Entries in tree (ActiveFolders)
- ActiveTreeEntries : int4;
- // 0x00e4
- // Pointer to the root node of a tree all entries are sorted by there index
- // m : Points to all message info objects
- // f : Points to all folder info objects
- SortTreeRootNode : int4;
- // 0x00e8
- // Pointer to the root node of a tree
- // m : Points to all watched or ignored message info objects
- // f : Points to the same folder info objects like (39) sorted by there
- // parent folders index followed by there name
- TreeRootNode : int4;
- // 0x00ec
- // f : Pointer to the root node of a tree. points to all activ subfolders
- // of "Outlook Express". this are the folders you can see in OE on the
- // folders pane. sorted like the tree in (TreeRootNode)
- ActiveFolders : int4;
- // 0x0108
- // must be "01 00 00 00"
- reserved7 : array[0..3] of int1;
- // 0x010c
- // f : "02 00 00 00"
- reserved8 : array[0..3] of int1;
- // 0x027c
- // Used space for _indexed_info_ objects
- // m : _message_info_
- // f : _folder_info_
- IndexedInfoSpace : int4;
- // 0x0280
- // Used space for _conditions_ objects
- // m : 0x50 _message_conditions_
- // f : 0x2c _folder_conditions_
- ConditionsSpace : int4;
- // 0x0288
- // f : used space for _folder_list_ objects
- FolderListSpace : int4;
- // 0x028c
- // used space for _tree_ objects
- TreeSpace : int4;
- // 0x0290
- // m : used space for _message_ objects
- MessageSpace : int4;
- // (MiddleSectorSpace) - (ReuseMiddleSectorSpace) =
- // (IndexedInfoSpace) + (ConditionsSpace) + (FolderListSpace) +
- // (TreeSpace) + (MessageSpace)
- // 0x22bc
- // must be "01 00 00 00"
- reserved9 : array[0..3] of int1;
- // 0x22ec
- // must be "00 00 02 00"
- reserved10 : array[0..3] of int1;
- // 0x22f0
- // m : "07 00 00 00"
- // f : "01 00 00 00 00 00 02 05"
- reserved11 : array[0..7] of int1;
- // 0x2320
- // f : "02 00 01 00 .. .. .. .. 02 05 00 00"
- reserved12 : array[0..299] of int1;
- // 0x244c
- // must be "68 00 00 00"
- reserved13 : array[0..3] of int1;
- end;
- TDbxMessageFileInfo = record
- // Starts from 0x24bc
- // 0x0000
- // must be "01 00 00 00"
- reserved0 : array[0..3] of int1;
- // 0x0004
- // Source type (3 - Local store, 0 - News)
- SourceType : int1;
- // 0x0005
- // Registry key of the account
- AccountRegistryKey : array[0..255] of int1;
- // 0x0105
- // Folder name used in Outlook Express
- FolderName : array[0..266] of int1;
- // 0x0210
- // A small value (3 or 4 or ...)
- SmallValue : int4;
- // 0x0214
- // must be "01 00 00 00 00 00 00 00 fa 0f 00 00"
- reserved1 : array[0..11] of int1;
- // 0x0220
- // OE session number file last changed
- SessionNumber : int4;
- // 0x0224
- // ??
- reserved2 : int4;
- // 0x0348
- // must be "01 00 01 00"
- reserved3 : array[0..3] of int1;
- end;
- TDbxFolderFileInfo = record
- // Starts from 0x24bc
- // 0x0000
- // Win32 filetime - date/time creation foldres.dbx
- CreationTime : dtDateTime;
- // 0x0008
- // must be "01 00 00 00"
- reserved0 : array[0..3] of int1;
- end;
- // The middle sector is used to store all other objects. The first value of
- // each object in this sector is the address of the object(object marker).
- // This sector is divided up into segments. I found three different types of segments :
- // * The variable segments are used to store objects of different type and
- // size. This segments are used because objects of the same type don't
- // have the same size (_indexed_info_ objects) or there are only a few
- // objects of a special type (_conditions_ or _folder_list_ objects).
- // * The tree segments are used to store the _tree_node_ objects. Each object
- // has a size of 0x27c bytes.
- // * The message segments are used to store the _message_ objects. Each object
- // has a size of 0x210 bytes. This segments are only used in the message dbx files.
- TDbxIndexedInfo = record
- // Object marker
- ObjectMarker : int4;
- // Length of the following _indexed_info_ object
- IndexedInfoBodyLength : int4;
- // Length of this _indexed_info_ object. (Not always set)
- IndexedInfoObjectLength : int2;
- // Entries in the following index field
- Entries : int1;
- // Counts the changes on this _indexed_info_ object
- ChangesCount : int1;
- data : paint1;
- BeginIndex, LengthIndex : array[0..$1f] of int4;
- end;
- TDbxConditions = record
- // Object marker
- ObjectMarker : int4;
- // Length of the following text
- TextLength : int4;
- // 0x00 is terminated C-string
- text : pointer;
- // In the message dbx files is a message conditions object used.
- // A pointer to this object is stored in (MessageConditions) in the TDbxFileHeader.
- // In the folders.dbx file is a folder conditions object used.
- // A pointer to this object is stored at (FolderConditions) in the TDbxFileHeader.
- end;
- TDbxTreeNode = record
- // The tree stores int4 values. In the dbx files the int4 values are pointers
- // to indexed info objects. The nodes of the tree are the tree nodes. The
- // tree node is the basic part of the tree. Each node object is 0x27c bytes
- // long. 0x18 bytes for the header and 0x264 bytes for the body.
- // Object marker
- ObjectMarker : int4;
- // --- unused
- reserved0 : int4;
- // Pointer to child node
- ChildNode : int4;
- // Pointer to parent node
- ParentNode : int4;
- // Node ID
- NodeID : int1;
- // Entries in the body of this node
- EntriesCount : int1;
- // --- unused
- reserved1 : int2;
- // Stored values in the child tree (ChildNode)
- Values : int4;
- end;
- // The body of a tree node contains (EntriesCount) entries.
- // Each entry consists of 3 int4 values :
- TDbxTreeEntry = record
- // Value
- Value : int4;
- // Pointer to child node
- ChildNode : int4;
- // Stored values in the child tree (ChildNode)
- Values : int4;
- end;
- PDbxTreeEntryArray = ^TDbxTreeEntryArray;
- TDbxTreeEntryArray = array[0..1] of TDbxTreeEntry;
- TDbxTree = record
- Node : TDbxTreeNode;
- Entries : paint4;
- Count : int4;
- end;
- // * Because of the size of 0x264 for the body, (TDbxTreeNode.EntriesCount)
- // can be up to 0x33.
- // * The root node of the tree has no parent, so (TDbxTreeNode.ParentNode)
- // is set to 0.
- // * The leafs have no child nodes, so (TDbxTreeNode.ChildNode),
- // (TDbxTreeNode.VAlues), (TDbxTreeEntry.ChildNode) and
- // (TDbxTreeEntry.Values) are set to 0.
- // * The child node (TDbxTreeNode.ChildNode) has a node id(TDbxTreeNode.NodeID)
- // of 0. The other child nodes (TDbxTreeEntry.ChildNode) have node id's from 0 to
- // (TDbxTreeNode.EntriesCount) -1.
- // In the message dbx files are two trees used.
- // They are used to store pointers to _message_info_ objects.
- // * This first one is used to store pointers to 'all' _message_info_ objects.
- // * The second tree is used to store pointers to all watched or ignored
- // _message_info_ objects.
- // In the folders.dbx file are three trees.
- // They are used to store pointers to _folder_info_ objects.
- // * The first one is used to store pointers to all _folder_info_ objects,
- // sorted by there index.
- // * The second one is used to store pointers to all _folder_info_ objects,
- // sorted by there parent folders index followed by there name.
- // * The third one is used to store all pointers to _folder_info_ objects
- // which are active subfolders of "Outlook Express", sorted by there
- // parent folders index followed by there name. This are the folders
- // you can see in OE on the folders pane.
- // This object is only used in the message dbx files.
- // The message is separated in several objects which are organized in
- // a single linked list. The pointer to the first one can be retrieved
- // from the corresponding _message_info_ object. To get the whole message
- // text you have to walk along the links and put the text segments together.
- TDbxMessage = record
- // Object Marker
- ObjectMarker : int4;
- // Length of the body
- BodyLength : int4;
- // Text. The lenght of this text segment is stored in TDbxMessageHeader.BodyTextSegmentLength
- Text : paint1;
- end;
- // All message objects have a size of 0x210 bytes. 0x10 bytes for the header
- // and 0x200 bytes for the text segment. Even if the text is shorter
- // the whole space is reserved, but (TDbxMessageHeader.BodyTextSegmentLength) provides the real length.
- // OE stores the message text with 0x0d 0x0a at the end of each line and no terminating 0x00.
- // This object is only used in the message dbx files.
- // The message info object stores information about a corresponding _message_ object.
- // The data structure of the message info object is the _indexed_info_.
- // The pointers to the message info objects are stored in the _tree_.
- TDbxMessageInfo = record
- // 00
- // Index
- Index : int4;
- // 01
- // Flags
- Flags : int4;
- // 02
- // (Win32 Filetime) Time when message was created/sent
- CreateTime : dtDateTime;
- // 03
- // if set, number of the lines in the message body
- LinesCount : int4;
- // 04
- // Pointer to the corresponding 'message'
- MessagePointer : int4;
- // 05
- // Original subject (without any "re:")
- OriginalSubject : string;
- // 06
- // (Win32 Filetime) time when message was saved in this folder
- SavedTime : dtDateTime;
- // 07
- // Message ID
- MessageID : string;
- // 08
- // Subject of the message
- Subject : string;
- // 09
- // Sender mail address and name
- Sender : string;
- // 0A
- // Answered to message id
- Answered : string;
- // 0B
- // Server / Newsgroup / Message number (list)
- ServerList : string;
- // 0C
- // Server
- Server : string;
- // 0D
- // Sender name
- SenderName : string;
- // 0E
- // Sender mail address
- SenderAddress : string;
- // 0F
- // unused ???
- // 10
- // Priority of the email (1 high, 3 normal, 5 low)
- Priority : int4;
- // 11
- // Length of the 'message' text(header and body)
- // !!! this value can be wrong !!!
- TextLength : int4;
- // 12
- // (Win32 FILETIME) time message created/received
- ReceivedTime : dtDateTime;
- // 13
- // Receiver name
- ReceiverName : string;
- // 14
- // Receiver mail address
- ReceiverAddress : string;
- // 15
- // not used ???
- // 16
- // When used always : lengt = 1 / values = 0x00
- reserved0 : int4;
- // 17
- // not used ???
- // 18
- // When used always : lengt = 1 / values = 0x00
- reserved1 : int4;
- // 19
- // When used always : lengt = 1 / values = 0x00
- reserved2 : int4;
- // 1A
- // OE mail or news account name
- AccountName : string;
- // 1B
- // Registry key for mail or news account (like "00000008")
- RegistryKey : string;
- // 1C
- // message text structure. this data is constructed, when a message
- // is read the first time.
- // Data : pointer;
- // 23
- // This index is used for the Hotmail Http email accounts and stores
- // a message id ("MSG982493141.24"). I don't know if other Http email
- // accounts are using this index too.
- IndexID : string;
- end;
- TDbxFolderInfo = record
- // 00
- // Index (for the root folder "Outlook Express" default 0)
- Index : int4;
- // 01
- // Index of the parent folder (for the root folder "Outlook Express" : 0xffffffff (-1))
- ParentIndex : int4;
- // 02
- // Folder name (newsgroup name)
- FolderName : string;
- // 03
- // dbx filename
- DBXFileName : string;
- // 04
- reserved0 : int4;
- // 05
- // Registry key of the account
- RegistryKey : string;
- // 06
- // Flags
- Flags : int4;
- // 07
- // Number of messages in the folder
- MessagesCount : int4;
- // 08
- // Number of unread messages in the folder
- UnreadCount : int4;
- // 09
- // all OE subfolders of 'local folders' have a unique index
- // int4
- // 0A
- // set for 'local folders' and all subfolders if set, always set to 0x03
- // int4
- // 0B
- // unused ???
- // 0C
- // unused ???
- // 0D
- // maximal message index on the server
- MaxIndexOnServer : int4;
- // 0E
- // minimal message index on the server
- MinIndexOnServer : int4;
- // 10
- // maximal message index local
- MaxIndexLocal : int4;
- // 11
- // minimal message index local
- MinIndexLocal : int4;
- // 12
- // Messages to download ((0D) - (10))
- DownloadCount : int4;
- // 13
- // data
- // 14
- // unused ???
- // 15
- // data
- // 16
- // unused ???
- // 17
- // unused ???
- // 18
- // unused ???
- // 19
- // unused ???
- // 1a
- // int4
- // 1b
- // unused ???
- // 1c
- // watched messages
- Watched : int4;
- end;
- // Each deleted object in the middle sector of the file gets a new header.
- // deleted objects are organized in a single linked list.
- // Deleted message und tree objects always have the same size. They are easy
- // to reuse. Only on single linked list is needed for each. You can find the
- // pointers to the roots at position (12) and (13) in the file header.
- // All other deleted objects (indexed info, conditions, folder list) from the
- // variable segments have no unique length. They are organized in several single
- // linked lists. For each length one. You can find the pointers to the roots
- // at position (a7) and following in the file header.
- TDbxDeleted = record
- // Object marker
- ObjectMarker : int4;
- // Length of field (FreeSpace)
- FieldLength : int4;
- // Length of this object, (FieldLength) + 0x14
- ObjectLength : int4;
- // not used, not cleared
- reserved : int4;
- // Pointer to the next deleted object
- Next : int4;
- // Free space, not cleared, length (FieldLength)
- end;
- PDbxFoldersList = ^TDbxFoldersList;
- TDbxFoldersList = record
- info : TDbxFolderInfo;
- next : PDbxFoldersList;
- end;
- TOEFolder = class
- ParentFolder : TOEFolder;
- ChildFolders : array of TDbxFolderInfo;
- NextFolder : TOEFolder;
- constructor Create;
- end;
- TOEMessage = class
- end;
- TOEIdentity = class
- UserID : string; // IID
- Username : string; // e.g. Main Identrity
- StoreRoot : string; // path to dbx files
- version : string;
- end;
- // if function returns true, then getting messages will be continue
- TFGetMessageInfo = function (MessageInfo : TDbxMessageInfo) : boolean of object;
- // Class for importing messages and folders from Outlook Express database files
- TOEImport = class
- // Folders tree
- FoldersTree : TOEFolder;
- // List of OE identities
- Identities : array of TOEIdentity;
- // Main Identity
- MainIdentity : TOEIdentity;
- constructor Create;
- // Sets up Identities and MainIdentity;
- procedure GetIdentities;
- procedure LoadFileHeader(var f : file; var FileHeader : TDbxFileHeader);
- procedure LoadFolderFileInfo(var f : file; var FileInfo : TDbxFolderFileInfo);
- procedure LoadFolderInfo(var f : file; Address : int4; var FolderInfo : TDbxFolderInfo);
- procedure LoadIndexedInfo(var f : file; Address : int4; var IndexedInfo : TDbxIndexedInfo);
- procedure LoadMessageFileInfo(var f : file; var FileInfo : TDbxMessageFileInfo);
- procedure LoadMessageInfo(var f : file; Address : int4; var MessageInfo : TDbxMessageInfo);
- procedure LoadTree(var f : file; Address, Entries : int4; var Tree : TDbxTree);
- function GetIndexedValue(IndexedInfo : TDbxIndexedInfo; index : byte) : int4;
-
- function GetIndexedDateTime(IndexedInfo : TDbxIndexedInfo; index : byte) : dtDateTime;
- function GetIndexedString(IndexedInfo : TDbxIndexedInfo; index : byte) : string;
- procedure LoadMessagesList(filename : string; Func : TFGetMessageInfo);
- procedure LoadMessage(var f : file; address : int4; var Message : TDbxMessage);
- // Imports folders tree;
- procedure ImportFoldersTree(Identity : TOEIdentity);
- destructor Destroy; override;
- end;
- implementation
- uses SysUtils;
- constructor TOEImport.Create;
- begin
- Identities := nil;
- FoldersTree := TOEFolder.Create;
- MainIdentity := nil;
- GetIdentities;
- end;
- function GetFullPath(path : pchar) : string;
- var
- f, p : pchar;
- resPath, srcPath, s, VarName : string;
- i : integer;
- begin
- srcPath := AnsiUpperCase(path);
- resPath := path;
- while (length(respath) > 0) and (pos(#0, respath) > 0) do
- delete(respath, pos(#0, respath), 1);
- p := GetEnvironmentStrings;
- f := p;
- while p^ <> #0 do
- begin
- s := UpperCase(String(p));
- if s <> '' then OEMToChar(PChar(s), PChar(s));
- VarName := copy(s, 1, pos('=', s) - 1);
- i := pos('%' + VarName + '%', srcPath);
- delete(s, 1, pos('=', s));
- if i > 0 then
- begin
- Delete(srcPath, i, 2 + length(VarName));
- insert(s, srcpath, i);
- Delete(resPath, i, 2 + length(VarName));
- insert(s, respath, i);
- end;
- inc(p, lStrLen(p) + 1);
- end;
- FreeEnvironmentStrings(f);
- if Length(resPath) > 0 then
- if resPath[Length(resPath)] <> '' then
- resPath := resPath + '';
- result := resPath;
- end;
- procedure TOEImport.GetIdentities;
- var
- Reg : HKey;
- k, keys : PStrList;
- i, j : integer;
- identity : TOEIdentity;
- begin
- SetLength(Identities, 0);
- try
- Reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities');
- keys := NewStrList;
- k := NewStrList;
- RegKeyGetSubKeys(Reg, keys);
- RegKeyClose(reg);
- for i := 0 to Keys.Count - 1 do
- begin
- Reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i] + 'SoftwareMicrosoftOutlook Express');
- RegKeyGetSubKeys(Reg, k);
- RegKeyClose(reg);
- for j := 0 to k.Count - 1 do
- begin
- identity := TOEIdentity.Create;
- identity.version := k.Items[j];
- identity.UserID := keys.Items[i];
- reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i] + 'SoftwareMicrosoftOutlook Express' + k.Items[j]);
- identity.StoreRoot := GetFullPath(PChar(RegKeyGetStrEx(reg, 'Store Root')));
- RegKeyClose(reg);
- reg := RegKeyOpenRead(HKEY_CURRENT_USER, 'Identities' + Keys.Items[i]);
- identity.Username := RegKeyGetStr(reg, 'Username');
- if identity.Username = 'Main Identity' then
- MainIdentity := identity;
- SetLength(Identities, length(Identities) + 1);
- Identities[length(Identities) - 1] := identity;
- RegKeyClose(reg);
- end;
- end;
- keys.Free;
- k.Free;
- finally
- end;
- end;
- destructor TOEImport.Destroy;
- var
- i : integer;
- begin
- FoldersTree.Free;
- for i := 0 to length(identities) - 1 do
- begin
- identities[i].Free;
- end;
- SetLength(Identities, 0);
- inherited;
- end;
- procedure TOEImport.LoadFileHeader(var f : file; var FileHeader : TDbxFileHeader);
- begin
- FillChar(FileHeader, sizeof(FileHeader), 0);
- try
- BlockRead(f, FileHeader.reserved0, sizeof(FileHeader.reserved0));
- BlockRead(f, FileHeader.dbxtype, sizeof(FileHeader.dbxtype));
- BlockRead(f, FileHeader.reserved1, sizeof(FileHeader.reserved1));
- BlockRead(f, FileHeader.FileInfoLength, sizeof(FileHeader.FileInfoLength));
- Seek(f, $024);
- BlockRead(f, FileHeader.LastVariableSegment, sizeof(FileHeader.LastVariableSegment));
- BlockRead(f, FileHeader.VariableSegmentLength, sizeof(FileHeader.VariableSegmentLength));
- BlockRead(f, FileHeader.VariableSegmentSpace, sizeof(FileHeader.VariableSegmentSpace));
- BlockRead(f, FileHeader.LastTreeSegment, sizeof(FileHeader.LastTreeSegment));
- BlockRead(f, FileHeader.TreeSegmentLength, sizeof(FileHeader.TreeSegmentLength));
- BlockRead(f, FileHeader.TreeSegmentSpace, sizeof(FileHeader.TreeSegmentSpace));
- BlockRead(f, FileHeader.LastMessage, sizeof(FileHeader.LastMessage));
- Seek(f, $040);
- BlockRead(f, FileHeader.MessageSegmentLength, sizeof(FileHeader.MessageSegmentLength));
- BlockRead(f, FileHeader.MessageSegmentSpace, sizeof(FileHeader.MessageSegmentSpace));
- BlockRead(f, FileHeader.DeletedMessageList, sizeof(FileHeader.DeletedMessageList));
- BlockRead(f, FileHeader.DeletedTreeList, sizeof(FileHeader.DeletedTreeList));
- Seek(f, $054);
- BlockRead(f, FileHeader.MiddleSectorSpace, sizeof(FileHeader.MiddleSectorSpace));
- BlockRead(f, FileHeader.ReuseMiddleSectorSpace, sizeof(FileHeader.ReuseMiddleSectorSpace));
- BlockRead(f, FileHeader.LastTreeEntry, sizeof(FileHeader.LastTreeEntry));
- Seek(f, $064);
- BlockRead(f, FileHeader.reserved2, sizeof(FileHeader.reserved2));
- BlockRead(f, FileHeader.reserved3, sizeof(FileHeader.reserved3));
- BlockRead(f, FileHeader.FirstFolderListNode, sizeof(FileHeader.FirstFolderListNode));
- BlockRead(f, FileHeader.LastFolderListNode, sizeof(FileHeader.LastFolderListNode));
- BlockRead(f, FileHeader.reserved4, sizeof(FileHeader.reserved4));
- BlockRead(f, FileHeader.reserved5, sizeof(FileHeader.reserved5));
- BlockRead(f, FileHeader.UsedFileSpace, sizeof(FileHeader.UsedFileSpace));
- BlockRead(f, FileHeader.reserved6, sizeof(FileHeader.reserved6));
- Seek(f, $088);
- BlockRead(f, FileHeader.MessageConditions, sizeof(FileHeader.MessageConditions));
- BlockRead(f, FileHeader.FolderConditions, sizeof(FileHeader.FolderConditions));
- Seek(f, $0c4);
- BlockRead(f, FileHeader.SortTreeEntries, sizeof(FileHeader.SortTreeEntries));
- BlockRead(f, FileHeader.TreeRootEntries, sizeof(FileHeader.TreeRootEntries));
- BlockRead(f, FileHeader.ActiveTreeEntries, sizeof(FileHeader.ActiveTreeEntries));
- Seek(f, $0e4);
- BlockRead(f, FileHeader.SortTreeRootNode, sizeof(FileHeader.SortTreeRootNode));
- BlockRead(f, FileHeader.TreeRootNode, sizeof(FileHeader.TreeRootNode));
- BlockRead(f, FileHeader.ActiveFolders, sizeof(FileHeader.ActiveFolders));
- Seek(f, $108);
- BlockRead(f, FileHeader.reserved7, sizeof(FileHeader.reserved7));
- BlockRead(f, FileHeader.reserved8, sizeof(FileHeader.reserved8));
- Seek(f, $27c);
- BlockRead(f, FileHeader.IndexedInfoSpace, sizeof(FileHeader.IndexedInfoSpace));
- BlockRead(f, FileHeader.ConditionsSpace, sizeof(FileHeader.ConditionsSpace));
- Seek(f, $288);
- BlockRead(f, FileHeader.FolderListSpace, sizeof(FileHeader.FolderListSpace));
- BlockRead(f, FileHeader.TreeSpace, sizeof(FileHeader.TreeSpace));
- BlockRead(f, FileHeader.MessageSpace, sizeof(FileHeader.MessageSpace));
- finally
- end;
- end;
- procedure TOEImport.LoadFolderInfo(var f : file; Address : int4; var FolderInfo : TDbxFolderInfo);
- var
- IndexedInfo : TDbxIndexedInfo;
- begin
- try
- FillChar(FolderInfo, sizeof(FolderInfo), 0);
- IndexedInfo.data := nil;
- LoadIndexedInfo(f, Address, IndexedInfo);
- FolderInfo.Index := GetIndexedValue(IndexedInfo, 0);
- FolderInfo.ParentIndex := GetIndexedValue(IndexedInfo, 1);
- FolderInfo.FolderName := GetIndexedString(IndexedInfo, 2);
- FolderInfo.DBXFileName := GetIndexedString(IndexedInfo, 3);
- FolderInfo.RegistryKey := GetIndexedString(IndexedInfo, 5);
- FolderInfo.Flags := GetIndexedValue(IndexedInfo, 6);
- FolderInfo.MessagesCount := GetIndexedValue(IndexedInfo, 7);
- FolderInfo.UnreadCount := GetIndexedValue(IndexedInfo, 8);
- FolderInfo.MaxIndexOnServer := GetIndexedValue(IndexedInfo, $0d);
- FolderInfo.MinIndexOnServer := GetIndexedValue(IndexedInfo, $0e);
- FolderInfo.MaxIndexLocal := GetIndexedValue(IndexedInfo, $10);
- FolderInfo.MinIndexLocal := GetIndexedValue(IndexedInfo, $11);
- FolderInfo.DownloadCount := GetIndexedValue(IndexedInfo, $12);
- FolderInfo.Watched := GetIndexedValue(IndexedInfo, $1c);
- FreeMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
- finally
- end;
- end;
- procedure TOEImport.LoadMessageInfo(var f : file; Address : int4; var MessageInfo : TDbxMessageInfo);
- var
- IndexedInfo : TDbxIndexedInfo;
- begin
- try
- FillChar(MessageInfo, sizeof(MessageInfo), 0);
- LoadIndexedInfo(f, Address, IndexedInfo);
- MessageInfo.Index := GetIndexedValue(IndexedInfo, 0);
- MessageInfo.Flags := GetIndexedValue(IndexedInfo, 1);
- MessageInfo.CreateTime := GetIndexedDateTime(IndexedInfo, 2);
- MessageInfo.LinesCount := GetIndexedValue(IndexedInfo, 3);
- MessageInfo.MessagePointer := GetIndexedValue(IndexedInfo, 4);
- MessageInfo.OriginalSubject := GetIndexedString(IndexedInfo, 5);
- MessageInfo.SavedTime := GetIndexedDateTime(IndexedInfo, 6);
- MessageInfo.MessageID := GetIndexedString(IndexedInfo, 7);
- MessageInfo.Subject := GetIndexedString(IndexedInfo, 8);
- MessageInfo.Sender := GetIndexedString(IndexedInfo, 9);
- MessageInfo.Answered := GetIndexedString(IndexedInfo, $0a);
- MessageInfo.ServerList := GetIndexedString(IndexedInfo, $0b);
- MessageInfo.Server := GetIndexedString(IndexedInfo, $0c);
- MessageInfo.SenderName := GetIndexedString(IndexedInfo, $0d);
- MessageInfo.SenderAddress := GetIndexedString(IndexedInfo, $0e);
- MessageInfo.Priority := GetIndexedValue(IndexedInfo, $10);
- MessageInfo.TextLength := GetIndexedValue(IndexedInfo, $11);
- MessageInfo.ReceivedTime := GetIndexedDateTime(IndexedInfo, $12);
- MessageInfo.ReceiverName := GetIndexedString(IndexedInfo, $13);
- MessageInfo.ReceiverAddress := GetIndexedString(IndexedInfo, $14);
- MessageInfo.AccountName := GetIndexedString(IndexedInfo, $1a);
- MessageInfo.RegistryKey := GetIndexedString(IndexedInfo, $1b);
- MessageInfo.IndexID := GetIndexedString(IndexedInfo, $23);
- FreeMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
- finally
- end;
- end;
- procedure TOEImport.LoadIndexedInfo(var f : file; Address : int4; var IndexedInfo : TDbxIndexedInfo);
- var
- lastIndirect, data, index, i, value : int4;
- isIndirect, isDirect : boolean;
- begin
- FillChar(IndexedInfo, sizeof(IndexedInfo), 0);
- Seek(f, Address);
- BlockRead(f, IndexedInfo.ObjectMarker, sizeof(IndexedInfo.ObjectMarker));
- BlockRead(f, IndexedInfo.IndexedInfoBodyLength, sizeof(IndexedInfo.IndexedInfoBodyLength));
- BlockRead(f, IndexedInfo.IndexedInfoObjectLength, sizeof(IndexedInfo.IndexedInfoObjectLength));
- BlockRead(f, IndexedInfo.Entries, sizeof(IndexedInfo.Entries));
- BlockRead(f, IndexedInfo.ChangesCount, sizeof(IndexedInfo.ChangesCount));
- GetMem(IndexedInfo.data, IndexedInfo.IndexedInfoBodyLength);
- BlockRead(f, IndexedInfo.data^, IndexedInfo.IndexedInfoBodyLength);
- isIndirect := false;
- lastIndirect := 0;
- data := byte(IndexedInfo.entries) shl 2;
- for i := 0 to byte(IndexedInfo.Entries) - 1 do
- if i * 4 + 3 < IndexedInfo.IndexedInfoBodyLength then
- begin
- value := byte(IndexedInfo.data^[i * 4]) + byte(IndexedInfo.data^[i * 4 + 1]) * $100 +
- byte(IndexedInfo.data^[i * 4 + 2]) * $10000 + byte(IndexedInfo.data^[i * 4 + 3]) * $1000000;
- isDirect := (value and $80) = $80;
- index := byte(value and $7f);
- value := value shr 8;
- if isDirect then
- begin
- IndexedInfo.BeginIndex[index] := i shl 2 + 1;
- IndexedInfo.LengthIndex[index] := 3;
- end else
- begin
- IndexedInfo.BeginIndex[index] := data + value;
- IndexedInfo.LengthIndex[index] := 0;
- if isIndirect then
- IndexedInfo.LengthIndex[lastIndirect] := data+value - IndexedInfo.BeginIndex[lastIndirect];
- isIndirect := true;
- lastIndirect := index;
- end;
- end;
- if isIndirect then
- IndexedInfo.LengthIndex[LastIndirect] := IndexedInfo.IndexedInfoBodyLength - IndexedInfo.BeginIndex[lastIndirect];
- end;
- function TOEImport.GetIndexedValue(IndexedInfo : TDbxIndexedInfo; index : byte) : int4;
- var
- value : int4;
- begin
- if IndexedInfo.BeginIndex[index] = 0 then
- begin
- result := 0;
- exit;
- end;
- value := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index]]) +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 1]) * $100 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 2]) * $10000 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 3]) * $1000000;
- if IndexedInfo.LengthIndex[index] < 4 then
- value := value and ((1 shl (IndexedInfo.LengthIndex[index] shl 3)) - 1);
- result := value;
- end;
- function TOEImport.GetIndexedDateTime(IndexedInfo : TDbxIndexedInfo; index : byte) : dtDateTime;
- var
- value : dtDateTime;
- begin
- value[0] := 0;
- value[1] := 0;
- result := value;
- if IndexedInfo.BeginIndex[index] = 0 then exit;
- value[0] := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index]]) +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 1]) * $100 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 2]) * $10000 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 3]) * $1000000;
- value[1] := byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 4]) +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 5]) * $100 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 6]) * $10000 +
- byte(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + 7]) * $1000000;
- result := value;
- end;
- function TOEImport.GetIndexedString(IndexedInfo : TDbxIndexedInfo; index : byte) : string;
- var
- i : int4;
- s : string;
- begin
- s := '';
- if IndexedInfo.BeginIndex[index] <> 0 then
- begin
- // SetLength(s, IndexedInfo.LengthIndex[index] - 1);
- for i := 0 to IndexedInfo.LengthIndex[index] - 2 do
- if IndexedInfo.data^[IndexedInfo.BeginIndex[index] + i] = #0 then break else
- s := s + char(IndexedInfo.data^[IndexedInfo.BeginIndex[index] + i]);
- end;
- result := s;
- // result := StrPas(@IndexedInfo.data^[IndexedInfo.BeginIndex[index]]);
- end;
- procedure TOEImport.LoadFolderFileInfo(var f : file; var FileInfo : TDbxFolderFileInfo);
- begin
- try
- FillChar(FileInfo, sizeof(FileInfo), 0);
- Seek(f, $24bc);
- BlockRead(f, FileInfo.CreationTime, sizeof(FileInfo.CreationTime));
- finally
- end;
- end;
- procedure TOEImport.LoadMessageFileInfo(var f : file; var FileInfo: TDbxMessageFileInfo);
- begin
- try
- FillChar(FileInfo, sizeof(FileInfo), 0);
- Seek(f, $24bc);
- BlockRead(f, FileInfo.reserved0, sizeof(FileInfo.reserved0));
- BlockRead(f, FileInfo.SourceType, sizeof(FileInfo.SourceType));
- BlockRead(f, FileInfo.AccountRegistryKey, sizeof(FileInfo.AccountRegistryKey));
- Seek(f, $24bc + $105);
- BlockRead(f, FileInfo.FolderName, sizeof(FileInfo.FolderName));
- Seek(f, $24bc + $210);
- BlockRead(f, FileInfo.SmallValue, sizeof(FileInfo.SmallValue));
- BlockRead(f, FileInfo.reserved1, sizeof(FileInfo.reserved1));
- BlockRead(f, FileInfo.SessionNumber, sizeof(FileInfo.SessionNumber));
- finally
- end;
- end;
- procedure TOEImport.LoadTree(var f : file; Address, Entries : int4; var Tree : TDbxTree);
- procedure readValues(parent : int4; address : int4; position : int4; values : int4);
- var
- buffer : array[0..($027c div 4)] of int4;
- n : int4;
- entr : byte;
- i : integer;
- pos : int4;
- val : int4;
- begin
- n := 0;
- if Address = 0 then exit;
- Seek(f, Address);
- BlockRead(f, buffer, $027c);
- entr := (buffer[4] shr 8) and $ff;
- if buffer[2] <> 0 then
- begin
- readValues(address, buffer[2], position, buffer[5]);
- inc(n, buffer[5]);
- end;
- for i := 0 to entr - 1 do
- begin
- pos := 6 + i * 3;
- if buffer[pos] <> 0 then
- begin
- inc(n);
- val := position + n;
- paint4(tree.Entries)^[val - 1] := buffer[pos];
- end;
- if buffer[pos + 1] <> 0 then
- begin
- readValues(address, buffer[pos + 1], position + n, buffer[pos + 2]);
- inc(n, buffer[pos + 2]);
- end;
- end;
- end;
- begin
- FillChar(Tree.Node, sizeof(Tree.Node), 0);
- tree.Count := Entries;
- GetMem(tree.Entries, sizeof(int4) * Entries);
- readValues(0, address, 0, Entries);
- end;
- procedure TOEImport.ImportFoldersTree(Identity : TOEIdentity);
- var
- f : file;
- FileHeader : TDbxFileHeader;
- FolderFileInfo : TDbxFolderFileInfo;
- folderfile : boolean;
- Tree : TDbxTree;
- i, j : integer;
- info : TDbxFolderInfo;
- begin
- try
- SetLength(FoldersTree.ChildFolders, 0);
- if not fileexists(Identity.StoreRoot + 'folders.dbx') then exit;
- AssignFile(f, Identity.StoreRoot + 'folders.dbx');
- Reset(f, 1);
- FillChar(FolderFileInfo, sizeof(FolderFileInfo), 0);
- LoadFileHeader(f, FileHeader);
- FolderFile := FileHeader.dbxtype = CLSID_FolderDatabase;
- if FolderFile then
- begin
- LoadFolderFileInfo(f, FolderFileInfo);
- LoadTree(f, FileHeader.ActiveFolders, FileHeader.ActiveTreeEntries, Tree);
- for i := 0 to Tree.Count - 1 do
- begin
- j := length(FoldersTree.ChildFolders);
- setlength(FoldersTree.ChildFolders, j + 1);
- LoadFolderInfo(f, tree.Entries^[i], FoldersTree.ChildFolders[j]);
- end;
- FreeMem(tree.Entries, sizeof(int4) * FileHeader.ActiveTreeEntries);
- end;
- CloseFile(f);
- finally
- end;
- end;
- procedure TOEImport.LoadMessagesList(FileName : string; Func : TFGetMessageInfo);
- var
- f : file;
- MessageFileInfo : TDbxMessageFileInfo;
- FileHeader : TDbxFileHeader;
- MessageFile : boolean;
- Tree : TDbxTree;
- i : integer;
- info : TDbxMessageInfo;
- begin
- try
- {$i-}
- AssignFile(f, FileName);
- Reset(f, 1);
- if ioresult <> 0 then exit;
- {$i+}
- LoadFileHeader(f, FileHeader);
- MessageFile := FileHeader.dbxtype = CLSID_MessageDatabase;
- if MessageFile then
- begin
- LoadMessageFileInfo(f, MessageFileInfo);
- Tree.Entries := nil;
- LoadTree(f, FileHeader.SortTreeRootNode, FileHeader.SortTreeEntries, Tree);
- for i := 0 to Tree.Count - 1 do
- begin
- LoadMessageInfo(f, tree.Entries^[i], info);
- if @Func <> nil then if not Func(info) then break;
- setlength(info.OriginalSubject, 0);
- setlength(info.MessageID, 0);
- setlength(info.Subject, 0);
- setlength(info.Sender, 0);
- setlength(info.Answered, 0);
- setlength(info.ServerList, 0);
- setlength(info.Server, 0);
- setlength(info.SenderName, 0);
- setlength(info.SenderAddress, 0);
- setlength(info.ReceiverName, 0);
- setlength(info.ReceiverAddress, 0);
- setlength(info.AccountName, 0);
- setlength(info.RegistryKey, 0);
- setlength(info.IndexID, 0);
- end;
- FreeMem(tree.Entries, sizeof(int4) * FileHeader.SortTreeEntries);
- end;
- CloseFile(f);
- finally
- end;
- end;
- procedure TOEImport.LoadMessage(var f : file; Address : int4; var Message : TDbxMessage);
- var
- addr : int4;
- header : array[0..3] of int4;
- pos : integer;
- length : integer;
- begin
- try
- addr := address;
- length := 0;
- Message.ObjectMarker := address;
- while (addr > 0) do
- begin
- Seek(f, addr);
- BlockRead(f, header, $10);
- inc(length, header[2]);
- addr := header[3];
- end;
- Message.BodyLength := length;
- if length > 20000000 then MsgOK('too big');
- GetMem(message.Text, length + 1);
- pos := 0;
- addr := Address;
- while (addr > 0) do
- begin
- Seek(f, addr);
- BlockRead(f, header, $10);
- BlockRead(f, message.Text[pos], header[2]);
- addr := header[3];
- inc(pos, header[2]);
- end;
- message.Text[pos] := #0;
- finally
- end;
- end;
- constructor TOEFolder.Create;
- begin
- ParentFolder := nil;
- SetLength(ChildFolders, 0);
- NextFolder := nil;
- end;
- end.