Outlook Express for Mac(PC?) ----------------------------------- I had a file for Outlook Express on Mac which i wanted to import on my PC. Unfournatly I did not have access to the Mac where I otherwise whold have just dragged the files out of OE, renamed the files with extension .eml and dragged them back into OE on my PC. I had to dig in and make a fileparser and I discovered that it it is relativly easy to extract emails. / Anders Lönnberg, anders@siteisfaction.com, 2003-10-28 All files for OE on the Mac looks like this: At offset: 0x000c (long) FileOffset to First TOC 0x0014 (long) FileOffset to 1st deleted mail 0x0100 (long) Place of First TOC ( Normally, may be changed) 0x007c (long) Unknown 0x00e4 (long) Unknown, Marker for Mac/PC, ie big endian? 0x00e8 (long) Unknown 0x00ec (long) Unknown All entries share the same struct: typedef struct { long marker; // 0x0 (normal email), 0x544f4320 (TOC ) or 0x44454c45 (DELE), Don't know if it flags prio and such.. long relativeNext; // Length to next entry after mailEntry long folderID; // ID of folder, can be 0x0 for TOC long blockLength; // Length of block } mailEntry; Here is an example of a file: Offset: Data: Description: ----------------------------------------------------------------------------------------------- 0x0000000c 0x00002100 Pointer to First TOC 0x00002100 mailEntry { 0x544f4320 "TOC " 0x00000010 = 0x00002104, Next mailEntry 0x00000000 TOC belongs to no folder 0x00000004 Length of TOC } 0x00002104 0x00000100 FileOffset to the TOC 0x00000100 mailEntry { 0x544f4320 "TOC " 0x00001FF0 = 0x00002100, Points back to previous => Last TOC 0x00000000 TOC belongs to no folder 0x00000020 We have 0x20 / 0x04 = 8 emails } 0x00000110 offsetMail1 (oM1) 0x00000114 offsetMail2 ... 0x00000130 0x000000000 No more emails oM1 mailEntry { 0x00000000 Not deleted, nor any prio or such X Relative pointer to next FolderID Length } oM1 + 0x10 oM1.Length bytes The actual email, must be parsed according to RFC for mail -------------------------------------------------------- Code Example showing how to read the file I had to split. Implement the correct TOC reader and arbitrary file if you want to. No need to calculate sizes read, just wanted to make sure I didn't miss any data... #include // FOR files #include // FOR cin & cout #include // FOR files #include #include //for declaration of sort using namespace std; #define READREVERSE FILE* f; bool readl(long& l); vector mailoffsets; long full; long readl() { long l = 0; readl(l); return l; } void TellMailData(long offset, long id) { int length, n; char s[200] =""; if(ftell(f) < offset) { int at = ftell(f); sprintf(s, "At %d, now %8x, should be %8x, DelLen: %8x(%8x), ID: %8x\n", id, at, offset, offset - at - 0x10, length = readl(), readl()); cout << s; full -= length; full -= 16; fprintf(fD, "At %d\n----------\n", at); length = offset - at; char* buf = new char[length + 1]; fread(buf, 1, length, f); fwrite(buf, 1 ,length, fD); delete buf; } fseek(f, offset, SEEK_SET); sprintf(s, "Off: %8x, L: %8x, S: %8x, N: %8x, H: %8x", offset, (length = readl()), readl(), (n = readl()), readl()); //cout << s; int b = ftell(f); int l = fread(s, 1, sizeof(s) - 1, f); if(l > 0) { s[l] = 0; // cout << "read: " << l << ", " << strlen(s) << ", " << length << "\n" << s; sprintf(s, "Mail%3d.eml", id); FILE* fO = fopen(s, "w"); fseek(f, b, SEEK_SET); char* buf = new char[length + 1]; fread(buf, 1, length, f); fwrite(buf, 1 ,length, fO); full -= n; n -= length; fseek(f, n, SEEK_CUR); full -= 16; delete buf; } } void main() { f = fopen("folders", "rb"); if(!f) return; fD = fopen("folders.diff", "wb"); long l = -1; fseek(f, 0x0, SEEK_END); full = ftell(f) - 0x2120; fseek(f, 0x110, SEEK_SET); do { if(!readl(l)) break; if(l == 0) break; mailoffsets.push_back(l); } while(true); std::sort(mailoffsets.begin(), mailoffsets.end()); vector::iterator mailo; l = 0; fseek(f, 0x2120, SEEK_SET); for ( mailo = mailoffsets.begin(); mailo != mailoffsets.end(); ++mailo) { l++; // cout << "\n------------------\n" << l << ". "; TellMailData(*mailo, l); } cout << "\n\nLength not read: " << full; fclose(f); fclose(fD); } bool readl(long& l) { #ifdef READREVERSE char* data = ((char*)&l) + 3; for(int i = 0; i < 4; i++) { if(fread(data, 1, 1, f) != 1) { cout << "Broke at: " << ftell(f) << ", " << i; return false; } data--; } return true; #else return fread(%l, 1, 4, f) != 4; #endif }