--- a
+++ b/src/bincimapmime/iodevice.cc
@@ -0,0 +1,317 @@
+/*-*-mode:c++-*-*/
+/*  --------------------------------------------------------------------
+ *  Filename:
+ *    src/iodevice.cc
+ *  
+ *  Description:
+ *    Implementation of the IODevice class.
+ *  --------------------------------------------------------------------
+ *  Copyright 2002, 2003 Andreas Aardal Hanssen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *  --------------------------------------------------------------------
+ */
+#include "iodevice.h"
+#include "convert.h" // BincStream
+#include "session.h" // getEnv/hasEnv
+
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace ::std;
+using namespace ::Binc;
+
+//------------------------------------------------------------------------
+IODevice::IODevice(int f) : flags(f | IsEnabled),
+			      maxInputBufferSize(0),
+			      maxOutputBufferSize(0),
+			      timeout(0), 
+			      readCount(0), writeCount(0),
+			      outputLevel(0), outputLevelLimit(0),
+			      error(Unknown), errorString("Unknown error"),
+			      dumpfd(0)
+{
+}
+
+//------------------------------------------------------------------------
+IODevice::~IODevice(void)
+{
+}
+
+//------------------------------------------------------------------------
+IODevice &IODevice::operator <<(ostream &(*source)(ostream &))
+{
+  if (!(flags & IsEnabled) || outputLevel > outputLevelLimit)
+    return *this;
+
+  static std::ostream &(*endl_funcptr)(ostream &) = endl;
+  
+  if (source != endl_funcptr)
+    return *this;
+
+  outputBuffer << "\r\n";
+
+  if (dumpfd)
+    ::write(dumpfd, "\r\n", 2);
+
+  if (flags & FlushesOnEndl)
+    flush();
+  else if (flags & HasOutputLimit)
+    if (outputBuffer.getSize() > maxOutputBufferSize)
+      flush();
+
+  return *this;
+}
+
+//------------------------------------------------------------------------
+bool IODevice::canRead(void) const
+{
+  return false;
+}
+
+//------------------------------------------------------------------------
+void IODevice::clear()
+{
+  if (!(flags & IsEnabled))
+    return;
+
+  inputBuffer.clear();
+  outputBuffer.clear();
+}
+
+//------------------------------------------------------------------------
+bool IODevice::flush()
+{
+  if (!(flags & IsEnabled))
+    return true;
+
+  WriteResult writeResult = WriteWait;
+  do {
+    unsigned int s = outputBuffer.getSize();
+    if (s == 0)
+      break;
+
+    if (!waitForWrite())
+      return false;
+    
+    writeResult = write();
+    if (writeResult == WriteError)
+      return false;
+
+    writeCount += s - outputBuffer.getSize();
+  } while (outputBuffer.getSize() > 0 && writeResult == WriteWait);
+
+  outputBuffer.clear();
+  return true;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setFlags(unsigned int f)
+{
+  flags |= f;
+}
+
+//------------------------------------------------------------------------
+void IODevice::clearFlags(unsigned int f)
+{
+  flags &= ~f;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setMaxInputBufferSize(unsigned int max)
+{
+  maxInputBufferSize = max;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setMaxOutputBufferSize(unsigned int max)
+{
+  maxOutputBufferSize = max;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setTimeout(unsigned int t)
+{
+  timeout = t;
+
+  if (t)
+    flags |= HasTimeout;
+  else
+    flags &= ~HasTimeout;
+}
+
+//------------------------------------------------------------------------
+unsigned int IODevice::getTimeout(void) const
+{
+  return timeout;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setOutputLevel(unsigned int level)
+{
+  outputLevel = level;
+}
+
+//------------------------------------------------------------------------
+unsigned int IODevice::getOutputLevel(void) const
+{
+  return outputLevel;
+}
+
+//------------------------------------------------------------------------
+void IODevice::setOutputLevelLimit(unsigned int level)
+{
+  outputLevelLimit = level;
+}
+
+//------------------------------------------------------------------------
+unsigned int IODevice::getOutputLevelLimit(void) const
+{
+  return outputLevelLimit;
+}
+
+//------------------------------------------------------------------------
+bool IODevice::readStr(string *dest, unsigned int max)
+{
+  // If max is 0, fill the input buffer once only if it's empty.
+  if (!max && inputBuffer.getSize() == 0 && !fillInputBuffer())
+    return false;
+
+  // If max is != 0, wait until we have max.
+  while (max && inputBuffer.getSize() < max) {
+      if (!fillInputBuffer())
+	  return false;
+  }
+
+  unsigned int bytesToRead = max ? max : inputBuffer.getSize();
+  *dest += inputBuffer.str().substr(0, bytesToRead);
+  if (dumpfd) {
+      ::write(dumpfd, inputBuffer.str().substr(0, bytesToRead).c_str(), 
+	      bytesToRead);
+  }
+  
+  inputBuffer.popString(bytesToRead);
+  readCount += bytesToRead;
+  return true;
+}
+
+//------------------------------------------------------------------------
+bool IODevice::readChar(char *dest)
+{
+  if (inputBuffer.getSize() == 0 && !fillInputBuffer())
+    return false;
+
+  char c = inputBuffer.popChar();
+  if (dest)
+    *dest = c;
+  if (dumpfd)
+    ::write(dumpfd, &c, 1);
+
+  ++readCount;
+  return true;
+}
+
+//------------------------------------------------------------------------
+void IODevice::unreadChar(char c)
+{
+  inputBuffer.unpopChar(c);
+}
+
+//------------------------------------------------------------------------
+void IODevice::unreadStr(const string &s)
+{
+  inputBuffer.unpopStr(s);
+}
+
+//------------------------------------------------------------------------
+bool IODevice::skipTo(char c)
+{
+  char dest = '\0';
+  do {
+    if (!readChar(&dest))
+      return false;
+    if (dumpfd)
+      ::write(dumpfd, &dest, 1);
+  } while (c != dest);
+
+  return true;
+}
+
+//------------------------------------------------------------------------
+string IODevice::service(void) const
+{
+  return "nul";
+}
+
+//------------------------------------------------------------------------
+bool IODevice::waitForWrite(void) const
+{
+  return false;
+}
+
+//------------------------------------------------------------------------
+bool IODevice::waitForRead(void) const
+{
+  return false;
+}
+
+//------------------------------------------------------------------------
+IODevice::WriteResult IODevice::write(void)
+{
+  return WriteError;
+}
+
+//------------------------------------------------------------------------
+bool IODevice::fillInputBuffer(void)
+{
+  return false;
+}
+
+//------------------------------------------------------------------------
+IODevice::Error IODevice::getLastError(void) const
+{
+  return error;
+}
+
+//------------------------------------------------------------------------
+string IODevice::getLastErrorString(void) const
+{
+  return errorString;
+}
+
+//------------------------------------------------------------------------
+unsigned int IODevice::getReadCount(void) const
+{
+  return readCount;
+}
+
+//------------------------------------------------------------------------
+unsigned int IODevice::getWriteCount(void) const
+{
+  return writeCount;
+}
+
+//------------------------------------------------------------------------
+void IODevice::enableProtocolDumping(void)
+{
+  BincStream ss;
+  ss << "/tmp/bincimap-dump-" << (int) time(0) << "-" 
+     << Session::getInstance().getIP() << "-XXXXXX";
+  char *safename = strdup(ss.str().c_str());
+  dumpfd = mkstemp(safename);
+  if (dumpfd == -1)
+    dumpfd = 0;
+  delete safename;
+}