home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / plugin / npwplat.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  31.5 KB  |  867 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. // npwplat.cpp
  20. #include "stdafx.h"
  21. #include <afxole.h>
  22. #include <afxpriv.h>
  23. #include <afxwin.h>
  24. #include <errno.h>
  25. #include <direct.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #ifdef WIN32
  29.     #include <io.h>
  30.     #include <winver.h>
  31. #else
  32.     #include <dos.h>
  33.     #include <ver.h>
  34. #endif
  35. #include "npwplat.h"
  36. #include "nppg.h"
  37. #include "plgindll.h"
  38. #include "np.h"
  39. #include "helper.h"
  40. #include "java.h"
  41. #include "edt.h"
  42. #include "npglue.h"
  43.  
  44. NPPMgtBlk* g_pRegisteredPluginList = NULL;
  45.  
  46. // Tests that the directory specified by "dir" exists.
  47. // Returns true if it does.
  48.  
  49. static XP_Bool wfe_CheckDir(const char * dir)
  50. {
  51.     int ret;
  52.     XP_StatStruct statinfo; 
  53.  
  54.     ret = _stat((char *) dir, &statinfo);
  55.     if(ret == -1)
  56.         return(FALSE);
  57.  
  58.     return(TRUE);
  59.  
  60. }
  61.  
  62. // Get the name of the directory where plugins live.  "csDirname" is where the
  63. // name of the dir is written to, and the trailing slash is removed.
  64. // It always returns NPERR_NO_ERROR, since the Nav had to be started to get
  65. // here, and the plugin dir is under where Nav started from.
  66. NPError wfe_GetPluginsDirectory(CString& csDirname)
  67. {
  68.     char ca_default[_MAX_PATH];
  69.     ::GetModuleFileName(AfxGetApp()->m_hInstance, ca_default, _MAX_PATH);
  70.     char *cp_lastslash = ::strrchr(ca_default, '\\');
  71.     *cp_lastslash = NULL;
  72.     csDirname = ca_default;
  73.     csDirname += "\\plugins";
  74.     return NPERR_NO_ERROR;
  75. }
  76.  
  77. // Fetches the "MIME type" string from the DLL VERSIONINFO structure.
  78. // "pVersionInfo" is ptr to the VERSIONINFO data, and "pNPMgtBlk" is a handle
  79. // to a plugin management data structure created during fe_RegisterPlugin().
  80. // The string is copied from the VERSIONINFO data into the
  81. // "pNPMgtBlk->szMIMEType" member.
  82. // An error is returned if out of memory.  The MIME type string IS
  83. // required, so an error is returned if the string does not exist.
  84. NPError wfe_GetPluginMIMEType(VS_FIXEDFILEINFO* pVersionInfo,
  85.                               NPPMgtBlk* pNPMgtBlk)
  86. {
  87.     // get the mime type of this plugin
  88.     static char szMimeTypeBlock[] = "StringFileInfo\\040904E4\\MIMEType";
  89.     void* lpBuffer = NULL;
  90.     UINT  uValueSize = 0;
  91.     if(::VerQueryValue(pVersionInfo, szMimeTypeBlock,
  92.                        &lpBuffer, &uValueSize) == 0) // couldn't find MIME type
  93.         return NPERR_GENERIC_ERROR;
  94.  
  95.     pNPMgtBlk->szMIMEType = new char[uValueSize];
  96.     if(pNPMgtBlk->szMIMEType == NULL)
  97.         return NPERR_OUT_OF_MEMORY_ERROR;
  98.      
  99.     strcpy(pNPMgtBlk->szMIMEType, (const char*)lpBuffer);
  100.  
  101.     return NPERR_NO_ERROR;
  102. }
  103.  
  104. // Fetches the "File Extents" string from the DLL VERSIONINFO structure.
  105. // "pVersionInfo" is ptr to the VERSIONINFO data, and "pNPMgtBlk" is a handle
  106. // to a plugin management data structure created during fe_RegisterPlugin().
  107. // The string is copied from the VERSIONINFO data into the
  108. // "pNPMgtBlk->szFileExtents" member.
  109. // An error is returned if out of memory, but the extents string is not
  110. // required, so it is not an error if the string does not exist.
  111. NPError wfe_GetPluginExtents(VS_FIXEDFILEINFO* pVersionInfo,
  112.                              NPPMgtBlk* pNPMgtBlk)
  113. {   // get the file extent list of this plugin
  114.     pNPMgtBlk->szFileExtents = NULL;
  115.     
  116.     static char szFileExtentsBlock[] = "StringFileInfo\\040904E4\\FileExtents";
  117.     void* lpBuffer = NULL;
  118.     UINT  uValueSize = 0;
  119.  
  120.     if(::VerQueryValue(pVersionInfo, szFileExtentsBlock,
  121.                        &lpBuffer, &uValueSize) == 0)
  122.         // couldn't find file extent
  123.         return NPERR_NO_ERROR;
  124.     
  125.     if((*((char*)lpBuffer) == '\0') || (uValueSize == 0))   // no extents
  126.         return NPERR_NO_ERROR;
  127.  
  128.     // alloc char array
  129.     pNPMgtBlk->szFileExtents = new char[uValueSize];
  130.     if(pNPMgtBlk->szFileExtents == NULL)
  131.         return NPERR_OUT_OF_MEMORY_ERROR;
  132.     strcpy(pNPMgtBlk->szFileExtents, (const char*)lpBuffer);
  133.         
  134.     return NPERR_NO_ERROR;
  135. }
  136.  
  137. // Fetches the "File Open Template" string from the DLL VERSIONINFO structure.
  138. // "pVersionInfo" is ptr to the VERSIONINFO data, and "pNPMgtBlk" is a handle
  139. // to a plugin management data structure created during fe_RegisterPlugin().
  140. // The string is copied from the VERSIONINFO data into the
  141. // "pNPMgtBlk->szFileOpenName" member.
  142. // An error is returned if out of memory, but the template string is not
  143. // required, so it is not an error if the string does not exist.
  144. NPError wfe_GetPluginFileOpenTemplate(VS_FIXEDFILEINFO* pVersionInfo,
  145.                                       NPPMgtBlk* pNPMgtBlk)
  146. {   // get the file open template this plugin
  147.     pNPMgtBlk->szFileOpenName = NULL;
  148.     
  149.     static char szFileOpenBlock[] = "StringFileInfo\\040904E4\\FileOpenName";
  150.     void* lpBuffer = NULL;
  151.     UINT  uValueSize = 0;
  152.  
  153.     if(::VerQueryValue(pVersionInfo, szFileOpenBlock,
  154.                        &lpBuffer, &uValueSize) == 0)
  155.         // couldn't find file extent
  156.         return NPERR_NO_ERROR;
  157.     
  158.     if((*((char*)lpBuffer) == '\0') || (uValueSize == 0))   // no extents
  159.         return NPERR_NO_ERROR;
  160.  
  161.     // alloc char array
  162.     pNPMgtBlk->szFileOpenName = new char[uValueSize];
  163.     if(pNPMgtBlk->szFileOpenName == NULL)
  164.         return NPERR_OUT_OF_MEMORY_ERROR;
  165.     strcpy(pNPMgtBlk->szFileOpenName, (const char*)lpBuffer);
  166.  
  167.     return NPERR_NO_ERROR;
  168. }
  169.  
  170. // Fetches the plugin name and description from the resource info.
  171. // Uses predefined version information strings
  172. NPError wfe_GetPluginNameAndDescription(VS_FIXEDFILEINFO* pVersionInfo,
  173.                                         CString&          strName,
  174.                                         CString&          strDescription)
  175. {
  176.     static char szNameBlock[] = "StringFileInfo\\040904E4\\ProductName";
  177.     static char szDescBlock[] = "StringFileInfo\\040904E4\\FileDescription";
  178.     void* lpBuffer = NULL;
  179.     UINT  uValueSize = 0;
  180.  
  181.     // Get the product name
  182.     if(::VerQueryValue(pVersionInfo, szNameBlock, &lpBuffer, &uValueSize) > 0)
  183.         strName = (LPSTR)lpBuffer;
  184.  
  185.     // Get the file description
  186.     if(::VerQueryValue(pVersionInfo, szDescBlock, &lpBuffer, &uValueSize) > 0)
  187.         strDescription = (LPSTR)lpBuffer;
  188.  
  189.     return NPERR_NO_ERROR;
  190. }
  191.  
  192. // Loads plugin properties from the DLL VERSIONINFO data structure.
  193. // MIME type and version are required, but file extents and string
  194. // file open templates are optional.  "pPluginFilespec" is a string
  195. // containing the file name of a DLL.  "pNPMgtBlk" is a handle to a
  196. // plugin management data structure created during fe_RegisterPlugin().  
  197. // Returns an error if "pPluginFilespec" did not have the required MIME
  198. // type and version fields.
  199. //
  200. // Also returns the plugin name and description
  201. NPError wfe_GetPluginProperties(char*         pPluginFilespec,
  202.                                 NPPMgtBlk*     pNPMgtBlk,
  203.                                 CString&    strPluginName,
  204.                                 CString&    strPluginDescription)
  205. {
  206.     // prepare to read the version info tags
  207.     DWORD dwHandle = NULL;
  208.     DWORD dwVerInfoSize = ::GetFileVersionInfoSize(pPluginFilespec, &dwHandle);
  209.     if(dwVerInfoSize == NULL)
  210.         return NPERR_GENERIC_ERROR;
  211.  
  212.     VS_FIXEDFILEINFO* pVersionInfo =
  213.         (VS_FIXEDFILEINFO*)new char[dwVerInfoSize];
  214.     if(pVersionInfo == NULL)
  215.         return NPERR_OUT_OF_MEMORY_ERROR;
  216.  
  217.     if(::GetFileVersionInfo(pPluginFilespec, dwHandle,
  218.                             dwVerInfoSize, pVersionInfo) == 0)
  219.     {
  220.         delete [] (char*)pVersionInfo;
  221.         return NPERR_GENERIC_ERROR;
  222.     }
  223.  
  224.     NPError result;
  225.     // get the mime type of this plugin
  226.     if((result = wfe_GetPluginMIMEType(pVersionInfo, pNPMgtBlk))
  227.        != NPERR_NO_ERROR)
  228.     {
  229.         delete [] (char*)pVersionInfo;
  230.         return result;
  231.     }
  232.  
  233.     // get the file extent list of this plugin
  234.     if((result = wfe_GetPluginExtents(pVersionInfo, pNPMgtBlk))
  235.        != NPERR_NO_ERROR)
  236.     
  237.     {
  238.         delete [] pNPMgtBlk->szMIMEType;
  239.         delete [] (char*)pVersionInfo;
  240.         return result;
  241.     }
  242.  
  243.     // get the file type template string of this plugin
  244.     if((result = wfe_GetPluginFileOpenTemplate(pVersionInfo, pNPMgtBlk))
  245.        != NPERR_NO_ERROR)
  246.     
  247.     {
  248.         delete [] pNPMgtBlk->szFileExtents;
  249.         delete [] pNPMgtBlk->szMIMEType;
  250.         delete [] (char*)pVersionInfo;
  251.         return result;
  252.     }
  253.  
  254.     // get the version of this plugin
  255.     void* lpBuffer = NULL;
  256.     UINT  uValueSize = 0;
  257.     if(::VerQueryValue(pVersionInfo, "\\", &lpBuffer, &uValueSize) == 0)
  258.     {   // couldn't find versioninfo
  259.         delete [] pNPMgtBlk->szFileExtents;
  260.         delete [] pNPMgtBlk->szMIMEType;
  261.         delete [] (char*)pVersionInfo;
  262.         return NPERR_GENERIC_ERROR;
  263.     }
  264.     pNPMgtBlk->versionMS  = ((VS_FIXEDFILEINFO*)lpBuffer)->dwProductVersionMS;
  265.     pNPMgtBlk->versionLS  = ((VS_FIXEDFILEINFO*)lpBuffer)->dwProductVersionLS;
  266.  
  267.     // get the plugin name and description. It's not fatal if these fail
  268.     wfe_GetPluginNameAndDescription(pVersionInfo, strPluginName, strPluginDescription);
  269.  
  270.     delete [] (char*)pVersionInfo;
  271.  
  272.     return NPERR_NO_ERROR;
  273. }
  274.  
  275. // Given a file open filter, e.g. Text Documents(*.txt), extracts the
  276. // description and returns a copy of it
  277. static LPSTR
  278. ExtractDescription(LPCSTR lpszFileOpenFilter)
  279. {
  280.     ASSERT(lpszFileOpenFilter);
  281.  
  282.     LPSTR lpszDescription = XP_STRDUP(lpszFileOpenFilter);
  283.  
  284.     // Strip off an filter pattern at the end
  285.     LPSTR lpszPattern = strrchr(lpszDescription, '(');
  286.  
  287.     if (lpszPattern)
  288.         *lpszPattern = '\0';
  289.  
  290.     return lpszDescription;
  291. }
  292.  
  293. // Registers one plugin.  "pPluginFilespec" is a string containing the file
  294. // name of a DLL.
  295. // This function can be called more than once so a plugin which has copied
  296. // into the plugins subdir AFTER the Nav has started can be registered
  297. // and loaded.
  298. // The DLL is a plugin candidate, and is qualified during
  299. // this function, by checking the DLL VERSIONINFO data structure for a
  300. // MIME type string.  If this string is found successfully, the handle
  301. // of the management block is used to register the plugin for its MIME type.
  302. // The extents which are to be associated with this MIME type are also grokked
  303. // from the VERSIONINFO data structure, once the candidate is accepted.
  304. // This function also takes the opportunity to overrided any helper app, by
  305. // setting a helper app data structure member to allow the plugin to handle
  306. // the MIME type instead of the helper, (pApp->how_handle = HANDLE_VIA_PLUGIN).
  307. // Returns an error if "pPluginFilespec" was not registered.
  308. NPError fe_RegisterPlugin(char* pPluginFilespec)
  309. {
  310.     CString    strName, strDescription;
  311.  
  312.     // initialize a new plugin list mgt block
  313.     NPPMgtBlk* pNPMgtBlk = new NPPMgtBlk;
  314.     if(pNPMgtBlk == NULL)   // fatal, can't continue
  315.         return NPERR_OUT_OF_MEMORY_ERROR;
  316.         
  317.     pNPMgtBlk->pPluginFuncs = NULL;
  318.     pNPMgtBlk->pLibrary        = NULL;
  319.     pNPMgtBlk->uRefCount    = 0;
  320.     pNPMgtBlk->next         = NULL;
  321.     
  322.     // determine the MIME type and version of this plugin
  323.     if(wfe_GetPluginProperties(pPluginFilespec, pNPMgtBlk, strName, strDescription) != NPERR_NO_ERROR)
  324.     {
  325.         delete pNPMgtBlk;
  326.         return NPERR_GENERIC_ERROR;
  327.     }
  328.  
  329.     // if a plugin is already registered for this MIME type, return.  this
  330.     // allows downloading and registering new plugins without exiting the nav
  331.     for(NPPMgtBlk* pListBlk = g_pRegisteredPluginList; pListBlk != NULL;
  332.         pListBlk = pListBlk->next) {
  333.         BOOL bSameFile =
  334.             (strcmp(pListBlk->pPluginFilename, pPluginFilespec) == 0);
  335.         BOOL bSameMIMEtype =
  336.             (strstr(pNPMgtBlk->szMIMEType, pListBlk->szMIMEType) != NULL);
  337.         if(bSameFile && bSameMIMEtype) {
  338.             // the plugin DLL's filename and the MIME type it's registering for
  339.             // are the same, don't reregister
  340.             delete pNPMgtBlk;
  341.             return NPERR_GENERIC_ERROR;
  342.         }
  343.     }    
  344.  
  345.     pNPMgtBlk->pPluginFilename = XP_STRDUP(pPluginFilespec);
  346.     if(pNPMgtBlk->pPluginFilename == NULL) // fatal, can't continue
  347.     {
  348.         delete pNPMgtBlk;
  349.         return NPERR_OUT_OF_MEMORY_ERROR;
  350.     }
  351.  
  352.     // Register the plugin file with the XP plugin code
  353.     NPL_RegisterPluginFile(strName, pNPMgtBlk->pPluginFilename, strDescription,
  354.                            pNPMgtBlk);
  355.  
  356.     // Iterate through the filename extensions.  These are a list which are
  357.     // delimited via the '|' character.  The list of MIME Types,File Extents, 
  358.     // and Open Names must all coordinate
  359.     char *pStartMIME, *pEndMIME, *pStartExt, *pEndExt, *pStartName, *pEndName;
  360.  
  361.     pStartMIME = pNPMgtBlk->szMIMEType;
  362.     pStartExt = pNPMgtBlk->szFileExtents;
  363.     pStartName = pNPMgtBlk->szFileOpenName;
  364.  
  365.     pEndMIME = strchr(pStartMIME ,'|');
  366.     while (pEndMIME) {
  367.         pEndExt = strchr(pStartExt,'|');
  368.         pEndName = strchr(pStartName,'|');
  369.         if (pEndMIME) *pEndMIME = 0;
  370.         else return NPERR_GENERIC_ERROR;
  371.         if (pEndExt)  *pEndExt = 0;
  372.         else return NPERR_GENERIC_ERROR;
  373.         if (pEndName) *pEndName = 0;
  374.         else return NPERR_GENERIC_ERROR;
  375.  
  376.         // Register the MIME type with the XP plugin code. We need to pass in
  377.         // a description. If there's a file open template specified, then use the
  378.         // description from there. Otherwise use the MIME type
  379.         LPSTR    lpszDescription = NULL;
  380.  
  381.         if (pStartName)
  382.             lpszDescription = ExtractDescription(pStartName);
  383.  
  384.         NPL_RegisterPluginType(pStartMIME, (LPCSTR)pStartExt, lpszDescription ?
  385.                                lpszDescription : pStartMIME, (void *)pStartName, pNPMgtBlk, TRUE);
  386.  
  387.         if (lpszDescription)
  388.             XP_FREE(lpszDescription);
  389.  
  390.         CHelperApp *pApp;
  391.         if(theApp.m_HelperListByType.Lookup(pStartMIME, (CObject *&)pApp))  {
  392.             //  We've a match.
  393.             //  Make sure the app is marked to handle the load
  394.             //      via a plugin
  395.             pApp->how_handle = HANDLE_VIA_PLUGIN;
  396.         }
  397.  
  398.         if ((pEndMIME+1) && (pEndExt+1) && (pEndName+1)) {
  399.             pStartMIME = pEndMIME+1;
  400.             pStartExt = pEndExt+1;
  401.             pStartName = pEndName+1;
  402.         }
  403.         pEndMIME = strchr(pStartMIME ,'|');    
  404.     }
  405.  
  406.     // Register the MIME type with the XP plugin code. We need to pass in
  407.     // a description. If there's a file open template specified, then use the
  408.     // description from there. Otherwise use the MIME type
  409.     LPSTR    lpszDescription = NULL;
  410.  
  411.     if (pStartName)
  412.         lpszDescription = ExtractDescription(pStartName);
  413.  
  414.     NPL_RegisterPluginType(pStartMIME, (LPCSTR)pStartExt, lpszDescription ?
  415.                            lpszDescription : pStartMIME, (void *)pStartName, pNPMgtBlk, TRUE);
  416.  
  417.     if (lpszDescription)
  418.         XP_FREE(lpszDescription);
  419.  
  420.     CHelperApp *pApp;
  421.     if(theApp.m_HelperListByType.Lookup(pStartMIME, (CObject *&)pApp))  {
  422.         //  We've a match.
  423.         //  Make sure the app is marked to handle the load
  424.         //      via a plugin
  425.         pApp->how_handle = HANDLE_VIA_PLUGIN;
  426.     }
  427.  
  428.     // insert the plugin mgt blk at the head of the list of registered plugins.
  429.     // this means they are listed in the reverse order from which they were
  430.     // created, which doesn't matter.
  431.     pNPMgtBlk->next = g_pRegisteredPluginList;
  432.     g_pRegisteredPluginList = pNPMgtBlk;
  433.  
  434.     return NPERR_NO_ERROR;
  435. }
  436.  
  437. // FE_RegisterPlugins is called from navigator main via npglue's NP_Init(). Finds all
  438. // plugins and begins tracking them using a NPPMgtBlk.  Uses the NPPMgtBlk
  439. // block handle to register the plugin with the xp plugin glue. Looks
  440. // in the directory under the netscape.exe dir, named "plugins" and all
  441. // subdirectories in recursive way (see fe_RegisterPlugins).  If the
  442. // directory doesn't exist, no warning dialog is shown.
  443. // There are no input or return vals.
  444. void fe_RegisterPlugins(char* pszPluginDir)
  445. {
  446.     CString csPluginSpec;
  447.     csPluginSpec = pszPluginDir; 
  448.  
  449. #ifdef JAVA
  450.     // add directory to the java path no matter what
  451.     LJ_AddToClassPath(pszPluginDir);
  452. #endif
  453.  
  454.     csPluginSpec += "\\*.*"; 
  455.  
  456. #ifndef _WIN32
  457.     _find_t fileinfo;
  458.     unsigned result = _dos_findfirst((LPSTR)((LPCSTR)csPluginSpec), _A_NORMAL | _A_SUBDIR, &fileinfo );
  459.  
  460.     if (result == 0) {
  461.  
  462.         result = _dos_findnext(&fileinfo); // skip "."
  463.         result = _dos_findnext(&fileinfo); // skip ".."
  464.  
  465.         CString csFileSpec;
  466.  
  467.         while(result == 0)
  468.         {
  469.             csFileSpec = pszPluginDir;
  470.             csFileSpec += "\\";
  471.             csFileSpec += fileinfo.name;
  472.  
  473.             // we got a subdir, call recursively this function to load plugin
  474.             if (fileinfo.attrib & _A_SUBDIR ) {
  475.                 fe_RegisterPlugins((LPSTR)(LPCSTR)csFileSpec);
  476.             }
  477.             else {
  478.                 size_t len = strlen(fileinfo.name);
  479.  
  480.                 // it's a file, see if it can be a plugin file
  481.                 if ( len > 6 && // at least "np.dll"
  482.                      (fileinfo.name[0] == 'n' || fileinfo.name[0] == 'N') && 
  483.                      (fileinfo.name[1] == 'p' || fileinfo.name[1] == 'P') &&
  484.                      !_stricmp(fileinfo.name + len - 4, ".dll"))
  485.                     fe_RegisterPlugin((LPSTR)((LPCSTR)csFileSpec));
  486. #ifdef EDITOR
  487.                 // If it's a cpXXX.zip file,register it as a composer plugin.
  488.                 else if ( len > 6 && // at least cp.zip
  489.                           (fileinfo.name[0] == 'c' || fileinfo.name[0] == 'C') && 
  490.                           (fileinfo.name[1] == 'p' || fileinfo.name[1] == 'P') &&
  491.                           (!_stricmp(fileinfo.name + len - 4, ".zip")
  492.                            || !_stricmp(fileinfo.name + len - 4, ".jar"))
  493.                     )
  494.                     EDT_RegisterPlugin((LPSTR)((LPCSTR)csFileSpec));
  495. #endif /* EDITOR */
  496.             }
  497.             result = _dos_findnext(&fileinfo);
  498.         }
  499.     }
  500. #else   /* _WIN32 */
  501.     _finddata_t fileinfo;
  502.     unsigned handle = _findfirst((LPSTR)((LPCSTR)csPluginSpec), &fileinfo );
  503.     unsigned result = 0;
  504.  
  505.     if (handle != -1) {
  506.         result = _findnext(handle, &fileinfo); // skip "."
  507.         result = _findnext(handle, &fileinfo); // skip ".."
  508.     
  509.  
  510.         CString csFileSpec;
  511.  
  512.         while((result != -1) && (handle != -1))
  513.         {
  514.             csFileSpec = pszPluginDir;
  515.             csFileSpec += "\\";
  516.             csFileSpec += fileinfo.name;
  517.  
  518.             // we got a subdir, call recursively this function to load plugin
  519.             if (fileinfo.attrib & _A_SUBDIR ) {
  520.                 fe_RegisterPlugins((LPSTR)(LPCSTR)csFileSpec);
  521.             }
  522.             else {
  523.                 size_t len = strlen(fileinfo.name);
  524.  
  525.                 // it's a file, see if it can be a plugin file
  526.                 if ( len > 6 && // at least "np.dll"
  527.                      (fileinfo.name[0] == 'n' || fileinfo.name[0] == 'N') && 
  528.                      (fileinfo.name[1] == 'p' || fileinfo.name[1] == 'P') &&
  529.                      !_stricmp(fileinfo.name + len - 4, ".dll"))
  530.                     fe_RegisterPlugin((LPSTR)((LPCSTR)csFileSpec));
  531. #ifdef EDITOR
  532.                 // If it's a cpXXX.zip file, add it to the java class path.
  533.                 else if ( len > 6 && // at least cp.zip
  534.                           (fileinfo.name[0] == 'c' || fileinfo.name[0] == 'C') && 
  535.                           (fileinfo.name[1] == 'p' || fileinfo.name[1] == 'P') &&
  536.                           (!_stricmp(fileinfo.name + len - 4, ".zip")
  537.                            || !_stricmp(fileinfo.name + len - 4, ".jar"))
  538.                     )
  539.                     EDT_RegisterPlugin((LPSTR)((LPCSTR)csFileSpec));
  540. #endif
  541.             }
  542.             result = _findnext(handle, &fileinfo);
  543.         }
  544.         _findclose(handle);
  545.     }
  546. #endif  /* _WIN32 */
  547. }
  548.  
  549. // called from the navigator main, dispatch to the previous function
  550. void FE_RegisterPlugins()
  551. {
  552.     CString csPluginDir;
  553.     // get the main plugins directory and start the process
  554.     wfe_GetPluginsDirectory(csPluginDir);
  555.     fe_RegisterPlugins((LPSTR)(LPCSTR)csPluginDir);
  556. }
  557.     
  558. // saves the current path in the variable passed.  ppPathSave is the
  559. // address of the ptr which stores the path string.  returns out of memory
  560. // error if allocation for the string returned by _getcwd() fails.  returns
  561. // generic error if the "one deep" stack is already full.
  562. NPError wfe_PushPath(LPSTR *ppPathSave)
  563. {
  564.     // only allow "one deep" stack
  565.     if(*ppPathSave != NULL)
  566.         return NPERR_GENERIC_ERROR;
  567.  
  568.     // save the CWD
  569.     *ppPathSave = _getcwd(NULL, 0);
  570.     if(*ppPathSave == NULL)
  571.         return NPERR_OUT_OF_MEMORY_ERROR;
  572.  
  573.     return NPERR_NO_ERROR;
  574. }
  575.  
  576. // calculate the drive letter value for _chdrive().  ascii in, int out 
  577. int wfe_MapAsciiToDriveNum(char cAsciiNum)
  578. {
  579.     int iDriveLetter = cAsciiNum;
  580.     if(islower(cAsciiNum))
  581.         iDriveLetter = _toupper(cAsciiNum);
  582.     // plus one because for _chdrive(),  A = 1, B = 2, etc
  583.     return iDriveLetter - 'A' + 1;
  584. }
  585.  
  586. // restores the path from the variable passed.  pDirSave stores the pointer
  587. // to the path string.  returns an error if a path has never been pushed.
  588. NPError wfe_PopPath(LPSTR pPathSave)
  589. {
  590.     // only allows "one deep" stack
  591.     if(pPathSave == NULL)
  592.         return NPERR_GENERIC_ERROR;
  593.  
  594.     // restore the drive
  595.     int chdriveErr = _chdrive(wfe_MapAsciiToDriveNum(pPathSave[0]));
  596.  
  597.     // restore the CWD
  598.     int chdirErr = _chdir(pPathSave);
  599.     free(pPathSave);
  600.  
  601.     return NPERR_NO_ERROR;
  602. }
  603.  
  604. // Load a plugin dll.  "pluginType" is a handle to a plugin management data
  605. // structure created during FE_RegisterPlugins().  "pNavigatorFuncs" is
  606. // a table of entry points into Navigator, which are the services provided
  607. // by Navigator to plugins, such as requestread() and GetUrl().  These entry
  608. // points are stored and called by the plugin when services are needed.
  609. // The return val is a table of functions which are entry points to the
  610. // newly loaded plugin, such as NewStream() and Write().
  611. NPPluginFuncs* FE_LoadPlugin(void* pluginType, NPNetscapeFuncs* pNavigatorFuncs, np_handle* handle)
  612. {
  613.     if(pluginType == NULL)
  614.         return NULL;
  615.  
  616.     NPPMgtBlk* pNPMgtBlock = (NPPMgtBlk*)pluginType;
  617.  
  618.     CString csPluginDir;
  619.     wfe_GetPluginsDirectory(csPluginDir);
  620.  
  621.     LPSTR pPathSave = NULL;   // storage for one dir spec
  622.  
  623.     wfe_PushPath(&pPathSave);  // save the current drive and dir
  624.  
  625.     // change the default dir so that implib'd plugins won't fail
  626.     if(_chdir(csPluginDir) != 0) {
  627.         wfe_PopPath(pPathSave);  // restore the path
  628.         return NULL;
  629.     }
  630.  
  631.     // must change the drive as well as the dir path
  632.     if(isalpha(csPluginDir[0]) && csPluginDir[1] == ':') {
  633.         if(_chdrive(wfe_MapAsciiToDriveNum(csPluginDir[0])) != 0) {
  634.             wfe_PopPath(pPathSave);  // restore the path
  635.             return NULL;
  636.         }
  637.     }
  638.  
  639.     pNPMgtBlock->pLibrary = PR_LoadLibrary(pNPMgtBlock->pPluginFilename);
  640.  
  641.     // the cross platform code should take care of the 16/32 bit issues
  642.     if(pNPMgtBlock->pLibrary == NULL)
  643.         return NULL;
  644.     
  645.     NP_CREATEPLUGIN npCreatePlugin =
  646. #ifndef NSPR20
  647.         (NP_CREATEPLUGIN)PR_FindSymbol("NP_CreatePlugin", pNPMgtBlock->pLibrary);
  648. #else
  649.         (NP_CREATEPLUGIN)PR_FindSymbol(pNPMgtBlock->pLibrary, "NP_CreatePlugin");
  650. #endif
  651.     if (npCreatePlugin != NULL) {
  652.         if (thePluginManager == NULL) {
  653.             static NS_DEFINE_IID(kIPluginManagerIID, NP_IPLUGINMANAGER_IID);
  654.             if (nsPluginManager::Create(NULL, kIPluginManagerIID, (void**)&thePluginManager) != NS_OK)
  655.                 return NULL;
  656.         }
  657.         NPIPlugin* plugin = NULL;
  658.         NPPluginError err = npCreatePlugin(thePluginManager, &plugin);
  659.         handle->userPlugin = plugin;
  660.         if (err == NPPluginError_NoError && plugin != NULL) {
  661.             pNPMgtBlock->pPluginFuncs = (NPPluginFuncs*)-1;   // something to say it's loaded, but != 0
  662.         }
  663.     }
  664.     else {
  665.  
  666.         NP_GETENTRYPOINTS getentrypoints =
  667. #ifndef NSPR20
  668.             (NP_GETENTRYPOINTS)PR_FindSymbol("NP_GetEntryPoints", pNPMgtBlock->pLibrary);
  669. #else
  670.             (NP_GETENTRYPOINTS)PR_FindSymbol(pNPMgtBlock->pLibrary, "NP_GetEntryPoints");
  671. #endif
  672.         if(getentrypoints == NULL)
  673.         {
  674.             PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  675.             wfe_PopPath(pPathSave);  // restore the path
  676.             return NULL;
  677.         }
  678.     
  679.         if(pNPMgtBlock->pPluginFuncs == NULL)
  680.         {
  681.             pNPMgtBlock->pPluginFuncs = new NPPluginFuncs;
  682.             pNPMgtBlock->pPluginFuncs->size = sizeof NPPluginFuncs;
  683.             pNPMgtBlock->pPluginFuncs->javaClass = NULL;
  684.             if(pNPMgtBlock->pPluginFuncs == NULL)   // fatal, can't continue
  685.             {
  686.                 PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  687.                 wfe_PopPath(pPathSave);  // restore the path
  688.                 return NULL;
  689.             }
  690.         }
  691.  
  692.         if(getentrypoints(pNPMgtBlock->pPluginFuncs) != NPERR_NO_ERROR)
  693.         {
  694.             PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  695.             delete pNPMgtBlock->pPluginFuncs;
  696.             pNPMgtBlock->pPluginFuncs = NULL;
  697.             wfe_PopPath(pPathSave);  // restore the path
  698.             return NULL;
  699.         }
  700.  
  701.         // if the plugin's major ver level is lower than the Navigator's,
  702.         // then they are incompatible, and should return an error
  703.         if(HIBYTE(pNPMgtBlock->pPluginFuncs->version) < NP_VERSION_MAJOR)
  704.         {
  705.             PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  706.             delete pNPMgtBlock->pPluginFuncs;
  707.             pNPMgtBlock->pPluginFuncs = NULL;
  708.             wfe_PopPath(pPathSave);  // restore the path
  709.             return NULL;
  710.         }
  711.  
  712.         NP_PLUGININIT npinit = NULL;
  713.  
  714.         // if this DLL is not already loaded, call its initialization entry point
  715.         if(pNPMgtBlock->uRefCount == 0) {
  716.             // the NP_Initialize entry point was misnamed as NP_PluginInit, early
  717.             // in plugin project development.  Its correct name is documented
  718.             // now, and new developers expect it to work.  However, I don't want
  719.             // to  break the plugins already in the field, so I'll accept either
  720.             // name
  721.             npinit =
  722. #ifndef NSPR20
  723.                 (NP_PLUGININIT)PR_FindSymbol("NP_Initialize", pNPMgtBlock->pLibrary);
  724. #else
  725.                 (NP_PLUGININIT)PR_FindSymbol(pNPMgtBlock->pLibrary, "NP_Initialize");
  726. #endif
  727.             if(!npinit) {
  728.                 npinit =
  729. #ifndef NSPR20
  730.                     (NP_PLUGININIT)PR_FindSymbol("NP_PluginInit", pNPMgtBlock->pLibrary);
  731. #else
  732.                     (NP_PLUGININIT)PR_FindSymbol(pNPMgtBlock->pLibrary, "NP_PluginInit");
  733. #endif
  734.             }
  735.         }
  736.  
  737.         if(npinit == NULL) {
  738.             PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  739.             delete pNPMgtBlock->pPluginFuncs;
  740.             pNPMgtBlock->pPluginFuncs = NULL;
  741.             wfe_PopPath(pPathSave);  // restore the path
  742.             return NULL;
  743.         }
  744.  
  745.         if (npinit(pNavigatorFuncs) != NPERR_NO_ERROR) {
  746.             PR_UnloadLibrary(pNPMgtBlock->pLibrary);
  747.             delete pNPMgtBlock->pPluginFuncs;
  748.             pNPMgtBlock->pPluginFuncs = NULL;
  749.             wfe_PopPath(pPathSave);  // restore the path
  750.             return NULL;
  751.         }
  752.     }
  753.     
  754.     pNPMgtBlock->uRefCount++;   // all is well, remember it was loaded
  755.     
  756.     // can't pop the path until plugins have been completely loaded/init'd
  757.     wfe_PopPath(pPathSave);  // restore the path
  758.     return pNPMgtBlock->pPluginFuncs;
  759. }
  760.  
  761. // Unloads a plugin DLL.  "pluginType" is a handle to a plugin management data
  762. // structure created during FE_RegisterPlugins().  There is no return val.
  763. void FE_UnloadPlugin(void* pluginType, struct _np_handle* handle)
  764. {
  765.     NPPMgtBlk* pNPMgtBlk = (NPPMgtBlk*)pluginType;
  766.     if (pNPMgtBlk == NULL)
  767.         return;
  768.  
  769.     // XXX Note that we're double refcounting here. If we were rewriting this 
  770.     // from scratch, we could eliminate this pNPMgtBlk and its refcount and just
  771.     // rely on the one in the userPlugin.
  772.  
  773.     pNPMgtBlk->uRefCount--;   // another one bites the dust
  774.  
  775.     // if this DLL is the last one, call its shutdown entry point
  776.     if (pNPMgtBlk->uRefCount == 0) {
  777.         if (handle->userPlugin) {
  778.             handle->userPlugin->Release();
  779.         }
  780.         else {
  781.             // the NP_Shutdown entry point was misnamed as NP_PluginShutdown, early
  782.             // in plugin project development.  Its correct name is documented
  783.             // now, and new developers expect it to work.  However, I don't want
  784.             // to  break the plugins already in the field, so I'll accept either
  785.             // name
  786.             NP_PLUGINSHUTDOWN npshutdown =
  787. #ifndef NSPR20
  788.                 (NP_PLUGINSHUTDOWN)PR_FindSymbol("NP_Shutdown", pNPMgtBlk->pLibrary);
  789. #else
  790.                 (NP_PLUGINSHUTDOWN)PR_FindSymbol(pNPMgtBlk->pLibrary, "NP_Shutdown");
  791. #endif
  792.             if (!npshutdown) {
  793.                 npshutdown =
  794. #ifndef NSPR20
  795.                     (NP_PLUGINSHUTDOWN)PR_FindSymbol("NP_PluginShutdown", pNPMgtBlk->pLibrary);
  796. #else
  797.                     (NP_PLUGINSHUTDOWN)PR_FindSymbol(pNPMgtBlk->pLibrary, "NP_PluginShutdown");
  798. #endif
  799.             }
  800.  
  801.             if (npshutdown != NULL) {
  802.                 NPError result = npshutdown();
  803.             }
  804.         }
  805.     }
  806.  
  807.     // XXX Shouldn't the rest of this be inside the if statement, above?...
  808.  
  809.     PR_UnloadLibrary(pNPMgtBlk->pLibrary);
  810.     pNPMgtBlk->pLibrary = NULL;
  811.     
  812.     if (handle->userPlugin) {
  813.         PR_ASSERT(pNPMgtBlk->pPluginFuncs == (NPPluginFuncs*)-1);     // set in FE_LoadPlugin
  814.         handle->userPlugin = NULL;
  815.     }
  816.     else {
  817.         delete pNPMgtBlk->pPluginFuncs;
  818.     }
  819.     pNPMgtBlk->pPluginFuncs = NULL;
  820. }
  821.  
  822. // Removes a plugin DLL from memory, and frees its NPPMgtBlk management block.
  823. // "pluginType" is a handle to the plugin management data structure created
  824. // during FE_RegisterPlugins().  There is no return val.
  825. void FE_UnregisterPlugin(void* pluginType)
  826. {
  827.     NPPMgtBlk* pNPMgtBlk = (NPPMgtBlk*)pluginType;
  828.     if(pNPMgtBlk == NULL)
  829.         return;
  830.     
  831.     if(pNPMgtBlk->pLibrary != NULL)
  832.         PR_UnloadLibrary(pNPMgtBlk->pLibrary);
  833.     
  834.     delete [] (char*)*pNPMgtBlk->pPluginFilename;
  835.     delete [] pNPMgtBlk->pPluginFilename;
  836.     delete [] pNPMgtBlk->szMIMEType;
  837.     delete pNPMgtBlk->pPluginFuncs;
  838.     delete pNPMgtBlk;
  839. }
  840.  
  841. // Provides the entry point used by xp plugin code, (NPGLUE.C), to control
  842. // scroll bars.  The inputs are obvious, and there is no return val.
  843. void FE_ShowScrollBars(MWContext* pContext, XP_Bool show)
  844. {
  845.     if(ABSTRACTCX(pContext)->IsWindowContext())    {
  846.         CPaneCX *pPaneCX = PANECX(pContext);
  847.  
  848.         pPaneCX->ShowScrollBars(SB_BOTH, show);
  849.     }
  850. }
  851.  
  852. #ifdef XP_WIN32
  853. void*
  854. WFE_BeginSetModuleState()
  855. {
  856.     return AfxSetModuleState(AfxGetAppModuleState());    
  857. }
  858.  
  859. void
  860. WFE_EndSetModuleState(void* pPrevState)
  861. {
  862.     AfxSetModuleState((AFX_MODULE_STATE*)pPrevState);    
  863. }
  864. #endif
  865.  
  866.  
  867.