/*
 * mime.c - MIME routines.
 */


/* Headers
 **********/

#include "all.h"
#pragma hdrstop

#include "htmlutil.h"
#include "mime.h"
#ifdef FEATURE_IMAGE_VIEWER
#include "winview.h"
#endif


/* Types
 ********/

/* internal MIME type handler description */

typedef struct internalmimehandler
{
   /* MIME content type */

   PCSTR pcszMIMEType;

   /* internal content handler function */

   HTConverter InternalHandler;

   /* atom for pcszMIMEType string */

   HTAtom atomMIMEType;
}
INTERNALMIMEHANDLER;
DECLARE_STANDARD_TYPES(INTERNALMIMEHANDLER);


/* Module Constants
 *******************/

#pragma data_seg(DATA_SEG_READ_ONLY)

CCHAR m_cszEncoding[]               = "Encoding";

CCHAR m_cszBinary[]                 = "binary";
CCHAR m_csz7Bit[]                   = "7bit";
CCHAR m_csz8Bit[]                   = "8bit";

CCHAR m_cszShellOpenCmdSubKeyFmt[]  = "Shell\\Open\\Command";

#pragma data_seg()


/* Module Variables
 *******************/

/* array of internal handlers used by MIME_GetInternalHandler() */

PRIVATE_DATA INTERNALMIMEHANDLER s_intmimehnd[] =
{
   { "text/html",       HTMLPresent,            0 },
   { "text/plain",      HTPlainPresent,         0 },

#ifdef FEATURE_IMG_INLINE
   { "image/x-xbitmap", Viewer_Present,         0 },
#endif   /* FEATURE_IMG_INLINE */

#ifdef FEATURE_IMAGE_VIEWER
   { "image/jpeg",      Viewer_Present,         0 },
   { "image/gif",       Viewer_Present,         0 },
#ifdef FEATURE_VRML
   { "x-world/x-vrml",  VRML_Present,         0 },
#endif
#endif   /* FEATURE_IMAGE_VIEWER */

#ifdef FEATURE_SOUND_PLAYER
   { "audio/basic",     SoundPlayer_Present,    0 },
   { "audio/aiff",      SoundPlayer_Present,    0 },
   { "audio/x-aiff",    SoundPlayer_Present,    0 },
#endif   /* FEATURE_SOUND_PLAYER */

};


/***************************** Private Functions *****************************/


#ifdef DEBUG

PRIVATE_CODE BOOL IsValidPCINTERNALMIMEHANDLER(
                                          PCINTERNALMIMEHANDLER pcintmimehnd)
{
   return(IS_VALID_READ_PTR(pcintmimehnd, CINTERNALMIMEHANDLER) &&
          IS_VALID_STRING_PTR(pcintmimehnd->pcszMIMEType, CSTR) &&
          IS_VALID_CODE_PTR(pcintmimehnd->InternalHandler, HTConverter) &&
          EVAL(IsValidHTAtom(pcintmimehnd->atomMIMEType)));
}

#endif


/*
** AddInternalMIMEHandlerAtoms()
**
** Adds HTAtom for each MIME type string in an array of INTERNALMIMEHANDLERs.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PRIVATE_CODE BOOL AddInternalMIMEHandlerAtoms(PINTERNALMIMEHANDLER pintmimehnd,
                                              UINT ucHandlers)
{
   BOOL bResult = TRUE;
   UINT u;

   ASSERT(IS_VALID_READ_BUFFER_PTR(pintmimehnd, INTERNALMIMEHANDLER, ucHandlers * sizeof(*pintmimehnd)));

   for (u = 0; u < ucHandlers; u++)
   {
      HTAtom atom;

      atom = HTAtom_for(pintmimehnd[u].pcszMIMEType);

      if (atom != -1)
      {
         pintmimehnd[u].atomMIMEType = atom;

         ASSERT(IS_VALID_STRUCT_PTR(&(pintmimehnd[u]), CINTERNALMIMEHANDLER));
      }
      else
      {
         /* Do not delete HTAtoms added so far.  HTAtom_deleteAll() will. */

         bResult = FALSE;
         break;
      }
   }

   return(bResult);
}


/****************************** Public Functions *****************************/


/*
** InitMIMEModule()
**
** Adds MIME type atoms for module array of INTERNALMIMEHANDLERs.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL InitMIMEModule(void)
{
   return(AddInternalMIMEHandlerAtoms(s_intmimehnd,
                                      ARRAY_ELEMENTS(s_intmimehnd)));
}


/*
** ExitMIMEModule()
**
** NOP
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE void ExitMIMEModule(void)
{
   return;
}


/*
** MIME_GetDescription()
**
** Retrieves the description of a registered MIME type.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL MIME_GetDescription(HTAtom atomMIMEType, PSTR pszDescBuf,
                                     UINT ucDescBufLen)
{
   BOOL bResult;
   DWORD dwValueType;
   DWORD dwcbDescBufLen = ucDescBufLen;

   /* GetMIMEFileTypeValue() will verify parameters. */

   /* The description of a file type is the file type key's default value. */

   bResult = (GetMIMEFileTypeValue(HTAtom_name(atomMIMEType), NULL, NULL,
                                   &dwValueType, pszDescBuf, &dwcbDescBufLen) &&
              dwValueType == REG_SZ);

   if (bResult)
      TRACE_OUT(("MIME_GetDescription(): MIME type %s's description is %s.",
                 HTAtom_name(atomMIMEType),
                 pszDescBuf));

   return(bResult);
}


/*
** MIME_GetMIMEAtomFromExtension()
**
** Determines the MIME type associated with a file extension.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL MIME_GetMIMEAtomFromExtension(PCSTR pcszPath,
                                         PHTAtom phtatomMIMEType)
{
   char szMIMEType[MAX_PATH_LEN];

   ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
   ASSERT(IS_VALID_WRITE_PTR(phtatomMIMEType, HTAtom));

   *phtatomMIMEType = (MIME_GetMIMETypeFromExtension(pcszPath, szMIMEType,
                                                     sizeof(szMIMEType))
                       ? HTAtom_for(szMIMEType)
                       : -1);

   ASSERT(*phtatomMIMEType == -1 ||
          EVAL(IsValidHTAtom(*phtatomMIMEType)));

   return(*phtatomMIMEType != -1);
}


/*
** MIME_GetEncoding()
**
** Determines the ENCODING expected for a MIME type.
**
** Arguments:
**
** Returns:       ENCODING_BINARY if encoding not registered.
**
** Side Effects:  none
*/
PUBLIC_CODE ENCODING MIME_GetEncoding(HTAtom atomMIMEType)
{
   ENCODING enc;
   DWORD dwValueType;
   DWORD dwEncoding;
   DWORD dwcLen = sizeof(dwEncoding);

   /* GetMIMEValue() will verify parameters. */

   if (GetMIMEValue(HTAtom_name(atomMIMEType), m_cszEncoding, &dwValueType,
                    (PBYTE)&dwEncoding, &dwcLen) &&
       (dwValueType == REG_BINARY || dwValueType == REG_DWORD) &&
       IsValidENCODING(dwEncoding))
   {
      enc = dwEncoding;

      TRACE_OUT(("MIME_GetEncoding(): %s of MIME type %s is %d.",
                 m_cszEncoding,
                 HTAtom_name(atomMIMEType),
                 enc));
   }
   else
      enc = ENCODING_BINARY;

   ASSERT(IsValidENCODING(enc));

   return(enc);
}


/*
** ENCODINGFromString()
**
** Retrieves the ENCODING corresponding to a string.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE ENCODING ENCODINGFromString(PCSTR pcszEncoding)
{
   ENCODING enc;

   ASSERT(IS_VALID_STRING_PTR(pcszEncoding, CSTR));

   if (! lstrcmp(pcszEncoding, m_csz7Bit))
      enc = ENCODING_7BIT;
   else if (! lstrcmp(pcszEncoding, m_csz8Bit))
      enc = ENCODING_8BIT;
   else
   {
      if (lstrcmp(pcszEncoding, m_cszBinary))
         ERROR_OUT(("ENCODINGFromString(): Unrecognized encoding %s.",
                    pcszEncoding));

      enc = ENCODING_BINARY;
   }

   ASSERT(IsValidENCODING(enc));

   return(enc);
}


/*
** MIME_GetInternalHandler()
**
** Retrieves the internal handler associated with a MIME type.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL MIME_GetInternalHandler(HTAtom atomMIMEType,
                                         HTConverter *phtconv)
{
   BOOL bResult = FALSE;
   UINT u;

   ASSERT(IsValidHTAtom(atomMIMEType));
   ASSERT(IS_VALID_WRITE_PTR(phtconv, HTConverter));

   *phtconv = NULL;

   for (u = 0; u < ARRAY_ELEMENTS(s_intmimehnd); u++)
   {
      if (s_intmimehnd[u].atomMIMEType == atomMIMEType)
      {
         *phtconv = s_intmimehnd[u].InternalHandler;
         bResult = TRUE;

         TRACE_OUT(("MIME_GetInternalHandler(): Found internal handler for MIME type %s.",
                    HTAtom_name(atomMIMEType)));
      }
   }

   ASSERT((bResult &&
           IS_VALID_CODE_PTR(*phtconv, HTConverter)) ||
          (! bResult &&
           ! *phtconv));

   return(bResult);
}


/*
** IsExtensionHandlerRegistered()
**
** Determines whether or not a handler is registered for a path-type URL's
** (e.g., file:, ftp:, http:) referent's extension.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL IsExtensionHandlerRegistered(PCSTR pcszURL)
{
   BOOL bResult;
   PCSTR pcszExt;

   /* Look up the open command of the extension's associated file type. */

   pcszExt = ExtractExtension(pcszURL);

   if (*pcszExt)
   {
      DWORD dwValueType;
      char szOpenCmd[MAX_PATH_LEN];
      DWORD dwcbOpenCmdLen = sizeof(szOpenCmd);

      bResult = (GetFileTypeValue(pcszExt, m_cszShellOpenCmdSubKeyFmt, NULL,
                                  &dwValueType, szOpenCmd, &dwcbOpenCmdLen) &&
                 (dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ));
   }
   else
      bResult = FALSE;

   TRACE_OUT(("IsExtensionHandlerRegistered(): %s external handler is registered for the referent of URL %s.",
              bResult ? "An" : "No",
              pcszURL));

   return(bResult);
}


/*
** IsValidENCODING()
**
** Determines whether or not an ENCODING is valid.
**
** Arguments:
**
** Returns:
**
** Side Effects:  none
*/
PUBLIC_CODE BOOL IsValidENCODING(ENCODING enc)
{
   BOOL bResult;

   switch (enc)
   {
      case ENCODING_BINARY:
      case ENCODING_7BIT:
      case ENCODING_8BIT:
         bResult = TRUE;
         break;

      default:
         bResult = FALSE;
         ERROR_OUT(("IsValidEncoding(): Invalid ENCODING %d.",
                    enc));
         break;
   }

   return(bResult);
}