home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / helpers.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  54.3 KB  |  1,754 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20.  
  21. #include "helper.h"
  22. #include "il_strm.h"
  23. #include "display.h"
  24. #include "prefapi.h" //CRN_MIME
  25.  
  26. //  List of all helpers in our helper app struct.
  27. //  Static must be declared here.
  28. CPtrList CHelperApp::m_cplHelpers;
  29.  
  30. //
  31. // Parse a list of extensions for file types
  32. //
  33. // Extensions will come in as a list .sg,.earh,.rts .ear
  34. //
  35. // Parse this list, white space is used to delimit between entries.  The
  36. //  number of entries is returned in num_exts and the individual extensions
  37. //  are returned in list
  38. //
  39. // I think I've fixed it so that we are no longer dropping extensions 
  40. //  for .mp2 files.  chouck 29-Dec-94
  41. //
  42.  
  43.  
  44. void fe_ParseExtList(const char * ext_string, int *num_exts, char **list) 
  45. {
  46.     char * start, *cur, *newext;
  47.     int iLen, idx;
  48.     BOOL bInExt = FALSE;
  49.     char * copy = strdup(ext_string);  // make copy to muck with
  50.     int iExtCnt = 0;
  51.     
  52.     start = cur = copy;
  53.     iLen = strlen(copy);
  54.  
  55.     // traverse string    
  56.     for (idx =0; idx < iLen; idx++) {
  57.         if (bInExt) {
  58.             // We are currently reading an extension
  59.             // If we have a character add it to the current extension
  60.  
  61.             if (!isalnum(*cur))    {
  62.  
  63.                 // Found a delimiter character, end the extension
  64.  
  65.                 bInExt = FALSE;
  66.                 *cur = 0; // mark end
  67.                 list[iExtCnt] = strdup(newext);
  68.                 iExtCnt++;                
  69.  
  70.             }
  71.  
  72.         } else {
  73.  
  74.             // We are not currently in an extension, search for next alpha numeric character
  75.  
  76.             if (isalnum(*cur)) {
  77.                 // found one! -- mark start of new extenison -- set flag
  78.                 newext = cur;
  79.                 bInExt = TRUE;
  80.  
  81.             }
  82.  
  83.         }
  84.  
  85.         cur++;
  86.     }
  87.     // save last one
  88.     if (bInExt) {
  89.         list[iExtCnt] = strdup(newext);
  90.         iExtCnt++;                
  91.     }
  92.     *num_exts = iExtCnt;
  93.     
  94.     //    Be sure to free your copy to muck with
  95.     XP_FREE(copy);
  96. }
  97.  
  98. // Returns TRUE if lpszExt is in the list of comma delimited extensions
  99. // (this is the Netscape format used to write the suffixes associated a
  100. // particular MIME type). lpszExt should not have a lead '.'
  101. static BOOL
  102. ExtensionIsInList(LPCSTR lpszExtList, LPCSTR lpszExt)
  103. {
  104.     LPSTR    extlist[50]; // XXX - fe_ParseExtList needs another parameter...
  105.     int     nExtensions = 0;
  106.     BOOL    bResult = FALSE;
  107.     
  108.     ASSERT(lpszExt && (*lpszExt != '.'));
  109.     fe_ParseExtList(lpszExtList, &nExtensions, extlist);
  110.  
  111.     // Look for our extension
  112.     for (int i = 0; i < nExtensions; i++) {
  113.         if (strcmpi(extlist[i], lpszExt) == 0) {
  114.             bResult = TRUE;
  115.             break;
  116.         }
  117.     }
  118.  
  119.     // Free the extensions
  120.     for (i = 0; i < nExtensions; i++)
  121.         XP_FREE(extlist[i]);
  122.  
  123.     return bResult;
  124. }
  125.  
  126. // Returns TRUE if lpszExt is in the list of extensions for this
  127. // type. lpszExt should not have a lead '.' (none of the extensions
  128. // in pcdata have a leading '.')
  129. static BOOL
  130. ExtensionIsInList(NET_cdataStruct *pcdata, LPCSTR lpszExt)
  131. {
  132.     ASSERT(lpszExt && (*lpszExt != '.'));
  133.     for (int i = 0; i < pcdata->num_exts; i++)    {
  134.         if (stricmp(lpszExt, pcdata->exts[i]) == 0)    {
  135.             return TRUE;
  136.         }
  137.     }
  138.  
  139.     return FALSE;
  140. }
  141.  
  142. // Creates a front-end data structure (CHelperApp object) if there isn't already one
  143. // Looks in the Viewers section to see how the MIME type should be configured
  144. void fe_AddTypeToList(NET_cdataStruct *cd_item) 
  145. {
  146.     CHelperApp *app = NULL;
  147.  
  148.     if(cd_item->ci.fe_data) {
  149.         app = (CHelperApp *)cd_item->ci.fe_data;
  150.     }
  151.     else    {
  152.         // Create a front-end data structure
  153.         app = new CHelperApp();
  154.     }
  155.     
  156.     app->bChanged = FALSE;
  157.     app->bNewType = FALSE;
  158.     app->bChangedExts = FALSE;
  159.     
  160.     CString csCmd = theApp.GetProfileString("Viewers", cd_item->ci.type);
  161.  
  162.     // Handle internally by default
  163.     if (csCmd.IsEmpty()) {
  164.         if ( (!strcmp(cd_item->ci.type, TEXT_HTML))  || 
  165.              (!strcmp(cd_item->ci.type, TEXT_PLAIN)) ||
  166.              (!strcmp(cd_item->ci.type, IMAGE_GIF))  || 
  167.              (!strcmp(cd_item->ci.type, IMAGE_XBM))  || 
  168.              (!strcmp(cd_item->ci.type, IMAGE_JPG)) ||
  169.             // (!strcmp(cd_item->ci.type, APPLICATION_BINHEX)) ||
  170.              (!strcmp(cd_item->ci.type, "application/x-ns-proxy-autoconfig"))) {
  171.             app->how_handle = HANDLE_VIA_NETSCAPE;
  172.         }
  173.  
  174.         if(!stricmp(cd_item->ci.type, APPLICATION_OCTET_STREAM)) {
  175.                 app->how_handle = HANDLE_SAVE;
  176.         }
  177.     }
  178.     else {
  179.         int iPercent = csCmd.ReverseFind('%');  // strip %ls from config
  180.         if (iPercent > 0)
  181.             csCmd = csCmd.Left(iPercent-1);
  182.  
  183.         if (csCmd == MIME_SAVE) 
  184.             app->how_handle = HANDLE_SAVE;
  185.         else if (csCmd == MIME_INTERNALLY)
  186.             app->how_handle = HANDLE_VIA_NETSCAPE;
  187.         else if (csCmd == MIME_PROMPT)
  188.             app->how_handle = HANDLE_UNKNOWN;    
  189.         else if (csCmd == MIME_OLE)    {
  190.             app->how_handle = HANDLE_BY_OLE;
  191.         }
  192.         else if (csCmd == MIME_SHELLEXECUTE)    {
  193.             app->how_handle = HANDLE_SHELLEXECUTE;
  194.         }
  195.         else {
  196.             char    szFile[_MAX_FNAME];
  197.             
  198.             // This is the default case.
  199.             app->csCmd = csCmd;
  200.             app->how_handle = HANDLE_EXTERNAL;
  201.  
  202.             // If there's no description then the helper app UI won't display the item
  203.             // Use the base filename without extension
  204.             szFile[0] = '\0';
  205.             _splitpath((LPCSTR)csCmd, NULL, NULL, szFile, NULL);
  206.             if (szFile[0] == '\0') {
  207.                 // Just use the MIME type for the description
  208.                 cd_item->ci.desc = XP_STRDUP(cd_item->ci.type);
  209.  
  210.             } else {
  211.                 szFile[0] = toupper(szFile[0]);
  212.                 cd_item->ci.desc = PR_smprintf("%s %s", szFile, szLoadString(IDS_STRING_FILE));
  213.             }
  214.         }
  215.  
  216.         if (app->how_handle == HANDLE_SHELLEXECUTE || app->how_handle == HANDLE_BY_OLE) {
  217.             // We need to have a description or the helper app UI won't display the
  218.             // item. If it's set as shell execute or launch as OLE that means we're getting
  219.             // it from the registry, and it better have a description...
  220.             ASSERT(cd_item->ci.desc);
  221.         }
  222.     }
  223.  
  224.     app->cd_item = cd_item;
  225.     cd_item->ci.fe_data = app;  // store the helper app object
  226.     theApp.m_HelperListByType.SetAt(cd_item->ci.type,app);  // store in global list
  227. }
  228.  
  229. void fe_SetExtensionList(NET_cdataStruct *cd_item) 
  230. {
  231.     if (!cd_item)
  232.         return;
  233.  
  234.     char * extlist[50]; // BUG shouldn't limit it to 50 extensions-- big deal...blah easier to debug
  235.     int iNumExt =0;  // number from ini file
  236.     int idx;
  237.  
  238.     CString csExtListFromINI = theApp.GetProfileString("Suffixes",cd_item->ci.type);
  239.     if (!csExtListFromINI.IsEmpty()) {
  240.         // add extension out of ini file
  241.         fe_ParseExtList((const char *) csExtListFromINI, &iNumExt, extlist);
  242.     }
  243.  
  244.     if (iNumExt > 0) {
  245.         // got extension from INI file...overwrite netlib stuff
  246.         for (idx = 0; idx < cd_item->num_exts ; idx++) {
  247.             if (cd_item->exts[idx]) {
  248.                 XP_FREE(cd_item->exts[idx]);
  249.                 cd_item->exts[idx] = NULL;
  250.             }
  251.         }
  252.         // store our new stuff
  253.         if (cd_item->exts) XP_FREE(cd_item->exts);
  254.         cd_item->exts = (char **)XP_ALLOC(iNumExt * sizeof(char *));
  255.         cd_item->num_exts = iNumExt;
  256.         for (idx = 0; idx < cd_item->num_exts ; idx++)
  257.             cd_item->exts[idx] = extlist[idx];
  258.     }
  259. }
  260.  
  261. // Retrieve the class name for the given extension
  262. BOOL
  263. GetClassName(LPCSTR lpszExtension, CString &strClass)
  264. {
  265.     char    szKey[_MAX_EXT + 1];  // space for '.'
  266.     char    szClass[128];
  267.     LONG    lResult;
  268.     LONG    lcb;
  269.  
  270.     // Look up the file association key which maps a file extension
  271.     // to a file class
  272.     wsprintf(szKey, ".%s", lpszExtension);
  273.  
  274.     lcb = sizeof(szClass);
  275.     lResult = RegQueryValue(HKEY_CLASSES_ROOT, szKey, szClass, &lcb);
  276.     
  277. #ifdef _WIN32
  278.     ASSERT(lResult != ERROR_MORE_DATA);
  279. #endif
  280.     if (lResult != ERROR_SUCCESS || lcb <= 1)
  281.         return FALSE;
  282.  
  283.     strClass = szClass;
  284.     return TRUE;
  285. }
  286.  
  287. //  Return value must be freed by caller.
  288. char *InventMime(const char *pExtension)
  289. {
  290.     LPSTR   lpszMimeType = NULL;
  291.     char    szKey[_MAX_EXT + 1];  // space for '.'
  292.  
  293.     if (!pExtension)
  294.         return NULL;
  295.  
  296.     // Build the file association key. It must begin with a '.'
  297.     wsprintf(szKey, ".%s", pExtension);
  298.     
  299. #ifdef XP_WIN32
  300.     //  See if the extension has a mime type (Content Type).
  301.     HKEY hExt = NULL;
  302.     LONG lCheckOpen = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_QUERY_VALUE, &hExt);
  303.  
  304.     if (lCheckOpen == ERROR_SUCCESS) {
  305.         DWORD    dwType;
  306.         DWORD    cbData;
  307.         LONG    lResult;
  308.          
  309.         // See how much space we need
  310.         cbData = 0;
  311.         lResult = RegQueryValueEx(hExt, "Content Type", NULL, &dwType, NULL, &cbData);
  312.         if (lResult == ERROR_SUCCESS && cbData > 1) {
  313.             lpszMimeType = (LPSTR)XP_ALLOC(cbData);
  314.             if (!lpszMimeType) {
  315.                 VERIFY(RegCloseKey(hExt) == ERROR_SUCCESS);
  316.                 return NULL;
  317.             }
  318.  
  319.             // Get the string
  320.             lResult = RegQueryValueEx(hExt, "Content Type", NULL, &dwType, (LPBYTE)lpszMimeType, &cbData);
  321.             ASSERT(lResult == ERROR_SUCCESS);
  322.         }
  323.  
  324.         VERIFY(RegCloseKey(hExt) == ERROR_SUCCESS);
  325.     }
  326. #endif
  327.  
  328.     //  Finally, default to fake generated mime type
  329.     if (!lpszMimeType) {
  330.         CString strClass;
  331.         
  332.         // Only do this is there's a class associated with the extension
  333.         if (GetClassName(pExtension, strClass) && !strClass.IsEmpty())
  334.             lpszMimeType = PR_smprintf("%s%s", SZ_WINASSOC, (LPCSTR)strClass);
  335.     }
  336.  
  337.     return lpszMimeType;
  338. }
  339.  
  340. //  Return value must be freed by caller.
  341. char *InventDescription(const char *pExtension)
  342. {
  343.     CString strClass;
  344.  
  345.     if (!pExtension)
  346.         return NULL;
  347.  
  348.     // Get the class name
  349.     if (GetClassName(pExtension, strClass) && !strClass.IsEmpty()) {
  350.         LONG    cbData;
  351.         LONG    lResult;
  352.  
  353. #ifdef _WIN32
  354.         // See how much space we need
  355.         cbData = 0;
  356.         lResult = RegQueryValue(HKEY_CLASSES_ROOT, (LPCSTR)strClass, NULL, &cbData);
  357.         if (lResult == ERROR_SUCCESS && cbData > 1) {
  358.             LPSTR   lpszDescription = (LPSTR)XP_ALLOC(cbData);
  359.  
  360.             if (!lpszDescription)
  361.                 return NULL;
  362.  
  363.             // Get the string
  364.             VERIFY(RegQueryValue(HKEY_CLASSES_ROOT, (LPCSTR)strClass, lpszDescription, &cbData) == ERROR_SUCCESS);
  365.             return lpszDescription;
  366.         }
  367. #else
  368.         // Win 3.1 RegQueryValue() doesn't support asking for the size of the data
  369.         char    szDescription[128];
  370.  
  371.         // Get the string
  372.         cbData = sizeof(szDescription);
  373.         lResult = RegQueryValue(HKEY_CLASSES_ROOT, (LPCSTR)strClass, szDescription, &cbData);
  374.         return lResult == ERROR_SUCCESS ? XP_STRDUP(szDescription) : NULL;
  375. #endif
  376.     }
  377.  
  378.     return NULL;
  379. }
  380.  
  381. static BOOL
  382. HasShellOpenCommand(LPCSTR lpszFileClass)
  383. {
  384.     char    szKey[_MAX_PATH];
  385.     HKEY    hKey;
  386.  
  387.     // See if there's a shell/open key specified for the file class
  388.     PR_snprintf(szKey, sizeof(szKey), "%s\\shell\\open", lpszFileClass);
  389.  
  390.     if (RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey) == ERROR_SUCCESS) {
  391.         RegCloseKey(hKey);
  392.         return TRUE;
  393.     }
  394.  
  395.     return FALSE;
  396. }
  397.  
  398. // Create a front-end data structure if necessary, and set how_handle as
  399. // HANDLE_SHELLEXECUTE if there's a shell\open command for the file extension.
  400. // It will also set the description if there isn't already one
  401. void ShellHelper(NET_cdataStruct *pNet, const char *pExtension)
  402. {
  403.     if(pNet != NULL && pNet->ci.fe_data == NULL)    {
  404.         //  Create front end counter-part.
  405.         CHelperApp *pApp = new CHelperApp();
  406.         if(pApp)    {
  407.             pApp->cd_item = pNet;
  408.             pNet->ci.fe_data = (void *)pApp;
  409.  
  410.             pApp->bChanged = FALSE;
  411.             pApp->bNewType = FALSE;
  412.             pApp->bChangedExts = FALSE;
  413.  
  414.             // Don't set how_handle to HANDLE_SHELLEXECUTE unless there's a file
  415.             // type class associated with the extension which has a shell\open
  416.             // command
  417.             //
  418.             // Assume that we can't shell execute it
  419.             pApp->how_handle = HANDLE_UNKNOWN;
  420.  
  421.             if (GetClassName(pExtension, pApp->strFileClass)) {
  422.                 // XXX - We really should handle verbs other than Open. FindExecutable()
  423.                 // and ShellExecute() don't either, but ShellExecuteEx() does...
  424.                 if (HasShellOpenCommand((LPCSTR)pApp->strFileClass)) {
  425.                     pApp->how_handle = HANDLE_SHELLEXECUTE;
  426.                     pApp->csCmd = MIME_SHELLEXECUTE;
  427.                 }
  428.             }
  429.  
  430.  
  431.             //  application/octet-stream is always save.
  432.             if(!stricmp(pNet->ci.type, APPLICATION_OCTET_STREAM)) {
  433.                     pApp->how_handle = HANDLE_SAVE;
  434.             }
  435.  
  436.             theApp.m_HelperListByType.SetAt(pNet->ci.type, pApp);
  437.         }
  438.  
  439.         //  Give it a description if not already set.
  440.         if(pExtension != NULL && pNet->ci.desc == NULL)   {
  441.             pNet->ci.desc = InventDescription(pExtension);
  442.         }
  443.     }
  444. }
  445.  
  446. // Given a file extension and its associated MIME type (may be NULL),
  447. // make sure there's a corresponding entry in the netlib list of
  448. // NET_cdataStruct structures
  449. //
  450. // There must be an extension, and the extension must not begin with
  451. // a leading '.'
  452. NET_cdataStruct *
  453. ProcessFileExtension(const char *pExtension, const char *ccpMimeType)
  454. {
  455.     NET_cdataStruct *pExistingItem = NULL;
  456.  
  457.     //  Must have an extension to be considered, must not begin with a period.
  458.     if(pExtension == NULL)  {
  459.         return NULL;
  460.     }
  461.     else if(*pExtension == '.')  {
  462.         ASSERT(0);
  463.         return NULL;
  464.     }
  465.  
  466.     // See if the extension is already in the netlib list. If it is AND it has a MIME
  467.     // type then call ShellHelper() which will set how_handle to HANDLE_SHELLEXECUTE
  468.     // if there is a shell\open command for the extension
  469.     XP_List *pTypesList = cinfo_MasterListPointer();
  470.     NET_cdataStruct *pListEntry = NULL;
  471.     while ((pListEntry = (NET_cdataStruct *)XP_ListNextObject(pTypesList)))    {
  472.         if(pListEntry->ci.type != NULL || pListEntry->ci.encoding != NULL)    {
  473.             for(int iFind = 0; iFind < pListEntry->num_exts; iFind++)    {
  474.                 if(stricmp(pExtension, pListEntry->exts[iFind]) == 0)    {
  475.                     // This call will create a front-end data structure if
  476.                     // necessary, and set how to handle as HANDLE_SHELLEXECUTE if
  477.                     // there's a shell\open command for the file extension. It will
  478.                     // also set the description if there isn't already one
  479.                     if(pListEntry->ci.type)
  480.                         ShellHelper(pListEntry, pExtension);
  481.  
  482.                     // Remember this item
  483.                     pExistingItem = pListEntry;
  484.                 }
  485.             }
  486.         }
  487.     }
  488.  
  489.     if(pExistingItem && pExistingItem->ci.encoding)
  490.     {
  491.         /* don't overwrite existing encodings with nonsense types */
  492.         return NULL;
  493.     }
  494.  
  495.     //  If no mime type was passed in, invent one.
  496.     const char *pMimeType = ccpMimeType;
  497.     BOOL bFreeMimeType = FALSE;
  498.     if(pMimeType == NULL)   {
  499.         pMimeType = (const char *)InventMime(pExtension);
  500.         if(pMimeType)   {
  501.             bFreeMimeType = TRUE;
  502.         }
  503.         else    {
  504.             return NULL;
  505.         }
  506.     }
  507.  
  508.     // Ignore extensions in the registry that have content type "application/x-msdownload"
  509.     if (bFreeMimeType && stricmp(pMimeType, "application/x-msdownload") == 0) {
  510.         XP_FREE((void *)pMimeType);
  511.         pMimeType = XP_STRDUP(APPLICATION_OCTET_STREAM);
  512.     }
  513.     
  514.     //  If mime type already exists in the list, must add extention to it.
  515.     pTypesList = cinfo_MasterListPointer();
  516.     pListEntry = NULL;
  517.     BOOL bExisted = FALSE;
  518.     while ((pListEntry = (NET_cdataStruct *)XP_ListNextObject(pTypesList)))    {
  519.         if(pListEntry->ci.type != NULL)    {
  520.             if(stricmp(pListEntry->ci.type, pMimeType) == 0)    {
  521.                 bExisted = TRUE;
  522.  
  523.                 // Check if the extension is already in the list
  524.                 if (!ExtensionIsInList(pListEntry, pExtension)) {
  525.                     char **ppTest = (char **)XP_REALLOC((void *)(pListEntry->exts), sizeof(char *) * (pListEntry->num_exts + 1));
  526.                     if(ppTest)  {
  527.                         pListEntry->exts = ppTest;
  528.                         pListEntry->exts[pListEntry->num_exts] = XP_STRDUP(pExtension);
  529.                         if(pListEntry->exts[pListEntry->num_exts])    {
  530.                             pListEntry->num_exts++;
  531.     
  532.                             // This call will create a front-end data structure if
  533.                             // necessary, and set how to handle as HANDLE_SHELLEXECUTE if
  534.                             // there's a shell\open command for the file extension. It will
  535.                             // also set the description if there isn't already one
  536.                             ShellHelper(pListEntry, pExtension);
  537.                         }
  538.                     }
  539.                 }
  540.             }
  541.         }
  542.     }
  543.     if(bExisted)    {
  544.         if(bFreeMimeType)   {
  545.             XP_FREE((void *)pMimeType);
  546.             pMimeType = NULL;
  547.         }
  548.         return pListEntry;
  549.     }
  550.  
  551.     // There's no entry in the netlib list for this MIME type so create a new entry. Don't
  552.     // do this if there's an existing entry in the netlib list with the same extension and
  553.     // we made up the MIME type (it's a fake generated MIME type)
  554.     if (pExistingItem && strncmp(pMimeType, SZ_WINASSOC, strlen(SZ_WINASSOC)) == 0)
  555.     {
  556.            if(bFreeMimeType)   {
  557.                XP_FREE((void *)pMimeType);
  558.            }
  559.         return pExistingItem;
  560.     }
  561.  
  562.     NET_cdataStruct *pNew = NET_cdataCreate();
  563.     if(pNew)    {
  564.         pNew->ci.type = XP_STRDUP(pMimeType);
  565.         if(pNew->ci.type)   {
  566.             pNew->num_exts = 1;
  567.             pNew->exts = (char **)XP_ALLOC(sizeof(char *));
  568.             if(pNew->exts)  {
  569.                 pNew->exts[0] = XP_STRDUP(pExtension);
  570.                 if(pNew->exts[0])   {
  571.                     NET_cdataAdd(pNew);
  572.                 }
  573.                 else    {
  574.                     NET_cdataFree(pNew);
  575.                     pNew = NULL;
  576.                 }
  577.             }
  578.             else    {
  579.                 NET_cdataFree(pNew);
  580.                 pNew = NULL;
  581.             }
  582.         }
  583.         else    {
  584.             NET_cdataFree(pNew);
  585.             pNew = NULL;
  586.         }
  587.  
  588.         if(pNew)    {
  589.             // This call will create a front-end data structure if
  590.             // necessary, and set how to handle as HANDLE_SHELLEXECUTE if
  591.             // there's a shell\open command for the file extension. It will
  592.             // also set the description if there isn't already one
  593.             ShellHelper(pNew, pExtension);
  594.         }
  595.     }
  596.  
  597.     if(bFreeMimeType)   {
  598.         XP_FREE((void *)pMimeType);
  599.         pMimeType = NULL;
  600.     }
  601.  
  602.     return pNew;
  603. }
  604.  
  605. // This routines looks at every file type association in the registry.
  606. // For each file extension it calls ProcessFileExtension()
  607. void registry_GenericFileTypes()
  608. {
  609.     char aExtension[MAX_PATH + 1];
  610.     memset(aExtension, 0, sizeof(aExtension));
  611.     DWORD dwExtKey = 0;
  612.     LONG lCheckEnum = ERROR_SUCCESS;
  613.  
  614.     do  {
  615.         lCheckEnum = RegEnumKey(HKEY_CLASSES_ROOT, dwExtKey++, aExtension, sizeof(aExtension));
  616.         if(lCheckEnum == ERROR_SUCCESS && aExtension[0] == '.') {
  617.             ProcessFileExtension(&aExtension[1], NULL);
  618.         }
  619.     }
  620.     while(lCheckEnum == ERROR_SUCCESS);
  621. }
  622.  
  623. #ifndef _WIN32
  624. // This routines looks at every file type association in the WIN.INI file.
  625. // For each file extenion it calls ProcessFileExtension()
  626. void winini_GenericFileTypes()
  627. {
  628.     const char *pSection = "Extensions";
  629.     int iAllocSize = 1024 * 16;
  630.     char *pBuffer = (char *)XP_ALLOC(iAllocSize);
  631.     if(pBuffer) {
  632.         memset(pBuffer, 0, iAllocSize);
  633.         if(0 != GetProfileString(pSection, NULL, "", pBuffer, iAllocSize))  {
  634.             char *pTraverse = pBuffer;
  635.             char aExt[_MAX_PATH];
  636.             memset(aExt, 0, sizeof(aExt));
  637.             while(*pTraverse != '\0')   {
  638.                 strcpy(aExt, pTraverse);
  639.                 pTraverse += strlen(aExt) + 1;
  640.                 ProcessFileExtension(aExt, NULL);
  641.             }
  642.         }
  643.  
  644.         XP_FREE((void *)pBuffer);
  645.         pBuffer = NULL;
  646.     }
  647. }
  648. #endif
  649.  
  650. // See if there are any user defined MIME types that need to be added to the
  651. // netlib list. These are stored in the Viewers section. Add them first so
  652. // they're handled like the types in mktypes.h
  653. static void
  654. fe_UserDefinedFileTypes()
  655. {
  656.     for (int idx=0 ; ; idx++) {    
  657.         char     szBuf[20];
  658.         
  659.         sprintf(szBuf, "TYPE%d", idx);
  660.         CString csType(theApp.GetProfileString("Viewers", szBuf));
  661.         
  662.         // XXX - we expect the list of user defined items to be contiguously numbered
  663.         // starting at 0, and so we stop when we get back an empty value. We should
  664.         // really handle the case where there are holes in the numbering, e.g. an
  665.         // uninstaller removed one of the items...
  666.         if (csType.IsEmpty())
  667.             break;
  668.          
  669.         // See whether the MIME type is already in the netlib list
  670.         XP_List               *pTypesList = cinfo_MasterListPointer();
  671.         NET_cdataStruct *pcdata;
  672.         while ((pcdata = (NET_cdataStruct *)XP_ListNextObject(pTypesList)))    {
  673.             if (pcdata->ci.type != NULL && (stricmp(pcdata->ci.type, (LPCSTR)csType) == 0))
  674.                 break;
  675.         }
  676.  
  677.         if (!pcdata) {
  678.             // Create a new netlib type
  679.             pcdata = NET_cdataCreate();
  680.             pcdata->ci.type = XP_STRDUP((LPCSTR)csType);
  681.  
  682.             // Add it to the netlib list
  683.             NET_cdataAdd(pcdata);
  684.  
  685.             // Note: don't look in the Viewers section to see how the MIME type should be
  686.             // configured. We'll do that last after checking the registry
  687.         }
  688.  
  689.         if (pcdata) {
  690.             // Look in the Suffixes section to get the list of extensions associated with
  691.             // this MIME type
  692.             fe_SetExtensionList(pcdata);
  693.         }
  694.     }
  695.     
  696.     theApp.m_iNumTypesInINIFile = idx;
  697. }
  698.  
  699. //Begin CRN_MIME
  700. NET_cdataStruct *
  701. FileExtensionInNetlibList(const char *pExtension, const char *ccpMimeType)
  702. {
  703.     NET_cdataStruct *pExistingItem = NULL;
  704.  
  705.     //  Must have an extension to be considered, must not begin with a period.
  706.     if(pExtension == NULL)  {
  707.         return NULL;
  708.     }
  709.     else if(*pExtension == '.')  {
  710.         ASSERT(0);
  711.         return NULL;
  712.     }
  713.  
  714.     // See if the extension is already in the netlib list. If it is AND it has a MIME
  715.     // type then return the NET_cdataStruct pointer
  716.     XP_List *pTypesList = cinfo_MasterListPointer();
  717.     NET_cdataStruct *pListEntry = NULL;
  718.     while ((pListEntry = (NET_cdataStruct *)XP_ListNextObject(pTypesList)))    {
  719.         if(pListEntry->ci.type != NULL)    {
  720.             for(int iFind = 0; iFind < pListEntry->num_exts; iFind++)    {
  721.                 if(stricmp(pExtension, pListEntry->exts[iFind]) == 0)    {
  722.                     // Remember this item
  723.                     pExistingItem = pListEntry;
  724.                 }
  725.             }
  726.         }
  727.     }
  728.  
  729.     return pExistingItem;
  730. }
  731.  
  732. const char *GetMimeCmd(int load_action)
  733. {
  734.     switch(load_action) 
  735.     {
  736.         case HANDLE_SAVE: 
  737.             return MIME_SAVE;
  738.  
  739.         case HANDLE_SHELLEXECUTE: 
  740.             return MIME_SHELLEXECUTE;
  741.  
  742.         case HANDLE_UNKNOWN:
  743.             return MIME_SHELLEXECUTE;    //????? What should this be set to ???
  744.  
  745.         case HANDLE_VIA_PLUGIN:
  746.             return MIME_SHELLEXECUTE;    //????? What should this be set to ???
  747.  
  748.         default:
  749.             return MIME_SHELLEXECUTE;    //????? What should this be set to ???            
  750.     }    
  751. }
  752.  
  753. int GetPrefLoadAction(char * pPrefix)
  754. {
  755.     //Get load_action, if any
  756.     int32 load_action;
  757.     char szPref[512];
  758.  
  759.     wsprintf(szPref, "%s.load_action", pPrefix);
  760.     int iRet = PREF_GetIntPref(szPref, &load_action);
  761.     if(iRet == PREF_NOERROR)
  762.     {
  763.         switch(load_action) 
  764.         {
  765.             case 1: //Save
  766.                 iRet = HANDLE_SAVE;
  767.                 break;
  768.             case 2: //Launch 
  769.                 iRet = HANDLE_SHELLEXECUTE;
  770.                 break;
  771.             case 3://Unknown
  772.                 iRet = HANDLE_UNKNOWN;
  773.                 break;
  774.             case 4://Plug-In
  775.                 iRet = HANDLE_VIA_PLUGIN;
  776.                 break;
  777.             default:
  778.                 iRet = HANDLE_SHELLEXECUTE;
  779.                 break;
  780.         }
  781.     }    
  782.     else
  783.         iRet = HANDLE_SHELLEXECUTE;
  784.  
  785.     return iRet;
  786. }
  787.  
  788. void fe_ChangeDescription(NET_cdataStruct *pcdata, LPCSTR lpszExt, LPCSTR lpszDescription)
  789. {
  790.     // See if the Description has changed
  791.     if (strcmpi(pcdata->ci.desc, lpszDescription) != 0) {
  792.  
  793.        CString strClass;
  794.  
  795.         // Get the class name
  796.         if (GetClassName(lpszExt, strClass) && !strClass.IsEmpty()) {
  797.             // Set the description
  798.             RegSetValue(HKEY_CLASSES_ROOT, strClass, REG_SZ, lpszDescription, lstrlen(lpszDescription));
  799.  
  800.             // Now go ahead and change the description in the netlib data structure
  801.             StrAllocCopy(pcdata->ci.desc, lpszDescription);
  802.         }
  803.     }
  804. }
  805.  
  806.  
  807. void fe_UpdateMControlMimeTypes(void) 
  808. {
  809.     CString str;
  810.     char * child_list;
  811.     int bOK = PREF_NOERROR;
  812.     char * type = NULL;
  813.     char * ext = NULL;
  814.     char * desc = NULL;
  815.     char * open_cmd = NULL;
  816.  
  817.  
  818.     if ( PREF_CreateChildList("mime", &child_list) == 0 )
  819.     {    
  820.         char szPref[512];
  821.         int index = 0;
  822.         char *child = NULL;
  823.         while (child = PREF_NextChild(child_list, &index)) 
  824.         {
  825.             TRACE(child);TRACE("\r\n");    
  826.             
  827.             wsprintf(szPref, "%s.mimetype", child);
  828.             bOK = PREF_CopyCharPref(szPref, &type);
  829.             if (bOK == PREF_NOERROR) 
  830.             {
  831.                 wsprintf(szPref, "%s.extension", child);
  832.                 bOK = PREF_CopyCharPref(szPref, &ext);
  833.                 if(bOK == PREF_NOERROR)
  834.                 {
  835.                     wsprintf(szPref, "%s.description", child);
  836.                     bOK = PREF_CopyCharPref(szPref, &desc);
  837.                     if(bOK == PREF_NOERROR)
  838.                     {
  839.                         wsprintf(szPref, "%s.win_appname", child);
  840.                         bOK = PREF_CopyCharPref(szPref, &open_cmd);
  841.                     }
  842.                 }
  843.             }
  844.             //Register new type only if all the fields are specified.
  845.             if(type && type[0] && ext && ext[0] && desc && desc[0] && open_cmd && open_cmd[0])
  846.             {
  847.                 //char szJunk[256];
  848.                 //wsprintf(szJunk, "%s - %s - %s - %s\r\n", (type && type[0]) ? type : "", (ext && ext[0]) ? ext : "", (desc && desc[0]) ? desc : "", (open_cmd && open_cmd[0]) ? open_cmd : "");
  849.                 //TRACE(szJunk);
  850.                 
  851.                 NET_cdataStruct *pcdata= NULL;
  852.  
  853.                 int load_action = GetPrefLoadAction(child);
  854.  
  855.                 //Check and see if we already have this file extension with the mime type
  856.                 pcdata = FileExtensionInNetlibList(ext, type);
  857.                 if(pcdata == NULL)
  858.                 {
  859.                     pcdata = fe_NewFileType(desc, ext, type, open_cmd);
  860.                     CHelperApp *pApp = (CHelperApp *)pcdata->ci.fe_data;
  861.                     if(pApp)
  862.                     {
  863.                         pApp->how_handle = load_action;
  864.                         pApp->csCmd = GetMimeCmd(load_action);
  865.                         pApp->csMimePrefPrefix = child;
  866.                     }
  867.                 }
  868.                 else
  869.                 {
  870.                     CHelperApp *pApp = (CHelperApp *)pcdata->ci.fe_data;
  871.                     if(pApp)
  872.                     {
  873.                         pApp->csMimePrefPrefix = child;
  874.                     }
  875.  
  876.                     fe_ChangeFileType(pcdata, type, load_action, open_cmd);
  877.                     fe_ChangeDescription(pcdata, ext, desc);
  878.                 }
  879.             }
  880.  
  881.             if(type && type[0])
  882.             {
  883.                 XP_FREE(type);
  884.                 type = NULL;
  885.             }
  886.             if(ext && ext[0])
  887.             {
  888.                 XP_FREE(ext);
  889.                 ext = NULL;
  890.             }
  891.             if(desc && desc[0])
  892.             {
  893.                 XP_FREE(desc);
  894.                 desc = NULL;
  895.             }
  896.             if(open_cmd && open_cmd[0])
  897.             {
  898.                 XP_FREE(open_cmd);
  899.                 open_cmd = NULL;
  900.             }
  901.         }
  902.         XP_FREE(child_list);
  903.     }
  904.  
  905. }
  906. //End CRN_MIME
  907.  
  908. // This routine updates the netlib list of NET_cdataStruct objects with information
  909. // found in the registry, WIN.INI file, and the Netscape specific information
  910. // (the Viewers and Suffixes section)
  911. void fe_InitFileFormatTypes(void) {
  912.     // See if there are any user defined MIME types that need to be added to the
  913.     // netlib list. These are stored in the Viewers section. Add them first so
  914.     // they're handled like the types in mktypes.h
  915.     //
  916.     // This way when we look in the registry we'll find shell execute handlers for them
  917.     fe_UserDefinedFileTypes();
  918.  
  919.     // This call is going to look at every file extension in the registry and 
  920.     // update existing netlib structures that have matching file extenions and
  921.     // matching MIME types. It will also create a new netlib structure if necessary
  922.     registry_GenericFileTypes();
  923.  
  924. #ifndef _WIN32
  925.     // This call is going to look at every file association in WIN.INI and 
  926.     // update existing netlib structures that have matching file extenions. It
  927.     // will also create a new netlib structure if necessary
  928.     winini_GenericFileTypes();
  929. #endif
  930.  
  931.     NET_cdataStruct *cd_item;
  932.     XP_List   * infolist = cinfo_MasterListPointer();;  // Get beginning of the list
  933.  
  934.     // The last thing we do is use the Netscape specific information. This means looking
  935.     // at the Viewers and Suffixes sections
  936.     //
  937.     // Do this for every entry in the netlib list
  938.     while ((cd_item = (NET_cdataStruct *)XP_ListNextObject(infolist))) {  // iterate through the list  
  939.         if (cd_item->ci.type) {  // if it is a mime type
  940.             // Look in the Viewers section to see how the MIME type should be configured.
  941.             // This allows us to override anything we found in the registry, e.g. user wants to
  942.             // Save to disk or open as an OLE server
  943.             fe_AddTypeToList(cd_item);
  944.  
  945.             // Look in the Suffixes section to get the list of extensions associated with
  946.             // this MIME type
  947.             fe_SetExtensionList(cd_item);
  948.         }
  949.     }
  950. }
  951.  
  952. void fe_CleanupFileFormatTypes(void) 
  953. {
  954.     NET_cdataStruct *cd_item;
  955.     XP_List   * infolist = cinfo_MasterListPointer();;  // Get beginning of the list
  956.     CHelperApp * app;
  957.             
  958.     while ((cd_item = (NET_cdataStruct *)XP_ListNextObject(infolist))) {  // iterate through the list  
  959.         if (cd_item->ci.type) {  // if it is a mime type  
  960.             app = (CHelperApp *)cd_item->ci.fe_data;
  961.             
  962.             if (app) {
  963.                 if (app->bChanged)                 
  964.                     theApp.WriteProfileString("Viewers",cd_item->ci.type,app->csCmd);
  965.                 delete app;
  966.             }                
  967.         }
  968.     }
  969. }
  970. //
  971. // Add a user defined mime type to our list of helper applications
  972. //
  973. CHelperApp * fe_AddNewFileFormatType(const char *mime_type,const char *subtype) 
  974. {
  975.     NET_cdataStruct * cd_item;
  976.     XP_List           * infolist = cinfo_MasterListPointer();;  // Get beginning of the list
  977.     CString           csMime;
  978.  
  979.     if (!infolist) return NULL;
  980.     cd_item = (NET_cdataStruct *)XP_ALLOC(sizeof(NET_cdataStruct));
  981.     memset(cd_item,0,sizeof(NET_cdataStruct));
  982.     csMime += mime_type;
  983.     csMime += '/';
  984.     csMime += subtype;
  985.     cd_item->ci.type = XP_STRDUP((const char *)csMime);
  986.  
  987.     CHelperApp * app = new CHelperApp();
  988.     app->bChanged = TRUE;
  989.     app->bNewType = TRUE;
  990.     app->bChangedExts = FALSE;    
  991.     app->how_handle = HANDLE_UNKNOWN;
  992.     app->cd_item = cd_item;
  993.     app->csCmd = "";
  994.     cd_item->ci.fe_data = app;  // store the helper app object
  995.  
  996.     // store in FE's list of types
  997.     theApp.m_HelperListByType.SetAt(cd_item->ci.type, app);
  998.  
  999.     // tell the netlib about it
  1000.     XP_ListAddObjectToEnd(infolist,cd_item); 
  1001.     return app;
  1002. }
  1003.  
  1004. // Sets the shell open command string value for the given file class
  1005. void
  1006. SetShellOpenCommand(LPCSTR lpszFileClass, LPCSTR lpszCmdString)
  1007. {
  1008.     char    szKey[_MAX_PATH];
  1009.     HKEY    hKey;
  1010.     LONG    lResult;
  1011.  
  1012.     // Build the subkey string
  1013.     wsprintf(szKey, "%s\\shell\\open\\command", lpszFileClass);
  1014.  
  1015.     // Update the shell\open\command for the file type class
  1016.     lResult = RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hKey);
  1017.  
  1018.     if (lResult == ERROR_SUCCESS) {
  1019.         RegSetValue(hKey, NULL, REG_SZ, lpszCmdString, lstrlen(lpszCmdString));
  1020.         RegCloseKey(hKey);
  1021.     }
  1022. }
  1023.  
  1024. #ifdef _WIN32
  1025. // We expect the extension to begin with '.'
  1026. static void
  1027. AddToMIMEDatabase(LPCSTR lpszType, LPCSTR lpszExt)
  1028. {
  1029.     char    szKey[_MAX_PATH];
  1030.     HKEY    hKey;
  1031.  
  1032.     PR_snprintf(szKey, sizeof(szKey), "MIME\\Database\\Content Type\\%s", lpszType);
  1033.  
  1034.     // What we're really doing is setting the default extension for the
  1035.     // content type
  1036.     //
  1037.     // Since we don't have a UI for specifying the default extension when creating
  1038.     // a new file type, only add this is there's nothing already there
  1039.     if (RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hKey) == ERROR_SUCCESS) {
  1040.         DWORD    cbData;
  1041.         LONG    lResult;
  1042.  
  1043.         // See if there's anything there
  1044.         cbData = 0;
  1045.         lResult = RegQueryValueEx(hKey, "Extension", NULL, NULL, NULL, &cbData);
  1046.  
  1047.         if (lResult != ERROR_SUCCESS || cbData <= 1)
  1048.             RegSetValueEx(hKey, "Extension", 0, REG_SZ, (CONST BYTE *)lpszExt, lstrlen(lpszExt) + 1);
  1049.  
  1050.         // Close the key
  1051.         RegCloseKey(hKey);
  1052.     }
  1053. }
  1054. #endif
  1055.  
  1056. // Adds a new content type to the list of Netscape specific types, and adds lpszExtension
  1057. // to the list of extensions for the MIME type. lpszExtenion should have a leading '.'
  1058. static void
  1059. AddNetscapeMimeType(LPCSTR lpszMimeType, LPCSTR lpszExtension)
  1060. {
  1061.     char szBuf[20];
  1062.     
  1063.     // Add this to the list of user-defined MIME types
  1064.     sprintf(szBuf, "TYPE%d", theApp.m_iNumTypesInINIFile++);
  1065.     theApp.WriteProfileString("Viewers", szBuf, lpszMimeType);
  1066.  
  1067.     // Get the list of extensions for the MIME type
  1068.     CString strExtList(theApp.GetProfileString("Suffixes", lpszMimeType));
  1069.  
  1070.     ASSERT(lpszExtension && (*lpszExtension == '.'));
  1071.  
  1072.     strExtList.TrimLeft();
  1073.     strExtList.TrimRight();
  1074.     if (strExtList.IsEmpty()) {
  1075.         theApp.WriteProfileString("Suffixes", lpszMimeType, lpszExtension);
  1076.  
  1077.     } else if (!ExtensionIsInList(strExtList, lpszExtension + 1)) {
  1078.         // Add the extension to the end of the list
  1079.         strExtList += ',';
  1080.         strExtList += lpszExtension;
  1081.         theApp.WriteProfileString("Suffixes", lpszMimeType, (LPCSTR)strExtList);
  1082.     }
  1083. }
  1084.  
  1085. // Routine to add a new file type. Note that this routine is also called
  1086. // when the user is adding an additional MIME type to an existing file
  1087. // extension
  1088. NET_cdataStruct *
  1089. fe_NewFileType(LPCSTR lpszDescription,
  1090.                LPCSTR lpszExtension,
  1091.                LPCSTR lpszMimeType,
  1092.                LPCSTR lpszOpenCmd)
  1093. {
  1094.     char    szExtKey[_MAX_PATH];
  1095.     CString    strFileClass;
  1096.     HKEY    hKey;
  1097. #ifdef _WIN32
  1098.     BOOL    bAlreadyHasMimeType;
  1099. #endif
  1100.  
  1101.     // Create a key for the file type extension. There may already be a key for
  1102.     // this extension; that's okay this will open it
  1103.     wsprintf(szExtKey, ".%s", lpszExtension);
  1104.     if (RegCreateKey(HKEY_CLASSES_ROOT, szExtKey, &hKey) != ERROR_SUCCESS)
  1105.         return NULL;
  1106.  
  1107.     // Set the file type class associated with the extension. Note that we ONLY
  1108.     // do this if there is no file type class. If there's already a file type class
  1109.     // we assume that we're just adding another MIME type for this file type
  1110.     if (!GetClassName(lpszExtension, strFileClass)) {
  1111.         // Create a file type class
  1112.         strFileClass = lpszExtension;
  1113.         strFileClass += "file";
  1114.     
  1115.         // Set the file type class
  1116.         RegSetValue(hKey, NULL, REG_SZ, (LPCSTR)strFileClass, strFileClass.GetLength());
  1117.     }
  1118.  
  1119. #ifdef _WIN32
  1120.     // Add the Content Type for the extension. Only do this if there isn't already a
  1121.     // content type specified for the extension. Note: unfortunately Microsoft only
  1122.     // allows a single content type for a particular extension. If there's already a
  1123.     // content type that's okay, we'll add the additional content type to the MIME database
  1124.     LONG    lResult;
  1125.     DWORD    cbData;
  1126.  
  1127.     ASSERT(lpszMimeType);
  1128.     cbData = 0;
  1129.     lResult = RegQueryValueEx(hKey, "Content Type", NULL, NULL, NULL, &cbData);
  1130.     bAlreadyHasMimeType = (lResult == ERROR_SUCCESS && cbData > 1);
  1131.  
  1132.     if (!bAlreadyHasMimeType)
  1133.         RegSetValueEx(hKey, "Content Type", 0, REG_SZ, (CONST BYTE *)lpszMimeType, lstrlen(lpszMimeType) + 1);
  1134. #endif
  1135.     RegCloseKey(hKey);
  1136.  
  1137.     // Create a key for the file type class. If there's already a key this will open
  1138.     // it
  1139.     RegCreateKey(HKEY_CLASSES_ROOT, (LPCSTR)strFileClass, &hKey);
  1140.  
  1141.     // Set the description
  1142.     RegSetValue(hKey, NULL, REG_SZ, lpszDescription, lstrlen(lpszDescription));
  1143.     RegCloseKey(hKey);
  1144.  
  1145.     // Add the shell Open command
  1146.     SetShellOpenCommand((LPCSTR)strFileClass, lpszOpenCmd);
  1147.  
  1148.     // Update the MIME database information
  1149. #ifdef _WIN32
  1150.     AddToMIMEDatabase(lpszMimeType, szExtKey);
  1151.     
  1152.     // If there's already a MIME type and we're adding an additional type, then
  1153.     // add it to the Netscape specific information in the Suffixes section
  1154.     if (bAlreadyHasMimeType)
  1155.         AddNetscapeMimeType(lpszMimeType, szExtKey);
  1156. #else
  1157.     AddNetscapeMimeType(lpszMimeType, szExtKey);
  1158. #endif
  1159.  
  1160.     // Create the NET_cdataStruct structure and associated CHelperApp object
  1161.     NET_cdataStruct *pcdata = NET_cdataCreate();
  1162.  
  1163.     if (pcdata) {
  1164.         pcdata->ci.desc = XP_STRDUP(lpszDescription);
  1165.         pcdata->ci.type = XP_STRDUP(lpszMimeType);
  1166.         pcdata->num_exts = 0;
  1167.         pcdata->exts = (char **)XP_ALLOC(sizeof(char *));
  1168.         if (pcdata->exts) {
  1169.             pcdata->exts[0] = XP_STRDUP(lpszExtension);
  1170.             
  1171.             if (pcdata->exts[0]) {
  1172.                 pcdata->num_exts = 1;
  1173.  
  1174.             } else {
  1175.                 XP_FREE(pcdata->exts);
  1176.                 pcdata->exts = 0;
  1177.             }
  1178.         }
  1179.  
  1180.         // Add it to the netlib list
  1181.         NET_cdataAdd(pcdata);
  1182.  
  1183.         // Create the front-end data structure
  1184.         CHelperApp *pApp = new CHelperApp;
  1185.  
  1186.         if (pApp) {
  1187.             // Initialize the object
  1188.             pApp->bChanged = FALSE;
  1189.             pApp->bNewType = FALSE;
  1190.             pApp->bChangedExts = FALSE;
  1191.             pApp->how_handle = HANDLE_SHELLEXECUTE;
  1192.             pApp->csCmd = MIME_SHELLEXECUTE;
  1193.             pApp->strFileClass = strFileClass;
  1194.  
  1195.             // Front-end and netlib data structures need to point to each other
  1196.             pApp->cd_item = pcdata;
  1197.             pcdata->ci.fe_data = (void *)pApp;
  1198.  
  1199.             // Store it in the global list ordered by MIME type
  1200.             theApp.m_HelperListByType.SetAt(pcdata->ci.type, pApp);
  1201.         }
  1202.     }
  1203.  
  1204.     return pcdata;
  1205. }
  1206.  
  1207. #ifdef _WIN32
  1208. // Routine to recursively delete a key with subkeys. Needed under Win NT only
  1209. LONG
  1210. RegDeleteKeyNT(HKEY hStartKey, LPCSTR lpszKeyName)
  1211. {
  1212.     HKEY    hKey;
  1213.     LONG    lResult;
  1214.  
  1215.     // Do not allow NULL or empty key name
  1216.     if (!lpszKeyName || *lpszKeyName == '\0')
  1217.         return ERROR_BADKEY;
  1218.  
  1219.     lResult = RegOpenKeyEx(hStartKey, lpszKeyName, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey);
  1220.     if (lResult != ERROR_SUCCESS)
  1221.         return lResult;
  1222.  
  1223.      while (lResult == ERROR_SUCCESS) {
  1224.         char        szName[256];
  1225.         DWORD        cbName = sizeof(szName);
  1226.         FILETIME    ftLastWriteTime;
  1227.  
  1228.         // Recursively delete each of the subkeys
  1229.         lResult = RegEnumKeyEx(hKey, 0, szName, &cbName, NULL, NULL, NULL, &ftLastWriteTime);
  1230.  
  1231.         if (lResult == ERROR_SUCCESS)
  1232.             lResult = RegDeleteKeyNT(hKey, szName);
  1233.      }
  1234.  
  1235.      RegCloseKey(hKey);
  1236.      return RegDeleteKey(hStartKey, lpszKeyName);
  1237. #endif
  1238.  
  1239. // Returns the count of the number of NET_cdataStruct structures that have
  1240. // lpszFileClass as their file type class
  1241. static int
  1242. OccurencesOfFileClass(LPCSTR lpszFileClass)
  1243. {
  1244.     XP_List         *pTypesList = cinfo_MasterListPointer();
  1245.     NET_cdataStruct *pcdata = NULL;
  1246.     int                 nResult = 0;
  1247.  
  1248.     while ((pcdata = (NET_cdataStruct *)XP_ListNextObject(pTypesList)))    {
  1249.         if (pcdata->ci.fe_data) {
  1250.             CHelperApp *pHelperApp = (CHelperApp *)pcdata->ci.fe_data;
  1251.  
  1252.             if (pHelperApp->strFileClass == lpszFileClass)
  1253.                 nResult++;
  1254.         }
  1255.     }
  1256.  
  1257.     return nResult;
  1258. }
  1259.  
  1260. // Removes a file type
  1261. BOOL
  1262. fe_RemoveFileType(NET_cdataStruct *pcdata)
  1263. {
  1264.     CHelperApp    *pHelperApp = (CHelperApp *)pcdata->ci.fe_data;
  1265.     
  1266.     if (pHelperApp && (pHelperApp->how_handle == HANDLE_SHELLEXECUTE || pHelperApp->how_handle == HANDLE_BY_OLE)) {
  1267.         // Remove the registry keys
  1268.         for (int i = 0; i < pcdata->num_exts; i++) {
  1269.             CString    strClass;
  1270.     
  1271.             // Get the file type class
  1272.             if (GetClassName(pcdata->exts[i], strClass)) {
  1273.                 // Remove the subkey for the file type class. Don't delete the file type class
  1274.                 // unless this is the only netlib entry that has this file type class. The
  1275.                 // reason for this is that we arrange items by MIME type and not by file type class
  1276.                 // like Windows does. The user is asking to remove a particular MIME type and
  1277.                 // it's associated extensions; only remove the file type class if this is the only
  1278.                 // item with that file type class
  1279.                 ASSERT(pHelperApp->strFileClass == strClass);
  1280.                 if (OccurencesOfFileClass((LPCSTR)strClass) <= 1) {
  1281.     #ifdef _WIN32
  1282.                     RegDeleteKeyNT(HKEY_CLASSES_ROOT, (LPCSTR)strClass);
  1283.     #else
  1284.                     RegDeleteKey(HKEY_CLASSES_ROOT, (LPCSTR)strClass);
  1285.     #endif
  1286.                 }
  1287.             }
  1288.     
  1289.             // Remove the key for the file type extension
  1290.             char    szBuf[_MAX_PATH];
  1291.     
  1292.             PR_snprintf(szBuf, sizeof(szBuf), ".%s", pcdata->exts[i]);
  1293.     #ifdef _WIN32
  1294.             RegDeleteKeyNT(HKEY_CLASSES_ROOT, szBuf);
  1295.     #else
  1296.             RegDeleteKey(HKEY_CLASSES_ROOT, szBuf);
  1297.     #endif
  1298.     
  1299.     #ifdef _WIN32
  1300.             // Clean up the MIME database. Only remove this key if the default
  1301.             // extension matches this extension
  1302.             if (pcdata->ci.type) {
  1303.                 HKEY    hKey;
  1304.                 LONG    lResult;
  1305.     
  1306.                 PR_snprintf(szBuf, sizeof(szBuf), "MIME\\Database\\Content Type\\%s",
  1307.                     pcdata->ci.type);
  1308.     
  1309.                 if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szBuf, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
  1310.                     BOOL    bDeleteKey = FALSE;
  1311.                     DWORD    cbData;
  1312.                     char    szDefaultExt[_MAX_EXT];
  1313.     
  1314.                     // Get the extension associated with this MIME type
  1315.                     cbData = sizeof(szDefaultExt);
  1316.                     lResult = RegQueryValueEx(hKey, "Extension", NULL, NULL, (LPBYTE)szDefaultExt, &cbData);
  1317.                     if (lResult == ERROR_SUCCESS && cbData > 2) {
  1318.                         // Only delete the key if the extension matches one of the extensions in our list
  1319.                         bDeleteKey = ExtensionIsInList(pcdata, &szDefaultExt[1]);
  1320.                     }
  1321.     
  1322.                     RegCloseKey(hKey);
  1323.     
  1324.                     if (bDeleteKey)
  1325.                         RegDeleteKeyNT(HKEY_CLASSES_ROOT, szBuf);
  1326.                 }
  1327.             }
  1328.     #endif
  1329.         }
  1330.     }
  1331.  
  1332.     // Cleanup up any Netscape specific associations
  1333.     if (pcdata->ci.type) {
  1334.         theApp.WriteProfileString("Suffixes", pcdata->ci.type, NULL);
  1335.         theApp.WriteProfileString("Viewers", pcdata->ci.type, NULL);
  1336.     }
  1337.     
  1338.     // Clean up the FE data structures
  1339.     if (pHelperApp) {
  1340.         // Remove the helper app from the global list
  1341.         if (pcdata->ci.type)
  1342.             theApp.m_HelperListByType.RemoveKey(pcdata->ci.type);
  1343.  
  1344.         delete pHelperApp;
  1345.         pcdata->ci.fe_data = NULL;
  1346.     }
  1347.  
  1348.     // Remove the item from the cdata list. This frees it as well
  1349.     NET_cdataRemove(pcdata);
  1350.     return TRUE;
  1351. }
  1352.  
  1353. static void
  1354. ChangeMIMEType(NET_cdataStruct *pcdata, LPCSTR lpszMimeType, int nHowToHandle)
  1355. {
  1356.     // We need to check both the Netscape specific information, and we also
  1357.     // need to check the registry. First check the Netscape specific information
  1358.     CString strValue;
  1359.     
  1360.     // First thing to handle is the Viewers section.  See if there's an application
  1361.     // associated with this MIME type
  1362.     strValue = theApp.GetProfileString("Viewers", pcdata->ci.type, NULL);
  1363.     if (!strValue.IsEmpty()) {
  1364.         // Rename the key by removing the old key and creating a new key with the same value
  1365.         theApp.WriteProfileString("Viewers", pcdata->ci.type, NULL);
  1366.         theApp.WriteProfileString("Viewers", lpszMimeType, (LPCSTR)strValue);
  1367.     }
  1368.  
  1369.     // Check if there is a "TYPE%d" value associated with this MIME type
  1370.     for (int i = 0; i < theApp.m_iNumTypesInINIFile; i++) {
  1371.         char szBuf[20];
  1372.  
  1373.         sprintf(szBuf, "TYPE%d" ,i);
  1374.         strValue = theApp.GetProfileString("Viewers", szBuf, NULL);
  1375.         if (strValue.CompareNoCase(pcdata->ci.type) == 0) {
  1376.             // Rename the key by removing the old key and creating a new key with the same value
  1377.             theApp.WriteProfileString("Viewers", szBuf, NULL);
  1378.             theApp.WriteProfileString("Viewers", szBuf, lpszMimeType);
  1379.             break;
  1380.         }
  1381.     }
  1382.     
  1383.     // See if there are file extensions specified for the type
  1384.     strValue = theApp.GetProfileString("Suffixes", pcdata->ci.type, NULL);
  1385.     if (!strValue.IsEmpty()) {
  1386.         // Rename the key by removing the old key and creating a new key with the same value
  1387.         theApp.WriteProfileString("Suffixes", pcdata->ci.type, NULL);
  1388.         theApp.WriteProfileString("Suffixes", lpszMimeType, (LPCSTR)strValue);
  1389.     }
  1390.  
  1391. #ifdef _WIN32
  1392.     char    szKey[_MAX_PATH];
  1393.     HKEY    hKey;
  1394.     LONG    lResult;
  1395.  
  1396.     // Check the registry. We need to check the MIME database, and the Content Type associated
  1397.     // with each of the file extensions
  1398.     PR_snprintf(szKey, sizeof(szKey), "MIME\\Database\\Content Type\\%s", pcdata->ci.type);
  1399.  
  1400.     // Get the extension that's associated with this MIME type
  1401.     if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
  1402.         BOOL    bDeleteKey = FALSE;
  1403.         DWORD    cbData;
  1404.         char    szDefaultExt[_MAX_EXT];
  1405.  
  1406.         // Get the key value
  1407.         cbData = sizeof(szDefaultExt);
  1408.         lResult = RegQueryValueEx(hKey, "Extension", NULL, NULL, (LPBYTE)szDefaultExt, &cbData);
  1409.         RegCloseKey(hKey);
  1410.         
  1411.         if (lResult == ERROR_SUCCESS && cbData > 1) {
  1412.             // Only rename the key if the extension matches one of the extensions in our list
  1413.             if (ExtensionIsInList(pcdata, &szDefaultExt[1])) {
  1414.                 // Rename the key by deleting it and creating a new key
  1415.                 RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  1416.                 AddToMIMEDatabase(lpszMimeType, szDefaultExt);
  1417.             }
  1418.         }
  1419.     
  1420.     } else {
  1421.         char    szDefaultExt[_MAX_EXT];
  1422.         
  1423.         // There's no existing MIME type entry so go ahead and create a new key. Use
  1424.         // the first extension in the list
  1425.         wsprintf(szDefaultExt, ".%s", pcdata->exts[0]);
  1426.         AddToMIMEDatabase(lpszMimeType, szDefaultExt);
  1427.     }
  1428.     
  1429.     // Rename the Content Type values associated with the extensions
  1430.     for (i = 0; i < pcdata->num_exts; i++) {
  1431.         char    szKey[_MAX_EXT];
  1432.         HKEY    hKey;
  1433.         LONG    lResult;
  1434.  
  1435.         // Build the file association key. It must begin with a '.'
  1436.         wsprintf(szKey, ".%s", pcdata->exts[i]);
  1437.  
  1438.         // Open the key for the file extension
  1439.         lResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey);
  1440.         if (lResult == ERROR_SUCCESS) {
  1441.             char    szContentType[256];
  1442.             DWORD    cbData;
  1443.             DWORD    dwType;
  1444.  
  1445.             // Only change the MIME type for the extension if the MIME type that's currently
  1446.             // there matches
  1447.             cbData = sizeof(szContentType);
  1448.             lResult = RegQueryValueEx(hKey, "Content Type", NULL, &dwType, (LPBYTE)szContentType, &cbData);
  1449.             if (lResult == ERROR_SUCCESS && cbData > 1) {
  1450.                 if (lstrcmpi(szContentType, pcdata->ci.type) == 0) {
  1451.                     // Change the MIME type
  1452.                     RegSetValueEx(hKey, "Content Type", 0, REG_SZ, (CONST BYTE *)lpszMimeType, lstrlen(lpszMimeType) + 1);
  1453.                 }
  1454.  
  1455.             } else {
  1456.                 // There is no existing MIME type, so go ahead and add one
  1457.                 RegSetValueEx(hKey, "Content Type", 0, REG_SZ, (CONST BYTE *)lpszMimeType, lstrlen(lpszMimeType) + 1);
  1458.             }
  1459.  
  1460.             RegCloseKey(hKey);
  1461.         }
  1462.     }
  1463. #endif
  1464.  
  1465.     // Update the FE list ordered by MIME type
  1466.     theApp.m_HelperListByType.RemoveKey(pcdata->ci.type);
  1467.     theApp.m_HelperListByType.SetAt(lpszMimeType, (CHelperApp *)pcdata->ci.fe_data);
  1468.     
  1469.     // Now go ahead and change the MIME type in the netlib data structure
  1470.     StrAllocCopy(pcdata->ci.type, lpszMimeType);
  1471. }
  1472.  
  1473. BOOL
  1474. fe_ChangeFileType(NET_cdataStruct *pcdata, LPCSTR lpszMimeType, int nHowToHandle, LPCSTR lpszOpenCmd)
  1475. {
  1476.     CHelperApp *pHelperApp = (CHelperApp *)pcdata->ci.fe_data;
  1477.     CString     strFileClass;
  1478.  
  1479.     // See if the MIME type changed
  1480.     if (strcmpi(pcdata->ci.type, lpszMimeType) != 0) {
  1481.         ChangeMIMEType(pcdata, lpszMimeType, nHowToHandle);
  1482.     }
  1483.  
  1484.     // See if how we handle it changed
  1485.     if (pHelperApp->how_handle != nHowToHandle) {
  1486.         pHelperApp->how_handle = nHowToHandle;
  1487.  
  1488.         if (pcdata->ci.type) {
  1489.             // Almost everything is stored in the registry now except for
  1490.             // the special types that Netscape can handle internally
  1491.             if (strcmp(pcdata->ci.type, IMAGE_GIF) == 0) {
  1492.                 if (pHelperApp->how_handle == HANDLE_VIA_NETSCAPE)
  1493.                     NET_RegisterContentTypeConverter(IMAGE_GIF, FO_PRESENT, NULL, IL_ViewStream);
  1494.                 else {
  1495.                     if (pHelperApp->how_handle == HANDLE_SHELLEXECUTE)
  1496.                         pHelperApp->how_handle = HANDLE_EXTERNAL;  // save in Netscape specific information
  1497.                     NET_RegisterContentTypeConverter(IMAGE_GIF, FO_PRESENT, NULL , external_viewer_disk_stream);
  1498.                 }
  1499.             }
  1500.  
  1501.             if (strcmp(pcdata->ci.type, IMAGE_JPG) == 0) {
  1502.                 if (pHelperApp->how_handle == HANDLE_VIA_NETSCAPE)
  1503.                     NET_RegisterContentTypeConverter(IMAGE_JPG, FO_PRESENT, NULL, IL_ViewStream);
  1504.                 else {
  1505.                     if (pHelperApp->how_handle == HANDLE_SHELLEXECUTE)
  1506.                         pHelperApp->how_handle = HANDLE_EXTERNAL;  // save in Netscape specific information
  1507.                     NET_RegisterContentTypeConverter(IMAGE_JPG, FO_PRESENT, NULL , external_viewer_disk_stream);
  1508.                 }
  1509.             }
  1510.         
  1511.             if (strcmp(pcdata->ci.type, IMAGE_XBM) == 0) {
  1512.                 if (pHelperApp->how_handle == HANDLE_VIA_NETSCAPE)
  1513.                     NET_RegisterContentTypeConverter(IMAGE_XBM, FO_PRESENT, NULL, IL_ViewStream);
  1514.                 else {
  1515.                     if (pHelperApp->how_handle == HANDLE_SHELLEXECUTE)
  1516.                         pHelperApp->how_handle = HANDLE_EXTERNAL;  // save in Netscape specific information
  1517.                     NET_RegisterContentTypeConverter(IMAGE_XBM, FO_PRESENT, NULL , external_viewer_disk_stream);
  1518.                 }
  1519.             }
  1520.         }
  1521.  
  1522.         // Make sure we don't leave old Netscape specific information lying around. Note that
  1523.         // for types that Netscape can handle internally it's assumed we're handling it unless
  1524.         // it's marked as HANDLE_EXTERNAL in the Netscape specific information
  1525.         if (pHelperApp->how_handle == HANDLE_EXTERNAL || pHelperApp->how_handle == HANDLE_SAVE) {
  1526.             // This gets saved in fe_CleanupFileFormatTypes()
  1527.             if (pHelperApp->how_handle == HANDLE_SAVE)
  1528.                 pHelperApp->csCmd = MIME_SAVE;
  1529.             pHelperApp->bChanged = TRUE;
  1530.         
  1531.         } else {
  1532.             // Remove any existing entry for this MIME type. If the MIME type isn't listed in the
  1533.             // Viewers section, then we use the default behavior which is HANDLE_SHELLEXECUTE
  1534.             theApp.WriteProfileString("Viewers", pcdata->ci.type, NULL);
  1535.         }
  1536.     }
  1537.  
  1538.     // See if the Open command has changed
  1539.     switch (pHelperApp->how_handle) {
  1540.         case HANDLE_EXTERNAL:
  1541.             if (pHelperApp->csCmd.Compare(lpszOpenCmd) != 0) {
  1542.                 pHelperApp->csCmd = lpszOpenCmd;
  1543.  
  1544.                 // Update the Netscape specific association
  1545.                 if (pcdata->ci.type)
  1546.                     theApp.WriteProfileString("Viewers", pcdata->ci.type, lpszOpenCmd);
  1547.             }
  1548.             break;
  1549.  
  1550.         case HANDLE_SHELLEXECUTE:
  1551.             if (GetClassName(pcdata->exts[0], strFileClass) && !strFileClass.IsEmpty())
  1552.                 SetShellOpenCommand(strFileClass, lpszOpenCmd);
  1553.             break;
  1554.  
  1555.         case HANDLE_BY_OLE:
  1556.             fe_SetHandleByOLE(pcdata->ci.type, pHelperApp, TRUE);
  1557.             break;
  1558.         default:
  1559.             break;
  1560.     }
  1561.     return TRUE;
  1562. }
  1563.  
  1564. // exts - Array of Pointers of extension.
  1565. // numofExt - number of extension in this array.
  1566. // return - TRUE if these extension can be handle by OLE, otherwise FALSE.
  1567. BOOL fe_CanHandleByOLE(char** exts, short numOfExt)
  1568. {
  1569.     char aExtension[MAX_PATH + 1];
  1570.     BOOL canHandleByOLE = FALSE;
  1571.     HKEY    hkSubCLSID ;
  1572.     HKEY    hTempKey;
  1573.     LONG    cb;
  1574.     TCHAR    szName[MAX_PATH + 1];
  1575.     TCHAR     szBuf[MAX_PATH + 1];
  1576.     TCHAR     szTempCLSID[MAX_PATH + 1];
  1577.  
  1578.     cb = sizeof(szName);
  1579.     
  1580.     for (int i = 0; i < numOfExt; i++) {
  1581.         strcpy(aExtension, exts[i]);  // reset for next extension.
  1582.         if ((RegQueryValue( HKEY_CLASSES_ROOT, (LPTSTR)aExtension, szName, &cb) == ERROR_SUCCESS) &&
  1583.             (RegOpenKey( HKEY_CLASSES_ROOT, szName, &hkSubCLSID ) == ERROR_SUCCESS)) {
  1584.             cb = sizeof(szName);
  1585.             // get the clsid key for this extension.
  1586.             if (RegQueryValue(hkSubCLSID, "CLSID", szTempCLSID, &cb) == ERROR_SUCCESS) {
  1587.                 wsprintf( szBuf, _T("CLSID\\%s\\Insertable"), (LPTSTR)szTempCLSID) ;
  1588.                 if (RegOpenKey( HKEY_CLASSES_ROOT, szBuf, &hTempKey ) == ERROR_SUCCESS)    {
  1589.                     canHandleByOLE = TRUE;
  1590.                     RegCloseKey( hTempKey ) ;
  1591.                 }
  1592.             }
  1593.             RegCloseKey( hkSubCLSID ) ;
  1594.         }
  1595.     }
  1596.     return canHandleByOLE;
  1597. }
  1598.  
  1599.  
  1600. BOOL fe_SetHandleByOLE(char* mimeType, CHelperApp* app, BOOL handleByOLE)
  1601. {
  1602.     if (handleByOLE) {
  1603.         app->how_handle = HANDLE_BY_OLE;
  1604.         app->csCmd = MIME_OLE;
  1605.         return theApp.WriteProfileString("Viewers", mimeType, MIME_OLE);
  1606.     }
  1607.     else {
  1608.         app->how_handle = HANDLE_SHELLEXECUTE;
  1609.         app->csCmd = MIME_SHELLEXECUTE;
  1610.         return theApp.WriteProfileString("Viewers", mimeType, NULL);
  1611.     }
  1612. }
  1613.  
  1614. BOOL fe_IsHandleByOLE(char* mimeType)
  1615. {
  1616.     CString csCmd = theApp.GetProfileString("Viewers", mimeType);  
  1617.     if (csCmd.Compare( MIME_OLE))
  1618.         return FALSE;
  1619.     else return TRUE;
  1620. }
  1621.  
  1622. #ifdef XP_WIN32
  1623. //This function is taken from the PE file Profile.cpp
  1624.  
  1625. BOOL  CopyRegKeys(HKEY  hKeyOldName,
  1626.                    HKEY  hKeyNewName,
  1627.                    DWORD subkeys,
  1628.                    DWORD maxSubKeyLen,
  1629.                    DWORD maxClassLen,
  1630.                    DWORD values,
  1631.                    DWORD maxValueNameLen,
  1632.                    DWORD maxValueLen,
  1633.                    const char *OldPath,
  1634.                    const char *NewPath)
  1635. {
  1636.  
  1637.     BOOL Err = FALSE;
  1638.     DWORD index;
  1639.  
  1640.  
  1641.     // first loop through and copies all the value keys
  1642.  
  1643.     if (values > 0) {
  1644.  
  1645.         DWORD valueNameSize = maxValueNameLen + 1;
  1646.         char *valueName = (char *)malloc(sizeof(char) * valueNameSize);
  1647.         DWORD dataSize = maxValueLen + 1;
  1648.         unsigned char *data = (unsigned char *)malloc(sizeof(char) * dataSize);
  1649.         DWORD type;
  1650.  
  1651.         if ((valueName) && (data)) {
  1652.  
  1653.             for (index=0; index<values; index++) {
  1654.  
  1655.                 // gets each value name and its data
  1656.                 if (ERROR_SUCCESS == RegEnumValue(hKeyOldName, index, valueName, &valueNameSize, NULL, &type, data, &dataSize)) {
  1657.                 
  1658.                     // create value in our new profile key
  1659.                     if (ERROR_SUCCESS != RegSetValueEx(hKeyNewName, valueName, 0, type, data, dataSize)) {
  1660.                         // unknown err occured... what do we do?
  1661.                         Err = TRUE;
  1662.                         return FALSE;
  1663.                     }
  1664.                 }
  1665.  
  1666.                 valueNameSize = maxValueNameLen + 1;
  1667.                 dataSize = maxValueLen + 1;
  1668.             }
  1669.  
  1670.             free(valueName);
  1671.             free(data);
  1672.         }
  1673.     }
  1674.  
  1675.  
  1676.     // next, we need to creates subkey folders
  1677.  
  1678.     if (subkeys > 0) {
  1679.  
  1680.         char OldSubkeyPath[260];
  1681.         char NewSubkeyPath[260];
  1682.         HKEY hkeyOldSubkey;
  1683.         HKEY hkeyNewSubkey;
  1684.  
  1685.  
  1686.         for (index=0; index<subkeys; index++) {
  1687.  
  1688.             DWORD subkeyNameSize = maxSubKeyLen + 1;
  1689.             char *subkeyName = (char *)malloc(sizeof(char) * subkeyNameSize);
  1690.  
  1691.             if (subkeyName) {
  1692.  
  1693.                 // gets each subkey name
  1694.                 if (ERROR_SUCCESS == RegEnumKey(hKeyOldName, index, subkeyName, subkeyNameSize)) {
  1695.                 
  1696.                     // create subkey in our new profile keypath
  1697.                     if (ERROR_SUCCESS != RegCreateKey(hKeyNewName, subkeyName, &hkeyNewSubkey))  {
  1698.                         Err = TRUE;
  1699.                         return FALSE;
  1700.                     }
  1701.  
  1702.                     // now the subkey is created, we need to get hkey value for oldpath and 
  1703.                     // then copy everything in the keys again
  1704.  
  1705.                     // construct key path
  1706.                     strcpy((char *)OldSubkeyPath, OldPath);
  1707.                     strcat((char *)OldSubkeyPath, "\\");
  1708.                     strcat((char *)OldSubkeyPath, subkeyName);
  1709.  
  1710.                     strcpy((char *)NewSubkeyPath, NewPath);
  1711.                     strcat((char *)NewSubkeyPath, "\\");
  1712.                     strcat((char *)NewSubkeyPath, subkeyName);
  1713.  
  1714.                     free(subkeyName);
  1715.  
  1716.  
  1717.                     // now... try to start the copying process for our subkey here
  1718.                     // first, gets the hkey for the old subkey profile path
  1719.                     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, (char *)OldSubkeyPath, NULL, KEY_ALL_ACCESS, &hkeyOldSubkey)) {
  1720.             
  1721.                         DWORD SubKeys;
  1722.                         DWORD MaxSubKeyLen;
  1723.                         DWORD MaxClassLen;
  1724.                         DWORD Values;
  1725.                         DWORD MaxValueNameLen;
  1726.                         DWORD MaxValueLen;
  1727.                         DWORD SecurityDescriptor;
  1728.                         FILETIME LastWriteTime;
  1729.  
  1730.                         // get some information about this old profile subkey 
  1731.                         if (ERROR_SUCCESS == RegQueryInfoKey(hkeyOldSubkey, NULL, NULL, NULL, &SubKeys, &MaxSubKeyLen, &MaxClassLen, &Values, &MaxValueNameLen, &MaxValueLen, &SecurityDescriptor, &LastWriteTime)) {
  1732.  
  1733.                             // copy the values & key stuff
  1734.  
  1735.                             Err = CopyRegKeys(hkeyOldSubkey, hkeyNewSubkey, SubKeys, MaxSubKeyLen, MaxClassLen, Values, MaxValueNameLen, MaxValueLen, (char *)OldSubkeyPath, (char *)NewSubkeyPath);
  1736.  
  1737.                             if (!Err)
  1738.                                 return FALSE;
  1739.  
  1740.                         }
  1741.  
  1742.                         RegCloseKey(hkeyOldSubkey);
  1743.                     }
  1744.                 }
  1745.             }
  1746.         }
  1747.     }
  1748.  
  1749.     return TRUE;
  1750. }
  1751.  
  1752. #endif
  1753.