/***************************************************************************
                          decodeRFC2047.cpp  -  description
                             -------------------
    begin                : Mon Jan 28 2002
    copyright            : (C) 2002 by Eggert Ehmke
    email                : eggert.ehmke@berlin.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/


#include "decodeRFC2047.h"

/*
 * These functions have been adapted from the KMail program
 */

QCString decodeQuotedPrintable(const QCString& aStr)
{
  QCString bStr = aStr;
  if (aStr.isNull())
    bStr = "";

  DwString dwsrc(bStr.data());
  DwString dwdest;

  DwDecodeQuotedPrintable(dwsrc, dwdest);
  return dwdest.c_str();
}

QCString decodeBase64(const QCString& aStr)
{
  QCString bStr = aStr;
  if (aStr.isNull())
    bStr = "";
  while (bStr.length() < 16) bStr += "=";

  DwString dwsrc(bStr.data(), bStr.length());
  DwString dwdest;
  QCString result;

  DwDecodeBase64(dwsrc, dwdest);
  result = dwdest.c_str();
  return result;
}

QTextCodec* codecForName(const QCString& _str)
{
  if (_str.isEmpty()) return NULL;
  if (_str.lower() == "shift_jis" || _str.lower() == "shift-jis")
    return QTextCodec::codecForName("sjis");
  return QTextCodec::codecForName(_str.lower().replace(
    QRegExp("windows"), "cp") );
}

QString Codecs::decodeRFC2047(const QCString& aStr)
{
  QString result;
  QCString charset;
  char *pos, *beg, *end, *mid;
  QCString str, cstr, LWSP_buffer;
  char encoding, ch;
  bool valid, lastWasEncodedWord=FALSE;
  const int maxLen=200;
  int i;

  if (aStr.find("=?") < 0)
    return QString::fromLocal8Bit(aStr).replace(QRegExp("\n[\t ]")," ");

  for (pos=aStr.data(); *pos; pos++)
  {
    // line unfolding
    if ( pos[0] == '\r' && pos[1] == '\n' ) {
      pos++;
      continue;
    }
    if ( pos[0] == '\n' )
      continue;
    // collect LWSP after encoded-words,
    // because we might need to throw it out
    // (when the next word is an encoded-word)
    if ( lastWasEncodedWord && ( pos[0] == ' ' || pos[0] == '\t' ) )
    {
      LWSP_buffer += pos[0];
      continue;
    }
    // verbatimly copy normal text
    if (pos[0]!='=' || pos[1]!='?')
    {
      result += LWSP_buffer + pos[0];
      LWSP_buffer = 0;
      lastWasEncodedWord = FALSE;
      continue;
    }
    // found possible encoded-word
    beg = pos+2;
    end = beg;
    valid = TRUE;
    // parse charset name
    charset = "";
    for (i=2,pos+=2; i<maxLen && (*pos!='?'&&(*pos==' '||ispunct(*pos)||isalnum(*pos))); i++)
    {
      charset += *pos;
      pos++;
    }
    if (*pos!='?' || i<4 || i>=maxLen) valid = FALSE;
    else
    {
      // get encoding and check delimiting question marks
      encoding = toupper(pos[1]);
      if (pos[2]!='?' || (encoding!='Q' && encoding!='B'))
				valid = FALSE;
      pos+=3;
      i+=3;
    }
    if (valid)
    {
      mid = pos;
      // search for end of encoded part
      while (i<maxLen && *pos && !(*pos=='?' && *(pos+1)=='='))
      {
				i++;
				pos++;
      }
      end = pos+2;//end now points to the first char after the encoded string
      if (i>=maxLen || !*pos)
      	valid = FALSE;
    }
    if (valid)
    {
      // valid encoding: decode and throw away separating LWSP
      ch = *pos;
      *pos = '\0';
      str = QCString(mid).left((int)(mid - pos - 1));
      if (encoding == 'Q')
      {
				// decode quoted printable text
				for (i=str.length()-1; i>=0; i--)
	  		if (str[i]=='_')
	  			str[i]=' ';
				cstr = decodeQuotedPrintable(str);
      }
      else
      {
				// decode base64 text
				cstr = decodeBase64(str);
      }
      QTextCodec *codec = codecForName(charset);
      if (!codec)
      	codec = codecForName(KGlobal::locale()->encoding());
      if (codec)
      	result += codec->toUnicode(cstr);
      else
      	result += QString::fromLocal8Bit(cstr);
      lastWasEncodedWord = TRUE;

      *pos = ch;
      pos = end -1;
    }
    else
    {
      // invalid encoding, keep separating LWSP.
      //result += "=?";
      //pos = beg -1; // because pos gets increased shortly afterwards
      pos = beg - 2;
      result += LWSP_buffer;
      result += *pos++;
      result += *pos;
      lastWasEncodedWord = FALSE;
    }
    LWSP_buffer = 0;
  }
  return result;
}

