/* wv1522.h V 1.1 1997/03/16 00:00:00 heirich */

/* Define the following to use ( only for read ! ) a feature by obsolete RFC1113
*  this RFC sayed that unencoded characters can be in base64 encoded text, when
*  it is enclosed in '*', newer RFC like 1341, 1521 don't support this
*  normaly let it undefined !
*/
#define RFC1113



#ifdef RFC1522

#include <tchar.h>


struct WVC_Char {
          WVC_Char * next;
          TCHAR c;
} ALIGNED;


//#define WVC_DECODE_NONE 0
//#define WVC_DECODE_Q         1
//#define WVC_DECODE_B         2

//#define WVC_ENCODE_NONE 10
//#define WVC_ENCODE_Q         11
//#define WVC_ENCODE_B         12


class FIFO {
private:
          WVC_Char *anchor; /* pointer to the first char of queue, NULL if queue empty */
          WVC_Char *last;   /* pointer to last char in list, for better performance */
          unsigned int PendingCharacters; /* number of chars the queue containing */
          void DeleteAll(); /* release all allocated heap storage */
protected:
          void Chain(const TCHAR); /* appends a character on the end of queue */
public:
          FIFO(); /* this creates a empty queue */
          FIFO(const char *); /* this creates a queue from a string */
          FIFO(unsigned int,const char *); /* same, but 0x00 don't end a string */
          ~FIFO(); /* deallocates all memory */
          void EndOfStream(); /* this singnals, that no more input comes in queue */
          void Putchar(const TCHAR); /* append char to the queue */
          BOOL Putallowed(); /* TRUE if it is allowed to use Putchar() */
          int Testchar(); /* like Getchar(), but char remains in queue */
          int Getchar(); /* takes the first char of queue */
          void Ungetchar(const TCHAR);  /* puts a char in front of a queue */
          unsigned int Pendingchars(); /* how many chars in queue */
          BOOL Getallowed(); /* true if a character available */
#ifdef UNICODE
          FIFO(const wchar_t *); /* this creates a queue from a wide string */
          FIFO(unsigned int, const wchar_t *); /* same, but 0x0000 don't end a string */
#endif
}ALIGNED;

class RFCFIFO : public FIFO {
          unsigned int nonASCIICharacters; /* number if chars >0x7F in queue */
protected:
          void Chain(const TCHAR); /* appends a char to the queue */
public:
          RFCFIFO(); /* this creates a empty queue */
          RFCFIFO(const char *); /* this creates a queue from a string */
          RFCFIFO(unsigned int,const char *); /* same, but 0x00 don't end a string */
          ~RFCFIFO(); /* deallocates all memory */
          int Getchar(); /* takes the first char of queue */
          void Ungetchar(const TCHAR); /* puts a char in front of a queue */
          unsigned int NonASCIIchars(); /* how many non-ASCII chars in queue */
#ifdef UNICODE
          RFCFIFO(const wchar_t *); /* this creates a queue from a wide string */
          RFCFIFO(unsigned int, const wchar_t *); /* same, but 0x0000 don't end a string */
#endif
}ALIGNED;


class WVBDecoder : public RFCFIFO {
private:
#ifdef UNICODE
          unsigned int octetwidth;
          unsigned long int Base64Bits;
#else
          unsigned int Base64Bits;
#endif            
          unsigned int Base64Index;
          
#ifdef RFC1113
          BOOL rfc1113;
          BOOL directCharacters;
#endif          
          BYTE base64num(const char ch); /* input to Base64 is always ASCII-char */
public:
#if 1//def JAPANESE
          void DeleteAll();
#endif
          WVBDecoder();
#ifdef RFC1113
          WVBDecoder(BOOL);
#endif
          WVBDecoder(const char *);
#ifdef RFC1113
          WVBDecoder(const char *, BOOL);
#endif
          WVBDecoder(unsigned int, const char *);
#ifdef RFC1113          
          WVBDecoder(unsigned int, const char *, BOOL);
#endif          
          ~WVBDecoder();
          void Putchar(const TCHAR);
          
#ifdef UNICODE
          WVBDecoder(unsigned int);
#ifdef RFC1113
          WVBDecoder(BOOL, unsigned int);
#endif
          WVBDecoder(const char *, unsigned int);
#ifdef RFC1113
          WVBDecoder(const char *, BOOL, unsigned int);
#endif
          WVBDecoder(unsigned int, const char *, unsigned int);
#ifdef RFC1113          
          WVBDecoder(unsigned int, const char *, BOOL, unsigned int);
#endif          
          WVBDecoder(const wchar_t *);
          WVBDecoder(const wchar_t *, unsigned int);
#ifdef RFC1113
          WVBDecoder(const wchar_t *, BOOL);
          WVBDecoder(const wchar_t *, BOOL, unsigned int);
#endif
          WVBDecoder(unsigned int, const wchar_t *);
          WVBDecoder(unsigned int, const wchar_t *, unsigned int);
#ifdef RFC1113
          WVBDecoder(unsigned int, const wchar_t *, BOOL);
          WVBDecoder(unsigned int, const wchar_t *, BOOL, unsigned int);
#endif          
#endif // UNICODE
}ALIGNED;


#ifdef UNICODE
#define WVC_DECODERBLOCKLENGTH 4
#else
#define WVC_DECODERBLOCKLENGTH 2
#endif

class WVQIDecoder : public RFCFIFO {
private:
           char DecoderBlock[WVC_DECODERBLOCKLENGTH];
           char * DecoderPtr;
#ifdef UNICODE     
           unsigned int octetwidth;
           unsigned int decodelength;
#endif     
           unsigned int outstanding;

           BYTE hexnum(const char ch); /* input to QP =xy are always ASCII-chars */
public:
           WVQIDecoder();
           WVQIDecoder(const char *);
           WVQIDecoder(unsigned int, const char *);
           ~WVQIDecoder();
           void Putchar(const TCHAR);
#ifdef UNICODE
           WVQIDecoder(unsigned int);
           WVQIDecoder(const char *, unsigned int);
           WVQIDecoder(unsigned int, const char *, unsigned int);
           WVQIDecoder(const wchar_t *);
           WVQIDecoder(const wchar_t *, unsigned int);
           WVQIDecoder(unsigned int, const wchar_t *);
           WVQIDecoder(unsigned int, const wchar_t *, unsigned int);
#endif     
}ALIGNED;



class WVBCoder : public FIFO {
private:
          unsigned int Base64Bits;
          unsigned int Base64Index;
#ifdef UNICODE
          unsigned int octetwidth;
#endif           
          char base64char(const BYTE); /* results of Base64 encoding are always ASCII-chars */
public:
          WVBCoder();
          WVBCoder(const char *);
          WVBCoder(unsigned int, const char *);
          ~WVBCoder();
          void EndOfStream();
          void Putchar(const char);
#ifdef UNICODE
          WVBCoder(unsigned int);
          WVBCoder(const char *, unsigned int);
          WVBCoder(unsigned int, const char *, unsigned int);
          WVBCoder(const wchar_t *);
          WVBCoder(const wchar_t *, unsigned int);
          WVBCoder(unsigned int, const wchar_t *);
          WVBCoder(unsigned int, const wchar_t *, unsigned int);
          void Putchar(const wchar_t);
#endif    
}ALIGNED;

class WVQICoder : public RFCFIFO {
private:

#ifdef UNICODE
          unsigned int octetwidth;
#endif
          
          char hexchar(const BYTE); /* results of QP encoding are always ASCII-chars */
public:
          WVQICoder();
          WVQICoder(const char *);
          WVQICoder(unsigned int, const char *);
          ~WVQICoder();
          void Putchar(const TCHAR);
#ifdef UNICODE
          WVQICoder(unsigned int);
          WVQICoder(const char *, unsigned int);
          WVQICoder(unsigned int, const char *, unsigned int);
          WVQICoder(const wchar_t *);
          WVQICoder(const wchar_t *, unsigned int);
          WVQICoder(unsigned int, const wchar_t *);
          WVQICoder(unsigned int, const wchar_t *, unsigned int);
#endif    
}ALIGNED;

class WVQCoder : public WVQICoder {
public:
          WVQCoder();
          WVQCoder(const char *);
          WVQCoder(unsigned int, const char *);
          ~WVQCoder();
          void Putchar(const TCHAR);
#ifdef UNICODE
          WVQCoder(unsigned int);
          WVQCoder(const char *, unsigned int);
          WVQCoder(unsigned int, const char *, unsigned int);
          WVQCoder(const wchar_t *, unsigned int);
          WVQCoder(unsigned int, const wchar_t *, unsigned int);
#endif    
}ALIGNED;


class WVQDecoder : public WVQIDecoder {
public:
           WVQDecoder();
           WVQDecoder(const char *);
           WVQDecoder(unsigned int, const char *);
           ~WVQDecoder();
           void Putchar(const TCHAR);
#ifdef UNICODE
           WVQDecoder(unsigned int);
           WVQDecoder(const char *, unsigned int);
           WVQDecoder(unsigned int, const char *, unsigned int);
           WVQDecoder(const wchar_t *);
           WVQDecoder(const wchar_t *, unsigned int);
           WVQDecoder(unsigned int, const wchar_t *);
           WVQDecoder(unsigned int, const wchar_t *, unsigned int);
#endif     
}ALIGNED;

enum WVC_usableDecoders {
    DecoderQ,           /* RFC1522 Q-Decoder */
    DecoderB            /* RFC1522 B-Decoder */
};


class WVDecoder {
private:
          void * Decoder;
          WVC_usableDecoders whichDecoder;
#ifdef UNICODE  
          void Init(const char *, unsigned int);
#else
          void Init(const char *);
#endif

public:
          WVDecoder(const char *);
          ~WVDecoder();
          void EndOfStream(); /* this singnals, that no more input comes in queue */
          void Putchar(const TCHAR); /* append char to the queue */
          BOOL Putallowed(); /* TRUE if it is allowed to use Putchar() */
          int Testchar(); /* like Getchar(), but char remains in queue */
          int Getchar(); /* takes the first char of queue */
          void Ungetchar(const TCHAR); /* puts a char in front of a queue */
          unsigned int Pendingchars(); /* how many chars in output */
          unsigned int NonASCIIchars(); /* how many non-ASCII chars in output */
          BOOL Getallowed(); /* true if a character available */
#ifdef UNICODE
          WVDecoder(const char *, unsigned int);
          WVDecoder(wchar_t *);
          WVDecoder(wchar_t *, unsigned int);
#endif    
}ALIGNED;


struct WVC_CharsetList {
    WVC_CharsetList *next;
    char *name; /* names of charactersets are always in US-ASCII */
#ifdef UNICODE
    unsigned int octetwidth; /* how many bytes represents a char 1= normal 2= UNICODE */
#endif    
//#ifdef JAPANESE
    int coding;
    #define WVCDS_THRU          (0)
    #define WVCDS_IGNORECTRL    (1)
    #define WVCDS_UTF7          (3)
    #define WVCDS_UTF8          (4)
	#define WVCDS_8859_15       (15)
	#define WVCDS_1252          (1252)  //ISO-8859-1
	#define WVCDS_1254          (1254)  //ISO-8859-9
    int codepage;
#ifdef JAPANESE
    #define WVCDS_ISO2022       (2)
  #ifndef OSCP_THRU
    #define OSCP_THRU           (0)
    #define OSCP_JAP_SJIS       (932)
    #define OSCP_KOR_KSC        (949)
    #define OSCP_CHI_BIG5       (950)
    #define OSCP_CHI_GB         (936)
    #define OSCP__8859_5        (28595)
    #define OSCP__8859_8        (1255)
	#define OSCP__8859_9        (1254)

  #endif
#endif
} ALIGNED ;

#define TAB 0x09
#define CR  0x0D
#define LF  0x0A

enum WVC_DecoderStatus {
    WVC_US_ASCII_TEXT,                  /* last character was part of US-ASCII unecoded text */
    WVC_RFC_ENCODING_ALLOWED,           /* last character was whitespace */
    WVC_POSSIBLE_RFC_ENCODING,          /* found = character */
    WVC_CHARSET_PART,                   /* found =? */
    WVC_CODING_PART,                    /* found 2nd ? */
    WVC_TEXT_PART,                      /* found 3rd ? */
    WVC_WAS_RFC_ENCODING,               /* found last ? */
    WVC_SUCCESSFULL_RFC_ENCODING        /* last = found and whitespace follows */
};

#if 1//def JAPANESE

class WVCharsetDecoder : public FIFO
{
private:
   char          unicache[128];
   char          mbscache[128];
   int           uniindex;
   int           mbsindex;
   int           charset;
   int           coding;
   int           state;
   int           prevstate;
   unsigned char inbuf[8];
   WVBDecoder *BDecoder;
public:
#ifdef UNICODE
   WVCharsetDecoder(int, int, unsigend int);
#endif
#ifdef JAPANESE
   WVCharsetDecoder(int charset = OSCP_JAP_SJIS, int coding = WVCDS_ISO2022);
#else
   WVCharsetDecoder(int charset = 0, int coding = WVCDS_THRU /*WVCDS_UTF8*/);
#endif
   ~WVCharsetDecoder();
   void SwitchStream(int, int);
   void PutHalfwchar(TCHAR ch);
   void Flushwcache();
   void Putchar(const TCHAR);
   inline void Thruchar(const TCHAR ch) {
        FIFO::Putchar(ch);
      }
   void EndOfStream();
   void SetEncoding(int code) {coding = code;};
} ALIGNED;
#endif

#define WVC_CHARSETNAMELENGTH 75+1 /* +1 for trailing \0 */
#define WVC_CODERNAMELENGTH 75+1   /* +1 for trailing \0 */

class WVRFCDecoder : public RFCFIFO
{
private:
   BOOL strictRFC;
#if 1//def JAPANESE
   int  foldingStatus; // 0: text 1: decoded
   FIFO foldingSpace;
   WVCharsetDecoder CharsetDecoder;
#endif
   WVC_DecoderStatus status;

   WVC_CharsetList * charsets; /* this points to the list of charsets */

   WVC_CharsetList * actualcharset; /* his points to the actual charset in usage */
   
   char Charsetname[WVC_CHARSETNAMELENGTH]; /* must always in US-ASCII */
   char *CharsetPtr;
   unsigned int CharsetnameLen;

   char Codername[WVC_CODERNAMELENGTH]; /* must always in US-ASCII */ 
   char *CoderPtr;
   unsigned int CodernameLen;
   
   FIFO * original; /* contains the undecoded stream for the case we must abort */

   WVDecoder * Decoder;

   void ChainSetStatus(const TCHAR);
   void abort();
   void Init();
public:
   WVRFCDecoder();
   WVRFCDecoder(const char *);
   WVRFCDecoder(const BOOL);
   WVRFCDecoder(const BOOL, const char *);
   ~WVRFCDecoder();
   WVC_CharsetList * RegisterCharsetName(const char *);
   void Putchar(const TCHAR);
   void EndOfStream();
   void SetEncoding(int code) { CharsetDecoder.SetEncoding(code); };

#ifdef UNICODE
   WVRFCDecoder(const char *, unsigned int);
   WVRFCDecoder(const BOOL, const char *, unsigned int);

   WVRFCDecoder(wchar_t *);
   WVRFCDecoder(wchar_t *, unsigned int);
   WVRFCDecoder(const BOOL, wchar_t *);
   WVRFCDecoder(const BOOL, wchar_t *, unsigned int);
   
   void RegisterCharsetName(const char *, unsigned int);
   void RegisterCharsetName(wchar_t *);
   void RegisterCharsetName(wchar_t *, unsigned int);      
#endif
}ALIGNED;


class WVC_prequeue : public RFCFIFO {
private:
    WVC_prequeue * next;
    unsigned int Specialcharacters;
    void processwords(BOOL);
public:
    WVC_prequeue();
    ~WVC_prequeue();
    void setnextword(WVC_prequeue *);
    WVC_prequeue * getnextword();
    unsigned int GetSpecialchars();
    void Putchar(const TCHAR);
}ALIGNED;


#define WVC_MAX_ENCODING_LENGTH 75 /* maximum length of a encoded word in output */

class WVRFCCoder : public FIFO
{
private:
   char Charsetname[WVC_CHARSETNAMELENGTH];

#ifdef UNICODE
   unsigned int octetwidth; /* width in byte of charset */
#endif

   TCHAR lastchar;
     
   WVC_prequeue *root;
   WVC_prequeue *prequeue;

   void processwords(BOOL);
   BOOL whitespace(const TCHAR);

public:
   WVRFCCoder();
   WVRFCCoder(const char *);
   ~WVRFCCoder();
   void Putchar(const TCHAR);
   void EndOfStream();
#ifdef UNICODE
   WVRFCCoder(const char *, unsigned int);
   WVRFCCoder(wchar_t *);
   WVRFCCoder(wchar_t *, unsigned int);
#endif
}ALIGNED;

void decodeRFC1522A(WVString &str);
void encodeHeaderA(WVString &str);
void decodeRFC1522W(WVString &str);
void encodeHeaderW(WVString &str);

#ifdef UNICODE
#define encodeHeader encodeHeaderW
#define decodeRFC1522 decodeRFC1522W
#else
#define encodeHeader encodeHeaderA
#define decodeRFC1522 decodeRFC1522A
#endif

#endif // RFC1522
