home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / fenet.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  35.9 KB  |  1,200 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 "npapi.h"
  22. #include "np.h"
  23. #include "npassoc.h"
  24. #include "edview.h"
  25. #include "prefapi.h"
  26. #include "hiddenfr.h"
  27. #include "extgen.h"
  28.  
  29. #define ASYNC_DNS 
  30. #ifndef _AFXDLL
  31. #define new DEBUG_NEW  // MSVC Debugging new...goes to regular new in release mode
  32. #endif
  33.  
  34.  
  35. CMapStringToOb DNSCacheMap(sizeof(CDNSObj));
  36. extern char *FE_FindFileExt(char * path);
  37.  
  38. /* Remove all objects from the dns cache map */
  39. PUBLIC void FE_DeleteDNSList(MWContext * currentContext)
  40. {
  41.     POSITION pos;
  42.     CString key;
  43.     CDNSObj *obj = NULL;
  44.  
  45.     /* Get the starting position. Actually, whether the position returned is actually the start
  46.        is irrelevant. */
  47.     pos = DNSCacheMap.GetStartPosition();
  48.     while (pos)
  49.     {
  50.         /* GetNextAssoc sets pos to another position in the map. Again, we don't care where
  51.            we just want to know that another position exists so we can continue removing objs. */
  52.         DNSCacheMap.GetNextAssoc(pos, key, (CObject *&)obj);
  53.         
  54.         /* Only delete from the list if the current context owns the particular lookup. */
  55.         if(obj->context == currentContext)
  56.         {
  57.             /* Only delete the dns object if there are no
  58.             more sockets in the sock list */
  59.             if (XP_ListCount(obj->m_sock_list) == 0) {
  60.                 DNSCacheMap.RemoveKey(key);
  61.                 delete obj;
  62.             }
  63.         }
  64.     }
  65. }
  66.  
  67. int FE_AsyncDNSLookup(MWContext *context, char * host_port, PRHostEnt ** hoststruct_ptr_ptr, PRFileDesc *socket)
  68. {
  69.     //  Initialize our DNS objects.
  70.     CDNSObj * dns_obj=NULL;
  71.     *hoststruct_ptr_ptr = NULL;
  72.  
  73.     //  Look up and see if the host is in our cached DNS lookups and if so....
  74.     if (DNSCacheMap.Lookup(host_port,(CObject *&)dns_obj)) {
  75.         //  See if the cached value was an error, and if so, return an error.
  76.         //  Should we retry the lookup if it was?
  77.         if (dns_obj->m_iError != 0 && dns_obj->i_finished != 0) {  // DNS error
  78.             WSASetLastError(dns_obj->m_iError);
  79.             DNSCacheMap.RemoveKey(host_port);
  80.             // Only delete the dns object if there are no
  81.             // more sockets in the sock list
  82.             if (dns_obj && XP_ListCount(dns_obj->m_sock_list) == 0) 
  83.                 delete dns_obj;
  84.  
  85.             return -1;
  86.         }
  87.         //  If this isn't NULL, then we have a good match.  Return it as such and clear the context.
  88.         else if (dns_obj->m_hostent->h_name != NULL && dns_obj->i_finished != 0) {
  89.             *hoststruct_ptr_ptr = (PRHostEnt *)dns_obj->m_hostent;
  90.             return 0;
  91.         }
  92.         //  There isn't an error, and there isn't a host name, return that we are waiting for the
  93.         //      lookup....  This doesn't make clear sense, unless you take into account that the
  94.         //      hostent structure is empty when another window is also looking this same host up,
  95.         //      so we return that we are waiting too.
  96.         else {
  97.             /* see if the socket we are looking up is already in
  98.              * the socket list.  If it isn't, add it.
  99.              * The socket list provides us with a way to
  100.              * send events to NET_ProcessNet for each socket
  101.              * waiting for a lookup
  102.              */
  103.             XP_List * list_ptr = dns_obj->m_sock_list;
  104.             PRFileDesc *tmp_sock;
  105.  
  106.             if(list_ptr)
  107.                 list_ptr = list_ptr->next;
  108.  
  109.             while(list_ptr) {
  110.                 tmp_sock = (PRFileDesc *) list_ptr->object;
  111.  
  112.                 if(tmp_sock == socket)
  113.                     return MK_WAITING_FOR_LOOKUP;
  114.  
  115.                 list_ptr = list_ptr->next;
  116.             }
  117.  
  118.             /* socket not in the list, add it */
  119.             XP_ListAddObject(dns_obj->m_sock_list, (void *) socket);
  120.             return MK_WAITING_FOR_LOOKUP;
  121.         }   
  122.     } else {
  123.         //  There is no cache entry, begin the async dns lookup.
  124.         //  Capture the current window handle, we pass this to the async code, for passing
  125.         //      back a message when the lookup is complete.
  126.         //  Actually, just pass the application's main window to avoid
  127.         //      needing a frame window to do DNS lookups.
  128.         HWND hWndFrame = AfxGetApp()->m_pMainWnd->m_hWnd;
  129.     
  130.         //  Create and initialize our dns object.  Allocating hostent struct, host name and port string,
  131.         //      and error code from the lookup.
  132.         dns_obj = new CDNSObj();
  133.         dns_obj->m_hostent = (struct hostent *)XP_ALLOC(MAXGETHOSTSTRUCT * sizeof(char));
  134.         if(dns_obj->m_hostent) {
  135.             memset(dns_obj->m_hostent, 0, MAXGETHOSTSTRUCT * sizeof(char));
  136.         }
  137.         dns_obj->m_host = XP_STRDUP(host_port);
  138.         dns_obj->m_sock_list = XP_ListNew();
  139.         dns_obj->context = context;
  140.         XP_ListAddObject(dns_obj->m_sock_list, (void *) socket);
  141.  
  142.         //  Insert the entry into the cached DNS lookups.
  143.         //  Also, set the context, and actually begin the DNS lookup.
  144.         //  Return that we're waiting for it to complete.
  145.  
  146.         if( !(dns_obj->m_handle = WSAAsyncGetHostByName(hWndFrame,
  147.                     msg_FoundDNS,
  148.                     dns_obj->m_host,
  149.                     (char *)dns_obj->m_hostent,
  150.                     MAXGETHOSTSTRUCT) ) ) {
  151.             delete dns_obj;
  152.             return -1;
  153.         }
  154.  
  155.         DNSCacheMap.SetAt(host_port,dns_obj);
  156.  
  157.         return MK_WAITING_FOR_LOOKUP;
  158.     }
  159. }
  160.  
  161. CDNSObj::CDNSObj()
  162. {
  163.     //  make sure we're clean.
  164.     m_hostent = NULL;
  165.     m_host = NULL;
  166.     m_handle = NULL;
  167.     context = NULL;
  168.     m_iError = 0;
  169.     i_finished = 0;
  170.     m_sock_list = 0;
  171. }
  172.  
  173. CDNSObj::~CDNSObj()
  174. {
  175.     if(m_hostent)   {
  176.         XP_FREE(m_hostent);
  177.         m_hostent = NULL;
  178.     }
  179.     if(m_host)  {
  180.         XP_FREE(m_host);
  181.         m_host = NULL;
  182.     }
  183.  
  184.     if (m_sock_list) {
  185.         while (XP_ListRemoveTopObject(m_sock_list))
  186.             ;
  187.         XP_ListDestroy(m_sock_list);
  188.     }
  189. }
  190.  
  191.  
  192. #ifdef DEBUG
  193. char * 
  194. NOT_NULL (const char *x) 
  195. {
  196.     if(!x) {
  197.         TRACE("Panic! -- An assert of NOT_NULL is about to fail\n");    
  198.     }
  199.     ASSERT(x);
  200.     return (char *)x;
  201. }
  202. #endif
  203.  
  204. // converts a URL to a local (8+3) filename
  205. // the return must be freed by caller
  206.  
  207. char * fe_URLtoLocalName(const char * url, const char *pMimeType) 
  208. {
  209.     CString *csURL, csExt,csName;
  210.  
  211.     //  Determine the extension.
  212.     char aExt[_MAX_EXT];
  213.     size_t stExt = 0;
  214.     DWORD dwFlags = 0;
  215.     
  216. #ifdef XP_WIN16
  217.     dwFlags = EXT_DOT_THREE;
  218. #endif
  219.     aExt[0] = '\0';
  220.     stExt = EXT_Invent(aExt, sizeof(aExt), dwFlags, url, pMimeType);
  221.     csExt = aExt;
  222.     
  223.     int idx;
  224.     csURL = new CString(url);
  225.     int iQuestionMark = csURL->Find('?');
  226.     int iPound = csURL->Find('#');
  227.     int iEnd;
  228.  
  229.     if ((iQuestionMark > 0) && (iPound > 0))    // wow both!
  230.         *csURL = csURL->Left(min(iQuestionMark,iPound));
  231.     else if ((iQuestionMark > 0) || (iPound > 0)) {  // 1 or the other
  232.         if (iQuestionMark > 0)
  233.             iEnd = iQuestionMark;
  234.         else if (iPound > 0)
  235.             iEnd = iPound;
  236.         *csURL = csURL->Left(iEnd);         
  237.     }
  238.  
  239.     int iDot = csURL->ReverseFind('.');
  240.     int iSlash = csURL->ReverseFind('/');
  241.  
  242.     if (iSlash > 0) {
  243.         if (iDot < iSlash) {
  244.             if( iSlash == csURL->GetLength() -1 ){
  245.                 // CLM: If here, there was no filename after last slash
  246.                 //      so lets try to make a name from end of URL path
  247.                 *csURL = csURL->Left(iSlash);
  248.                 iSlash = csURL->ReverseFind('/');
  249.             }
  250.             if (iSlash > 0) {
  251.                 csName = csURL->Right(csURL->GetLength() - iSlash -1);
  252.             }
  253.             iDot = 0;
  254.         }
  255.         else csName = csURL->Mid(iSlash+1, iDot-iSlash-1);
  256.     }
  257.     
  258.     //  Should we really return NULL?
  259.     //  There will be cases that don't fit, and does this mean that they won't be able to save a file
  260.     //      locally since a name can't be formulated?
  261.     if (csName.IsEmpty())   {
  262.         delete(csURL);
  263.         return NULL;
  264.     }
  265.  
  266. #ifdef XP_WIN16 
  267.     csName = csName.Left(8);
  268. #endif
  269.     char *name = csName.GetBuffer(0);
  270.  
  271.     // replace extra periods in 8 character name with underscores   
  272.     for (idx =0 ; idx < csName.GetLength(); idx++) {
  273.         if ((name[idx] == '.')||(name[idx] == ':')) name[idx] = '_';
  274.     }
  275.     csName.ReleaseBuffer(-1);
  276.     
  277.     *csURL = csName + csExt;
  278.     
  279.     char *cp_retval = strdup((const char *)*csURL);
  280.     delete csURL;
  281.     return(cp_retval);
  282. }
  283.  
  284. char* FE_URLToLocalName( char *pStr ){
  285.     return fe_URLtoLocalName( (const char*)pStr, NULL);
  286. }
  287.  
  288. #ifdef XP_WIN16
  289.  
  290. PUBLIC void * WIN16_malloc(unsigned long size)
  291. {
  292.  
  293.     if((size <= 0) || (size > 64000)) {
  294.         TRACE("WIN16_malloc() FUN FUN FUN %ld\n", size); 
  295.         return(NULL);
  296.     }           
  297.     
  298.     void *Ret = malloc((size_t) size);
  299.     
  300.     if (!Ret) 
  301.         TRACE("WIN16_malloc() failed to alloc %ld bytes\n", size);  
  302.     
  303.     return(Ret);
  304.  
  305. }
  306.  
  307. PUBLIC void * WIN16_realloc(void * ptr, unsigned long size)
  308. {
  309.  
  310.     if((size <= 0) || (size > 64000)) {
  311.         TRACE("WIN16_realloc() FUN FUN FUN %ld\n", size);
  312.         return(NULL);
  313.     }           
  314.  
  315.     void * Ret = realloc(ptr, (size_t) size);
  316.     
  317.     if (!Ret) 
  318.         TRACE("WIN16_realloc() failed to realloc %ld bytes\n", size);   
  319.     
  320.     return(Ret);
  321.  
  322. }
  323.  
  324. PUBLIC void WIN16_bcopy(char * from_ptr, char * to_ptr, unsigned long size)
  325. {
  326.  
  327.     if((!to_ptr) || (size > 64000)) {
  328.         TRACE("WIN16_bcopy() FUN FUN FUN %ld\n", size);
  329.         return;
  330.     }           
  331.         
  332.     memmove(to_ptr, from_ptr, (size_t) size);
  333. }
  334.  
  335.  
  336. #endif /* XP_WIN16 */
  337.  
  338.  
  339. //
  340. // Add a temporary file to the list of files that get deleted on exit
  341. //
  342. void FE_DeleteFileOnExit(const char *pFilename, const char *pURL)
  343. {
  344.     //  Remember the information in the INI file.
  345.     CString csFileName = pFilename;
  346.     csFileName.MakeLower();
  347.     theApp.WriteProfileString("Temporary File URL Resolution", csFileName, pURL);
  348. }
  349.  
  350. //
  351. // We are exiting now.  Clean up any temp files we have generated
  352. //
  353. void FE_DeleteTempFilesNow()
  354. {
  355.     char *pBuffer = new char[8192];
  356.     theApp.GetPrivateProfileString("Temporary File URL Resolution", NULL, "", pBuffer, 8192, AfxGetApp()->m_pszProfileName);
  357.  
  358.     //  We have a double null terminated list of file names here.
  359.     //  Go ahead and go through each one, deleteing them all.
  360.     char *pTraverse = pBuffer;
  361.     int iRemoveResult = 0;
  362.     while(*pTraverse != '\0')   {
  363.         //  Remove this file.
  364.         iRemoveResult = remove(pTraverse);
  365.         ASSERT(!iRemoveResult);
  366.  
  367.         //  Go on to the next entry.
  368.         while(*pTraverse != '\0')   {
  369.             pTraverse++;
  370.         }
  371.         pTraverse++;
  372.     }
  373.  
  374.     delete[] pBuffer;
  375.  
  376.     //  Clear out the section in the INI file also.
  377. #ifdef XP_WIN16
  378.     ::WritePrivateProfileString("Temporary File URL Resolution", NULL, NULL, AfxGetApp()->m_pszProfileName);
  379. #else
  380.     //  To clear them out in the Registry, use RegDeleteKey.
  381.     //  Create the appropriate key.
  382.     HKEY hKey;
  383.     DWORD dwDisposition;
  384.     char aBuffer[256];
  385.     sprintf(aBuffer, "Software\\%s\\%s", "Netscape", "Netscape Navigator");
  386.     long lResult = RegCreateKeyEx(HKEY_CURRENT_USER, aBuffer, NULL, NULL, NULL,
  387.         KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition);
  388.     if(lResult != ERROR_SUCCESS)    {
  389.         return;
  390.     }
  391.  
  392.     RegDeleteKey(hKey, "Temporary File URL Resolution");
  393.     RegCloseKey(hKey);
  394. #endif
  395. }
  396.  
  397. //
  398. // Since netlib is too stubborn to give us a flush cache function do it
  399. //   by hand
  400. //
  401. PUBLIC void
  402. FE_FlushCache()
  403. {
  404.     int32 prefInt;
  405.  
  406.     NET_SetMemoryCacheSize(0);
  407.     PREF_GetIntPref("browser.cache.memory_cache_size",&prefInt);
  408.     NET_SetMemoryCacheSize(prefInt * 1024);
  409. }
  410.  
  411. void CheckLegalFileName(char* full_path)
  412. {
  413.     CString temp = full_path;
  414. #ifdef XP_WIN16
  415.     static char funnychar[13] = "\\/:*?\"<>| ,+";
  416. #else
  417.     static char funnychar[10] = "\\/:*?\"<>|";
  418. #endif
  419.     int index;
  420.     while ((index = temp.FindOneOf(funnychar)) != -1) {
  421.         temp.SetAt(index, '_'); // replace the illegal char with space.
  422.     }
  423.     strcpy(full_path, temp);
  424. }
  425.  
  426. int SetCurrentDir(char * pDir)
  427. {
  428.     if( pDir ){
  429. #ifdef XP_WIN16
  430.     // We need to double "\" characters when setting directory
  431.         char dir[2*_MAX_PATH];
  432.         char * pSource = pDir;
  433.         char * pDest = dir;
  434.         while( *pSource ){
  435.             *pDest++ = *pSource;
  436.             if( *pSource == '\\' ){
  437.                 *pDest++ = '\\';
  438.             }
  439.             pSource++;
  440.         }
  441.         *pDest = '\0';
  442.         // This is SLOW ( > 5 sec) on Win95!
  443.         return _chdir(dir);
  444. #else
  445.         BOOL bRet = SetCurrentDirectory(pDir);
  446.         return bRet ? 0 : -1;
  447. #endif // XP_WIN16
  448.     }
  449.     return -1;
  450. }
  451.  
  452. //
  453. // Get a save file name from the user
  454. // If caller has an idea for the name it should be passed in initial else
  455. //   initial should be NULL
  456. // Return a pointer (to be freed by callee) of full path name else NULL if
  457. //   the selection was canceled
  458. // It is up to the user to free the filename
  459. //
  460. //CLM: Why the ?#$% is type passed in as a pointer???
  461. // If pDocumentTitle is not null, then edit box is added to allow user to enter document title for edited documents
  462.  
  463. MODULE_PRIVATE char * 
  464. wfe_GetSaveFileName(HWND m_hWnd, char * prompt, char * initial, int * type, char** ppPageTitle)
  465. {
  466.  
  467.     OPENFILENAME fname;
  468.     char * full_path;
  469.     char   name[2 * _MAX_FNAME];
  470.     char   filter[256];
  471.     char * extension = NULL;
  472.     char * pOldExt = NULL;
  473.     int    index = 1;
  474.     Bool   bAppendHTML_Ext = FALSE;
  475.     BOOL   bHtmlOnly = FALSE;
  476.     char aIExt[_MAX_EXT];
  477.  
  478.     // We restrict saving type to HTML in the editor
  479.     CString htm_filter_used;
  480.     // Only pre-4.0 version show the file filter bug
  481.     BOOL bBadNT = sysInfo.m_bWinNT && sysInfo.m_dwMajor < 4;
  482.  
  483.     if(type && *type == HTM_ONLY){
  484.         bHtmlOnly = TRUE;
  485.         if (bBadNT)
  486.             htm_filter_used.LoadString(IDS_FILTERNT_HTM);
  487.         else
  488. #ifdef XP_WIN16
  489.             htm_filter_used.LoadString(IDS_FILTER_HTM16);
  490. #else
  491.             htm_filter_used.LoadString(IDS_FILTER_HTM32);
  492. #endif
  493.     } else {
  494.         if (bBadNT)
  495.             // For NT, use same string as 16bit
  496.             htm_filter_used.LoadString(IDS_HTM_FILTER16);
  497.         else
  498. #ifdef XP_WIN16
  499.             htm_filter_used.LoadString(IDS_HTM_FILTER16);
  500. #else
  501.             htm_filter_used.LoadString(IDS_HTM_FILTER32);
  502. #endif
  503.     }
  504.  
  505.     // Default is to use the filter that includes *.htm/*.html, *.txt, and *.*
  506.     strcpy(filter, htm_filter_used);
  507.     
  508.     // try to guess the type
  509.     if(initial) {
  510.  
  511.         if( bHtmlOnly || strcasestr(initial, "htm") || strcasestr(initial, "html")) {
  512. /*__EDITOR__*/
  513. // Use ".html" for 32-bit versions
  514. #ifdef XP_WIN16
  515.             extension = "htm";
  516. #else
  517.             extension = "html";
  518. #endif
  519.             if( bHtmlOnly ){
  520.                 // This will force replacing any existing EXT with value "extension"
  521.                 bAppendHTML_Ext = TRUE;
  522.             }
  523.  
  524. /*__EDITOR__END*/
  525.             index = 1;
  526.         } else if(strcasestr(initial, "gif")) {
  527.             strcpy(filter, szLoadString(IDS_GIF_FILTER));
  528.             extension = "gif";
  529.             index = 1;
  530.         } else if(strcasestr(initial, "xbm")) {
  531.             strcpy(filter, szLoadString(IDS_XBM_FILTER));
  532.             extension = "xbm";
  533.             index = 1;
  534.         } else if(strcasestr(initial, "jpg") || strcasestr(initial, "jpeg")) {
  535. #ifdef XP_WIN16
  536.             strcpy(filter, szLoadString(IDS_JPG_FILTER16));
  537. #else
  538.             strcpy(filter, szLoadString(IDS_JPG_FILTER32));
  539. #endif
  540.             extension = "jpg";
  541.             index = 1;
  542.         } else if(strcasestr(initial, "txt")) {
  543.             strcpy(filter, htm_filter_used); //htm_filter
  544.             extension = "txt";
  545.             index = 2;
  546.         } else if(strcasestr(initial, "p12")) {
  547.             extension = "p12";
  548.             strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
  549.         } else {
  550.             extension = aIExt;
  551.             aIExt[0] = '\0';
  552.             size_t stExt = 0;
  553.             DWORD dwFlags = EXT_NO_PERIOD;
  554.             
  555. #ifdef XP_WIN16
  556.             dwFlags |= EXT_DOT_THREE;
  557. #endif
  558.             stExt = EXT_Invent(aIExt, sizeof(aIExt), dwFlags, initial, NULL);
  559.             if(!stExt) {
  560.                 extension = NULL;
  561.             }
  562.  
  563.             if(extension) {
  564.                 strcpy(filter, szLoadString(IDS_ALL_FILTER));
  565.             } else {
  566.                 // We have a name but no extension
  567.                 // Use the list for HTML files, *.txt, or *.*
  568.                 if ( !type || (*type == 0 || *type == ALL || *type == HTM || *type == HTM_ONLY) ) {
  569.                     // If HTM was requested type or no type requested, then build
  570.                     // a better suggested name
  571.                     bAppendHTML_Ext = TRUE; 
  572.                 }
  573.             }
  574.             // Show *.htm as initial filter
  575.             index = 1;
  576.         }
  577.     }
  578.  
  579.  
  580.     if( (!initial && type && (*type == HTM || *type == HTM_ONLY)) || bAppendHTML_Ext ){
  581.         bAppendHTML_Ext = TRUE;
  582.         // no initial name --- assume HTML if it was requested type
  583.         index = 1;
  584. // Use ".html" for 32-bit versions
  585. #ifdef XP_WIN16
  586.         extension = "htm";
  587. #else
  588.         extension = "html";
  589. #endif
  590.     } else if (!initial && type && (*type == P12)) {
  591.         extension = "p12";
  592.         strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
  593.     } else if(!initial) {
  594.         extension = "*";
  595.         index +=2;
  596.     }
  597.  
  598.     // Replace '\n' with '\0' before pass to FileCommon dialog 
  599.     for (char *p = filter; *p ; p++) {
  600.         if (*p == '\n')  
  601.             *p = '\0';
  602.     }
  603.     
  604.     // space for the full path name    
  605.     full_path = (char *) XP_ALLOC(2 * _MAX_PATH * sizeof(char));
  606.     if(!full_path)
  607.         return(NULL);
  608.  
  609.     // clear stuff out
  610.     name[0]      = '\0';
  611.     full_path[0] = '\0';
  612.     
  613.     char aDrive[_MAX_DRIVE];
  614.     char aPath[_MAX_PATH];
  615.     char aFName[_MAX_FNAME];
  616.     char aExt[_MAX_EXT];
  617.     CString defaultDir;
  618.     BOOL bUsingDefault = FALSE;
  619.     BOOL bUsingEditorDir = FALSE;
  620.     char *fileName = initial;
  621. #ifdef XP_WIN16
  622.     char dosFileName[13];
  623. #endif
  624.  
  625.     if(fileName) {
  626. #ifdef XP_WIN16
  627.         // convert file name to be 8.3
  628.         char *ext = FE_FindFileExt(fileName);
  629.         // Fill with 0 to assure proper termination
  630.         memset(dosFileName, 0, 13*sizeof(char));
  631.         if( ext ){
  632.             char *firstDot = strchr(fileName, '.');
  633.             if ((firstDot - fileName) > 8)
  634.                 // chop it to 8 characters
  635.                 firstDot = fileName+8;
  636.             strncpy(dosFileName, fileName, (firstDot-fileName));
  637.             strncpy(dosFileName+(firstDot-fileName), ext, 
  638.                     min(strlen(ext), 4));
  639.             fileName = dosFileName;
  640.         } else if( strlen(fileName) > 8 ){
  641.             strncpy(dosFileName, fileName, 8);
  642.             fileName = dosFileName;
  643.         }
  644. #endif
  645.         _splitpath(fileName, aDrive, aPath, aFName, aExt);
  646.         XP_STRCPY(full_path, aFName);
  647.         if(bAppendHTML_Ext){ 
  648.             // Here's where we build the better suggested name
  649.             XP_STRCAT(full_path, ".");
  650.             XP_STRCAT(full_path, extension);
  651.         }
  652.         else {
  653.             XP_STRCAT(full_path, aExt);
  654.         }
  655.  
  656.         defaultDir += aDrive;
  657.         defaultDir += aPath;
  658.     }
  659.  
  660.     char   currentDir[_MAX_PATH+1];
  661.     char * HaveCurrentDir = NULL;
  662.  
  663.     char dir[_MAX_PATH];
  664.     if (defaultDir.IsEmpty()) {
  665.         int iLen = _MAX_PATH;
  666.         if(bHtmlOnly){
  667.             PREF_GetCharPref("editor.html_directory",dir,&iLen);
  668.             bUsingEditorDir = TRUE;
  669.             // Save current directory to restore later
  670.             // This is Win16 Compatable (GetCurrentDirectory is available for Win32)
  671.             HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
  672.         } else {
  673.             PREF_GetCharPref("browser.download_directory",dir,&iLen);
  674.             bUsingDefault = TRUE;
  675.         }
  676.         defaultDir = dir;
  677.     }
  678.  
  679.     CheckLegalFileName(full_path);
  680.  
  681.     memset(&fname, 0, sizeof(fname));
  682.     fname.lStructSize = sizeof(OPENFILENAME);
  683.     fname.hwndOwner = m_hWnd;
  684.     fname.lpstrFilter = filter;
  685.     fname.lpstrCustomFilter = NULL;
  686.     fname.nFilterIndex = index;
  687.     fname.lpstrFile = full_path;
  688.     fname.nMaxFile = 2 * _MAX_PATH;
  689.     fname.lpstrFileTitle = name;
  690.     fname.nMaxFileTitle = 2 * _MAX_FNAME;
  691.     fname.lpstrInitialDir = defaultDir;
  692.     fname.lpstrTitle = prompt;
  693.     fname.lpstrDefExt = extension;
  694.     fname.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
  695.  
  696.     BOOL bResult = FEU_GetSaveFileName(&fname);
  697.  
  698.     // see if the user selects a file or hits cancel    
  699.     if(bResult) {
  700.         if (bUsingDefault || bUsingEditorDir ) {
  701.             char *full_dir = (char *) XP_STRDUP(full_path);
  702.             full_dir[fname.nFileOffset] = '\0';
  703.             
  704.             if( bUsingDefault ){
  705.                 PREF_SetCharPref("browser.download_directory", full_dir);
  706.             } else {
  707.                 PREF_SetCharPref("editor.html_directory", full_dir);
  708.                 if( HaveCurrentDir ){
  709.                     SetCurrentDir(currentDir);
  710.                 }
  711.             }
  712.             XP_FREE(full_dir);
  713.         }
  714.         // tell the caller if the user selected to save this as text
  715.         // if a source file and we want to save as text pass it back else
  716.         //   just pass back that we want to save it as source
  717.         if(type) {
  718.             if(filter == htm_filter_used && fname.nFilterIndex == TXT)
  719.                 *type = TXT;
  720.             else
  721.                 *type = HTM;
  722.         }
  723.  
  724.         // tack the extension on at the end if the name doesn't have one
  725.         // the Win9x dialog is not really respecting the DefExt as
  726.         //   explained in the help files
  727.         char * pLastBit = strrchr(full_path, '\\');
  728.         if(!pLastBit)
  729.             pLastBit = full_path;
  730.         else
  731.             pLastBit++; // skip over slash
  732.  
  733.         // figure out if the user has put an extension on the path name
  734.         char * pNewExt = strrchr(pLastBit, '.');
  735.  
  736.         // Common dialog will act incorrectly if user uses ".shtml".
  737.         // We get the following: "fname.shtml.html" so strip off the ".html"
  738.         if(pNewExt && !_stricmp(pNewExt, ".html")) {
  739.             *pNewExt = '\0';
  740.             char * pExt = strrchr(pLastBit, '.');
  741.             if(pExt && !_stricmp(pExt, ".shtml")){
  742.                 // We found the user's ".shtml", so return truncated version
  743.                 return(full_path);
  744.             }
  745.             // ".shtml" not found - restore the period
  746.             *pNewExt = '.';
  747.         }
  748.  
  749.         //
  750.         // so we have a new extension that is not equal to the original one
  751.         //
  752.  
  753.         // see if it ends .txt if so then the user really wanted to save a text file
  754.         //   no matter what the selector is set to.  Damn Win9x guidelines
  755.         if(pNewExt && !_stricmp(pNewExt, ".txt")) {
  756.             if(type)
  757.                 *type = TXT;                                                            
  758.             return(full_path);
  759.         }
  760.         return(full_path);
  761.     } else {
  762.  
  763.         // user hit cancel
  764.         if( full_path) XP_FREE(full_path);
  765.         return(NULL);
  766.     }
  767. }
  768.  
  769. // Appends the specified filter description and pattern to the end of szFilterString,
  770. // adding double NULL at the end. szFilterString must be a double NULL terminated
  771. // string upon entry
  772. //
  773. // This routine doesn't add a duplicate to the list of description/patterns that are
  774. // already there
  775. void wfe_AppendToFilterString(char* szFilterString, char* szDescription, char* szPattern)
  776. {
  777.     if(!szFilterString || !szDescription || !szPattern)
  778.         return;
  779.  
  780.     // Find the end of the existing filter (double NULL terminated). While we're at it,
  781.     // check for an existing entry that's an exact match
  782.     char*    pStr = szFilterString;
  783.     BOOL    bDescriptionMatches;
  784.  
  785.     while (*pStr != '\0') {
  786.         // See if the description matches
  787.         bDescriptionMatches = stricmp(pStr, szDescription) == 0;
  788.     
  789.         // Skip over the description and get the filter pattern
  790.         pStr = strchr(pStr, '\0') + 1;
  791.  
  792.         // Filter description and pattern really must exist as a pair
  793.         ASSERT(*pStr != '\0');
  794.         if (*pStr == '\0')
  795.             break;  // found the double NULL terminator
  796.  
  797.         // If the description matched, then check the filter pattern
  798.         if (bDescriptionMatches && stricmp(pStr, szPattern) == 0)
  799.             return;  // don't add a duplicate string
  800.  
  801.         // Skip over the filter pattern and get the next pair
  802.         pStr = strchr(pStr, '\0') + 1;
  803.     }
  804.  
  805.     // At this point we're pointing to the second NULL terminator. Add the new
  806.     // description to the end
  807.     strcpy(pStr, szDescription);
  808.  
  809.     // Append the filter pattern, leaving the NULL terminator at the end of the
  810.     // description
  811.     pStr += strlen(szDescription) + 1;
  812.     strcpy(pStr, szPattern);
  813.  
  814.     // Add a final NULL terminator
  815.     pStr += strlen(szPattern) + 1;
  816.     *pStr = '\0';
  817. }
  818.  
  819. // Appends the szFilterAppendString to the end of the szFilterString, adding
  820. // double NULL at the end. szFilterString must be a double NULL terminated string
  821. // upon entry. szFilterAppendString must also be a double NULL terminated string
  822. void wfe_AppendFilterStringToFilterString(char* szFilterString,
  823.                                           char* szFilterAppendString)
  824. {
  825.     if((szFilterString == NULL) || (szFilterAppendString == NULL))
  826.         return;
  827.  
  828.     // find the end of the existing filter, (double NULL)
  829.     // szFilterString MUST be a double NULL term'd string or bad things happen
  830.     char* pCharFilterString = szFilterString;
  831.     while(!((*pCharFilterString == '\0') && (*(pCharFilterString + 1) == '\0')))
  832.         pCharFilterString++;
  833.  
  834.     if(pCharFilterString != szFilterString) // if the string is not empty
  835.         pCharFilterString++;                // start at the second NULL
  836.  
  837.     // find the size of the szFilterAppendString
  838.     char* pCharString = szFilterAppendString;
  839.     int iStringSize = 0;
  840.     while(!((*pCharString == '\0') && (*(pCharString + 1) == '\0')))
  841.     {
  842.         pCharString++;
  843.         iStringSize++;
  844.     }
  845.  
  846.     // append the szFilterAppendString to the filter
  847.     memcpy(pCharFilterString, szFilterAppendString, iStringSize);
  848.  
  849.     // double NULL terminate the string
  850.     pCharFilterString += iStringSize;
  851.     *pCharFilterString = '\0', pCharFilterString++, *pCharFilterString = '\0';
  852. }
  853.  
  854. static BOOL
  855. IsNullPlugin(NPFileTypeAssoc* pAssociation)
  856. {
  857.     // The null plug-in is the default plug-in handler and has the wildcard
  858.     // '*' as it's file extent
  859.     return pAssociation->extentstring && strcmp(pAssociation->extentstring, "*") == 0;
  860. }
  861.  
  862. //
  863. // construct a filter string from all the plugins file associations, and
  864. // from the previous filter template
  865. //
  866. //CLM: Modified this to allow restricting filter to just *.HTM;*.HTML
  867. //     Use HTM_ONLY (-1) instead of HTM
  868. //
  869. char* wfe_ConstructFilterString(int type)
  870. {
  871.     NPFileTypeAssoc* pAssociation = NULL;
  872.     if (type != HTM_ONLY){
  873.         // get the list of associations for all plugin MIME types
  874.         // ONLY if we are not looking for just HTM/HTML files (used for Editor)
  875.         pAssociation = NPL_GetFileAssociation(NULL);
  876.     }
  877.     
  878.     char filter[256];
  879.     int  iFilterSize;
  880.  
  881.     // Pre-4.0 NT Common Dialog has a bug: *.htm;*.html shows ".htm" files as ".html"
  882.     if ( sysInfo.m_bWinNT && sysInfo.m_dwMajor < 4 ) {
  883.         if(type == HTM_ONLY)
  884.             strcpy(filter, szLoadString(IDS_FILTERNT_HTM));
  885.         else
  886.             strcpy(filter, szLoadString(IDS_FILTERNT));
  887.         iFilterSize = strlen(filter);
  888.     } 
  889.     else {
  890.         if (type == HTM_ONLY)
  891. #ifdef XP_WIN16
  892.             strcpy(filter, szLoadString(IDS_FILTER_HTM16));
  893. #else
  894.             strcpy(filter, szLoadString(IDS_FILTER_HTM32));
  895. #endif
  896.         else if(type == P12)
  897.             strcpy(filter, szLoadString(IDS_PKCS12_FILTER));
  898.         else
  899. #ifdef XP_WIN16
  900.             strcpy(filter, szLoadString(IDS_FILTER16));
  901. #else
  902.             strcpy(filter, szLoadString(IDS_FILTER32));
  903. #endif
  904.         iFilterSize = strlen(filter);
  905.     }
  906.     // Replace '\n' with '\0' before pass to CommDialog
  907.     for (char *p = filter; *p ; p++)
  908.         if (*p == '\n')  *p = '\0';
  909.  
  910.     if(pAssociation == NULL)
  911.     {
  912.         char* pString = NULL;
  913.         if(iFilterSize) {
  914.             pString = (char *)XP_ALLOC(iFilterSize);
  915.         }
  916.         if(pString) {
  917.             memcpy(pString, filter, iFilterSize);
  918.         }
  919.         return pString;
  920.     }
  921.  
  922.     // Determine how much memory to allocate. The filter string consists of pairs of NULL
  923.     // terminated strings. The first string describes the filter and the second string
  924.     // specifies the filter pattern
  925.     int iAccumulator = 0;
  926.     do {
  927.         if (pAssociation->fileType && pAssociation->extentlist) {
  928.             // Add in space for the filter description
  929.             iAccumulator += strlen((const char*)pAssociation->fileType);
  930.  
  931.             // NULL terminator between filter desciption and filter pattern
  932.             iAccumulator++;
  933.  
  934.             // Determine the space needed for the filter pattern. There can be multiple
  935.             // filter patterns per filter description by separating the filter patterns
  936.             // with a semicolon
  937.             for (char** ppExtentList = pAssociation->extentlist; *ppExtentList;) {
  938.                 // The extent list is just the file extension. The filter pattern should
  939.                 // include a "*."
  940.                 iAccumulator += strlen("*.") + strlen(*ppExtentList);
  941.  
  942.                 // If there's another filter pattern then add a semicolon delimiter
  943.                 if (*++ppExtentList)
  944.                     iAccumulator++;
  945.             }
  946.  
  947.             // Space for NULL terminating the filter pattern string
  948.             iAccumulator++;
  949.         }
  950.         pAssociation = pAssociation->pNext;
  951.     } while(pAssociation);
  952.  
  953.     // Add in room for the basic template (this size includes the final NULL
  954.     // terminator)
  955.     iAccumulator += iFilterSize;
  956.  
  957.     char* pFilterString = (char *) XP_ALLOC(iAccumulator);
  958.  
  959.     if (pFilterString) {
  960.         // Start off with an empty filter string
  961.         pFilterString[0] = '\0';
  962.         pFilterString[1] = '\0';
  963.     
  964.         // Add the basic template
  965.         wfe_AppendFilterStringToFilterString(pFilterString, filter);
  966.  
  967.         pAssociation = NPL_GetFileAssociation(NULL);
  968.     
  969.         // Add the plugin filters
  970.         for (pAssociation = NPL_GetFileAssociation(NULL); pAssociation; pAssociation = pAssociation->pNext) {
  971.             if (IsNullPlugin(pAssociation))
  972.                 continue;
  973.  
  974.             if (pAssociation->fileType && pAssociation->extentlist) {
  975.                 // Build the filter pattern(s). There can be multiple filter patterns for a
  976.                 // filter description by separating the filter patterns with a semicolon
  977.                 CString    strFilterPattern;
  978.     
  979.                 for (char** ppExtentList = pAssociation->extentlist; *ppExtentList;) {
  980.                     // The extent list is just the file extension. The filter pattern should
  981.                     // include a "*."
  982.                     strFilterPattern += "*.";
  983.                     strFilterPattern += *ppExtentList;
  984.     
  985.                     // If there's another filter pattern then add a semicolon delimiter
  986.                     if (*++ppExtentList)
  987.                         strFilterPattern += ';';
  988.                 }
  989.  
  990.                 // Add the filter description and filter pattern if it doesn't already exist
  991.                 // in the list. You can end up with duplicates if there is a plug-in that registers
  992.                 // more than one MIME type for a given extension, e.g. audio/aiff and audio/x-aiff
  993.                 wfe_AppendToFilterString(pFilterString, (char*)pAssociation->fileType,
  994.                     (char*)(const char*)strFilterPattern);
  995.             }
  996.         }
  997.     }
  998.  
  999.     return pFilterString;
  1000. }
  1001.  
  1002. #ifdef XP_WIN16
  1003. PRIVATE void wfe_InplaceToLower(char *pConvert) {
  1004.     while (pConvert && *pConvert) {
  1005.       *pConvert = XP_TO_LOWER(*pConvert);
  1006.       pConvert++;
  1007.     }
  1008. }
  1009. #endif
  1010.  
  1011.  
  1012. //
  1013. // Return the path name of a file the user has picked for a given task
  1014. // It is up to the user to free the filename
  1015. // The file must exist
  1016. // Return NULL if the user cancels
  1017. // If pOpenIntoEditor is not null, then radio buttons are added to select window type
  1018. //    set initial choice and read user's choice from this
  1019. MODULE_PRIVATE char * 
  1020. wfe_GetExistingFileName(HWND m_hWnd, char * prompt, int type, XP_Bool bMustExist, BOOL * pOpenIntoEditor)
  1021. {
  1022.  
  1023.     OPENFILENAME fname;
  1024.     char * full_path = NULL;
  1025.     char   name[_MAX_FNAME];
  1026.     char * defaultDir = NULL;
  1027.     char* filter = wfe_ConstructFilterString(type);
  1028.  
  1029.     /* initialize the OPENFILENAME struct */
  1030.     
  1031.     BOOL result;
  1032.     UINT index = (type == HTM_ONLY) ? 1 : type;
  1033.  
  1034.     // space for the full path name    
  1035.     full_path = (char *) XP_ALLOC(_MAX_PATH * sizeof(char));
  1036.     if(!full_path){
  1037.         XP_FREE(filter);
  1038.         return(NULL);
  1039.     }
  1040.     name[0]      = '\0';
  1041.     full_path[0] = '\0';
  1042.  
  1043.     char   currentDir[_MAX_PATH+1];
  1044.     char * HaveCurrentDir = NULL;
  1045.     
  1046.     char dir[_MAX_PATH];
  1047.     if(type == HTM_ONLY){
  1048.         int iLen = _MAX_PATH;
  1049.         PREF_GetCharPref("editor.html_directory",dir,&iLen);
  1050.         defaultDir = dir;
  1051.         // Save current directory to restore later
  1052.         HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
  1053.     }
  1054.     // set up the entries
  1055.     fname.lStructSize = sizeof(OPENFILENAME);
  1056.     fname.hwndOwner = m_hWnd;
  1057.     fname.lpstrFilter = filter;
  1058.     fname.lpstrCustomFilter = NULL;
  1059.     fname.nFilterIndex = index;
  1060.     fname.lpstrFile = full_path;
  1061.     fname.nMaxFile = _MAX_PATH;
  1062.     fname.lpstrFileTitle = name;
  1063.     fname.nMaxFileTitle = _MAX_FNAME;
  1064.     fname.lpstrInitialDir = defaultDir;
  1065.     fname.lpstrTitle = prompt;
  1066.     fname.Flags = OFN_HIDEREADONLY;
  1067.     fname.lpstrDefExt = NULL;
  1068.  
  1069.     if(bMustExist)
  1070.         fname.Flags |= OFN_FILEMUSTEXIST;
  1071.  
  1072.  
  1073.     result = FEU_GetOpenFileName(&fname);
  1074.  
  1075.     XP_FREE(filter);
  1076.  
  1077.     // see if the user selects a file or hits cancel    
  1078.     if(result) {
  1079.         // On win16 force to lower case.
  1080. #ifdef XP_WIN16
  1081.         wfe_InplaceToLower(full_path);
  1082. #endif
  1083.         if(type == HTM_ONLY){
  1084.             char *full_dir = (char *) XP_STRDUP(full_path);
  1085.             full_dir[fname.nFileOffset] = '\0';
  1086.             PREF_SetCharPref("editor.html_directory",full_dir);
  1087.             XP_FREE(full_dir);
  1088.             if( HaveCurrentDir ){
  1089.                 SetCurrentDir(currentDir);
  1090.             }
  1091.         }
  1092.         return(full_path);
  1093.     } else {
  1094.         // user hit cancel
  1095.         if(full_path) XP_FREE(full_path);
  1096.         return(NULL);
  1097.     }
  1098. }
  1099.  
  1100. // CLM: Similar to wfe_GetExistingFileName(),
  1101. //      but designed to select Image Files: *.jpg, *.gif
  1102. //
  1103. // Return the path name of a file the user has picked for a given task
  1104. // It is up to the user to free the filename
  1105. // Return NULL if the user cancels
  1106. //
  1107. MODULE_PRIVATE char * 
  1108. wfe_GetExistingImageFileName(HWND m_hWnd, char * prompt, XP_Bool bMustExist)
  1109. {
  1110.  
  1111.     OPENFILENAME fname;
  1112.     char * full_path;
  1113.     char   name[_MAX_FNAME];
  1114.     char filter[256];
  1115.  
  1116. #ifdef XP_WIN16
  1117.     strcpy(filter, szLoadString(IDS_IMAGE_FILTER16));
  1118. #else
  1119.     strcpy(filter, szLoadString(IDS_IMAGE_FILTER32));
  1120. #endif
  1121.     // replace '\n' with '\0' before pass to CommonDialog
  1122.     for (char *p = filter; *p ; p++)
  1123.         if (*p == '\n')  *p = '\0';
  1124.  
  1125.  
  1126.     /* initialize the OPENFILENAME struct */
  1127.     
  1128.     // space for the full path name    
  1129.     full_path = (char *) XP_ALLOC(_MAX_PATH * sizeof(char));
  1130.     if(!full_path)
  1131.         return(NULL);
  1132.  
  1133.     name[0]      = '\0';
  1134.     full_path[0] = '\0';
  1135.  
  1136.     // Save current directory to restore later
  1137.     char   currentDir[_MAX_PATH+1];
  1138.     char * HaveCurrentDir = _getdcwd(0, currentDir, _MAX_PATH);
  1139.  
  1140.     char defaultDir[_MAX_PATH];
  1141.     int iLen = _MAX_PATH;
  1142.     PREF_GetCharPref("editor.image_directory",defaultDir,&iLen);
  1143.  
  1144.     // set up the entries
  1145.     fname.lStructSize = sizeof(OPENFILENAME);
  1146.     fname.hwndOwner = m_hWnd;
  1147.     fname.lpstrFilter = filter;
  1148.     fname.lpstrCustomFilter = NULL;
  1149.     fname.nFilterIndex = 0;
  1150.     fname.lpstrFile = full_path;
  1151.     fname.nMaxFile = _MAX_PATH;
  1152.     fname.lpstrFileTitle = name;
  1153.     fname.nMaxFileTitle = _MAX_FNAME;
  1154.     fname.lpstrInitialDir = defaultDir;
  1155.     fname.lpstrTitle = prompt;
  1156.     fname.Flags = OFN_HIDEREADONLY;
  1157.     fname.lpstrDefExt = NULL;
  1158.  
  1159.     if(bMustExist)
  1160.         fname.Flags |= OFN_FILEMUSTEXIST;
  1161.  
  1162.     // see if the user selects a file or hits cancel    
  1163.     if(FEU_GetOpenFileName(&fname)) {
  1164.         // On win16 force to lower case.
  1165. #ifdef XP_WIN16
  1166.         wfe_InplaceToLower(full_path);        
  1167. #endif
  1168.         char *full_dir = (char *) XP_STRDUP(full_path);
  1169.         full_dir[fname.nFileOffset] = '\0';
  1170.         PREF_SetCharPref("editor.image_directory",full_dir);
  1171.         XP_FREE(full_dir);
  1172.  
  1173.         if( HaveCurrentDir ){
  1174.             SetCurrentDir(currentDir);
  1175.         }
  1176.         return(full_path);
  1177.  
  1178.     } else {
  1179.         // user hit cancel
  1180.         XP_FREE(full_path);
  1181.         return(NULL);
  1182.     }
  1183. }
  1184.  
  1185. // Just need a stub.  Always fail
  1186. //
  1187. extern "C" int dupsocket(int foo)
  1188. {
  1189.     return(-1); 
  1190. }
  1191.  
  1192.  
  1193. // INTL_ResourceCharSet(void)
  1194. //
  1195. extern "C" char *INTL_ResourceCharSet(void)
  1196. {
  1197.     return szLoadString(IDS_RESOURCE_CHARSET) ;
  1198. }
  1199.  
  1200.