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 Lnnberg, 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 <stdio.h> // FOR files
#include <iostream> // FOR cin & cout
#include <fstream> // FOR files
#include <vector>
#include <algorithm> //for declaration of sort

using namespace std;

#define READREVERSE

FILE* f;

bool readl(long& l);
vector<long> 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<long>::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
}
	