--- a
+++ b/src/internfile/mh_mail.cpp
@@ -0,0 +1,178 @@
+#ifndef lint
+static char rcsid[] = "@(#$Id: mh_mail.cpp,v 1.1 2005-03-25 09:40:27 dockes Exp $ (C) 2005 J.F.Dockes";
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <map>
+using std::map;
+
+#include "mimehandler.h"
+#include "debuglog.h"
+#include "csguess.h"
+#include "readfile.h"
+#include "transcode.h"
+#include "mimeparse.h"
+#include "indextext.h"
+#include "mail.h"
+#include "debuglog.h"
+#include "smallut.h"
+#include "mimeparse.h"
+
+using namespace std;
+
+// We are called for two different file types: mbox-type folders
+// holding multiple messages, and maildir-type files with one rfc822
+// message
+MimeHandler::Status 
+MimeHandlerMail::worker(RclConfig *cnf, const string &fn, 
+			const string &mtype, Rcl::Doc &docout, string&)
+{
+    LOGDEB(("MimeHandlerMail::worker: %s [%s]\n", mtype.c_str(), fn.c_str()));
+    conf = cnf;
+
+    if (!stringlowercmp("message/rfc822", mtype)) {
+	return processone(fn, docout);
+    } else  if (!stringlowercmp("text/x-mail", mtype)) {
+	return MimeHandler::MHError;
+    } else
+	return MimeHandler::MHError;
+}
+
+
+#include "mime.h"
+
+const char *hnames[] = {"Subject", "Content-type"};
+int nh = sizeof(hnames) / sizeof(char *);
+
+void walkmime(string &out, Binc::MimePart& doc, int fd, int depth);
+
+// Transform a single message into a document. The subject becomes the
+// title, and any simple body part with a content-type of text or html
+// and content-disposition inline gets concatenated as text.
+MimeHandler::Status 
+MimeHandlerMail::processone(const string &fn, Rcl::Doc &docout)
+{
+    int fd;
+    if ((fd = open(fn.c_str(), 0)) < 0) {
+	LOGERR(("MimeHandlerMail::processone: open(%s) errno %d\n",
+		fn.c_str(), errno));
+	return MimeHandler::MHError;
+    }
+    Binc::MimeDocument doc;
+    doc.parseFull(fd);
+
+    if (!doc.isHeaderParsed() && !doc.isAllParsed()) {
+	LOGERR(("MimeHandlerMail::processone: parse error for %s\n", 
+		fn.c_str()));
+	close(fd);
+	return MimeHandler::MHError;
+    }
+    LOGDEB(("MimeHandlerMail::processone: ismultipart %d mime subtype '%s'\n", 
+	    doc.isMultipart(), doc.getSubType().c_str()));
+    walkmime(docout.text, doc, fd, 0);
+    close(fd);
+    LOGDEB(("MimeHandlerMail::processone: text: '%s'\n",  docout.text.c_str()));
+    return MimeHandler::MHError;
+}
+
+void walkmime(string &out, Binc::MimePart& doc, int fd, int depth)
+{
+    if (depth > 5) {
+	LOGINFO(("walkmime: max depth exceeded\n"));
+	return;
+    }
+
+    if (doc.isMultipart()) {
+	LOGDEB(("walkmime: ismultipart %d subtype '%s'\n", 
+		doc.isMultipart(), doc.getSubType().c_str()));
+	// We only handle alternative and mixed for now. For
+	// alternative, we look for a text/plain part, else html and process it
+	// For mixed, we process each part.
+	std::vector<Binc::MimePart>::iterator it;
+	if (!stringicmp("mixed", doc.getSubType())) {
+	    for (it = doc.members.begin(); it != doc.members.end();it++) {
+		walkmime(out, *it, fd, depth+1);
+	    }
+	} else if (!stringicmp("alternative", doc.getSubType())) {
+	    std::vector<Binc::MimePart>::iterator ittxt, ithtml;
+	    ittxt = ithtml = doc.members.end();
+	    for (it = doc.members.begin(); it != doc.members.end();it++) {
+		// Get and parse content-type header
+		Binc::HeaderItem hi;
+		if (!doc.h.getFirstHeader("Content-Type", hi)) 
+		    continue;
+		LOGDEB(("walkmime:content-type: %s\n", hi.getValue().c_str()));
+	    }
+	}
+    } else {
+	// If content-type is text or html and content-disposition is inline, 
+	// decode and add to text.
+
+	// Get and parse content-type header.
+	Binc::HeaderItem hi;
+	string ctt = "text/plain";
+	if (doc.h.getFirstHeader("Content-Type", hi)) {
+	    ctt = hi.getValue();
+	}
+	LOGDEB(("walkmime:content-type: %s\n", ctt.c_str()));
+	MimeHeaderValue content_type;
+	parseMimeHeaderValue(ctt, content_type);
+	if (stringlowercmp("text/plain", content_type.value) && 
+	    stringlowercmp("text/html", content_type.value)) {
+	    return;
+	}
+	string charset = "us-ascii";
+	map<string,string>::const_iterator it;
+	it = content_type.params.find(string("charset"));
+	if (it != content_type.params.end())
+	    charset = it->second;
+
+	// Content disposition
+	string ctd = "inline";
+	if (doc.h.getFirstHeader("Content-Disposition", hi)) {
+	    ctd = hi.getValue();
+	}
+	MimeHeaderValue content_disposition;
+	parseMimeHeaderValue(ctd, content_disposition);
+	if (stringlowercmp("inline", content_disposition.value)) {
+	    return;
+	}
+
+	// Content transfer encoding
+	string cte = "7bit";
+	if (doc.h.getFirstHeader("Content-Transfer-Encoding", hi)) {
+	    cte = hi.getValue();
+	} 
+
+	LOGDEB(("walkmime: final: body start offset %d, length %d\n", 
+		doc.getBodyStartOffset(), doc.getBodyLength()));
+	string body;
+	doc.getBody(fd, body, 0, doc.bodylength);
+
+	// Decode content transfer encoding
+	if (stringlowercmp("quoted-printable", content_disposition.value)) {
+	    string decoded;
+	    qp_decode(body, decoded);
+	    body = decoded;
+	} else if (stringlowercmp("base64", content_disposition.value)) {
+	    string decoded;
+	    base64_decode(body, decoded);
+	    body = decoded;
+	}
+
+
+        // Transcode to utf-8 
+	string transcoded;
+	if (!transcode(body, transcoded, charset, "UTF-8")) {
+	    LOGERR(("walkmime: transcode failed from cs '%s' to UTF-8\n",
+		    charset.c_str()));
+	    transcoded = body;
+	}
+
+	out += string("\r\n") + transcoded;
+    }
+}
+
+