--- a/src/internfile/internfile.cpp
+++ b/src/internfile/internfile.cpp
@@ -380,20 +380,12 @@
 		temp->getreason().c_str()));
 	return TempFile();
     }
-
-    int fd = open(temp->filename(), O_WRONLY);
-    if (fd < 0) {
-	LOGERR(("FileInterner::dataToTempFile: open(%s) failed errno %d\n",
-		temp->filename(), errno));
+    string reason;
+    if (!stringtofile(dt, temp->filename(), reason)) {
+	LOGERR(("FileInterner::dataToTempFile: stringtofile: %s\n", 
+                reason.c_str()));
 	return TempFile();
     }
-    if (write(fd, dt.c_str(), dt.length()) != (int)dt.length()) {
-	close(fd);
-	LOGERR(("FileInterner::dataToTempFile: write to %s failed errno %d\n",
-		temp->filename(), errno));
-	return TempFile();
-    }
-    close(fd);
     return temp;
 }
 
@@ -892,7 +884,20 @@
     return url.substr(7, string::npos);
 }
 
-// Extract subdoc out of multidoc into temporary file. 
+bool FileInterner::tempFileForMT(TempFile& otemp, RclConfig* cnf, 
+                                 const string& mimetype)
+{
+    TempFile temp(new TempFileInternal(
+                      cnf->getSuffixFromMimeType(mimetype)));
+    if (!temp->ok()) {
+        LOGERR(("FileInterner::interntofile: can't create temp file\n"));
+        return false;
+    }
+    otemp = temp;
+    return true;
+}
+
+// Extract document (typically subdoc of multidoc) into temporary file. 
 // We do the usual internfile stuff: create a temporary directory,
 // then create an interner and call internfile. The target mtype is set to
 // the input mtype, so that no data conversion is performed.
@@ -901,22 +906,20 @@
 // - The internfile temporary directory gets destroyed by its destructor
 // - The output temporary file which is held in a reference-counted
 //   object and will be deleted when done with.
-// This DOES NOT work with a non-internal file (because at least one conversion 
-// is always performed).
+//
+// If the ipath is null, maybe we're called because the file is not
+// stored in the regular file system. We use the docfetcher to get a
+// copy (in topdocToFile())
+// 
+// We currently don't handle the case of an internal doc of a non-fs document.
+
 bool FileInterner::idocToFile(TempFile& otemp, const string& tofile,
 			      RclConfig *cnf, const Rcl::Doc& idoc)
 {
     LOGDEB(("FileInterner::idocToFile\n"));
-    // idoc.dump();
 
     if (idoc.ipath.empty()) {
-	LOGDEB(("FileInterner::idocToFile: not a sub-document !\n"));
-	// We could do a copy here but it's much more complicated than
-	// it seems because the source is not necessarily a simple
-	// depending on the backend. Until we fix the Internfile
-	// constructor to not do the first conversion, it's much saner
-	// to just return an error
-	return false;
+	return topdocToFile(otemp, tofile, cnf, idoc);
     }
 
     // We set FIF_forPreview for consistency with the previous version
@@ -925,6 +928,54 @@
     FileInterner interner(idoc, cnf, FIF_forPreview);
     interner.setTargetMType(idoc.mimetype);
     return interner.interntofile(otemp, tofile, idoc.ipath, idoc.mimetype);
+}
+
+bool FileInterner::topdocToFile(TempFile& otemp, const string& tofile,
+                                RclConfig *cnf, const Rcl::Doc& idoc)
+{
+    DocFetcher *fetcher = docFetcherMake(idoc);
+    if (fetcher == 0) {
+        LOGERR(("FileInterner::idocToFile no backend\n"));
+        return false;
+    }
+    DocFetcher::RawDoc rawdoc;
+    if (!fetcher->fetch(cnf, idoc, rawdoc)) {
+        LOGERR(("FileInterner::idocToFile fetcher failed\n"));
+        return false;
+    }
+    const char *filename = "";
+    TempFile temp;
+    if (tofile.empty()) {
+        if (!tempFileForMT(temp, cnf, idoc.mimetype)) {
+            return false;
+        }
+        filename = temp->filename();
+    } else {
+        filename = tofile.c_str();
+    }
+    string reason;
+    switch (rawdoc.kind) {
+    case DocFetcher::RawDoc::RDK_FILENAME:
+        if (!copyfile(rawdoc.data.c_str(), filename, reason)) {
+            LOGERR(("FileInterner::idocToFile: copyfile: %s\n", 
+                    reason.c_str()));
+            return false;
+        }
+        break;
+    case DocFetcher::RawDoc::RDK_DATA:
+        if (!stringtofile(rawdoc.data, filename, reason)) {
+            LOGERR(("FileInterner::idocToFile: stringtofile: %s\n", 
+                    reason.c_str()));
+            return false;
+        }
+        break;
+    default:
+        LOGERR(("FileInterner::FileInterner(idoc): bad rawdoc kind ??\n"));
+    }
+
+    if (tofile.empty())
+        otemp = temp;
+    return true;
 }
 
 bool FileInterner::interntofile(TempFile& otemp, const string& tofile,
@@ -952,35 +1003,22 @@
         doc.mimetype = "text/html";
     }
 
-    string filename;
+    const char *filename;
     TempFile temp;
     if (tofile.empty()) {
-	TempFile temp1(new TempFileInternal(
-			   m_cfg->getSuffixFromMimeType(mimetype)));
-	temp = temp1;
-	if (!temp->ok()) {
-	    LOGERR(("FileInterner::interntofile: can't create temp file\n"));
-	    return false;
-	}
+        if (!tempFileForMT(temp, m_cfg, mimetype)) {
+            return false;
+        }
 	filename = temp->filename();
     } else {
-	filename = tofile;
-    }
-
-    int fd = open(filename.c_str(), O_WRONLY|O_CREAT, 0600);
-    if (fd < 0) {
-	LOGERR(("FileInterner::interntofile: open(%s) failed errno %d\n",
-		filename.c_str(), errno));
+	filename = tofile.c_str();
+    }
+    string reason;
+    if (!stringtofile(doc.text, filename, reason)) {
+	LOGERR(("FileInterner::interntofile: stringtofile : %s\n",
+		reason.c_str()));
 	return false;
     }
-    const string& dt = doc.text;
-    if (write(fd, dt.c_str(), dt.length()) != (int)dt.length()) {
-	close(fd);
-	LOGERR(("FileInterner::interntofile: write to %s failed errno %d\n",
-		filename.c_str(), errno));
-	return false;
-    }
-    close(fd);
 
     if (tofile.empty())
 	otemp = temp;