home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / plugin / npglue.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  145.8 KB  |  5,059 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. /*
  20.  *
  21.  *  Function naming conventions:
  22.  *      NPL_   Functions exported to other libs or FEs (prototyped in np.h)
  23.  *        NPN_   Function prototypes exported to plug-ins via our function table (prototyped in npapi.h)
  24.  *      npn_   Function definitions whose addresses are placed in the function table 
  25.  *      np_    Miscellaneous functions internal to libplugin (this file)
  26.  *
  27.  */
  28.  
  29. #include "xp.h"
  30. #include "npglue.h"
  31.  
  32. #ifdef ANTHRAX
  33. static char* np_FindAppletNForMimeType(const char* mimetype, char index);
  34. static int32 np_GetNumberOfInstalledApplets(const char* mimetype);
  35. static void np_ReplaceChars(char* word, char oldChar, char newChar);
  36. static char* np_CreateMimePref(const char* mimetype, const char* pref);
  37. #endif /* ANTHRAX */
  38.  
  39. /* list of all plugins */
  40. static np_handle *np_plist = 0;
  41.  
  42. /* list of all applets for ANTHRAX */
  43. #ifdef ANTHRAX
  44. static np_handle *np_alist = NULL;
  45. #endif
  46.  
  47. int np_debug = 0;
  48.  
  49. NPNetscapeFuncs npp_funcs;
  50.  
  51. /*
  52.  * Determine whether or not this is a new-style plugin.
  53.  */
  54. static inline XP_Bool
  55. np_is50StylePlugin(np_handle* handle)
  56. {
  57.     XP_ASSERT(handle != NULL);
  58.     return (handle->userPlugin != NULL);
  59. }
  60.  
  61. /* Find a mimetype in the handle */
  62. static np_mimetype *
  63. np_getmimetype(np_handle *handle, char *mimeStr, XP_Bool wildCard)
  64. {
  65.     np_mimetype *mimetype;
  66.  
  67.     for (mimetype = handle->mimetypes; mimetype; mimetype = mimetype->next)
  68.     {
  69.         if (mimetype->enabled)
  70.         {
  71.             if ((wildCard && !strcmp(mimetype->type, "*")) ||
  72.                 !strcasecomp(mimetype->type, mimeStr))
  73.                 return (mimetype);
  74.         }
  75.     }
  76.     return (NULL);
  77. }
  78.     
  79.  
  80. /*
  81.  * Standard conversion from NetLib status
  82.  * code to plug-in reason code.
  83.  */
  84. static NPReason
  85. np_statusToReason(int status)
  86. {
  87.     if (status == MK_DATA_LOADED)
  88.         return NPRES_DONE;
  89.     else if (status == MK_INTERRUPTED)
  90.         return NPRES_USER_BREAK;
  91.     else
  92.         return NPRES_NETWORK_ERR;
  93. }
  94.  
  95.  
  96. /*
  97.  * Add a node to the list of URLs for this
  98.  * plug-in instance.  The caller must fill
  99.  * out the fields of the node, which is returned.
  100.  */
  101. static np_urlsnode*
  102. np_addURLtoList(np_instance* instance)
  103. {
  104.     np_urlsnode* node;
  105.     
  106.     if (!instance)
  107.         return NULL;
  108.         
  109.     if (!instance->url_list)
  110.         instance->url_list = XP_ListNew();
  111.     if (!instance->url_list)
  112.         return NULL;
  113.         
  114.     node = XP_NEW_ZAP(np_urlsnode);
  115.     if (!node)
  116.         return NULL;
  117.         
  118.     XP_ListAddObject(instance->url_list, node);
  119.     
  120.     return node;
  121. }
  122.  
  123.  
  124. /*
  125.  * Deal with one URL from the list of URLs for the instance
  126.  * before the URL is removed from the list.  If the URL was
  127.  * locked in the cache, we must unlock it and delete the URL.
  128.  * Otherwise, notify the plug-in that the URL is done (if 
  129.  * necessary) and break the reference from the URL to the 
  130.  * instance. 
  131.  */
  132. static void
  133. np_processURLNode(np_urlsnode* node, np_instance* instance, int status)
  134. {
  135.     if (node->cached)
  136.     {
  137.         /* Unlock the cache file */
  138.         XP_ASSERT(!node->notify);
  139.         if (node->urls)
  140.         {
  141.             NET_ChangeCacheFileLock(node->urls, NP_UNLOCK);
  142.  
  143.             NET_FreeURLStruct(node->urls);
  144.             node->urls = NULL;
  145.         }
  146.         
  147.         return;
  148.     }
  149.     
  150.     if (node->notify)
  151.     {
  152.         /* Notify the plug-in */
  153.         XP_ASSERT(!node->cached);
  154.         if (instance) {
  155.             TRACEMSG(("npglue.c: CallNPP_URLNotifyProc"));
  156.             if (np_is50StylePlugin(instance->handle)) {
  157.                 nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)instance->npp->pdata;
  158.                 NPIPluginInstance* userInst = peerInst->GetUserInstance();
  159.                 userInst->URLNotify(node->urls->address, node->urls->window_target,
  160.                                     (NPPluginReason)np_statusToReason(status),
  161.                                     node->notifyData);
  162.             }
  163.             else if (ISFUNCPTR(instance->handle->f->urlnotify)) {
  164.                 CallNPP_URLNotifyProc(instance->handle->f->urlnotify,
  165.                                       instance->npp,
  166.                                       node->urls->address,
  167.                                       np_statusToReason(status),
  168.                                       node->notifyData);
  169.             }
  170.         }
  171.     }
  172.     
  173.     /* Break the reference from the URL to the instance */
  174.     if (node->urls)
  175.         node->urls->fe_data = NULL;
  176. }
  177.  
  178.  
  179. /*
  180.  * Remove an individual URL from the list of URLs for this instance.
  181.  */
  182. static void
  183. np_removeURLfromList(np_instance* instance, URL_Struct* urls, int status)
  184. {
  185.     XP_List* url_list;
  186.     np_urlsnode* node;
  187.  
  188.     if (!instance || !urls || !instance->url_list)
  189.         return;
  190.  
  191.     /* Look for the URL in the list */
  192.     url_list = instance->url_list;
  193.     while ((node = (np_urlsnode*)XP_ListNextObject(url_list)) != NULL)
  194.     {
  195.         if (node->urls == urls)
  196.         {
  197.             XP_ASSERT(!node->cached);
  198.             np_processURLNode(node, instance, status);
  199.  
  200.             XP_ListRemoveObject(instance->url_list, node);
  201.             XP_FREE(node);
  202.             
  203.             /* If the list is now empty, delete it */
  204.             if (XP_ListCount(instance->url_list) == 0)
  205.             {
  206.                 XP_ListDestroy(instance->url_list);
  207.                 instance->url_list = NULL;
  208.             }
  209.  
  210.             return;
  211.         }
  212.     }
  213. }
  214.  
  215.  
  216. /* 
  217.  * Remove all URLs from the list of URLs for this instance.
  218.  */
  219. static void
  220. np_removeAllURLsFromList(np_instance* instance)
  221. {
  222.     XP_List* url_list;
  223.     np_urlsnode* node;
  224.  
  225.     if (!instance || !instance->url_list)
  226.         return;
  227.         
  228.     url_list = instance->url_list;
  229.     while ((node = (np_urlsnode*)XP_ListNextObject(url_list)) != NULL)
  230.     {
  231.         /* No notification of URLs now: the instance is going away */
  232.         node->notify = FALSE;
  233.         np_processURLNode(node, instance, 0);
  234.     }
  235.  
  236.     /* Remove all elements from the list */
  237.     url_list = instance->url_list;
  238.     while ((node = (np_urlsnode*)XP_ListRemoveTopObject(url_list)) != NULL)
  239.         XP_FREE(node); 
  240.         
  241.     /* The list should now be empty, so delete it */
  242.     XP_ASSERT(XP_ListCount(instance->url_list) == 0);
  243.     XP_ListDestroy(instance->url_list);
  244.     instance->url_list = NULL;
  245. }
  246.  
  247.  
  248.  
  249. /* maps from a urls to the corresponding np_stream.  
  250.    you might well ask why not just store the urls in the stream and
  251.    put the stream in the netlib obj.  the reason is that there can be
  252.    more than one active netlib stream for each plugin stream and
  253.    netlib specific data for seekable streams (current position and
  254.    so-on is stored in the urls and not in the stream.  what a travesty.
  255. */
  256. static np_stream *
  257. np_get_stream(URL_Struct *urls)
  258. {
  259.     if(urls)
  260.     {
  261.         NPEmbeddedApp *pEmbeddedApp = (NPEmbeddedApp*)urls->fe_data;
  262.         if(pEmbeddedApp)
  263.         {
  264.             np_data *ndata = (np_data *)pEmbeddedApp->np_data;
  265.             if(ndata && ndata->instance)
  266.             {
  267.                 np_stream *stream;
  268.                 for (stream=ndata->instance->streams; stream; stream=stream->next)
  269.                 {
  270.                     /*
  271.                      * Matching algorithm: Either this URL is the inital URL for
  272.                      * the stream, or it's a URL generated by a subsequent byte-
  273.                      * range request.  We don't bother to keep track of all the 
  274.                      * URLs for byte-range requests, but we can still detect if 
  275.                      * the URL matches this stream: since we know that this URL
  276.                      * belongs to one of the streams for this instance and that
  277.                      * there can only be one seekable stream for an instance
  278.                      * active at a time, then we know if this stream is seekable
  279.                      * and the URL is a byte-range URL then they must match.
  280.                      * NOTE: We check both urls->high_range and urls->range_header
  281.                      * because we could have been called before the range_header
  282.                      * has been parsed and the high_range set.
  283.                      */
  284.                     if ((stream->initial_urls == urls) ||
  285.                         (stream->seek && (urls->high_range || urls->range_header)))
  286.                         return stream;
  287.                 }
  288.             }
  289.         }
  290.     }
  291.     return NULL;
  292. }
  293.  
  294.  
  295. /*
  296.  * Create the two plug-in data structures we need to go along
  297.  * with a netlib stream for a plugin: the np_stream, which is
  298.  * private to libplugin, and the NPStream, which is exported
  299.  * to the plug-in.  The NPStream has an opaque reference (ndata)
  300.  * to the associated np_stream.  The np_stream as a reference
  301.  * (pstream) to the NPStream, and another reference (nstream)
  302.  * to the netlib stream.
  303.  */
  304. static np_stream*
  305. np_makestreamobjects(np_instance* instance, NET_StreamClass* netstream, URL_Struct* urls)
  306. {
  307.     np_stream* stream;
  308.     NPStream* pstream;
  309.     XP_List* url_list;
  310.     np_urlsnode* node;
  311.     void*  notifyData;
  312.     
  313.     /* check params */
  314.     if (!instance || !netstream || !urls)
  315.         return NULL;
  316.         
  317.     /* make a npglue stream */
  318.     stream = XP_NEW_ZAP(np_stream);
  319.     if (!stream)
  320.         return NULL;
  321.     
  322.     stream->instance = instance;
  323.     stream->handle = instance->handle;
  324.     stream->nstream = netstream;
  325.     stream->initial_urls = urls;
  326.     
  327.     XP_ASSERT(urls->address);
  328.     StrAllocCopy(stream->url, urls->address);
  329.     stream->len = urls->content_length;
  330.  
  331.     /* Look for notification data for this URL */
  332.     notifyData = NULL;
  333.     url_list = instance->url_list;
  334.     while ((node = (np_urlsnode*)XP_ListNextObject(url_list)) != NULL)
  335.     {
  336.         if (node->urls == urls && node->notify)
  337.         {
  338.             notifyData = node->notifyData;
  339.             break;
  340.         }
  341.     }
  342.  
  343.     /* make a plugin stream (the thing the plugin sees) */
  344.     pstream = XP_NEW_ZAP(NPStream);
  345.     if (!pstream) 
  346.     {
  347.         XP_FREE(stream);
  348.         return NULL;
  349.     }
  350.     pstream->ndata = stream;    /* confused yet? */
  351.     pstream->url = stream->url;
  352.     pstream->end = urls->content_length;
  353.     pstream->lastmodified = (uint32) urls->last_modified;
  354.     pstream->notifyData = notifyData;
  355.  
  356.     /* make a record of it */
  357.     stream->pstream = pstream;
  358.     stream->next = instance->streams;
  359.     instance->streams = stream;
  360.  
  361.     NPTRACE(0,("np: new stream, %s, %s", instance->mimetype->type, urls->address));
  362.  
  363.     return stream;
  364. }
  365.  
  366. /*
  367.  * Do the reverse of np_makestreamobjects: delete the two plug-in
  368.  * stream data structures (the NPStream and the np_stream).
  369.  * We also need to remove the np_stream from the list of streams
  370.  * associated with its instance.
  371.  */
  372. static void
  373. np_deletestreamobjects(np_stream* stream)
  374. {
  375.     np_instance* instance = stream->instance;
  376.     
  377.     /* remove it from the instance list */
  378.     if (stream == instance->streams)
  379.         instance->streams = stream->next;
  380.     else
  381.     {
  382.         np_stream* sx;
  383.         for (sx = instance->streams; sx; sx = sx->next)
  384.             if (sx->next == stream)
  385.             {
  386.                 sx->next = sx->next->next;
  387.                 break;
  388.             }
  389.     }
  390.  
  391.     /* and nuke the stream */
  392.     if (stream->pstream) 
  393.     {
  394.         XP_FREE(stream->pstream);
  395.         stream->pstream = 0;
  396.     }
  397.     stream->handle = 0;
  398.     XP_FREE(stream);
  399. }           
  400.  
  401.  
  402.  
  403. /*
  404.  * (a) There should be a delayed load LIST (multiple requests get lost currently!)
  405.  * (b) We should call NET_GetURL with the app in the fe_data (notification uses it!)
  406.  * (c) We need to store the target context (may be different than instance context!)
  407.  */
  408. static void
  409. np_dofetch(URL_Struct *urls, int status, MWContext *window_id)
  410. {
  411.     np_stream *stream = np_get_stream(urls);
  412.     if(stream && stream->instance)
  413.     {
  414.         FE_GetURL(stream->instance->cx, stream->instance->delayedload);
  415.     }
  416. }
  417.  
  418.  
  419. unsigned int
  420. NPL_WriteReady(NET_StreamClass *stream)
  421. {
  422.     URL_Struct *urls = (URL_Struct *)stream->data_object;
  423.     np_stream *newstream = nil;
  424.     int ret = 0;    
  425.  
  426.     if(!(newstream = np_get_stream(urls)))
  427.         return 0;
  428.  
  429.     if (newstream->asfile == NP_ASFILEONLY)
  430.         return NP_MAXREADY;
  431.  
  432.     /* if prev_stream is not ready to write, then neither is this one... */
  433.     if (newstream->prev_stream != NULL){
  434.         ret = (newstream->prev_stream->is_write_ready(newstream->prev_stream));
  435.         if (ret == FALSE)
  436.             return FALSE;
  437.     }
  438.         
  439.     XP_ASSERT(newstream->instance);
  440.     newstream->instance->reentrant = 1;
  441.  
  442.     if (newstream->seek >= 0) {
  443.         TRACEMSG(("npglue.c: CallNPP_WriteReadyProc"));
  444.         if (newstream->handle->userPlugin) {
  445.             nsPluginStreamPeer* peerStream = (nsPluginStreamPeer*)newstream->pstream->pdata;
  446.             NPIPluginStream* userStream = peerStream->GetUserStream();
  447.             ret = userStream->WriteReady();
  448.         }
  449.         else if (ISFUNCPTR(newstream->handle->f->writeready)) {
  450.             ret = CallNPP_WriteReadyProc(newstream->handle->f->writeready,
  451.                                          newstream->instance->npp, newstream->pstream);
  452.         }
  453.     }
  454.     else
  455.         ret = NP_MAXREADY;
  456.  
  457. #if defined(XP_WIN) || defined(XP_OS2)
  458.     /* Prevent WinFE from going to sleep when plug-in blocks */
  459.     if (ret == 0){
  460.       if(!newstream->instance->calling_netlib_all_the_time){
  461.         newstream->instance->calling_netlib_all_the_time = TRUE;
  462.         NET_SetCallNetlibAllTheTime(newstream->instance->cx, "npglue");
  463.       }
  464.       else{
  465.  
  466.         NET_ClearCallNetlibAllTheTime(newstream->instance->cx, "npglue");
  467.         newstream->instance->calling_netlib_all_the_time = FALSE;
  468.       }
  469.     }
  470. #endif
  471.     if(!newstream->instance->reentrant)
  472.     {
  473.         urls->pre_exit_fn = np_dofetch;
  474.         return (unsigned int)-1;
  475.     }
  476.     newstream->instance->reentrant = 0;
  477.  
  478.     return ret;
  479. }
  480.  
  481. int
  482. NPL_Write(NET_StreamClass *stream, const unsigned char *str, int32 len)
  483. {
  484.     int ret;
  485.     URL_Struct *urls = (URL_Struct *)stream->data_object;
  486.     np_stream *newstream = np_get_stream(urls);    
  487.  
  488.     if(!newstream || !(newstream->handle->userPlugin ? 1 : ISFUNCPTR(newstream->handle->f->write)))
  489.         return -1;
  490.  
  491.     if (newstream->asfile == NP_ASFILEONLY)
  492.         return len;
  493.  
  494.     if (newstream->prev_stream != NULL){
  495.         ret = newstream->prev_stream->put_block(newstream->prev_stream,(const char *)str,len); 
  496.         /* should put check here for ret == len?  if not, then what? */
  497.     }
  498.  
  499.  
  500.     /* if this is the first non seek write after we turned the
  501.        stream, then abort this (netlib) stream */
  502.  
  503.     if(!urls->high_range && (newstream->seek == -1))
  504.         return MK_UNABLE_TO_CONVERT; /* will cause an abort */
  505.  
  506.     XP_ASSERT(newstream->instance);
  507.     newstream->instance->reentrant = 1;
  508.  
  509.     newstream->pstream->end = urls->content_length;
  510.  
  511.     if(newstream->seek)
  512.     {
  513.         /* NPTRACE(0,("seek stream gets %d bytes with high %d low %d pos %d\n", len, 
  514.            urls->high_range, urls->low_range, urls->position)); */
  515.         /* since we get one range per urls, position will only be non-zero
  516.            if we are getting additional writes */
  517.         if(urls->position == 0)
  518.             urls->position = urls->low_range;
  519.     }
  520.     /*TRACEMSG(("npglue.c: CallNPP_WriteProc"));
  521.     */
  522.     if (newstream->handle->userPlugin) {
  523.         nsPluginStreamPeer* peerStream = (nsPluginStreamPeer*)newstream->pstream->pdata;
  524.         NPIPluginStream* userStream = peerStream->GetUserStream();
  525.         ret = userStream->Write(len, (void*)&str[urls->position]);
  526.     }
  527.     else if (ISFUNCPTR(newstream->handle->f->write)) {
  528.         ret = CallNPP_WriteProc(newstream->handle->f->write, newstream->instance->npp, newstream->pstream, 
  529.                                 urls->position, len, (void *)str);
  530.     }
  531.  
  532.     urls->position += len;
  533.  
  534.     if(!newstream->instance->reentrant)
  535.     {
  536.         urls->pre_exit_fn = np_dofetch;
  537.         return -1;
  538.     }
  539.     newstream->instance->reentrant = 0;
  540.  
  541.     return ret;
  542. }
  543.  
  544.  
  545. static char *
  546. np_make_byterange_string(NPByteRange *ranges)
  547. {
  548.     char *burl;
  549.     NPByteRange *br;
  550.     int count, maxlen;
  551.  
  552.     for(count=0, br=ranges; br; br=br->next)
  553.         count++;
  554.     maxlen = count*22 + 64; /* two 32-bit numbers, plus slop */
  555.  
  556.     burl = (char*)XP_ALLOC(maxlen);
  557.     if(burl)
  558.     {    
  559.         char range[64];
  560.         int len=0;
  561.         int iBytesEqualsLen;
  562.  
  563.         iBytesEqualsLen = strlen(RANGE_EQUALS);
  564.  
  565.         /* the range must begin with bytes=
  566.         * a final range string looks like:
  567.         *  bytes=5-8,12-56
  568.         */
  569.         XP_STRCPY(burl, RANGE_EQUALS);
  570.  
  571.         for(br=ranges; br; br=br->next)
  572.         {
  573.             int32 brlen = br->length;
  574.             if(len)
  575.                 XP_STRCAT(burl, ",");
  576.             if(br->offset<0)
  577.                 sprintf(range, "%ld", -((long)(br->length)));
  578.             else
  579.                 sprintf(range, "%ld-%ld", br->offset, (br->offset+(brlen-1)));
  580.  
  581.             len += XP_STRLEN(range);
  582.             if((len + iBytesEqualsLen) >= maxlen)
  583.                 break;
  584.             XP_STRCAT(burl, range);
  585.         }
  586.  
  587.         if(len == 0) /* no ranges added */
  588.             *burl = 0;
  589.     }
  590.     return burl;
  591. }
  592.  
  593. static NPByteRange *
  594. np_copy_rangelist(NPByteRange *rangeList)
  595. {
  596.     NPByteRange *r, *rn, *rl=0, *rh=0;
  597.  
  598.     for(r=rangeList; r; r=r->next)
  599.     {
  600.         if(!(rn = XP_NEW_ZAP(NPByteRange)))
  601.             break;
  602.         rn->offset = r->offset;
  603.         rn->length = r->length;
  604.  
  605.         if(!rh) 
  606.             rh = rn;
  607.         if(rl) 
  608.             rl->next = rn;
  609.         rl = rn;
  610.     }
  611.     return rh;
  612. }
  613.  
  614.  
  615. static void
  616. np_lock(np_stream *stream)
  617. {
  618.     if(!stream->islocked)
  619.     {
  620.         NET_ChangeCacheFileLock(stream->initial_urls, NP_LOCK);
  621.         stream->islocked = 1;
  622.     }
  623. }
  624.  
  625. static void
  626. np_unlock(np_stream *stream)
  627. {
  628.     if(stream->islocked)
  629.     {
  630.         NET_ChangeCacheFileLock(stream->initial_urls, NP_UNLOCK);
  631.         stream->islocked = 0;
  632.     }
  633. }
  634.  
  635. static void 
  636. np_GetURL(URL_Struct *pURL,FO_Present_Types iFormatOut,MWContext *cx,   Net_GetUrlExitFunc *pExitFunc, NPBool notify){
  637.  
  638.     XP_ASSERT(pURL->owner_data == NULL);
  639.     pURL->owner_id   = 0x0000BAC0; /* plugin's unique identifier */
  640.     pURL->owner_data = pURL->fe_data;
  641.     pURL->fe_data = NULL;
  642.     FE_GetURL(cx,pURL);
  643. }
  644.  
  645.  
  646.  
  647. NPError NP_EXPORT
  648. npn_requestread(NPStream *pstream, NPByteRange *rangeList)
  649. {
  650.     np_stream *stream;
  651.  
  652.     if (pstream == NULL || rangeList == NULL)
  653.         return NPERR_INVALID_PARAM;
  654.  
  655.     stream = (np_stream *)pstream->ndata;
  656.  
  657.     if (stream == NULL)
  658.         return NPERR_INVALID_PARAM;
  659.  
  660.     /* requestread may be called before newstream has returned */
  661.     if (stream)
  662.     {
  663.         if (!stream->seekable)
  664.         {
  665.             /*
  666.              * If the stream is not seekable, we can only fulfill
  667.              * the request if we're going to cache it (seek == 2);
  668.              * otherwise it's an error.   If we are caching it,
  669.              * the request must still wait until the entire file
  670.              * is cached (when NPL_Complete is finally called).
  671.              */
  672.             if (stream->seek == 2)
  673.             {
  674.                 /* defer the work */
  675.                 NPTRACE(0,("\tdeferred the request"));
  676.  
  677.                 if(!stream->deferred)
  678.                     stream->deferred = np_copy_rangelist(rangeList);
  679.                 else
  680.                 {
  681.                     NPByteRange *r;
  682.                     /* append */
  683.                     for(r=stream->deferred;r && r->next;r++)
  684.                         ;
  685.                     if(r)
  686.                     {
  687.                         XP_ASSERT(!r->next);
  688.                         r->next = np_copy_rangelist(rangeList);
  689.                     }
  690.                 }
  691.             }
  692.             else
  693.                 return NPERR_STREAM_NOT_SEEKABLE;
  694.         }
  695.         else
  696.         {
  697.             char *ranges;
  698.  
  699.             /* if seeking is ok, we delay this abort until now to get
  700.                the most out of the existing connection */
  701.             if(!stream->seek)
  702.                 stream->seek = -1; /* next write aborts */
  703.  
  704.             if ((ranges = np_make_byterange_string(rangeList)) != NULL)
  705.             {
  706.                 URL_Struct *urls;
  707.                 urls = NET_CreateURLStruct(stream->url, NET_DONT_RELOAD);
  708.                 urls->range_header = ranges;
  709.                 XP_ASSERT(stream->instance);
  710.                 if(stream->instance)
  711.                 {
  712.                     urls->fe_data = (void *)stream->instance->app;
  713.                     (void) NET_GetURL(urls, FO_CACHE_AND_BYTERANGE, stream->instance->cx, NPL_URLExit);
  714.                 }
  715.             }
  716.         }
  717.     }
  718.     
  719.     return NPERR_NO_ERROR;
  720. }
  721.  
  722.  
  723. static void
  724. np_destroystream(np_stream *stream, NPError reason)
  725. {
  726.     if (stream)
  727.     {
  728.         /* Tell the plug-in that the stream is going away, and why */
  729.         np_instance *instance = stream->instance;
  730.         TRACEMSG(("npglue.c: CallNPP_DestroyStreamProc"));
  731.         if (stream->handle->userPlugin) {
  732.             nsPluginStreamPeer* peerStream = (nsPluginStreamPeer*)stream->pstream->pdata;
  733.             NPIPluginStream* userStream = peerStream->GetUserStream();
  734.             peerStream->SetReason((NPPluginReason)reason);
  735.             userStream->Release();      // must be released before peer
  736.             peerStream->Release();
  737.         }
  738.         else if (ISFUNCPTR(stream->handle->f->destroystream)) {
  739.             CallNPP_DestroyStreamProc(stream->handle->f->destroystream, instance->npp, stream->pstream, reason);
  740.         }
  741.         
  742.         /* Delete the np_stream and associated NPStream objects */
  743.         np_deletestreamobjects(stream);
  744.     }           
  745. }
  746.  
  747.  
  748. void
  749. np_streamAsFile(np_stream* stream)
  750. {
  751.     char* fname = NULL;
  752.     XP_ASSERT(stream->asfile);
  753.  
  754.     if (stream->initial_urls)
  755.     {
  756. #ifdef XP_MAC
  757.         /* XXX - we should eventually do this for all platforms, but when I tested it with
  758.         PC, I encountered an issue w/ EXE files just before shipping, so we're only
  759.         checking this in for MAC.  */
  760.         if (NET_IsURLInDiskCache(stream->initial_urls))
  761. #else
  762.         if (stream->initial_urls->cache_file)
  763. #endif
  764.         {
  765.             np_urlsnode* node;
  766.             
  767.             /* paranoia check for ifdef mac change above */
  768.             XP_ASSERT(stream->initial_urls->cache_file != NULL);
  769.  
  770.             fname = WH_FileName(stream->initial_urls->cache_file, xpCache);
  771.  
  772.             /* Lock the file in the cache until we're done with it */
  773.             np_lock(stream);
  774.             node = np_addURLtoList(stream->instance);
  775.             if (node)
  776.             {
  777.                 /* make a copy of the urls */
  778.                 URL_Struct* newurls = NET_CreateURLStruct(stream->initial_urls->address, NET_DONT_RELOAD);
  779.  
  780.                 /* add the struct to the node */
  781.                 node->urls = newurls;
  782.                 node->cached = TRUE;
  783.             }
  784.         }
  785.         else if (NET_IsLocalFileURL(stream->initial_urls->address))
  786.         {
  787.             char* pathPart = NET_ParseURL(stream->initial_urls->address, GET_PATH_PART);
  788.             fname = WH_FileName(pathPart, xpURL);
  789.             XP_FREE(pathPart);
  790.         }
  791.             
  792.     }
  793.     
  794.     /* fname can be NULL if something went wrong */
  795.     TRACEMSG(("npglue.c: CallNPP_StreamAsFileProc"));
  796.     if (stream->handle->userPlugin) {
  797.         nsPluginStreamPeer* peerStream = (nsPluginStreamPeer*)stream->pstream->pdata;
  798.         NPIPluginStream* userStream = peerStream->GetUserStream();
  799.         userStream->AsFile(fname);
  800.     }
  801.     else if (ISFUNCPTR(stream->handle->f->asfile)) {
  802.         CallNPP_StreamAsFileProc(stream->handle->f->asfile, stream->instance->npp,
  803.                                  stream->pstream, fname);
  804.     }
  805.  
  806.     if (fname) XP_FREE(fname);
  807. }
  808.  
  809.  
  810. void
  811. NPL_Complete(NET_StreamClass *stream)
  812. {
  813.     URL_Struct *urls = (URL_Struct *)stream->data_object;
  814.     np_stream *newstream = nil;    
  815.  
  816.     if(!(newstream = np_get_stream(urls)))
  817.         return;
  818.  
  819.     if (newstream->prev_stream != NULL)
  820.         newstream->prev_stream->complete(newstream->prev_stream) ;
  821.  
  822.     if(newstream->seek)
  823.     {
  824.         if(newstream->seek == 2)
  825.         {
  826.             /* request all the outstanding reads that had been waiting */
  827.             newstream->seekable = 1; /* for cgi hack */
  828.             newstream->seek = 1;
  829.             np_lock(newstream);
  830.             npn_requestread(newstream->pstream, newstream->deferred);
  831.             /* and delete the copies we made */
  832.             {
  833.                 NPByteRange *r, *rl=0;
  834.                 for(r=newstream->deferred; r; rl=r, r=r->next)
  835.                     if(rl) XP_FREE(rl);
  836.                 if(rl) XP_FREE(rl);
  837.                 newstream->deferred = 0;
  838.             }
  839.             np_unlock(newstream);
  840.         }
  841.     }
  842.  
  843.     if (newstream->asfile)
  844.         np_streamAsFile(newstream);
  845.         
  846.     newstream->nstream = NULL;        /* Remove reference to netlib stream */
  847.  
  848.     newstream->prev_stream = NULL;
  849.  
  850.     if (!newstream->dontclose)
  851.         np_destroystream(newstream, NPRES_DONE);
  852. }
  853.  
  854.  
  855. void 
  856. NPL_Abort(NET_StreamClass *stream, int status)
  857. {
  858.     URL_Struct *urls = (URL_Struct *)stream->data_object;
  859.     np_stream *newstream = nil;    
  860.  
  861.     if(!(newstream = np_get_stream(urls)))
  862.         return;
  863.  
  864.     if (newstream->prev_stream != NULL)
  865.         newstream->prev_stream->abort(newstream->prev_stream, status);
  866.  
  867.     if(newstream->seek == -1)
  868.     {
  869.         /* this stream is being turned around */
  870.         newstream->seek = 1;
  871.     }
  872.  
  873.     newstream->nstream = NULL;        /* Remove reference to netlib stream */
  874.  
  875.     /*
  876.      * MK_UNABLE_TO_CONVERT is the special status code we
  877.      * return from NPL_Write to cancel the original netlib
  878.      * stream when we get a byte-range request, so we don't
  879.      * want to destroy the plug-in stream in this case (we
  880.      * shouldn't get this status code any other time here).
  881.      */
  882.     if (!newstream->dontclose || (status < 0 && status != MK_UNABLE_TO_CONVERT))
  883.         np_destroystream(newstream, np_statusToReason(status));
  884. }
  885.  
  886. extern XP_Bool
  887. NPL_HandleURL(MWContext *cx, FO_Present_Types iFormatOut, URL_Struct *pURL, Net_GetUrlExitFunc *pExitFunc)
  888. {
  889.     /* check the cx for takers */
  890.     return FALSE;
  891. }
  892.  
  893.  
  894. /*
  895.  * This exit routine is called for embed streams (the
  896.  * initial stream created when the plug-in is instantiated).
  897.  * We use a special exit routine in this case because FE's
  898.  * may want to take additional action when a plug-in stream
  899.  * finishes (e.g. show special error status indicating why
  900.  * the stream failed).
  901.  */
  902. /* This needs to have all the code in NPL_URLExit in it too! (notification) */
  903. void
  904. NPL_EmbedURLExit(URL_Struct *urls, int status, MWContext *cx)
  905. {
  906.     if (urls && status != MK_CHANGING_CONTEXT)
  907.     {
  908. #if defined(XP_WIN) || defined(XP_OS2)
  909.         /* WinFE is responsible for deleting the URL_Struct */   
  910.         FE_EmbedURLExit(urls, status, cx);
  911. #else
  912.         NET_FreeURLStruct (urls);
  913. #endif
  914.     }
  915. }
  916.  
  917. /* 
  918.  * This exit routine is used for all streams requested by the
  919.  * plug-in: byterange request streams, NPN_GetURL streams, and 
  920.  * NPN_PostURL streams.  NOTE: If the exit routine gets called
  921.  * in the course of a context switch, we must NOT delete the
  922.  * URL_Struct.  Example: FTP post with result from server
  923.  * displayed in new window -- the exit routine will be called
  924.  * when the upload completes, but before the new context to
  925.  * display the result is created, since the display of the
  926.  * results in the new context gets its own completion routine.
  927.  */
  928. void
  929. NPL_URLExit(URL_Struct *urls, int status, MWContext *cx)
  930. {
  931.     if (urls && status != MK_CHANGING_CONTEXT)
  932.     {
  933.         NPEmbeddedApp* app;
  934.         np_stream* pstream;
  935.         /* (part 2 of fix:  replace fe_data the way I expect it) */
  936.         if ((urls->owner_data != NULL) &&
  937.             (urls->owner_id == 0x0000BAC0))
  938.                 urls->fe_data = urls->owner_data;
  939.  
  940.         app = (NPEmbeddedApp*) urls->fe_data;
  941.         pstream = np_get_stream(urls);
  942.  
  943.         if (pstream)
  944.         {
  945.             /*
  946.              * MK_UNABLE_TO_CONVERT is the special status code we
  947.              * return from NPL_Write to cancel the original netlib
  948.              * stream when we get a byte-range request, so we don't
  949.              * want to destroy the plug-in stream in this case (we
  950.              * shouldn't get this status code any other time here).
  951.              */
  952.             if (!pstream->dontclose || (status < 0 && status != MK_UNABLE_TO_CONVERT))
  953.                 np_destroystream(pstream, np_statusToReason(status));
  954.                 
  955.             /*
  956.              * If the initial URL_Struct is being deleted, break our
  957.              * reference to it (we might need to unlock it, too).
  958.              */
  959.             if (pstream->initial_urls == urls)
  960.             {
  961.                 np_unlock(pstream);
  962.                 pstream->initial_urls = NULL;
  963.             }
  964.         }
  965.  
  966.         /*
  967.          * Check to see if the instance wants
  968.          * to be notified of the URL completion.
  969.          */
  970.         if (app)
  971.         {
  972.             np_data* ndata = (np_data*) app->np_data;
  973.             if (ndata && ndata->instance)
  974.                 np_removeURLfromList(ndata->instance, urls, status);
  975.         }
  976.         if (urls->owner_data == NULL)
  977.             NET_FreeURLStruct(urls);
  978.         
  979.     }
  980. }
  981.  
  982.              
  983.  
  984. static URL_Struct*
  985. np_makeurlstruct(np_instance* instance, const char* relativeURL,
  986.                  const char* altHost, const char* referrer)
  987. {
  988.     History_entry* history;   
  989.     URL_Struct* temp_urls = NULL;
  990.     char* absoluteURL = NULL;
  991.     URL_Struct* urls = NULL;   
  992.     
  993.     if (!instance || !relativeURL)
  994.         return NULL;
  995.         
  996.     /*
  997.      * Convert the (possibly) relative URL passed in by the plug-in
  998.      * to a guaranteed absolute URL.  To do this we need the base
  999.      * URL of the page we're on, which we can get from the history
  1000.      * info in the plug-in's context.
  1001.      */
  1002.     XP_ASSERT(instance->cx);
  1003.        history = SHIST_GetCurrent(&instance->cx->hist);
  1004.        if (history)
  1005.            temp_urls = SHIST_CreateURLStructFromHistoryEntry(instance->cx, history);
  1006.        if (temp_urls)
  1007.        {
  1008.            absoluteURL = NET_MakeAbsoluteURL(temp_urls->address, (char*) relativeURL);
  1009.         NET_FreeURLStruct(temp_urls);
  1010.     }
  1011.  
  1012.  
  1013.     /*
  1014.      * Now that we've got the absolute URL string, make a NetLib struct
  1015.      * for it. If something went wrong making the absolute URL, fall back
  1016.      * on the relative one.
  1017.      */
  1018.     XP_ASSERT(absoluteURL);
  1019.        if (absoluteURL)
  1020.        {
  1021.         urls = NET_CreateURLStruct(absoluteURL, NET_NORMAL_RELOAD);
  1022.         XP_FREE(absoluteURL);
  1023.     }
  1024.     else
  1025.         urls = NET_CreateURLStruct(relativeURL, NET_NORMAL_RELOAD);
  1026.  
  1027.     urls->owner_data = NULL;
  1028.     urls->owner_id   = 0x0000BAC0;
  1029.  
  1030.     if (altHost && NET_SetURLIPAddressString(urls, altHost)) {
  1031.         NET_FreeURLStruct(urls);
  1032.         return NULL;
  1033.     }
  1034.     if (referrer) {
  1035.         urls->referer = XP_STRDUP((char*)referrer);
  1036.     }
  1037.     return urls;
  1038. }
  1039.  
  1040.  
  1041. static MWContext*
  1042. np_makecontext(np_instance* instance, const char* window)
  1043. {
  1044.     MWContext* cx;
  1045.     
  1046.     /* Figure out which context to do this on */
  1047.     if ((!strcmp(window, "_self")) || (!strcmp(window, "_current")))
  1048.         cx = instance->cx;
  1049.     else
  1050.         cx = XP_FindNamedContextInList(instance->cx, (char*) window);
  1051.  
  1052.     /* If we didn't find a context, make a new one */
  1053.     if (!cx)
  1054.         cx = FE_MakeNewWindow(instance->cx, NULL, (char*) window, NULL);
  1055.         
  1056.     return cx;
  1057. }
  1058.  
  1059.  
  1060. PR_STATIC_CALLBACK(void)
  1061. np_redisable_js(URL_Struct* url_s, int status, MWContext* context)
  1062. {
  1063.     context->forceJSEnabled = PR_FALSE;
  1064. }
  1065.  
  1066. NPError
  1067. np_geturlinternal(NPP npp, const char* relativeURL, const char* target, 
  1068.                   const char* altHost, const char* referrer, PRBool forceJSEnabled,
  1069.                   NPBool notify, void* notifyData)
  1070. {
  1071.     URL_Struct* urls = NULL;   
  1072.     MWContext* cx;
  1073.     np_instance* instance;
  1074.     np_urlsnode* node = NULL;
  1075.     NPError err = NPERR_NO_ERROR;
  1076. #ifdef XP_WIN32
  1077.     void*    pPrevState;
  1078. #endif
  1079.     
  1080.     if (!npp || !relativeURL)        /* OK for window to be NULL */
  1081.         return NPERR_INVALID_PARAM;
  1082.         
  1083.     instance = (np_instance*) npp->ndata;
  1084.     if (!instance)
  1085.         return NPERR_INVALID_PARAM;
  1086.  
  1087.     /* Make an abolute URL struct from the (possibly) relative URL passed in */
  1088.     urls = np_makeurlstruct(instance, relativeURL, altHost, referrer);
  1089.     if (!urls)
  1090.     {
  1091.         err = NPERR_OUT_OF_MEMORY_ERROR;
  1092.         goto error;
  1093.      }
  1094.  
  1095.      /*
  1096.       * Add this URL to the list of URLs for this instance,
  1097.       * and remember if the instance would like notification.
  1098.       */
  1099.     node = np_addURLtoList(instance);
  1100.     if (node)
  1101.     {
  1102.           node->urls = urls;
  1103.           if (notify)
  1104.           {
  1105.             node->notify = TRUE;
  1106.             node->notifyData = notifyData;
  1107.         }
  1108.     }
  1109.     else
  1110.     {
  1111.         err = NPERR_OUT_OF_MEMORY_ERROR;
  1112.         goto error;
  1113.     }
  1114.  
  1115.     urls->fe_data = (void*) instance->app;
  1116.      
  1117.     /*
  1118.      * If the plug-in passed NULL for the target, load the URL with a special stream
  1119.      * that will deliver the data to the plug-in; otherwise, convert the target name
  1120.      * they passed in to a context and load the URL into that context (possibly unloading
  1121.      * the plug-in in the process, if the target context is the plug-in's context).
  1122.      */
  1123.     if (!target)
  1124.     {
  1125. #ifdef XP_WIN32
  1126.         pPrevState = WFE_BeginSetModuleState();
  1127. #endif
  1128.         (void) NET_GetURL(urls, FO_CACHE_AND_PLUGIN, instance->cx, NPL_URLExit);
  1129. #ifdef XP_WIN32
  1130.         WFE_EndSetModuleState(pPrevState);
  1131. #endif
  1132.     }
  1133.     else
  1134.     {
  1135.         cx = np_makecontext(instance, target);
  1136.         if (!cx)
  1137.         {
  1138.             err = NPERR_OUT_OF_MEMORY_ERROR;
  1139.             goto error;
  1140.         }
  1141.  
  1142.         /* 
  1143.          * Prevent loading "about:" URLs into the plug-in's context: NET_GetURL
  1144.          * for these URLs will complete immediately, and the new layout thus
  1145.          * generated will blow away the plug-in and possibly unload its code,
  1146.          * causing us to crash when we return from this function.
  1147.          */
  1148.         if (cx == instance->cx && NET_URL_Type(urls->address) == ABOUT_TYPE_URL)
  1149.         {
  1150.             err = NPERR_INVALID_URL;
  1151.             goto error;
  1152.         }
  1153.  
  1154.         if (forceJSEnabled && !cx->forceJSEnabled) {
  1155.             LM_ForceJSEnabled(cx);
  1156.             urls->pre_exit_fn = np_redisable_js;
  1157.         }
  1158.         
  1159. #ifdef XP_MAC
  1160.         /*
  1161.          * One day the code below should call FE_GetURL, and this call will be
  1162.          * unnecessary since the FE will do the right thing.  Right now (3.0b6)
  1163.          * starting to use FE_GetURL is not an option so we'll just create 
  1164.          * (yet another) FE callback for our purposes: we need to ask the FE
  1165.          * to reset any timer it might have (for META REFRESH) so that the 
  1166.          * timer doesn't go off after leaving the original page via plug-in
  1167.          * request.
  1168.          */
  1169.         FE_ResetRefreshURLTimer(cx);
  1170. #endif
  1171.  
  1172.         /* reentrancy matters for this case because it will cause the current
  1173.            stream to be unloaded which netlib can't deal with */
  1174.         if (instance->reentrant && (cx == instance->cx))
  1175.         {
  1176.             XP_ASSERT(instance->delayedload == NULL);    /* We lose queued requests if this is non-NULL! */
  1177.             if (instance->delayedload)
  1178.                 NET_FreeURLStruct(instance->delayedload);
  1179.             instance->delayedload = urls;
  1180.             instance->reentrant = 0;
  1181.         }
  1182.         else
  1183.         {
  1184.         if ((cx == instance->cx) || 
  1185.             (XP_IsChildContext(cx,instance->cx)) )
  1186.         {
  1187.             /* re-target:  use this until figure out why thread violation.
  1188.             this method obviates question of self-trouncing... */
  1189.             if   ((instance->cx->type == MWContextBrowser ||
  1190.                 instance->cx->type == MWContextPane) 
  1191.                 &&  ((XP_STRNCMP(urls->address, "mailbox:", 8)==0)  
  1192.                 || (XP_STRNCMP(urls->address, "mailto:" , 7)==0)
  1193.                 || (XP_STRNCMP(urls->address, "news:"   , 5)==0)))
  1194.                     cx = np_makecontext(instance,"_self");
  1195.             else{
  1196.                 /* Since the previous stuff generally worked for this, keep using it */
  1197.                  urls->fe_data = NULL;
  1198. #ifdef XP_WIN32
  1199.                 pPrevState = WFE_BeginSetModuleState();
  1200. #endif
  1201.                 /* clear the exit routine, since the recipient may not be present! */
  1202.                 (void) NET_GetURL(urls, FO_CACHE_AND_PRESENT, cx, NPL_URLExit);
  1203. #ifdef XP_WIN32
  1204.                 WFE_EndSetModuleState(pPrevState);
  1205. #endif
  1206.                 
  1207.                 return NPERR_NO_ERROR;  
  1208.             }
  1209.             /* Eventually, we should shut down the current instance and
  1210.             startup a new one */
  1211.         }
  1212. #ifdef XP_WIN32
  1213.             pPrevState = WFE_BeginSetModuleState();
  1214. #endif
  1215.  
  1216.             (void) np_GetURL(urls, FO_CACHE_AND_PRESENT, cx, NPL_URLExit,notify); 
  1217.  
  1218. #ifdef XP_WIN32
  1219.             WFE_EndSetModuleState(pPrevState);
  1220. #endif
  1221.         }
  1222.     }
  1223.  
  1224.     return NPERR_NO_ERROR;
  1225.     
  1226. error:
  1227.     if (node)
  1228.     {
  1229.         node->notify = FALSE;        /* Remove node without notification */
  1230.         np_removeURLfromList(instance, urls, 0);
  1231.     }
  1232.     if (urls)
  1233.         NET_FreeURLStruct(urls);
  1234.     return err;
  1235. }
  1236.  
  1237.  
  1238. static NPError
  1239. np_parsepostbuffer(URL_Struct* urls, const char* buf, uint32 len)
  1240. {
  1241.     /*
  1242.      * Search the buffer passed in for a /n/n. If we find it, break the
  1243.      * buffer in half: the first part is the header, the rest is the body.
  1244.      */
  1245.     uint32 index;
  1246.     for (index = 0; index < len; index++)
  1247.     {
  1248.         if (buf[index] == '\n' && ++index < len && buf[index] == '\n')
  1249.             break;
  1250.     }
  1251.     
  1252.     /*
  1253.      * If we found '\n\n' somewhere in the middle of the string then we 
  1254.      * have headers, so we need to allocate a new string for the headers,
  1255.      * copy the header data from the plug-in's buffer into it, and put
  1256.      * it in the appropriate place of the URL struct.
  1257.      */
  1258.     if (index > 1 && index < len)
  1259.         {
  1260.         uint32 headerLength = index;
  1261.         char* headers = (char*) XP_ALLOC(headerLength + 1);
  1262.         if (!headers)
  1263.             return NPERR_OUT_OF_MEMORY_ERROR;
  1264.         XP_MEMCPY(headers, buf, headerLength);
  1265.         headers[headerLength] = 0;
  1266.         urls->post_headers = headers;
  1267.         }
  1268.     
  1269.     /*
  1270.      * If we didn't find '\n\n', then the body starts at the beginning;
  1271.      * otherwise, it starts right after the second '\n'.  Make sure the
  1272.      * body is non-emtpy, allocate a new string for it, copy the data
  1273.      * from the plug-in's buffer, and put it in the URL struct.
  1274.      */
  1275.     if (index >= len) 
  1276.         index = 0;                                /* No '\n\n', start body from beginning */
  1277.     else
  1278.         index++;                                /* Found '\n\n', start body after it */
  1279.         
  1280.     if (len - index > 0)                        /* Non-empty body? */
  1281.     {
  1282.         uint32 bodyLength = len - index + 1;
  1283.         char* body = (char*) XP_ALLOC(bodyLength);
  1284.         if (!body)
  1285.             return NPERR_OUT_OF_MEMORY_ERROR;
  1286.         XP_MEMCPY(body, &(buf[index]), bodyLength);
  1287.         urls->post_data = body;
  1288.         urls->post_data_size = bodyLength;
  1289.         urls->post_data_is_file = FALSE;
  1290.     }    
  1291.     else
  1292.     {
  1293.         /* Uh-oh, no data to post */
  1294.         return NPERR_NO_DATA;
  1295.     }
  1296.     
  1297.     return NPERR_NO_ERROR;
  1298. }
  1299.  
  1300.  
  1301. NPError
  1302. np_posturlinternal(NPP npp, const char* relativeURL, const char *target, 
  1303.                    const char* altHost, const char* referrer, PRBool forceJSEnabled,
  1304.                    uint32 len, const char *buf, NPBool file, NPBool notify, void* notifyData)
  1305. {
  1306.     np_instance* instance;
  1307.     URL_Struct* urls = NULL; 
  1308.     char* filename = NULL; 
  1309.     XP_Bool ftp;
  1310.     np_urlsnode* node = NULL;
  1311.     NPError err = NPERR_NO_ERROR;
  1312. #ifdef XP_WIN32
  1313.     void*    pPrevState;
  1314. #endif
  1315.     
  1316.     /* Validate paramters */
  1317.     if (!npp || !relativeURL)
  1318.         return NPERR_INVALID_PARAM;
  1319.  
  1320.     instance = (np_instance*) npp->ndata;
  1321.     if (!instance)
  1322.         return NPERR_INVALID_PARAM;
  1323.    
  1324.     /* Make an absolute URL struct from the (possibly) relative URL passed in */
  1325.     urls = np_makeurlstruct(instance, relativeURL, altHost, referrer);
  1326.     if (!urls)
  1327.         return NPERR_INVALID_URL;
  1328.  
  1329.  
  1330.      /*
  1331.       * Add this URL to the list of URLs for this instance,
  1332.       * and remember if the instance would like notification.
  1333.       */
  1334.     node = np_addURLtoList(instance);
  1335.     if (node)
  1336.     {
  1337.           node->urls = urls;
  1338.           if (notify)
  1339.           {
  1340.             node->notify = TRUE;
  1341.             node->notifyData = notifyData;
  1342.         }
  1343.     }
  1344.     else
  1345.         return NPERR_OUT_OF_MEMORY_ERROR;
  1346.      
  1347.     /* 
  1348.      * FTP protocol requires that the data be in a file.
  1349.      * If we really wanted to, we could write code to dump the buffer to
  1350.      * a temporary file, give the temp file to netlib, and delete it when
  1351.      * the exit routine fires.
  1352.      */
  1353.     ftp = (strncasecomp(urls->address, "ftp:", 4) == 0);
  1354.     if (ftp && !file)
  1355.     {
  1356.         err = NPERR_INVALID_URL;        
  1357.         goto error;                
  1358.     }
  1359.     
  1360.     if (file)
  1361.     {
  1362.         XP_StatStruct stat;
  1363.         
  1364.         /* If the plug-in passed a file URL, strip the 'file://' */
  1365.         if (!strncasecomp(buf, "file://", 7))
  1366.             filename = XP_STRDUP((char*) buf + 7);
  1367.         else
  1368.             filename = XP_STRDUP((char*) buf);
  1369.  
  1370.         if (!filename)
  1371.         {
  1372.             err = NPERR_OUT_OF_MEMORY_ERROR;
  1373.             goto error;
  1374.         }
  1375.         
  1376.         /* If the file doesn't exist, return an error NOW before netlib get it */
  1377.         if (XP_Stat(filename, &stat, xpURL))
  1378.         {
  1379.             err = NPERR_FILE_NOT_FOUND;
  1380.             goto error;
  1381.         }
  1382.     }
  1383.     
  1384.     /*
  1385.      * NET_GetURL handles FTP posts differently: the post_data fields are
  1386.      * ignored; instead, files_to_post contains an array of the files.
  1387.      */
  1388.     if (ftp)
  1389.     {
  1390.         XP_ASSERT(filename);
  1391.         urls->files_to_post = (char**) XP_ALLOC(sizeof(char*) + sizeof(char*));
  1392.         if (!(urls->files_to_post))
  1393.         {
  1394.             err = NPERR_OUT_OF_MEMORY_ERROR;
  1395.             goto error;
  1396.         }
  1397.         urls->files_to_post[0] = filename;
  1398.         urls->files_to_post[1] = NULL;
  1399.         urls->post_data = NULL;
  1400.         urls->post_data_size = 0;
  1401.         urls->post_data_is_file = FALSE;
  1402.     }
  1403.     else if (file)
  1404.     {
  1405.         XP_ASSERT(filename);
  1406.         urls->post_data = filename;
  1407.         urls->post_data_size = XP_STRLEN(filename);
  1408.         urls->post_data_is_file = TRUE;
  1409.     }
  1410.     else
  1411.     {
  1412.         /* 
  1413.          * There are two different sets of buffer-parsing code.
  1414.          * The new code is contained within np_parsepostbuffer,
  1415.          * and is used when the plug-in calls NPN_PostURLNotify.
  1416.          * The old code, below, is preserved for compatibility
  1417.          * for when the plug-in calls NPN_PostURL.
  1418.          */
  1419.         if (notify)
  1420.         {
  1421.             NPError err = np_parsepostbuffer(urls, buf, len);
  1422.             if (err != NPERR_NO_ERROR)
  1423.                 goto error;
  1424.         }
  1425.         else
  1426.         {
  1427.             urls->post_data = (char*)XP_ALLOC(len);
  1428.             if (!urls->post_data)
  1429.             {
  1430.                 err = NPERR_OUT_OF_MEMORY_ERROR;
  1431.                 goto error;
  1432.             }
  1433.             XP_MEMCPY(urls->post_data, buf, len);
  1434.             urls->post_data_size = len;
  1435.             urls->post_data_is_file = FALSE;
  1436.         }
  1437.     }
  1438.     
  1439.     urls->method = URL_POST_METHOD;
  1440.  
  1441.     if (!target)
  1442.     {
  1443.         urls->fe_data = (void*) instance->app;
  1444. #ifdef XP_WIN32
  1445.         pPrevState = WFE_BeginSetModuleState();
  1446. #endif
  1447.         (void) NET_GetURL(urls, FO_CACHE_AND_PLUGIN, instance->cx, NPL_URLExit);
  1448. #ifdef XP_WIN32
  1449.         WFE_EndSetModuleState(pPrevState);
  1450. #endif
  1451.     }
  1452.     else
  1453.     {
  1454.         MWContext* cx = np_makecontext(instance, target);
  1455.         if (!cx)
  1456.         {
  1457.             err = NPERR_OUT_OF_MEMORY_ERROR;
  1458.             goto error;
  1459.         }
  1460.         urls->fe_data = (void*) instance->app;
  1461.  
  1462.         if (forceJSEnabled && !cx->forceJSEnabled) {
  1463.             LM_ForceJSEnabled(cx);
  1464.             urls->pre_exit_fn = np_redisable_js;
  1465.         }
  1466.         
  1467. #ifdef XP_MAC
  1468.         /*
  1469.          * One day the code below should call FE_GetURL, and this call will be
  1470.          * unnecessary since the FE will do the right thing.  Right now (3.0b6)
  1471.          * starting to use FE_GetURL is not an option so we'll just create 
  1472.          * (yet another) FE callback for our purposes: we need to ask the FE
  1473.          * to reset any timer it might have (for META REFRESH) so that the 
  1474.          * timer doesn't go off after leaving the original page via plug-in
  1475.          * request.
  1476.          */
  1477.         FE_ResetRefreshURLTimer(cx);
  1478. #endif
  1479.  
  1480. #ifdef XP_WIN32
  1481.         pPrevState = WFE_BeginSetModuleState();
  1482. #endif
  1483.             (void) np_GetURL(urls, FO_CACHE_AND_PRESENT, cx, NPL_URLExit,notify); 
  1484.  
  1485. #ifdef XP_WIN32
  1486.         WFE_EndSetModuleState(pPrevState);
  1487. #endif
  1488.     }
  1489.     
  1490.     return NPERR_NO_ERROR;
  1491.     
  1492. error:
  1493.     if (node)
  1494.     {
  1495.         node->notify = FALSE;        /* Remove node without notification */
  1496.         np_removeURLfromList(instance, urls, 0);
  1497.     }
  1498.     if (urls)
  1499.         NET_FreeURLStruct(urls);
  1500.     return err;
  1501. }
  1502.  
  1503.  
  1504.  
  1505. NPError NP_EXPORT
  1506. npn_geturlnotify(NPP npp, const char* relativeURL, const char* target, void* notifyData)
  1507. {
  1508.     return np_geturlinternal(npp, relativeURL, target, NULL, NULL, PR_FALSE, TRUE, notifyData);
  1509. }
  1510.  
  1511. NPError NP_EXPORT
  1512. npn_getvalue(NPP npp, NPNVariable variable, void *r_value)
  1513. {
  1514.     np_instance* instance;
  1515.     NPError ret = NPERR_NO_ERROR;
  1516.  
  1517.     if (r_value == NULL)
  1518.         return NPERR_INVALID_PARAM;
  1519.  
  1520.     /* Some of these variabled may be handled by backend. The rest is FE.
  1521.      * So Handle all the backend variables and pass the rest over to FE.
  1522.      */
  1523.  
  1524.     switch(variable) {
  1525.         case NPNVjavascriptEnabledBool : 
  1526.             ret = PREF_GetBoolPref("javascript.enabled", (XP_Bool*)r_value);    
  1527.             break;
  1528.         case NPNVasdEnabledBool :
  1529.             ret = PREF_GetBoolPref("autoupdate.enabled", (XP_Bool*)r_value);
  1530.             break;
  1531. #ifdef MOZ_OFFLINE        
  1532.         case NPNVisOfflineBool :{
  1533.             XP_Bool *bptr = (XP_Bool *)r_value; 
  1534.             *bptr = NET_IsOffline();
  1535.             ret = NPERR_NO_ERROR;
  1536.             break;        }
  1537. #endif /* MOZ_OFFLINE */
  1538.         default:
  1539.             instance = NULL;
  1540.             if (npp != NULL) {
  1541.                 instance = (np_instance*) npp->ndata;
  1542.             }
  1543. #ifdef XP_UNIX
  1544.             ret = FE_PluginGetValue(instance?instance->handle->pdesc:NULL,
  1545.                                     variable, r_value);
  1546. #else
  1547.             ret = FE_PluginGetValue(instance->cx, instance->app, variable,
  1548.                                     r_value);
  1549. #endif /* XP_UNIX */
  1550.     }
  1551.  
  1552.     return(ret);
  1553. }
  1554.  
  1555. NPError NP_EXPORT
  1556. npn_setvalue(NPP npp, NPPVariable variable, void *r_value)
  1557. {
  1558.     np_instance* instance = NULL;
  1559.     NPError ret = NPERR_NO_ERROR;
  1560.     
  1561.     if (npp != NULL) {
  1562.         instance = (np_instance*) npp->ndata;
  1563.     }
  1564.     
  1565.     if (!instance)
  1566.         return NPERR_INVALID_INSTANCE_ERROR;
  1567.     
  1568.     switch(variable) {
  1569.         case NPPVpluginWindowBool:
  1570.         /* 
  1571.          * XXX On the Mac, a window has already been allocated by the time NPP_New
  1572.          * has been called - which is fine, since we'll still use the window. 
  1573.          * Unfortunately, we can't use the window's presence to determine whether
  1574.          * it's too late to set the windowed property.
  1575.          */
  1576. #ifndef XP_MAC
  1577.             /* 
  1578.              * If the window has already been allocated, it's too late
  1579.              * to tell us.
  1580.              */
  1581.             if (!instance->app->wdata->window)
  1582.                 instance->windowed = (0 != r_value);
  1583.             else
  1584.                 ret = NPERR_INVALID_PARAM;
  1585. #else
  1586.             instance->windowed = (0 != r_value);
  1587. #endif 
  1588.             break;
  1589.         case NPPVpluginTransparentBool:
  1590.             instance->transparent = (0 != r_value);
  1591. #ifdef LAYERS
  1592.             if (instance->layer && 
  1593.                 (instance->transparent != !(CL_GetLayerFlags(instance->layer) & CL_OPAQUE)))
  1594.             {
  1595.                 XP_Rect bbox;
  1596.                 
  1597.                 /* Get the bbox and convert it into its own coordinate space */
  1598.                 CL_GetLayerBbox(instance->layer, &bbox);
  1599.                 
  1600.                 CL_ChangeLayerFlag(instance->layer, CL_OPAQUE, (PRBool)!instance->transparent);
  1601.                 CL_ChangeLayerFlag(instance->layer, 
  1602.                                    CL_PREFER_DRAW_OFFSCREEN,
  1603.                                    (PRBool)instance->transparent);
  1604.  
  1605.                 /* Force drawing of the entire transparent plug-in. */
  1606.                 CL_UpdateLayerRect(CL_GetLayerCompositor(instance->layer),
  1607.                                    instance->layer, &bbox, PR_FALSE);
  1608.              }
  1609. #endif /* LAYERS */            
  1610.             break;
  1611.         case NPPVpluginWindowSize:
  1612.           break;
  1613.         default:
  1614.           break;
  1615.     }
  1616.  
  1617.     return(ret);
  1618. }
  1619.  
  1620.  
  1621. NPError NP_EXPORT
  1622. npn_geturl(NPP npp, const char* relativeURL, const char* target)
  1623. {
  1624.     return np_geturlinternal(npp, relativeURL, target, NULL, NULL, PR_FALSE, FALSE, NULL);
  1625. }
  1626.  
  1627.  
  1628. NPError NP_EXPORT
  1629. npn_posturlnotify(NPP npp, const char* relativeURL, const char *target, uint32 len, const char *buf, NPBool file, void* notifyData)
  1630. {
  1631.     return np_posturlinternal(npp, relativeURL, target, NULL, NULL, PR_FALSE, len, buf, file, TRUE, notifyData);
  1632. }
  1633.  
  1634.  
  1635. NPError NP_EXPORT
  1636. npn_posturl(NPP npp, const char* relativeURL, const char *target, uint32 len, const char *buf, NPBool file)
  1637. {
  1638.     return np_posturlinternal(npp, relativeURL, target, NULL, NULL, PR_FALSE, len, buf, file, FALSE, NULL);
  1639. }
  1640.  
  1641.  
  1642.  
  1643. NPError NP_EXPORT
  1644. npn_newstream(NPP npp, NPMIMEType type, const char* window, NPStream** pstream)
  1645. {
  1646.     np_instance* instance;
  1647.     np_stream* stream;
  1648.     NET_StreamClass* netstream;
  1649.     URL_Struct* urls;
  1650.     MWContext* cx;
  1651.     *pstream = NULL;
  1652.     
  1653.     if (!npp || !type)
  1654.         return NPERR_INVALID_PARAM;
  1655.     instance = (np_instance*) npp->ndata;
  1656.     if (!instance)
  1657.         return NPERR_INVALID_PARAM;
  1658.  
  1659.     /* Convert the window name to a context */
  1660.     cx = np_makecontext(instance, window);
  1661.     if (!cx)
  1662.         return NPERR_OUT_OF_MEMORY_ERROR;
  1663.  
  1664.  
  1665.     /*
  1666.      * Make a bogus URL struct.  The URL doesn't point to
  1667.      * anything, but we need it to build the stream.
  1668.      */
  1669.     urls = NET_CreateURLStruct("", NET_DONT_RELOAD);
  1670.     if (!urls)
  1671.         return NPERR_OUT_OF_MEMORY_ERROR;
  1672.     StrAllocCopy(urls->content_type, type);
  1673.     
  1674.     /* Make a netlib stream */
  1675.     netstream = NET_StreamBuilder(FO_PRESENT, urls, cx);
  1676.     if (!netstream)
  1677.     {
  1678.         NET_FreeURLStruct(urls);
  1679.         return NPERR_OUT_OF_MEMORY_ERROR;
  1680.     }
  1681.     
  1682.     /* Make the plug-in stream objects */
  1683.     stream = np_makestreamobjects(instance, netstream, urls);
  1684.     if (!stream)
  1685.     {
  1686.         XP_FREE(netstream);
  1687.         NET_FreeURLStruct(urls);
  1688.         return NPERR_OUT_OF_MEMORY_ERROR;
  1689.     }
  1690.  
  1691.     *pstream = stream->pstream;
  1692.     return NPERR_NO_ERROR;
  1693. }
  1694.  
  1695.  
  1696. int32 NP_EXPORT
  1697. npn_write(NPP npp, NPStream *pstream, int32 len, void *buffer)
  1698. {
  1699.     np_instance* instance;
  1700.     np_stream* stream;
  1701.     NET_StreamClass* netstream;
  1702.     
  1703.     if (!npp || !pstream || !buffer || len<0)
  1704.         return NPERR_INVALID_PARAM;
  1705.  
  1706.     instance = (np_instance*) npp->ndata;
  1707.     stream = (np_stream*) pstream->ndata;
  1708.  
  1709.     if (!instance || !stream)
  1710.         return NPERR_INVALID_PARAM;
  1711.     
  1712.     netstream = stream->nstream;
  1713.     if (!netstream)
  1714.         return NPERR_INVALID_PARAM;
  1715.         
  1716.     return (*netstream->put_block)(netstream, (const char*) buffer, len);
  1717. }
  1718.  
  1719. NPError NP_EXPORT
  1720. npn_destroystream(NPP npp, NPStream *pstream, NPError reason)
  1721. {
  1722.     np_instance* instance;
  1723.     np_stream* stream;
  1724.     NET_StreamClass* netstream;
  1725.     URL_Struct* urls = NULL;
  1726.     
  1727.     if (!npp || !pstream)
  1728.         return NPERR_INVALID_PARAM;
  1729.  
  1730.     instance = (np_instance*) npp->ndata;
  1731.     stream = (np_stream*) pstream->ndata;
  1732.  
  1733.     if (!instance || !stream)
  1734.         return NPERR_INVALID_PARAM;
  1735.     
  1736.     netstream = stream->nstream;
  1737.     if (netstream)
  1738.         urls = (URL_Struct*) netstream->data_object;
  1739.     
  1740.     /*
  1741.      * If we still have a valid netlib stream, ask netlib
  1742.      * to destroy it (it will call us back to inform the
  1743.      * plug-in and delete the plug-in-specific objects).
  1744.      * If we don't have a netlib stream (possible if the
  1745.      * stream was in NP_SEEK mode: the netlib stream might
  1746.      * have been deleted but we would keep the plug-in 
  1747.      * stream around because stream->dontclose was TRUE),
  1748.      * just inform the plug-in and delete our objects.
  1749.      */
  1750.     stream->dontclose = FALSE;        /* Make sure we really delete */
  1751.     if (urls)
  1752.     {
  1753.         if (NET_InterruptStream(urls) < 0)
  1754.         {
  1755.             /* Netlib doesn't know about this stream; we must have made it */
  1756.             /*MWContext* cx = netstream->window_id;*/
  1757.             switch (reason)
  1758.             {
  1759.                 case NPRES_DONE:
  1760.                     (*netstream->complete)(netstream);
  1761.                     break;
  1762.                 case NPRES_USER_BREAK:
  1763.                     (*netstream->abort)(netstream, MK_INTERRUPTED);
  1764.                     break;
  1765.                 case NPRES_NETWORK_ERR:
  1766.                     (*netstream->abort)(netstream, MK_BAD_CONNECT);
  1767.                     break;
  1768.                 default:            /* Unknown reason code */
  1769.                     (*netstream->abort)(netstream, -1);    
  1770.                     break;
  1771.             }
  1772.             np_destroystream(stream, reason);
  1773.             XP_FREE(netstream);
  1774.         }
  1775.     }
  1776.     else
  1777.         np_destroystream(stream, reason);
  1778.     
  1779. /*
  1780.  * We still need a way to pass the right status code
  1781.  * through to NPL_Abort (NET_InterruptStream doesn't
  1782.  * take a status code, so the plug-in always gets
  1783.  * NPRES_USER_BREAK, not what they passed in here).
  1784.  */
  1785.     return NPERR_NO_ERROR;
  1786. }
  1787.  
  1788.  
  1789. void NP_EXPORT
  1790. npn_status(NPP npp, const char *message)
  1791. {
  1792.     if(npp)
  1793.     {
  1794.         np_instance *instance = (np_instance *)npp->ndata;
  1795.         if(instance && instance->cx)
  1796. #ifdef XP_MAC
  1797.             /* Special entry point so MacFE can save/restore port state */
  1798.             FE_PluginProgress(instance->cx, message);
  1799. #else
  1800.             FE_Progress(instance->cx, message);
  1801. #endif
  1802.     }
  1803. }
  1804.  
  1805. #if defined(XP_MAC) && !defined(powerc)
  1806. #pragma pointers_in_D0
  1807. #endif
  1808. const char * NP_EXPORT
  1809. npn_useragent(NPP npp)
  1810. {
  1811.     static char *uabuf = 0;
  1812.     if(!uabuf)
  1813.         uabuf = PR_smprintf("%.100s/%.90s", XP_AppCodeName, XP_AppVersion);
  1814.     return (const char *)uabuf;
  1815. }
  1816. #if defined(XP_MAC) && !defined(powerc)
  1817. #pragma pointers_in_A0
  1818. #endif
  1819.  
  1820.  
  1821. #if defined(XP_MAC) && !defined(powerc)
  1822. #pragma pointers_in_D0
  1823. #endif
  1824. void * NP_EXPORT
  1825. npn_memalloc (uint32 size)
  1826. {
  1827.     return XP_ALLOC(size);
  1828. }
  1829. #if defined(XP_MAC) && !defined(powerc)
  1830. #pragma pointers_in_A0
  1831. #endif
  1832.  
  1833.  
  1834. void NP_EXPORT
  1835. npn_memfree (void *ptr)
  1836. {
  1837.     (void)XP_FREE(ptr);
  1838. }
  1839.  
  1840. #ifdef XP_MAC
  1841. /* For the definition of CallCacheFlushers() */
  1842. #ifndef NSPR20
  1843. #include "prmacos.h"
  1844. #else
  1845. #include "MacMemAllocator.h"
  1846. #endif
  1847. #endif
  1848.  
  1849. uint32 NP_EXPORT
  1850. npn_memflush(uint32 size)
  1851. {
  1852. #ifdef XP_MAC
  1853.     /* Try to free some memory and return the amount we freed. */
  1854.     if (CallCacheFlushers(size))
  1855.         return size;
  1856.     else
  1857. #endif
  1858.     return 0;
  1859. }
  1860.  
  1861.  
  1862.  
  1863.  
  1864. /*
  1865.  * Given an instance, switch its handler from whatever it 
  1866.  * currently is to the handler passed in.  Assuming the new
  1867.  * handler really is different, to do this we need to destroy
  1868.  * the current NPP instance (so the old plug-in's out of the
  1869.  * picture), then make a new NPP with the new handler
  1870.  */
  1871. NPError
  1872. np_switchHandlers(np_instance* instance,
  1873.                   np_handle* newHandle,
  1874.                   np_mimetype* newMimeType,
  1875.                   char* requestedType)
  1876. {
  1877.     NPEmbeddedApp* app = instance->app;
  1878.     MWContext* cx = instance->cx;
  1879.     np_data* ndata = (np_data*) app->np_data;
  1880.     
  1881.     if (app == NULL || cx == NULL || ndata == NULL)
  1882.         return NPERR_INVALID_PARAM;
  1883.         
  1884.     /*
  1885.      * If it's a full-page plug-in, just reload the document.
  1886.      * We have to reload the data anyway to send it to the
  1887.      * new instance, and since the instance is the only thing
  1888.      * on the page it's easier to just reload the whole thing.
  1889.      * NOTE: This case shouldn't ever happen, since you can't
  1890.      * have full-page Default plug-ins currently.
  1891.      */
  1892.     XP_ASSERT(app->pagePluginType != NP_FullPage);
  1893.     if (app->pagePluginType == NP_FullPage)
  1894.     {
  1895.         History_entry* history = SHIST_GetCurrent(&cx->hist);
  1896.         URL_Struct* urls = SHIST_CreateURLStructFromHistoryEntry(cx, history);
  1897.         if (urls != NULL)
  1898.         {
  1899.             urls->force_reload = NET_NORMAL_RELOAD;
  1900.             FE_GetURL(cx, urls);
  1901.             return NPERR_NO_ERROR;
  1902.         }
  1903.         else
  1904.             return NPERR_GENERIC_ERROR;
  1905.     }
  1906.     
  1907.     /* Nuke the old instance */
  1908.     np_delete_instance(instance);
  1909.     if (ndata != NULL && ndata->instance == instance)
  1910.         ndata->instance = NULL;
  1911.     
  1912.     /* Make a new instance */
  1913.     ndata->instance = np_newinstance(newHandle, cx, app, newMimeType, requestedType);
  1914.     NPL_EmbedSize(app);
  1915.  
  1916.     if (ndata->instance == NULL)
  1917.         return NPERR_GENERIC_ERROR;
  1918.         
  1919.     /* Get the data stream for the new instance, if necessary */
  1920.     if (ndata->lo_struct->embed_src != NULL)
  1921.     {
  1922.         char* address;
  1923.         URL_Struct* urls;    
  1924.         
  1925.         PA_LOCK(address, char*, ndata->lo_struct->embed_src);
  1926.         XP_ASSERT(address);
  1927.  
  1928.         urls = NET_CreateURLStruct(address, NET_DONT_RELOAD);
  1929.          
  1930.         PA_UNLOCK(ndata->lo_struct->embed_src); 
  1931.        
  1932.         if (urls != NULL)
  1933.         {
  1934.             urls->fe_data = (void*) app;
  1935.             (void) NET_GetURL(urls, FO_CACHE_AND_EMBED, cx, NPL_EmbedURLExit);
  1936.             return NPERR_NO_ERROR;
  1937.         }
  1938.         else
  1939.             return NPERR_GENERIC_ERROR;
  1940.     }
  1941.     
  1942.     return NPERR_NO_ERROR;
  1943. }
  1944.  
  1945.  
  1946.  
  1947. /*
  1948.  * Ask the FE to throw away its old plugin handlers and
  1949.  * re-scan the plugins folder to find new ones.  This function
  1950.  * is intended for use by the null plugin to signal that
  1951.  * some new plugin has been installed and we should make a
  1952.  * note of it.  If "reloadPages" is true, we should also
  1953.  * reload all open pages with plugins on them (since plugin
  1954.  * handlers could have come or gone as a result of the re-
  1955.  * registration).
  1956.  */
  1957. void NP_EXPORT
  1958. npn_reloadplugins(NPBool reloadPages)
  1959. {
  1960.     np_handle* oldHead = NULL;
  1961.  
  1962.     /*
  1963.      * We won't unregister old plug-ins, we just register new ones.
  1964.      * The new plug-ins will go on the front of the list, so to see
  1965.      * if we got any new ones we just need to save a pointer to the
  1966.      * current front of the list.
  1967.      */
  1968.     if (reloadPages)
  1969.         oldHead = np_plist;
  1970.     
  1971.     /* Ask the FE to load new plug-ins */
  1972.     FE_RegisterPlugins();
  1973.      
  1974.     /*
  1975.      * At least one plug-in was added to the front of the list.
  1976.      * Now we need to find all instances of the default plug-in
  1977.      * to see if they can be handled by one of the new plug-ins.
  1978.      */
  1979.     if (reloadPages && oldHead != np_plist)
  1980.     {
  1981.         np_handle* defaultPlugin = np_plist;
  1982.         np_instance* instance;
  1983.         
  1984.         /* First look for the default plug-in */
  1985.         while (defaultPlugin != NULL)
  1986.         {
  1987.             if (defaultPlugin->mimetypes != NULL &&
  1988.                 defaultPlugin->mimetypes->type &&
  1989.                 XP_STRCMP(defaultPlugin->mimetypes->type, "*") == 0)
  1990.             {
  1991.                 break;
  1992.             }
  1993.             defaultPlugin = defaultPlugin->next;
  1994.         }
  1995.         
  1996.         if (defaultPlugin == NULL)
  1997.             return;
  1998.         
  1999.         /* Found the default plug-in; now check its instances */
  2000.         instance = defaultPlugin->instances;
  2001.         while (instance != NULL)
  2002.         {
  2003.             NPBool switchedHandler = FALSE;
  2004.             char* type = instance->typeString;
  2005.             XP_ASSERT(instance->mimetype == defaultPlugin->mimetypes);
  2006.             
  2007.             if (type != NULL)
  2008.             {
  2009.                 /*
  2010.                  * Try to match this instance's type against the
  2011.                  * types of all new plug-ins to see if any of them
  2012.                  * can handle it.  Since the new plug-is were added
  2013.                  * to the front of the list, we only need to look
  2014.                  * at plug-ins up to the old head of the list. 
  2015.                  */
  2016.                 np_handle* handle = np_plist;
  2017.                 while (handle != NULL && handle != oldHead)
  2018.                 {
  2019.                     np_mimetype* mimeType;
  2020.                     XP_ASSERT(handle != defaultPlugin);
  2021.                     mimeType = np_getmimetype(handle, type, FALSE);
  2022.                     
  2023.                     /* 
  2024.                      * We found a new handler for this type! Now we
  2025.                      * can destroy the plug-in instance and make a
  2026.                      * new instance handled by the new plug-in.
  2027.                      * Note that we have to point "instance" to the
  2028.                      * next object NOW, because np_switchHandlers
  2029.                      * will remove it from the list.
  2030.                      */
  2031.                     if (mimeType != NULL)
  2032.                     {
  2033.                         np_instance* switcher = instance;
  2034.                         instance = instance->next;
  2035.                         (void) np_switchHandlers(switcher, handle, mimeType, type);
  2036.                         switchedHandler = TRUE;
  2037.                         break;    /* Out of handle "while" loop */
  2038.                     }
  2039.                     
  2040.                     handle = handle->next;
  2041.                 }
  2042.             }
  2043.             
  2044.             /*
  2045.              * In the case where we switch the handler (above), 
  2046.              * "instance" already points to the next object.
  2047.              */
  2048.             if (!switchedHandler)
  2049.                 instance = instance->next;
  2050.         }
  2051.     }
  2052. }
  2053.  
  2054.  
  2055. NPError
  2056. NPL_RefreshPluginList(XP_Bool reloadPages)
  2057. {
  2058.     npn_reloadplugins(reloadPages);
  2059.     return NPERR_NO_ERROR;        /* Always succeeds for now */
  2060. }
  2061.  
  2062.  
  2063. void NP_EXPORT
  2064. npn_invalidaterect(NPP npp, NPRect *invalidRect)
  2065. {
  2066.     np_instance* instance = NULL;
  2067.     XP_Rect rect;
  2068.  
  2069.     if (npp != NULL) {
  2070.         instance = (np_instance*) npp->ndata;
  2071.     }
  2072.     
  2073.     if (instance && !instance->windowed) {
  2074.         rect.left = invalidRect->left;
  2075.         rect.top = invalidRect->top;
  2076.         rect.right = invalidRect->right;
  2077.         rect.bottom = invalidRect->bottom;
  2078.         
  2079.         CL_UpdateLayerRect(CL_GetLayerCompositor(instance->layer),
  2080.                            instance->layer, &rect, PR_FALSE);
  2081.     }
  2082. }
  2083.  
  2084. void NP_EXPORT
  2085. npn_invalidateregion(NPP npp, NPRegion invalidRegion)
  2086. {
  2087.     np_instance* instance = NULL;
  2088.  
  2089.     if (npp != NULL) {
  2090.         instance = (np_instance*) npp->ndata;
  2091.     }
  2092.     
  2093.     if (instance && !instance->windowed) {
  2094.         CL_UpdateLayerRegion(CL_GetLayerCompositor(instance->layer),
  2095.                              instance->layer, invalidRegion, PR_FALSE);
  2096.     }
  2097. }
  2098.  
  2099. void NP_EXPORT
  2100. npn_forceredraw(NPP npp)
  2101. {
  2102.     np_instance* instance = NULL;
  2103.  
  2104.     if (npp != NULL) {
  2105.         instance = (np_instance*) npp->ndata;
  2106.     }
  2107.     
  2108.     if (instance && !instance->windowed) {
  2109.         CL_CompositeNow(CL_GetLayerCompositor(instance->layer));
  2110.     }
  2111. }
  2112.  
  2113. /******************************************************************************/
  2114.  
  2115. #ifdef JAVA
  2116. #define JRI_NO_CPLUSPLUS
  2117. #define IMPLEMENT_netscape_plugin_Plugin
  2118. #include "netscape_plugin_Plugin.h"
  2119. #ifdef MOCHA
  2120. #include "libmocha.h"
  2121. #endif /* MOCHA */
  2122. #endif /* JAVA */
  2123.  
  2124. #if defined(XP_MAC) && !defined(powerc)
  2125. #pragma pointers_in_D0
  2126. #endif
  2127. JRIEnv* NP_EXPORT
  2128. npn_getJavaEnv(void)
  2129. {
  2130. #ifdef JAVA
  2131.     JRIEnv* env;
  2132.  
  2133. #ifdef    XP_MAC
  2134.     short resNum1, resNum2;
  2135.     resNum1 = CurResFile();
  2136. #endif /* XP_MAC */ 
  2137.  
  2138.     env = LJ_EnsureJavaEnv(NULL); /* NULL means for the current thread */
  2139.  
  2140. #ifdef    XP_MAC
  2141.     /* if Java changed the res file, change it back to the plugin's res file */
  2142.     resNum2 = CurResFile();
  2143.     if(resNum1 != resNum2)
  2144.         UseResFile(resNum1);
  2145. #endif  /* XP_MAC */ 
  2146.  
  2147.     return env;
  2148. #else /* JAVA */
  2149.     return NULL;
  2150. #endif /* JAVA */
  2151. }
  2152. #if defined(XP_MAC) && !defined(powerc)
  2153. #pragma pointers_in_A0
  2154. #endif
  2155.  
  2156. #ifdef JAVA
  2157. void
  2158. np_recover_mochaWindow(JRIEnv * env, np_instance * instance)
  2159. {
  2160.      netscape_plugin_Plugin* javaInstance = NULL;
  2161.  
  2162.      if (env && instance && instance->mochaWindow && instance->javaInstance){
  2163.          javaInstance = (struct netscape_plugin_Plugin *)
  2164.               JRI_GetGlobalRef(env, instance->javaInstance);
  2165.          if (javaInstance)  {
  2166.              /* Store the JavaScript context as the window object: */
  2167.             set_netscape_plugin_Plugin_window(env, javaInstance, 
  2168.                                               (netscape_javascript_JSObject*)
  2169.                                               JRI_GetGlobalRef(env, instance->mochaWindow));
  2170.          }        
  2171.      }
  2172. }
  2173.  
  2174. #define NPN_NO_JAVA_INSTANCE    ((jglobal)-1)
  2175.  
  2176. jglobal classPlugin = NULL;
  2177.  
  2178. #endif // JAVA
  2179.  
  2180. extern void
  2181. ET_SetPluginWindow(MWContext *cx, void *instance);
  2182.  
  2183. NS_DEFINE_IID(kLiveConnectPluginIID, NP_ILIVECONNECTPLUGIN_IID);
  2184.  
  2185. #if defined(XP_MAC) && !defined(powerc)
  2186. #pragma pointers_in_D0
  2187. #endif
  2188.  
  2189. struct java_lang_Class* NP_EXPORT
  2190. npn_getJavaClass(np_handle* handle)
  2191. {
  2192. #ifdef JAVA
  2193.     if (handle->userPlugin) {
  2194.         NPIPlugin* userPluginClass = (NPIPlugin*)handle->userPlugin;
  2195.         NPILiveConnectPlugin* lcPlugin;
  2196.         if (userPluginClass->QueryInterface(kLiveConnectPluginIID,
  2197.                                             (void**)&lcPlugin) != NS_NOINTERFACE) {
  2198.             java_lang_Class* clazz = (java_lang_Class*)lcPlugin->GetJavaClass();
  2199.  
  2200.             // Remember, QueryInterface increments the ref count;
  2201.             // since we're done with it in this scope, release it.
  2202.             lcPlugin->Release();
  2203.  
  2204.             return clazz;
  2205.         }
  2206.         return NULL;    // not a LiveConnected plugin
  2207.     }
  2208.     else if (handle && handle->f) {
  2209.         JRIEnv* env = npn_getJavaEnv();        /* may start up the java runtime */
  2210.         if (env == NULL) return NULL;
  2211.         return (java_lang_Class*)JRI_GetGlobalRef(env, handle->f->javaClass);
  2212.     }
  2213. #endif
  2214.     return NULL;
  2215. }
  2216.  
  2217. jref NP_EXPORT
  2218. npn_getJavaPeer(NPP npp)
  2219. {
  2220. #ifdef JAVA
  2221.     netscape_plugin_Plugin* javaInstance = NULL;
  2222.     np_instance* instance;
  2223.  
  2224.     if (npp == NULL)
  2225.         return NULL;
  2226.     instance = (np_instance*) npp->ndata;
  2227.     if (instance == NULL) return NULL;
  2228.  
  2229.     if (instance->javaInstance == NPN_NO_JAVA_INSTANCE) {
  2230.         /* Been there, done that. */
  2231.         return NULL;
  2232.     }
  2233.     else if (instance->javaInstance != NULL) {
  2234.         /*
  2235.         ** It's ok to get the JRIEnv here -- it won't initialize the
  2236.         ** runtime because it would have already been initialized to
  2237.         ** create the instance that we're just about to return.
  2238.         */
  2239.  
  2240.         /* But first, see if we need to recover the mochaWindow... */
  2241.         np_recover_mochaWindow(npn_getJavaEnv(),instance);
  2242.  
  2243.         return (jref)JRI_GetGlobalRef(npn_getJavaEnv(), instance->javaInstance);
  2244.     }
  2245.     else {
  2246.         struct java_lang_Class* clazz = npn_getJavaClass(instance->handle);
  2247.         if (clazz) {
  2248.             JRIEnv* env = npn_getJavaEnv();        /* may start up the java runtime */
  2249.             if (classPlugin == NULL) {
  2250.                 /*
  2251.                 ** Make sure we never unload the Plugin class. Why? Because
  2252.                 ** the method and field IDs we're using below have the same
  2253.                 ** lifetime as the class (theoretically):
  2254.                 */
  2255.                 classPlugin = JRI_NewGlobalRef(env, use_netscape_plugin_Plugin(env));
  2256.             }
  2257.  
  2258.             /* instantiate the plugin's class: */
  2259.             javaInstance = netscape_plugin_Plugin_new(env, clazz);
  2260.             if (javaInstance) {
  2261.  
  2262.                  instance->javaInstance = JRI_NewGlobalRef(env, javaInstance);
  2263.  
  2264.                 np_recover_mochaWindow(env,instance);
  2265.  
  2266.                 /* Store the plugin as the peer: */
  2267.                 set_netscape_plugin_Plugin_peer(env, javaInstance, (jint)instance->npp); 
  2268.  
  2269.  
  2270.                 netscape_plugin_Plugin_init(env, javaInstance);
  2271.             }
  2272.         }
  2273.         else {
  2274.             instance->javaInstance = NPN_NO_JAVA_INSTANCE;        /* prevent trying this every time around */
  2275.             return NULL;
  2276.         }
  2277.     }
  2278.     return (jref)javaInstance;
  2279. #else
  2280.     return NULL;
  2281. #endif
  2282. }
  2283. #if defined(XP_MAC) && !defined(powerc)
  2284. #pragma pointers_in_A0
  2285. #endif
  2286.  
  2287. static XP_Bool
  2288. np_IsLiveConnected(np_handle* handle)
  2289. {
  2290.     if (handle->userPlugin) {
  2291.         NPIPlugin* userPluginClass = (NPIPlugin*)handle->userPlugin;
  2292.         NPILiveConnectPlugin* lcPlugin;
  2293.  
  2294.         if (userPluginClass->QueryInterface(kLiveConnectPluginIID,
  2295.                                             (void**)&lcPlugin) != NS_NOINTERFACE) {
  2296.             // Remember, QueryInterface increments the ref count;
  2297.             // since we're done with it in this scope, release it.
  2298.             lcPlugin->Release();
  2299.  
  2300.             return TRUE;
  2301.         } else {
  2302.             return FALSE;
  2303.         }
  2304.     }
  2305.     else {
  2306.         return npn_getJavaClass(handle) != NULL;
  2307.     }
  2308. }
  2309.  
  2310. /* Is the plugin associated with this embedStruct liveconnected? */
  2311. XP_Bool NPL_IsLiveConnected(LO_EmbedStruct *embed)
  2312. {
  2313. #ifdef JAVA
  2314.     NPEmbeddedApp* app;
  2315.     np_data* ndata;
  2316.  
  2317.     if (embed == NULL)
  2318.         return FALSE;
  2319.  
  2320.     app = (NPEmbeddedApp*) embed->FE_Data;
  2321.     if (app == NULL)
  2322.         return FALSE;
  2323.  
  2324.     ndata = (np_data*) app->np_data;
  2325.     XP_ASSERT(ndata);
  2326.     return np_IsLiveConnected(ndata->instance->handle);
  2327. #else
  2328.     return FALSE; 
  2329. #endif
  2330. }
  2331.  
  2332.  
  2333.  
  2334. /******************************************************************************/
  2335.  
  2336.  
  2337.  
  2338. static void
  2339. np_setwindow(np_instance *instance, NPWindow *appWin)
  2340. {
  2341.     /*
  2342.      * On Windows and UNIX, we don't want to give a window
  2343.      * to hidden plug-ins.  To determine if we're hidden,
  2344.      * we can look at the flag bit of the LO_EmbedStruct.
  2345.      */
  2346.     NPEmbeddedApp* app;
  2347.     np_data* ndata;
  2348.     LO_EmbedStruct* lo_struct;
  2349.     
  2350.     if (instance)
  2351.     {
  2352.         app = instance->app;
  2353.         if (app)
  2354.         {
  2355.             ndata = (np_data*) app->np_data;
  2356.             lo_struct = ndata->lo_struct;
  2357. #ifndef XP_MAC
  2358.             if (lo_struct && lo_struct->ele_attrmask & LO_ELE_HIDDEN)
  2359.                 return;
  2360. #endif
  2361.                 
  2362.         }
  2363.     }
  2364.  
  2365.     XP_ASSERT(instance);
  2366.     if (instance && appWin)
  2367.     {
  2368.         TRACEMSG(("npglue.c: CallNPP_SetWindowProc"));
  2369.         if (instance->handle->userPlugin) {
  2370.             nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)instance->npp->pdata;
  2371.             NPIPluginInstance* userInst = peerInst->GetUserInstance();
  2372.             userInst->SetWindow((NPPluginWindow*)appWin);
  2373.  
  2374.             // If this is the first time we're drawing this, then call
  2375.             // the plugin's Start() method.
  2376.             if (lo_struct && ! (lo_struct->ele_attrmask & LO_ELE_DRAWN))
  2377.                 userInst->Start();
  2378.         }
  2379.         else if (ISFUNCPTR(instance->handle->f->setwindow)) {
  2380.             CallNPP_SetWindowProc(instance->handle->f->setwindow, instance->npp, appWin);
  2381.         }
  2382.     }
  2383.     else
  2384.     {
  2385.         NPTRACE(0,("setwindow before appWin was valid"));
  2386.     }
  2387. }
  2388.  
  2389. static void
  2390. np_UnloadPluginClass(np_handle *handle)
  2391. {
  2392.     /* only called when we truly want to dispose the plugin class */
  2393.     XP_ASSERT(handle && handle->refs == 0);
  2394.  
  2395. #ifdef JAVA 
  2396.     if (handle->userPlugin == NULL && handle->f && handle->f->javaClass != NULL) {
  2397.         /* Don't get the environment unless there is a Java class,
  2398.            because this would cause the java runtime to start up. */
  2399.         JRIEnv* env = npn_getJavaEnv();
  2400.         JRI_DisposeGlobalRef(env, handle->f->javaClass);
  2401.         handle->f->javaClass = NULL;
  2402.     }
  2403. #endif /* JAVA */ 
  2404.  
  2405.     FE_UnloadPlugin(handle->pdesc, handle);
  2406.     handle->f = NULL;
  2407.  
  2408.     XP_ASSERT(handle->instances == NULL);
  2409.     handle->instances = NULL;
  2410. }
  2411.  
  2412.  
  2413. /* this is called from the mocha thread to set the mocha window,
  2414. * in response to getJavaPeer */
  2415. PR_IMPLEMENT(void)
  2416. NPL_SetPluginWindow(void *data)
  2417. {
  2418.      JRIEnv * env = NULL;
  2419.      np_instance *instance = (np_instance *) data;
  2420.      struct netscape_javascript_JSObject *mochaWindow = NULL;
  2421.  
  2422.      if (instance && instance->cx)
  2423.         mochaWindow = LJ_GetMochaWindow(instance->cx);
  2424.  
  2425. #ifdef JAVA
  2426.      env = LJ_EnsureJavaEnv(PR_CurrentThread());
  2427.  
  2428.      if (mochaWindow){
  2429.          instance->mochaWindow = JRI_NewGlobalRef(env, (jref) mochaWindow);
  2430.  
  2431.          /* That's done, now stuff it in */
  2432.           np_recover_mochaWindow(env,instance);
  2433.      }
  2434. #endif
  2435. }
  2436.  
  2437.  
  2438. np_instance*
  2439. np_newinstance(np_handle *handle, MWContext *cx, NPEmbeddedApp *app,
  2440.                np_mimetype *mimetype, char *requestedType)
  2441. {
  2442.     NPError err = NPERR_GENERIC_ERROR;
  2443.     np_instance* instance = NULL;
  2444.     NPP npp = NULL;
  2445.     void* tmp;
  2446.     np_data* ndata;
  2447.        
  2448.     XP_ASSERT(handle && app);
  2449.     if (!handle || !app)
  2450.         return NULL;
  2451.  
  2452.     /* make sure the plugin is loaded */
  2453.     if (!handle->refs)
  2454.     {
  2455. #ifdef JAVA
  2456.         JRIEnv* env = NULL;
  2457. #endif
  2458.         FE_Progress(cx, XP_GetString(XP_PLUGIN_LOADING_PLUGIN));               
  2459.         if (!(handle->f = FE_LoadPlugin(handle->pdesc, &npp_funcs, handle))) 
  2460.         {
  2461.             char* msg = PR_smprintf(XP_GetString(XP_PLUGIN_CANT_LOAD_PLUGIN), handle->name, mimetype->type);
  2462.             FE_Alert(cx, msg);
  2463.             XP_FREE(msg);
  2464.             return NULL;
  2465.         }
  2466. #ifdef JAVA
  2467.         /*
  2468.         ** Don't use npn_getJavaEnv here. We don't want to start the
  2469.         ** interpreter, just use env if it already exists.
  2470.         */
  2471.         env = JRI_GetCurrentEnv();
  2472.  
  2473.         /*
  2474.         ** An exception could have occurred when the plugin tried to load
  2475.         ** it's class file. We'll print any exception to the console.
  2476.         */
  2477.         if (env && JRI_ExceptionOccurred(env)) {
  2478.             JRI_ExceptionDescribe(env);
  2479.             JRI_ExceptionClear(env);
  2480.         }
  2481. #endif
  2482.     }
  2483.  
  2484.     ndata = (np_data*) app->np_data;
  2485.     NPSavedData* savedData = (NPSavedData*) (ndata ? ndata->sdata : NULL);
  2486.         
  2487.     if (handle->userPlugin == NULL || savedData == NULL) {
  2488.         // Then we're either an old style plugin that needs to get
  2489.         // (re)created, or a new style plugin that hasn't yet saved
  2490.         // its data, so it needs to get created the first time.
  2491.  
  2492.         /* make an instance */
  2493.         if (!(instance = XP_NEW_ZAP(np_instance)))
  2494.             goto error;
  2495.  
  2496.         instance->handle = handle;
  2497.         instance->cx = cx;
  2498.         instance->app = app;
  2499.         instance->mimetype = mimetype;
  2500.         instance->type = (app->pagePluginType == NP_FullPage) ? NP_FULL : NP_EMBED;
  2501.         instance->typeString = (char*) (requestedType ? XP_STRDUP(requestedType) : NULL);
  2502.  
  2503.         instance->mochaWindow = NULL;
  2504.         instance->javaInstance = NULL;
  2505.  
  2506.         app->type = NP_Plugin;
  2507.     
  2508.         /* make an NPP */
  2509.         if (!(tmp = XP_NEW_ZAP(NPP_t)))
  2510.             goto error;
  2511.         npp = (NPP) tmp;             /* make pc compiler happy */
  2512.         npp->ndata = instance;
  2513.         instance->npp = npp;
  2514.         instance->windowed = TRUE;
  2515.         instance->transparent = FALSE;
  2516.  
  2517. #ifdef LAYERS
  2518.         if (ndata)
  2519.             instance->layer = ndata->lo_struct->layer;
  2520. #endif /* LAYERS */
  2521.  
  2522.         /* invite the plugin */
  2523.         TRACEMSG(("npglue.c: CallNPP_NewProc"));
  2524.         if (handle->userPlugin) {
  2525.             NPIPlugin* userPluginClass = (NPIPlugin*)handle->userPlugin;
  2526.             nsPluginInstancePeer* peerInst = new nsPluginInstancePeer(npp);
  2527.             if (peerInst == NULL) {
  2528.                 err = NPERR_OUT_OF_MEMORY_ERROR;
  2529.             }
  2530.             else {
  2531.                 peerInst->AddRef();
  2532.                 NPIPluginInstance* userInst;
  2533.                 NPPluginError err2 = userPluginClass->NewInstance(peerInst, &userInst);
  2534.                 if (err2 == NPPluginError_NoError && userInst != NULL) {
  2535.                     npp->pdata = peerInst;
  2536.                     peerInst->SetUserInstance(userInst);
  2537.                     ndata->sdata = (NPSavedData*)userInst;
  2538.                     err = NPERR_NO_ERROR;
  2539.                 }
  2540.                 else
  2541.                     err = NPERR_INVALID_INSTANCE_ERROR;
  2542.             }
  2543.         }
  2544.         else {
  2545.             if (ISFUNCPTR(handle->f->newp))
  2546.             {
  2547.                 XP_ASSERT(ndata);
  2548.                 if (instance->type == NP_EMBED)
  2549.                 {
  2550.                     /* Embedded plug-ins get their attributes passed in from layout */
  2551.                     int16 argc = (int16) ndata->lo_struct->attribute_cnt;
  2552.                     char** names = ndata->lo_struct->attribute_list;
  2553.                     char** values = ndata->lo_struct->value_list;
  2554.  
  2555.                     err = CallNPP_NewProc(handle->f->newp, requestedType, npp, 
  2556.                                           instance->type, argc, names, values, savedData);
  2557.                 }
  2558.                 else
  2559.                 {
  2560.                     /* A full-page plugin must be told its palette may
  2561.                        be realized as a foreground palette */ 
  2562.                     char name[] = "PALETTE";
  2563.                     char value[] = "foreground";
  2564.                     char* names[1];
  2565.                     char* values[1];
  2566.                     int16 argc = 1;
  2567.                     names[0] = name;
  2568.                     values[0] = value;
  2569.  
  2570.                     err = CallNPP_NewProc(handle->f->newp, requestedType, npp, 
  2571.                                           instance->type, argc, names, values, savedData);
  2572.                 }
  2573.             }
  2574.         }
  2575.         if (err != NPERR_NO_ERROR)
  2576.             goto error;
  2577.     
  2578.         /* add this to the handle chain */
  2579.         instance->next = handle->instances;
  2580.         handle->instances = instance;
  2581.         handle->refs++;
  2582.  
  2583.         /*
  2584.          * In the full-page case, FE_DisplayEmbed hasn't been called yet, 
  2585.          * so the window hasn't been created and wdata is still NULL.
  2586.          * We don't want to give the plug-in a NULL window.
  2587.          * N.B.: Actually, on the Mac, the window HAS been created (we
  2588.          * need it because even undisplayed/hidden plug-ins may need a
  2589.          * window), so wdata is not NULL; that's why we check the plug-in
  2590.          * type rather than wdata here.
  2591.          */
  2592. #ifndef LAYERS
  2593.         /* 
  2594.          * We don't know that layout has set the final position of the plug-in at this
  2595.          * point. The danger is that the plug-in will draw into the window incorrectly
  2596.          * with this call. With layers, we don't display the window until layout
  2597.          * is completely done - at that we can call NPP_SetWindow.
  2598.          */
  2599.         if (app->pagePluginType == NP_Embedded)
  2600.         {
  2601.             XP_ASSERT(app->wdata);
  2602.             np_setwindow(instance, app->wdata);
  2603.         }
  2604. #endif
  2605.     }
  2606.  
  2607.     /* XXX This is _not_ where Start() should go (IMO). Start() should be
  2608.        called whenever we re-visit an applet
  2609.  
  2610.     // Finally, if it's a 5.0-style (C++) plugin, send it the Start message.
  2611.     // Do this before sending the mocha OnLoad message.
  2612.     if (handle->userPlugin && ndata->sdata) {
  2613.         NPIPluginInstance* userInst = (NPIPluginInstance*)ndata->sdata;
  2614.         NPPluginError err = userInst->Start();
  2615.         if (err != NPPluginError_NoError) goto error;
  2616.     }
  2617.     */
  2618.  
  2619. #ifdef MOCHA
  2620.     {
  2621.         /* only wait on applets if onload flag */
  2622.         lo_TopState *top_state = lo_FetchTopState(XP_DOCID(cx));
  2623.         if (top_state != NULL && top_state->mocha_loading_embeds_count)
  2624.         {
  2625.             top_state->mocha_loading_embeds_count--;
  2626.             ET_SendLoadEvent(cx, EVENT_XFER_DONE, NULL, NULL, 
  2627.                              LO_DOCUMENT_LAYER_ID, FALSE);
  2628.         }
  2629.  
  2630.         /* tell the mocha thread to set us up with the window when it can */
  2631.         if (
  2632. #if 0
  2633.             // XXX This is what we really want here, because it doesn't actually
  2634.             // start up the jvm, it just checks that the plugin is LiveConnected.
  2635.             // The problem is that by deferring the jvm startup, we cause it to 
  2636.             // happen later on the wrong thread. 
  2637.             np_IsLiveConnected(handle)
  2638. #else
  2639.             npn_getJavaClass(handle)           
  2640. #endif
  2641.             ) { /*  for liveconnected plugins only */
  2642.             ET_SetPluginWindow(cx, (void *)instance);
  2643.         }
  2644.     }
  2645. #endif /* MOCHA */
  2646.  
  2647.     return instance;
  2648.     
  2649. error:
  2650.     /* Unload the plugin if there are no other instances */
  2651.     if (handle->refs == 0)
  2652.     {
  2653.         np_UnloadPluginClass(handle);
  2654.     }
  2655.  
  2656.     if (instance)
  2657.         XP_FREE(instance);
  2658.     if (npp)
  2659.         XP_FREE(npp);
  2660.     return NULL;
  2661. }
  2662.  
  2663.  
  2664.  
  2665. NET_StreamClass *
  2666. np_newstream(URL_Struct *urls, np_handle *handle, np_instance *instance)
  2667. {
  2668.     NET_StreamClass *nstream = nil;
  2669.     NPStream *pstream = nil;
  2670.     np_stream *stream = nil;
  2671.     uint16 stype;
  2672.     XP_Bool alreadyLocal;
  2673.     XP_Bool b1;
  2674.     XP_Bool b2;
  2675.  
  2676.     /* make a netlib stream */
  2677.     if (!(nstream = XP_NEW_ZAP(NET_StreamClass))) 
  2678.         return 0;
  2679.  
  2680.     /* make the plugin stream data structures */
  2681.     stream = np_makestreamobjects(instance, nstream, urls);
  2682.     if (!stream)
  2683.     {
  2684.         XP_FREE(nstream);
  2685.         return 0;
  2686.     }
  2687.     pstream = stream->pstream;
  2688.  
  2689.     stream->prev_stream = NULL;
  2690.     
  2691.     /* Let us treat mailbox as remote too
  2692.        Not doing so causes problems with some attachments (Adobe)
  2693.     */
  2694.     b1 = NET_IsURLInDiskCache(stream->initial_urls);
  2695.     b2 = (XP_STRNCASECMP(urls->address, "mailbox:", 8) == 0) ? 0 : NET_IsLocalFileURL(urls->address);
  2696.  
  2697.     alreadyLocal = b1 || b2;
  2698.   
  2699.     /* determine if the stream is seekable */
  2700.     if (urls->server_can_do_byteranges || alreadyLocal)
  2701.     {
  2702.         /*
  2703.          * Zero-length streams are never seekable.
  2704.          * This will force us to download the entire
  2705.          * stream if a byterange request is made.
  2706.          */
  2707.         if (urls->content_length > 0)
  2708.             stream->seekable = 1;
  2709.     }
  2710.  
  2711.     /* and call the plugin */
  2712.     instance->reentrant = 1;
  2713.     stype = NP_NORMAL;
  2714.     TRACEMSG(("npglue.c: CallNPP_NewStreamProc"));
  2715.     if (handle->userPlugin) {
  2716.         nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)instance->npp->pdata;
  2717.         NPIPluginInstance* userInst = peerInst->GetUserInstance();
  2718.         nsPluginStreamPeer* peerStream = new nsPluginStreamPeer(urls, stream);
  2719.         if (peerStream == NULL) {
  2720.             /* XXX where's the error go? */
  2721.         }
  2722.         else {
  2723.             peerStream->AddRef();
  2724.             NPIPluginStream* userStream;
  2725.             NPPluginError err = userInst->NewStream(peerStream, &userStream);
  2726.             if (err == NPPluginError_NoError && userStream != NULL) {
  2727.                 peerStream->SetUserStream(userStream);
  2728.                 pstream->pdata = peerStream;
  2729.  
  2730.                 stype = userStream->GetStreamType();
  2731.             }
  2732.             else {
  2733.                 /* XXX where's the error go? */
  2734.             }
  2735.         }
  2736.     }
  2737.     else if (ISFUNCPTR(handle->f->newstream))
  2738.     {
  2739.         /*XXX*/CallNPP_NewStreamProc(handle->f->newstream, instance->npp, urls->content_type, 
  2740.                                      pstream, stream->seekable, &stype);
  2741.     }
  2742.     if(!instance->reentrant)
  2743.     {
  2744.         urls->pre_exit_fn = np_dofetch;
  2745.         XP_FREE(nstream);       /* will not call abort */
  2746.         return 0;
  2747.     }
  2748.     instance->reentrant = 0;
  2749.  
  2750.     /* see if its hard */
  2751.     if(stype == NP_SEEK)
  2752.     {
  2753.         if(!stream->seekable)
  2754.         {
  2755.             NPTRACE(0,("stream is dumb, force caching"));
  2756.             stream->seek = 2;
  2757.         }
  2758.         /* for a seekable stream that doesn't require caching, in the SSL case, don't cache, because that 
  2759.         will leave the supposedly secure file laying around in the cache! */
  2760.         if (   !alreadyLocal 
  2761.             && !(XP_STRNCASECMP(urls->address, "https:", 6)==0))
  2762.             urls->must_cache = TRUE; 
  2763.         stream->dontclose++;
  2764.     }
  2765.     else if (stype == NP_ASFILE || stype == NP_ASFILEONLY)
  2766.     {   
  2767.         NPTRACE(0,("stream as file"));
  2768.         if (!alreadyLocal)
  2769.             urls->must_cache = TRUE;
  2770.         stream->asfile = stype;
  2771.     }
  2772.     
  2773.     /*
  2774.      * If they want just the file, and the file is local, there's 
  2775.      * no need to continue with the netlib stream: just give them
  2776.      * the file and we're done.
  2777.      */
  2778.     if (stype == NP_ASFILEONLY)    
  2779.     {
  2780.         if (urls->cache_file || NET_IsLocalFileURL(urls->address))    
  2781.         {
  2782.             np_streamAsFile(stream);
  2783.             np_destroystream(stream, NPRES_DONE);
  2784.             XP_FREE(nstream);
  2785.             return NULL;
  2786.         }
  2787.     }
  2788.  
  2789.     /* and populate the netlib stream */
  2790.     nstream->name           = "plug-in";
  2791.     nstream->complete       = NPL_Complete;
  2792.     nstream->abort          = NPL_Abort;
  2793.     nstream->is_write_ready = NPL_WriteReady;
  2794.     nstream->put_block      = (MKStreamWriteFunc)NPL_Write;
  2795.     nstream->data_object    = (void *)urls;
  2796.     nstream->window_id      = instance->cx;
  2797.  
  2798.     /* In case of Mailbox->StreamAsFile, use cache code to store, handle... */
  2799.     if ( ((stype == NP_ASFILE) || (stype == NP_ASFILEONLY)) && 
  2800.          ((XP_STRNCASECMP(urls->address, "mailbox:", 8)==0)  
  2801.        || (XP_STRNCASECMP(urls->address, "news:"   , 5)==0)
  2802.        || (XP_STRNCASECMP(urls->address, "snews:"  , 6)==0))         
  2803.          && 
  2804.          (stream != NULL) && 
  2805.          (urls->cache_file == NULL)) /* if already cached, is well-handled */
  2806.        {
  2807.            urls->must_cache = TRUE;
  2808.            stream->prev_stream = NET_StreamBuilder(FO_CACHE_ONLY,urls,instance->cx);
  2809.        }
  2810.  
  2811.     return nstream;
  2812. }
  2813.  
  2814. XP_Bool np_FakeHTMLStream(URL_Struct* urls, MWContext* cx, char * fakehtml)
  2815. {
  2816.     NET_StreamClass* viewstream;
  2817.     char* org_content_type = urls->content_type; 
  2818.     XP_Bool ret = FALSE;
  2819.     
  2820.     urls->content_type = NULL;
  2821.  
  2822.     StrAllocCopy(urls->content_type, TEXT_HTML);
  2823.     if(urls->content_type == NULL) /* StrAllocCopy failed */
  2824.         goto Exit;
  2825.  
  2826.     urls->is_binary = 1;                            /* flag for mailto and saveas */
  2827.  
  2828.     if ((viewstream = NET_StreamBuilder(FO_PRESENT, urls, cx)) != 0)
  2829.     {
  2830.         (*viewstream->put_block)(viewstream, fakehtml, XP_STRLEN(fakehtml));
  2831.         (*viewstream->complete)(viewstream);
  2832.  
  2833.         XP_FREEIF(viewstream);
  2834.         viewstream = NULL;
  2835.         ret = TRUE;
  2836.     }
  2837.  
  2838.     XP_FREE(urls->content_type);
  2839.  
  2840. Exit:
  2841.     urls->content_type = org_content_type;
  2842.     return ret;
  2843. }
  2844.  
  2845. NET_StreamClass*
  2846. NPL_NewPresentStream(FO_Present_Types format_out, void* type, URL_Struct* urls, MWContext* cx)
  2847. {
  2848.     np_handle* handle = (np_handle*) type;
  2849.     np_instance* instance = NULL;
  2850.     np_data* ndata = NULL;
  2851.     np_mimetype* mimetype = NULL;
  2852.     np_reconnect* reconnect;
  2853.     NPEmbeddedApp *app = NULL;
  2854.  
  2855. #ifdef    ANTHRAX
  2856.     char* fileName;
  2857.     char* newTag;
  2858.     uint32 strLen;
  2859. #endif    /* ANTHRAX */
  2860.  
  2861.     XP_ASSERT(type && urls && cx);
  2862.     if (!type || !urls || !cx)
  2863.         return NULL;
  2864.  
  2865.     /* fe_data is set by EmbedCreate, which hasn't happed yet for PRESENT streams */
  2866.     XP_ASSERT(urls->fe_data == NULL);    
  2867.  
  2868. #ifdef    ANTHRAX
  2869.     if((fileName = NPL_FindAppletEnabledForMimetype(handle->name)) != NULL)
  2870.     {
  2871.         XP_FREE(fileName);    /* we don't need the applet name here, so discard it */
  2872.         fileName = strrchr(urls->address, '/')+1;
  2873.         
  2874.         strLen = XP_STRLEN(fileName);
  2875.         
  2876.         newTag = XP_ALLOC((36+strLen)*sizeof(char));
  2877.         newTag[0] = 0;
  2878.         
  2879.         XP_STRCAT(newTag, "<embed src=");
  2880.         XP_STRCAT(newTag, fileName);
  2881.         XP_STRCAT(newTag, " width=100% height=100%>");
  2882.         
  2883.         np_FakeHTMLStream(urls,cx,newTag);
  2884.         XP_FREE(newTag);
  2885.         return NULL;                
  2886.     }
  2887. #endif    /* ANTHRAX */
  2888.                 
  2889.     mimetype = np_getmimetype(handle, urls->content_type, TRUE);
  2890.     if (!mimetype)
  2891.         return NULL;
  2892.  
  2893.      /*
  2894.       * The following code special-cases the LiveAudio plug-in to open 
  2895.       * a new chromeless window.  A new window is only opened if there's
  2896.       * history information for the current context; that prevents us from
  2897.       * opening ANOTHER new window if the FE has already made one (for
  2898.       * example, if the user chose "New window for this link" from the
  2899.       * popup).
  2900.       */
  2901.     if (handle->name && (XP_STRCASECMP(handle->name, "LiveAudio") == 0))
  2902.     {
  2903.         History_entry* history = SHIST_GetCurrent(&cx->hist);
  2904.         if (history)
  2905.         {
  2906.             MWContext* oldContext = cx;
  2907.             Chrome* customChrome = XP_NEW_ZAP(Chrome);
  2908.             if (customChrome == NULL)
  2909.                 return NULL;
  2910.             customChrome->w_hint = 144 + 1;
  2911.             customChrome->h_hint = 60 + 1;
  2912.             customChrome->allow_close = TRUE;
  2913.             
  2914.             /* Make a new window with no URL or window name, but special chrome */
  2915.             cx = FE_MakeNewWindow(oldContext, NULL, NULL, customChrome);
  2916.             if (cx == NULL)
  2917.             {
  2918.                 XP_FREE(customChrome);
  2919.                 return NULL;
  2920.             }
  2921.             /* Insert some HTML to notify of Java delay: */
  2922.             {
  2923.                 JRIEnv* env = NULL;
  2924.                 /* Has Java already been started? */
  2925. #ifdef JAVA
  2926.                 env = JRI_GetCurrentEnv();
  2927. #endif
  2928.                 if (env == NULL){ 
  2929.                     /* nope, java not yet started */
  2930.                     static char fakehtml[255] = "";
  2931.  
  2932.                     XP_SPRINTF(fakehtml,"<HTML><p><CENTER>%s</CENTER></HTML>",XP_GetString(XP_PROGRESS_STARTING_JAVA));
  2933.                     np_FakeHTMLStream(urls,cx,fakehtml);
  2934.                 }
  2935.             }
  2936.             
  2937.             /* Switch to the new context, but don't change the exit routine */
  2938.             NET_SetNewContext(urls, cx, NULL);
  2939.         }
  2940.     }
  2941.  
  2942.      
  2943.      /*
  2944.       * Set up the "reconnect" data, which is used to communicate between this
  2945.       * function and the call to EmbedCreate that will result from pushing the
  2946.       * data into the stream below.  EmbedCreate needs to know from us the 
  2947.       * np_mimetype and requestedtype for this stream, and we need to know from
  2948.       * it the NPEmbeddedApp that it created.
  2949.       */
  2950.     XP_ASSERT(cx->pluginReconnect == NULL);
  2951.     reconnect = XP_NEW_ZAP(np_reconnect);
  2952.     if (!reconnect)
  2953.         return NULL;
  2954.     cx->pluginReconnect = (void*) reconnect;
  2955.     reconnect->mimetype = mimetype;
  2956.     reconnect->requestedtype = XP_STRDUP(urls->content_type);
  2957.  
  2958.     /*
  2959.      * To actually create the instance we need to create a stream of
  2960.      * fake HTML to cause layout to create a new embedded object.
  2961.      * EmbedCreate will be called, which will created the NPEmbeddedApp
  2962.      * and put it into urls->fe_data, where we can retrieve it.
  2963.      */
  2964.     {
  2965.         static char fakehtml[] = "<embed src=internal-external-plugin width=1 height=1>";
  2966.         np_FakeHTMLStream(urls,cx,fakehtml);                
  2967.     }
  2968.     
  2969.     /*
  2970.      * Retrieve the app created by EmbedCreate and stashed in the reconnect data.
  2971.      * From the app we can get the np_data, which in turn holds the handle and
  2972.      * instance, which we need to create the streams.
  2973.      */
  2974.     app = reconnect->app;
  2975.     XP_FREE(reconnect);
  2976.     cx->pluginReconnect = NULL;
  2977.     
  2978.     if (!app)
  2979.         return NULL;  /* will be NULL if the plugin failed to initialize */
  2980.     XP_ASSERT(app->pagePluginType == NP_FullPage);
  2981.     
  2982.     urls->fe_data = (void*) app;        /* fe_data of plug-in URLs always holds NPEmbeddedApp */
  2983.     
  2984.     ndata = (np_data*) app->np_data;
  2985.     XP_ASSERT(ndata);
  2986.     if (!ndata)
  2987.         return NULL;
  2988.         
  2989.     handle = ndata->handle;
  2990.     instance = ndata->instance;
  2991.     XP_ASSERT(handle && instance);
  2992.     if (!handle || !instance)
  2993.         return NULL;
  2994.         
  2995.     /* now actually make a plugin and netlib stream */
  2996.     return np_newstream(urls, handle, instance);
  2997. }
  2998.  
  2999.  
  3000.  
  3001. NET_StreamClass*
  3002. NPL_NewEmbedStream(FO_Present_Types format_out, void* type, URL_Struct* urls, MWContext* cx)
  3003. {
  3004.     np_handle* handle = (np_handle*) type;
  3005.      np_data* ndata = NULL;
  3006.     NPEmbeddedApp* app = NULL;
  3007.  
  3008.     XP_ASSERT(type && urls && cx);
  3009.     if (!type || !urls || !cx)
  3010.         return NULL;
  3011.         
  3012.     /* fe_data is set by EmbedCreate, which has already happened for EMBED streams */
  3013.     app = (NPEmbeddedApp*) urls->fe_data;
  3014.     XP_ASSERT(app);
  3015.     if (!app)
  3016.         return NULL;
  3017.     XP_ASSERT(app->pagePluginType == NP_Embedded);
  3018.  
  3019.     ndata = (np_data*) app->np_data;
  3020.     XP_ASSERT(ndata && ndata->lo_struct);
  3021.     if (!ndata)
  3022.         return NULL;
  3023.         
  3024.     if (ndata->instance == NULL)
  3025.     {
  3026.         np_instance* instance;
  3027.         np_mimetype* mimetype;
  3028.  
  3029.         /* Map the stream's MIME type to a np_mimetype object */
  3030.         mimetype = np_getmimetype(handle, urls->content_type, TRUE);
  3031.         if (!mimetype)
  3032.             return NULL;
  3033.      
  3034.         /* Now that we have the MIME type and the layout data, we can create an instance */
  3035.         instance = np_newinstance(handle, cx, app, mimetype, urls->content_type);
  3036.         if (!instance)
  3037.             return NULL;
  3038.  
  3039.         ndata->instance = instance;
  3040.         ndata->handle = handle;
  3041. #ifdef LAYERS
  3042.         LO_SetEmbedType(ndata->lo_struct, (PRBool) ndata->instance->windowed);
  3043. #endif
  3044.     }
  3045.     
  3046.     /* now actually make a plugin and netlib stream */
  3047.     return np_newstream(urls, ndata->instance->handle, ndata->instance);
  3048. }
  3049.  
  3050.  
  3051. static NET_StreamClass *
  3052. np_newbyterangestream(FO_Present_Types format_out, void *type, URL_Struct *urls, MWContext *cx)
  3053. {
  3054.     NET_StreamClass *nstream = nil;
  3055.  
  3056.     /* make a netlib stream */
  3057.     if (!(nstream = XP_NEW_ZAP(NET_StreamClass))) 
  3058.         return 0;
  3059.  
  3060.     urls->position = 0;         /* single threaded for now */
  3061.  
  3062.     /* populate netlib stream */
  3063.     nstream->name           = "plug-in byterange";
  3064.     nstream->complete       = NPL_Complete;
  3065.     nstream->abort          = NPL_Abort;
  3066.     nstream->is_write_ready = NPL_WriteReady;
  3067.     nstream->put_block      = (MKStreamWriteFunc)NPL_Write;
  3068.     nstream->data_object    = (void *)urls;
  3069.     nstream->window_id      = cx;
  3070.  
  3071.     return nstream;
  3072. }
  3073.  
  3074. static NET_StreamClass *
  3075. np_newpluginstream(FO_Present_Types format_out, void *type, URL_Struct *urls, MWContext *cx)
  3076. {
  3077.     NPEmbeddedApp* app = (NPEmbeddedApp*) urls->fe_data;
  3078.  
  3079.     if (app)
  3080.     {
  3081.         np_data *ndata = (np_data *)app->np_data;
  3082.         if(ndata && ndata->instance)
  3083.         {
  3084.             XP_ASSERT(ndata->instance->app == app);
  3085.             return np_newstream(urls, ndata->instance->handle, ndata->instance);
  3086.         }
  3087.     }
  3088.     return 0;
  3089. }
  3090.  
  3091. NPError
  3092. NPL_RegisterPluginFile(const char* pluginname, const char* filename, const char* description,
  3093.                        void *pdesc)
  3094. {
  3095.     np_handle* handle;
  3096.  
  3097.     NPTRACE(0,("np: register file %s", filename));
  3098.  
  3099. #ifdef DEBUG
  3100.     /* Ensure uniqueness of pdesc values! */
  3101.     for (handle = np_plist; handle; handle = handle->next)
  3102.         XP_ASSERT(handle->pdesc != pdesc);
  3103. #endif
  3104.     
  3105.     handle = XP_NEW_ZAP(np_handle);
  3106.     if (!handle)
  3107.         return NPERR_OUT_OF_MEMORY_ERROR;
  3108.     
  3109.     StrAllocCopy(handle->name, pluginname);
  3110.     StrAllocCopy(handle->filename, filename);
  3111.     StrAllocCopy(handle->description, description);
  3112.     
  3113.     handle->pdesc = pdesc;
  3114.     handle->next = np_plist;
  3115.     handle->userPlugin = NULL;
  3116.        np_plist = handle;
  3117.        
  3118.        return NPERR_NO_ERROR;
  3119. }
  3120.  
  3121. /*
  3122.  * Given a pluginName and a mimetype, this will enable the plugin for
  3123.  * the mimetype and disable anyother plugin that had been enabled for
  3124.  * this mimetype.
  3125.  *
  3126.  * pluginName and type cannot be NULL.
  3127.  *
  3128.  * WARNING: If enable is FALSE, this doesn't unregister the converters yet.
  3129.  */
  3130. NPError
  3131. NPL_EnablePlugin(NPMIMEType type, const char *pluginName, XP_Bool enabled)
  3132. {
  3133.     np_handle* handle;
  3134.     np_mimetype* mimetype;
  3135.     NPTRACE(0,("np: enable plugin %s for type %s", pluginName, type));
  3136.  
  3137.     if (!pluginName || !*pluginName || !type || !*type)
  3138.         return(NPERR_INVALID_PARAM);
  3139.  
  3140.     for (handle = np_plist; handle; handle = handle->next)
  3141.     {
  3142.         if (!strcmp(handle->name, pluginName))
  3143.             break;
  3144.     }
  3145.  
  3146.     if (!handle)
  3147.         /* Plugin with the specified name not found */
  3148.         return(NPERR_INVALID_INSTANCE_ERROR);
  3149.     
  3150.     /* Look for an existing MIME type object for the specified type */
  3151.     /* We can't use np_getmimetype, because it respects enabledness and
  3152.        here we don't care */
  3153.     for (mimetype = handle->mimetypes; mimetype; mimetype = mimetype->next)
  3154.     {
  3155.         if (strcasecomp(mimetype->type, type) == 0)
  3156.             break;
  3157.     }
  3158.  
  3159.     if (!mimetype)
  3160.         /* This plugin cannot handler the specified mimetype */
  3161.         return(NPERR_INVALID_PLUGIN_ERROR);
  3162.  
  3163.     /* Find the plug-in that was previously enabled for this type and
  3164.        disable it */
  3165.     if (enabled)
  3166.     {
  3167.         XP_Bool foundType = FALSE;
  3168.         np_handle* temphandle;
  3169.         np_mimetype* temptype;
  3170.         
  3171.         for (temphandle = np_plist; temphandle && !foundType; temphandle = temphandle->next)
  3172.         {
  3173.             for (temptype = temphandle->mimetypes; temptype && !foundType; temptype = temptype->next)
  3174.             {
  3175.                 if (temptype->enabled && strcasecomp(temptype->type, type) == 0)
  3176.                 {
  3177.                     temptype->enabled = FALSE;
  3178.                     foundType = TRUE;
  3179.                 }
  3180.             }
  3181.         }
  3182.     }
  3183.     
  3184.     mimetype->enabled = enabled;
  3185.     
  3186.     if (mimetype->enabled)
  3187.     {
  3188.         /*
  3189.          * Is this plugin the wildcard (a.k.a. null) plugin?
  3190.          * If so, we don't want to register it for FO_PRESENT
  3191.          * or it will interfere with our normal unknown-mime-
  3192.          * type handling.
  3193.          */
  3194.         XP_Bool wildtype = (strcmp(type, "*") == 0);
  3195.         
  3196. #if defined(XP_WIN) || defined(XP_OS2)
  3197.         /* EmbedStream does some Windows FE work and then calls NPL_NewStream */
  3198.         if (!wildtype)
  3199.             NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, EmbedStream);
  3200.         NET_RegisterContentTypeConverter(type, FO_EMBED, handle, EmbedStream); /* XXX I dont think this does anything useful */
  3201. #else
  3202.         if (!wildtype)
  3203.           {
  3204.             NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, NPL_NewPresentStream);
  3205. #ifdef XP_UNIX
  3206.             /* The following three lines should be outside the ifdef someday */
  3207.             NET_RegisterAllEncodingConverters(type, FO_PRESENT);
  3208.             NET_RegisterAllEncodingConverters(type, FO_EMBED);
  3209.             NET_RegisterAllEncodingConverters(type, FO_PLUGIN);
  3210.  
  3211.             /* While printing we use the FO_SAVE_AS_POSTSCRIPT format type. We want
  3212.              * plugin to possibly handle that case too. Hence this.
  3213.              */
  3214.             NET_RegisterContentTypeConverter(type, FO_SAVE_AS_POSTSCRIPT, handle,
  3215.                                              NPL_NewPresentStream);
  3216. #endif /* XP_UNIX */
  3217.         }
  3218.         NET_RegisterContentTypeConverter(type, FO_EMBED, handle, NPL_NewEmbedStream);
  3219. #endif
  3220.         NET_RegisterContentTypeConverter(type, FO_PLUGIN, handle, np_newpluginstream);
  3221.         NET_RegisterContentTypeConverter(type, FO_BYTERANGE, handle, np_newbyterangestream);
  3222.     }
  3223.  
  3224.     return(NPERR_NO_ERROR);
  3225. }
  3226.  
  3227.  
  3228. /* 
  3229.  * Look up the handle and mimetype objects given
  3230.  * the pdesc value and the mime type string.
  3231.  * Return TRUE if found successfully.
  3232.  */
  3233. void
  3234. np_findPluginType(NPMIMEType type, void* pdesc, np_handle** outHandle, np_mimetype** outMimetype)
  3235. {
  3236.     np_handle* handle;
  3237.     np_mimetype* mimetype;
  3238.  
  3239.     *outHandle = NULL;
  3240.     *outMimetype = NULL;
  3241.     
  3242.     /* Look for an existing handle */
  3243.     for (handle = np_plist; handle; handle = handle->next)
  3244.     {
  3245.         if (handle->pdesc == pdesc)
  3246.             break;
  3247.     }
  3248.  
  3249.     if (!handle)
  3250.         return;
  3251.     *outHandle = handle;
  3252.         
  3253.     /* Look for an existing MIME type object for the specified type */
  3254.     /* We can't use np_getmimetype, because it respects enabledness and here we don't care */
  3255.     for (mimetype = handle->mimetypes; mimetype; mimetype = mimetype->next)
  3256.     {
  3257.         if (strcasecomp(mimetype->type, type) == 0)
  3258.             break;
  3259.     }
  3260.     
  3261.     if (!mimetype)
  3262.         return;
  3263.     *outMimetype = mimetype;
  3264. }
  3265.  
  3266.  
  3267. void 
  3268. np_enablePluginType(np_handle* handle, np_mimetype* mimetype, XP_Bool enabled)
  3269. {
  3270.     char* type = mimetype->type;
  3271.     
  3272.     /*
  3273.      * Find the plug-in that was previously
  3274.      * enabled for this type and disable it.
  3275.      */
  3276.     if (enabled)
  3277.     {
  3278.         XP_Bool foundType = FALSE;
  3279.         np_handle* temphandle;
  3280.         np_mimetype* temptype;
  3281.         
  3282.         for (temphandle = np_plist; temphandle && !foundType; temphandle = temphandle->next)
  3283.         {
  3284.             for (temptype = temphandle->mimetypes; temptype && !foundType; temptype = temptype->next)
  3285.             {
  3286.                 if (temptype->enabled && strcasecomp(temptype->type, type) == 0)
  3287.                 {
  3288.                     temptype->enabled = FALSE;
  3289.                     foundType = TRUE;
  3290.                 }
  3291.             }
  3292.         }
  3293.     }
  3294.     
  3295.     mimetype->enabled = enabled;
  3296.  
  3297.     if (enabled)
  3298.     {
  3299.         /*
  3300.          * Is this plugin the wildcard (a.k.a. null) plugin?
  3301.          * If so, we don't want to register it for FO_PRESENT
  3302.          * or it will interfere with our normal unknown-mime-
  3303.          * type handling.
  3304.          */
  3305.         XP_Bool wildtype = (strcmp(type, "*") == 0);
  3306.         
  3307. #ifdef XP_WIN
  3308.         /* EmbedStream does some Windows FE work and then calls NPL_NewStream */
  3309.         if (!wildtype)
  3310.             NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, EmbedStream);
  3311.         NET_RegisterContentTypeConverter(type, FO_EMBED, handle, EmbedStream); /* XXX I dont think this does anything useful */
  3312. #else
  3313.         if (!wildtype)
  3314.           {
  3315.             NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, NPL_NewPresentStream);
  3316. #ifdef XP_UNIX
  3317.             /* While printing we use the FO_SAVE_AS_POSTSCRIPT format type. We want
  3318.              * plugin to possibly handle that case too. Hence this.
  3319.              */
  3320.             NET_RegisterContentTypeConverter(type, FO_SAVE_AS_POSTSCRIPT, handle,
  3321.                                              NPL_NewPresentStream);
  3322. #endif /* XP_UNIX */
  3323.           }
  3324.         NET_RegisterContentTypeConverter(type, FO_EMBED, handle, NPL_NewEmbedStream);
  3325. #endif
  3326.         NET_RegisterContentTypeConverter(type, FO_PLUGIN, handle, np_newpluginstream);
  3327.         NET_RegisterContentTypeConverter(type, FO_BYTERANGE, handle, np_newbyterangestream);
  3328.     }
  3329. }
  3330.  
  3331.  
  3332. NPError
  3333. NPL_EnablePluginType(NPMIMEType type, void* pdesc, XP_Bool enabled)
  3334. {
  3335.     np_handle* handle;
  3336.     np_mimetype* mimetype;
  3337.     
  3338.     if (!type)
  3339.         return NPERR_INVALID_PARAM;
  3340.         
  3341.     np_findPluginType(type, pdesc, &handle, &mimetype);
  3342.     
  3343.     if (!handle || !mimetype)
  3344.         return NPERR_INVALID_PARAM;
  3345.  
  3346.     np_enablePluginType(handle, mimetype, enabled);
  3347.         return NPERR_NO_ERROR;
  3348. }
  3349.  
  3350.  
  3351. /* XXX currently there is no unregister */
  3352. NPError
  3353. NPL_RegisterPluginType(NPMIMEType type, const char *extensions, const char* description,
  3354.         void* fileType, void *pdesc, XP_Bool enabled)
  3355. {
  3356.     np_handle* handle = NULL;
  3357.     np_mimetype* mimetype = NULL;
  3358.     NPTRACE(0,("np: register type %s", type));
  3359.  
  3360.     np_findPluginType(type, pdesc, &handle, &mimetype);
  3361.  
  3362.     /* We have to find the handle to do anything */
  3363.     XP_ASSERT(handle);
  3364.     if (!handle)
  3365.         return NPERR_INVALID_PARAM;
  3366.         
  3367.     /*If no existing mime type, add a new type to this handle */
  3368.     if (!mimetype)
  3369.     {
  3370.         mimetype = XP_NEW_ZAP(np_mimetype);
  3371.         if (!mimetype)
  3372.             return NPERR_OUT_OF_MEMORY_ERROR;
  3373.         mimetype->next = handle->mimetypes;
  3374.         handle->mimetypes = mimetype;
  3375.         mimetype->handle = handle;
  3376.         StrAllocCopy(mimetype->type, type);
  3377.     }
  3378.  
  3379.     /* Enable this plug-in for this type and disable any others */
  3380.     np_enablePluginType(handle, mimetype, enabled);
  3381.  
  3382.     /* Get rid of old file association info, if any */
  3383.     if (mimetype->fassoc)
  3384.     {
  3385.         void* fileType;
  3386.         fileType = NPL_DeleteFileAssociation(mimetype->fassoc);
  3387. #if 0
  3388.         /* Any FE that needs to free this, implement FE_FreeNPFileType */
  3389.         if (fileType)
  3390.             FE_FreeNPFileType(fileType);
  3391. #endif
  3392.         mimetype->fassoc = NULL;
  3393.     }
  3394.             
  3395.     /* Make a new file association and register it with netlib if enabled */
  3396.     XP_ASSERT(extensions && description);
  3397.     mimetype->fassoc = NPL_NewFileAssociation(type, extensions, description, fileType);
  3398.     if (mimetype->fassoc && enabled)
  3399.         NPL_RegisterFileAssociation(mimetype->fassoc);
  3400.     
  3401.     return NPERR_NO_ERROR;
  3402. }
  3403.  
  3404.  
  3405. /*
  3406.  * Add a NPEmbeddedApp to the list of plugins for the specified context.
  3407.  * We need to append items, because the FEs depend on them appearing
  3408.  * in the list in the same order in which they were created.
  3409.  */
  3410. void
  3411. np_bindContext(NPEmbeddedApp* app, MWContext* cx)
  3412. {
  3413.     np_data* ndata;
  3414.     
  3415.     XP_ASSERT(app && cx);
  3416.     XP_ASSERT(app->next == NULL);
  3417.     
  3418.     if (cx->pluginList == NULL)                      /* no list yet, just insert item */
  3419.         cx->pluginList = app;
  3420.     else                                              /* the list has at least one item in it, append to it */
  3421.     {
  3422.         NPEmbeddedApp* pItem = cx->pluginList;      /* the first element */
  3423.         while(pItem->next) pItem = pItem->next;     /* find the last element */
  3424.         pItem->next = app;                          /* append */
  3425.     }
  3426.     
  3427.     /* If there's an instance, set the instance's context */
  3428.     ndata = (np_data*) app->np_data;
  3429.     if (ndata)
  3430.     {
  3431.         np_instance* instance = (np_instance*) ndata->instance;
  3432.         if (instance)
  3433.             instance->cx = cx;
  3434.     }
  3435.         
  3436. }
  3437.  
  3438. void
  3439. np_unbindContext(NPEmbeddedApp* app, MWContext* cx)
  3440. {
  3441.     np_data* ndata;
  3442.  
  3443.     XP_ASSERT(app && cx);
  3444.  
  3445.     if (app == cx->pluginList)
  3446.         cx->pluginList = app->next;
  3447.     else
  3448.     {
  3449.         NPEmbeddedApp *ax;
  3450.         for (ax=cx->pluginList; ax; ax=ax->next)
  3451.             if (ax->next == app)
  3452.             {
  3453.                 ax->next = ax->next->next;
  3454.                 break;
  3455.             }
  3456.     }
  3457.  
  3458.     app->next = NULL;
  3459.     
  3460.     /* If there's an instance, clear the instance's context */
  3461.     ndata = (np_data*) app->np_data;
  3462.     if (ndata)
  3463.     {
  3464.         np_instance* instance = (np_instance*) ndata->instance;
  3465.         if (instance)
  3466.             instance->cx = NULL;
  3467.     }
  3468. }
  3469.  
  3470.  
  3471. void
  3472. np_delete_instance(np_instance *instance)
  3473. {
  3474.     if(instance)
  3475.     {
  3476.         np_handle *handle = instance->handle;
  3477.         np_stream *stream;
  3478.  
  3479.         /* nuke all open streams */
  3480.         for(stream=instance->streams; stream;)
  3481.         {
  3482.             np_stream *next = stream->next;
  3483.             stream->dontclose = 0;
  3484.             if (stream->nstream)
  3485.             {
  3486.                 /* Make sure the urls doesn't still point to us */
  3487.                 URL_Struct* urls = (URL_Struct*) stream->nstream->data_object;
  3488.                 if (urls)
  3489.                     urls->fe_data = NULL;
  3490.             }
  3491.             np_destroystream(stream, NPRES_USER_BREAK);
  3492.             stream = next;
  3493.         }
  3494.         instance->streams = 0;
  3495.  
  3496.         if (handle) {
  3497.             NPSavedData *save = NULL;
  3498.  
  3499.             TRACEMSG(("npglue.c: CallNPP_DestroyProc"));
  3500.             if (np_is50StylePlugin(instance->handle)) {
  3501.                 nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)instance->npp->pdata;
  3502.                 NPIPluginInstance* userInst = peerInst->GetUserInstance();
  3503.  
  3504.                 userInst->SetWindow(NULL);
  3505.  
  3506.                 nsrefcnt cnt;
  3507.                 cnt = userInst->Release();
  3508.                 XP_ASSERT(cnt == 0);
  3509.  
  3510.                 // XXX Is this the right place to be releasing the
  3511.                 // peer?
  3512.                 cnt = peerInst->Release();
  3513.                 XP_ASSERT(cnt == 0);
  3514.  
  3515.                 // XXX Any other bookkeeping we need to do here?
  3516.  
  3517.                 // Since this is a 5.0-style (C++) plugin, we know we've
  3518.                 // been called from NPL_DeleteSessionData (at best),
  3519.                 // or other similarly terminal functions. So there is
  3520.                 // no chance that the plugin will be able to save any
  3521.                 // of its state for later...
  3522.             } else if (handle->f && ISFUNCPTR(handle->f->destroy)) {
  3523.                 CallNPP_DestroyProc(handle->f->destroy, instance->npp, &save);
  3524.             }
  3525.             if (instance->app && instance->app->np_data) {
  3526.                 np_data* pnp = (np_data*)instance->app->np_data;
  3527.                 pnp->sdata = save;
  3528.             }
  3529. #ifdef JAVA        
  3530.             /*
  3531.             ** Break any association we have made between this instance and
  3532.             ** its corresponding Java object. That way other java objects
  3533.             ** still referring to it will be able to detect that the plugin
  3534.             ** went away (by calling isActive).
  3535.             */
  3536.             if (instance->javaInstance != NULL &&
  3537.                 instance->javaInstance != NPN_NO_JAVA_INSTANCE)
  3538.             {
  3539.                 /* Don't get the environment unless there is a Java instance,
  3540.                    because this would cause the java runtime to start up. */
  3541.                  JRIEnv* env = npn_getJavaEnv();
  3542.                 netscape_plugin_Plugin* javaInstance = (netscape_plugin_Plugin*)
  3543.                     JRI_GetGlobalRef(env, instance->javaInstance);
  3544.  
  3545.                 /* upcall to the user's code */
  3546.                 netscape_plugin_Plugin_destroy(env, javaInstance);
  3547.  
  3548.                 set_netscape_plugin_Plugin_peer(env, javaInstance, 0);
  3549.                 JRI_DisposeGlobalRef(env, instance->javaInstance);
  3550.                 instance->javaInstance = NULL;
  3551.             }
  3552. #endif /* JAVA */
  3553.  
  3554.             /* If we come through here after having been unbound from
  3555.                a context, then we need to make one up to call into the
  3556.                front-end */
  3557.             MWContext *context = (instance->cx != NULL)
  3558.                 ? instance->cx : XP_FindSomeContext();
  3559.  
  3560.             if (XP_OK_ASSERT(context != NULL)) {
  3561.  
  3562. #ifdef XP_MAC
  3563.                 /* turn scrollbars back on */
  3564.                 if(instance->type == NP_FULL)
  3565.                     FE_ShowScrollBars(context, TRUE);
  3566. #endif                
  3567.  
  3568.                 /* Tell the front end to blow away the plugin window */
  3569.                 FE_DestroyEmbedWindow(context, instance->app);
  3570.             }
  3571.  
  3572.             /* remove it from the handle list */
  3573.             if(instance == handle->instances)
  3574.                 handle->instances = instance->next;
  3575.             else
  3576.             {
  3577.                 np_instance *ix;
  3578.                 for(ix=handle->instances; ix; ix=ix->next)
  3579.                     if(ix->next == instance)
  3580.                     {
  3581.                         ix->next = ix->next->next;
  3582.                         break;
  3583.                     }
  3584.             }
  3585.  
  3586.             handle->refs--;
  3587.             XP_ASSERT(handle->refs>=0);
  3588.             if(!handle->refs)
  3589.             {
  3590.                 np_UnloadPluginClass(handle);
  3591.             }
  3592.         }
  3593.  
  3594.         np_removeAllURLsFromList(instance);
  3595.         
  3596.         if (instance->typeString)
  3597.             XP_FREE(instance->typeString);
  3598.         XP_FREE(instance);
  3599.     }
  3600. }
  3601.  
  3602. #ifdef XP_UNIX
  3603. static NET_StreamClass *
  3604. np_noembedfound (FO_Present_Types format_out, 
  3605.                  void *type, 
  3606.                  URL_Struct *urls, MWContext *cx)
  3607. {
  3608.     char *msg = PR_smprintf(XP_GetString(XP_PLUGIN_NOT_FOUND),
  3609.                             urls->content_type);
  3610.     if(msg)
  3611.       {
  3612.         FE_Alert(cx, msg);
  3613.         XP_FREE(msg);
  3614.       }
  3615.  
  3616.     return(NULL);
  3617. }
  3618. #endif /* XP_UNIX */
  3619.  
  3620. void
  3621. NPL_RegisterDefaultConverters()
  3622. {
  3623.     /* get netlib to deal with our content streams */
  3624.     NET_RegisterContentTypeConverter("*", FO_CACHE_AND_EMBED, NULL, NET_CacheConverter);
  3625.     NET_RegisterContentTypeConverter("*", FO_CACHE_AND_PLUGIN, NULL, NET_CacheConverter);
  3626.     NET_RegisterContentTypeConverter("*", FO_CACHE_AND_BYTERANGE, NULL, NET_CacheConverter);
  3627.  
  3628.     NET_RegisterContentTypeConverter("multipart/x-byteranges", FO_CACHE_AND_BYTERANGE, NULL, CV_MakeMultipleDocumentStream);
  3629.  
  3630.     NET_RegisterContentTypeConverter("*", FO_PLUGIN, NULL, np_newpluginstream);
  3631.     NET_RegisterContentTypeConverter("*", FO_BYTERANGE, NULL, np_newbyterangestream);
  3632. #ifdef XP_UNIX
  3633.     NET_RegisterContentTypeConverter("*", FO_EMBED, NULL, np_noembedfound);
  3634. #endif /* XP_UNIX */
  3635. }
  3636.  
  3637. /* called from netscape main */
  3638. void
  3639. NPL_Init()
  3640. {
  3641.  
  3642. #if defined(XP_UNIX) && defined(DEBUG)
  3643.     {
  3644.         char *str;
  3645.         str = getenv("NPD");
  3646.         if(str)
  3647.             np_debug=atoi(str);
  3648.     }
  3649. #endif
  3650.  
  3651.     /* Register all default plugin converters. Do this before
  3652.      * FE_RegisterPlugins() because this registers a not found converter
  3653.      * for "*" and FE can override that with the nullplugin if one is
  3654.      * available.
  3655.      */
  3656.     NPL_RegisterDefaultConverters();
  3657.  
  3658.     /* call the platform specific FE code to enumerate and register plugins */
  3659.     FE_RegisterPlugins();
  3660.  
  3661.     /* construct the function table for calls back into netscape.
  3662.        no plugin sees this until its actually loaded */
  3663.     npp_funcs.size = sizeof(npp_funcs);
  3664.     npp_funcs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
  3665.  
  3666.     npp_funcs.geturl = NewNPN_GetURLProc(npn_geturl);
  3667.     npp_funcs.posturl = NewNPN_PostURLProc(npn_posturl);
  3668.     npp_funcs.requestread = NewNPN_RequestReadProc(npn_requestread);
  3669.     npp_funcs.newstream = NewNPN_NewStreamProc(npn_newstream);
  3670.     npp_funcs.write = NewNPN_WriteProc(npn_write);
  3671.     npp_funcs.destroystream = NewNPN_DestroyStreamProc(npn_destroystream);
  3672.     npp_funcs.status = NewNPN_StatusProc(npn_status);
  3673.     npp_funcs.uagent = NewNPN_UserAgentProc(npn_useragent);
  3674.     npp_funcs.memalloc = NewNPN_MemAllocProc(npn_memalloc);
  3675.     npp_funcs.memfree = NewNPN_MemFreeProc(npn_memfree);
  3676.     npp_funcs.memflush = NewNPN_MemFlushProc(npn_memflush);
  3677.     npp_funcs.reloadplugins = NewNPN_ReloadPluginsProc(npn_reloadplugins);
  3678.     npp_funcs.getJavaEnv = NewNPN_GetJavaEnvProc(npn_getJavaEnv);
  3679.     npp_funcs.getJavaPeer = NewNPN_GetJavaPeerProc(npn_getJavaPeer);
  3680.     npp_funcs.geturlnotify = NewNPN_GetURLNotifyProc(npn_geturlnotify);
  3681.     npp_funcs.posturlnotify = NewNPN_PostURLNotifyProc(npn_posturlnotify);
  3682.     npp_funcs.getvalue = NewNPN_GetValueProc(npn_getvalue);
  3683.     npp_funcs.setvalue = NewNPN_SetValueProc(npn_setvalue);
  3684.     npp_funcs.invalidaterect = NewNPN_InvalidateRectProc(npn_invalidaterect);
  3685.     npp_funcs.invalidateregion = NewNPN_InvalidateRegionProc(npn_invalidateregion);
  3686.     npp_funcs.forceredraw = NewNPN_ForceRedrawProc(npn_forceredraw);
  3687. }
  3688.  
  3689.  
  3690. void
  3691. NPL_Shutdown()
  3692. {
  3693.     np_handle *handle, *dh;
  3694.     np_instance *instance, *di;
  3695.  
  3696.     for(handle=np_plist; handle;)
  3697.     {
  3698.         dh=handle;
  3699.         handle = handle->next;
  3700.  
  3701.         /* delete handle */
  3702.         for(instance=dh->instances; instance;)
  3703.         {
  3704.             di = instance;
  3705.             instance=instance->next;
  3706.             np_delete_instance(di);
  3707.         }
  3708.     }
  3709. }
  3710.  
  3711.  
  3712.  
  3713. /*
  3714.  * Like NPL_SamePage, but for an individual element.
  3715.  * It is called by laytable.c when relaying out table cells. 
  3716.  */
  3717. void
  3718. NPL_SameElement(LO_EmbedStruct* embed_struct)
  3719. {
  3720.     if (embed_struct)
  3721.     {
  3722.         NPEmbeddedApp* app = (NPEmbeddedApp*) embed_struct->FE_Data;
  3723.         if (app)
  3724.         {
  3725.             np_data* ndata = (np_data*) app->np_data;
  3726.             XP_ASSERT(ndata);
  3727.             if (ndata && ndata->state != NPDataSaved)
  3728.                 ndata->state = NPDataCache;
  3729.         }
  3730.     }
  3731. }
  3732.  
  3733.  
  3734.  
  3735. /*
  3736.  * This function is called by the FE's when they're resizing a page.
  3737.  * We take advantage of this information to mark all our instances
  3738.  * so we know not to delete them when the layout information is torn
  3739.  * down so we can keep using the same instances with the new, resized,
  3740.  * layout structures.
  3741.  */
  3742. void
  3743. NPL_SamePage(MWContext* resizedContext)
  3744. {
  3745.     MWContext* cx;
  3746.     XP_List* children;
  3747.     NPEmbeddedApp* app;
  3748.     
  3749.     if (!resizedContext)
  3750.         return;
  3751.         
  3752.     /* Mark all plug-ins in this context */
  3753.     app = resizedContext->pluginList;
  3754.     while (app)
  3755.     {
  3756.         np_data* ndata = (np_data*) app->np_data;
  3757.         XP_ASSERT(ndata);
  3758.         if (ndata && ndata->state != NPDataSaved)
  3759.             ndata->state = NPDataCache;
  3760.         app = app->next;
  3761.     }
  3762.     
  3763.     /* Recursively traverse child contexts */
  3764.     children = resizedContext->grid_children;
  3765.     while ((cx = (MWContext*)XP_ListNextObject(children)) != NULL)
  3766.         NPL_SamePage(cx);
  3767. }
  3768.  
  3769. int
  3770. NPL_HandleEvent(NPEmbeddedApp *app, void *event, void* window)
  3771. {
  3772.     if (app)
  3773.     {
  3774.         np_data *ndata = (np_data *)app->np_data;
  3775.         if(ndata && ndata->instance)
  3776.         {
  3777.             np_handle *handle = ndata->instance->handle;
  3778.             if (handle) {
  3779.                 TRACEMSG(("npglue.c: CallNPP_HandleEventProc"));
  3780.                 if (handle->userPlugin) {
  3781.                     nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)ndata->instance->npp->pdata;
  3782.                     NPIPluginInstance* userInst = peerInst->GetUserInstance();
  3783.  
  3784.                     // Note that the new NPPluginEvent struct is different from the
  3785.                     // old NPEvent (which is the argument passed in) so we have to
  3786.                     // translate. (Later we might fix the front end code to pass us 
  3787.                     // the new thing instead.)
  3788.                     NPEvent* oldEvent = (NPEvent*)event;
  3789.                     NPPluginEvent newEvent;
  3790. #if defined(XP_MAC)
  3791.                     newEvent.event = oldEvent;
  3792.                     newEvent.window = window;
  3793. #elif defined(XP_WIN)
  3794.                     newEvent.event = oldEvent->event;
  3795.                     newEvent.wParam = oldEvent->wParam;
  3796.                     newEvent.lParam = oldEvent->lParam;
  3797. #elif defined(XP_OS2)
  3798.                     newEvent.event = oldEvent->event;
  3799.                     newEvent.wParam = oldEvent->wParam;
  3800.                     newEvent.lParam = oldEvent->lParam;
  3801. #elif defined(XP_UNIX)
  3802.                     XP_MEMCPY(&newEvent.event, event, sizeof(XEvent));
  3803.                     // we don't need window for unix -- it's already in the event
  3804. #endif
  3805.                     return userInst->HandleEvent(&newEvent);
  3806.                 }
  3807.                 else if (handle->f && ISFUNCPTR(handle->f->event)) {
  3808.                     // window is not passed through to old-style plugins
  3809.                     // XXX shouldn't this check for windowless plugins only?
  3810.                     return CallNPP_HandleEventProc(handle->f->event, ndata->instance->npp, event);
  3811.                 }
  3812.             }
  3813.         }
  3814.     }
  3815.     return 0;
  3816. }
  3817.  
  3818. void npn_registerwindow(NPP npp, void* window)
  3819. {
  3820. #ifdef XP_MAC
  3821.     if(npp) {
  3822.         np_instance* instance = (np_instance*) npp->ndata;
  3823.         FE_RegisterWindow(instance->app->fe_data, window);
  3824.     }
  3825. #endif
  3826. }
  3827.  
  3828. void npn_unregisterwindow(NPP npp, void* window)
  3829. {
  3830. #ifdef XP_MAC
  3831.     if(npp) {
  3832.         np_instance* instance = (np_instance*) npp->ndata;
  3833.         FE_UnregisterWindow(instance->app->fe_data, window);
  3834.     }
  3835. #endif
  3836. }
  3837.  
  3838. XP_Bool
  3839. npn_IsWindowless(np_handle* handle)
  3840. {
  3841.     if (handle->userPlugin) {
  3842.         // XXX anybody using the new plugin api supports windowless, right?
  3843.         return TRUE;
  3844.     }
  3845.     else {
  3846.         return handle->f->version >= NPVERS_HAS_WINDOWLESS;
  3847.     }
  3848. }
  3849.  
  3850. void
  3851. NPL_Print(NPEmbeddedApp *app, void *pdata)
  3852. {
  3853.     if (app)
  3854.     {
  3855.         np_data *ndata = (np_data *)app->np_data;
  3856.         if(ndata && ndata->instance)
  3857.         {
  3858.             np_handle *handle = ndata->instance->handle;
  3859.             if(handle)
  3860.             {
  3861.                 NPPrint * nppr = (NPPrint *)pdata;
  3862.                 if (nppr && (nppr->mode == NP_EMBED) && !npn_IsWindowless(handle)) 
  3863.                 {
  3864.                     /*
  3865.                        If old (pre-4.0) plugin version, have to the "platformPrint" void * up,
  3866.                        because window.type didn't previously exist.
  3867.                       
  3868.                         check plugin version:  
  3869.                         Major,Minor version = 0,11 or greater => 4.0, 
  3870.                         else < 4.0
  3871.                     */
  3872.  
  3873.                     NPWindowType old_type = nppr->print.embedPrint.window.type;
  3874.                     void * addr1 = (void *)&nppr->print.embedPrint.window.type;
  3875.  
  3876.                     void * old_plat_print = nppr->print.embedPrint.platformPrint;
  3877.                     void * addr2 = (void *)&nppr->print.embedPrint.platformPrint;
  3878.  
  3879.                     XP_MEMCPY(addr1,addr2,sizeof(nppr->print.embedPrint.platformPrint));
  3880.  
  3881.                     TRACEMSG(("npglue.c: CallNPP_PrintProc(1)"));
  3882.                     if (handle->userPlugin) {
  3883.                         nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)ndata->instance->npp->pdata;
  3884.                         NPIPluginInstance* userInst = peerInst->GetUserInstance();
  3885.                         userInst->Print((NPPluginPrint*)pdata);
  3886.  
  3887.                         
  3888.                     }
  3889.                     else if (handle->f && ISFUNCPTR(handle->f->print)) {
  3890.                         CallNPP_PrintProc(handle->f->print, ndata->instance->npp, (NPPrint*)pdata);
  3891.                     }
  3892.  
  3893.                     /* Now restore for downstream dependencies */
  3894.                     nppr->print.embedPrint.window.type   = old_type;
  3895.                     nppr->print.embedPrint.platformPrint = old_plat_print;
  3896.  
  3897.                 }
  3898.                 else{
  3899.                     TRACEMSG(("npglue.c: CallNPP_PrintProc(2)"));
  3900.                     if (handle->userPlugin) {
  3901.                         nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*)ndata->instance->npp->pdata;
  3902.                         NPIPluginInstance* userInst = peerInst->GetUserInstance();
  3903.                         userInst->Print((NPPluginPrint*)pdata);
  3904.                     }
  3905.                     else if (handle->f && ISFUNCPTR(handle->f->print)) {
  3906.                         CallNPP_PrintProc(handle->f->print, ndata->instance->npp, (NPPrint*)pdata);
  3907.                     }
  3908.                 }
  3909.  
  3910.             }
  3911.         }
  3912.     }
  3913. }
  3914.  
  3915. void
  3916. np_deleteapp(MWContext* cx, NPEmbeddedApp* app)
  3917. {
  3918.     if (app)
  3919.     {
  3920.         if (cx)
  3921.             np_unbindContext(app, cx);
  3922.         
  3923.         XP_FREE(app);
  3924.     }
  3925. }
  3926.  
  3927.  
  3928. /*
  3929.  * This is called by the front-end via layout when the plug-in's
  3930.  * context is going away.  Based on what kind of plugin this is, what
  3931.  * the context looks like, etc., we decided whether to destroy the
  3932.  * plug-in's window or to make the front-end store it somewhere safe
  3933.  * for us.
  3934.  */
  3935. extern void
  3936. NPL_EmbedDelete(MWContext* cx, LO_EmbedStruct* embed_struct)
  3937. {
  3938.     NPEmbeddedApp* app;
  3939.     np_data* ndata;
  3940.     
  3941.     if (!cx || !embed_struct || !embed_struct->FE_Data)
  3942.         return;
  3943.         
  3944.     app = (NPEmbeddedApp*) embed_struct->FE_Data;
  3945.     embed_struct->FE_Data = NULL;
  3946.  
  3947.     ndata = (np_data*) app->np_data;
  3948.  
  3949.     if (ndata)
  3950.     {
  3951.         embed_struct->session_data = (void*) ndata;
  3952.             
  3953.         ndata->refs--;
  3954.  
  3955.         /* -1 case is added. It happens when this is fake object */
  3956.         // XXX I think that "fake objects" should no longer be
  3957.         // required now that we actually have a front-end callback to
  3958.         // destroy the window.
  3959.         XP_ASSERT(/* ndata->refs == -1 || */ ndata->refs == 0 || ndata->refs == 1);
  3960.  
  3961.         if (ndata->refs > 0) {
  3962.             /* When done printing, don't delete and don't save session data */
  3963.             XP_ASSERT(cx->type == MWContextPrint || cx->type == MWContextMetaFile ||
  3964.                       cx->type == MWContextPostScript);
  3965.             ndata->state = NPDataCached;
  3966.  
  3967.             /* Tell the front-end to save the embedded window for us */
  3968.             FE_SaveEmbedWindow(cx, app);
  3969.             return;
  3970.            }
  3971.            else if (ndata->state == NPDataCache)
  3972.         {
  3973.             /* Someone is telling us to cache the window; e.g., during
  3974.                a nasty resize */
  3975.             XP_ASSERT(ndata->app);
  3976.             ndata->state = NPDataCached;
  3977.             ndata->lo_struct = NULL;             /* Remove ref to layout structure since it's about to be deleted */
  3978.             np_unbindContext(app, cx);            /* Remove ref to context since it may change */
  3979.  
  3980.             /* Tell the front-end to save the embedded window for us */
  3981.             FE_SaveEmbedWindow(cx, app);
  3982.             return;
  3983.         }
  3984.         else if (ndata->instance)
  3985.         {
  3986.             /* Otherwise, the context is just plain and simple getting
  3987.                blown away */
  3988.             XP_ASSERT(ndata->instance->handle != NULL);
  3989.             if (ndata->instance->handle->userPlugin) {
  3990.                 /* This is a 5.0-style (C++) plugin. We'll simply stop the plugin. */
  3991.  
  3992.                 /* XXX We could just get the _real_ instance by
  3993.                    traversing ndata->sdata, but that scares me for
  3994.                    some reason. */
  3995.                 nsPluginInstancePeer* peerInst = (nsPluginInstancePeer*) ndata->instance->npp->pdata;
  3996.                 NPIPluginInstance* userInst = peerInst->GetUserInstance();
  3997.  
  3998.                 /* XXX Where should this error go? */
  3999.                 NPPluginError err = userInst->Stop();
  4000.                 XP_ASSERT(err == NPPluginError_NoError);
  4001.  
  4002.                 /* XXX So I'm going out on a limb here and saying that
  4003.                    by keeping the plugin in a "cached" state, we
  4004.                    should pretty much not need to perturb much
  4005.                    else... */
  4006.                 ndata->state = NPDataCached;
  4007.                 ndata->lo_struct = NULL;
  4008.                 np_unbindContext(app, cx);
  4009.  
  4010.                 /* Tell the front-end to save the embedded window for us */
  4011.                 FE_SaveEmbedWindow(cx, app);
  4012.                 return;
  4013.             } else {
  4014.                 /* It's a normal old-fashioned plugin. Destroy the instance */
  4015.                 np_delete_instance(ndata->instance);
  4016.  
  4017.                 ndata->app = NULL;
  4018.                 ndata->instance = NULL;
  4019.                 ndata->lo_struct = NULL;
  4020.                 ndata->streamStarted = FALSE;
  4021.                 ndata->state = NPDataSaved;         /* ndata gets freed later when history goes away */
  4022.             }
  4023.         }
  4024.         else
  4025.         {
  4026.             /* If there's no instance, there's no need to save session data */
  4027.             embed_struct->session_data = NULL;
  4028.             app->np_data = NULL;
  4029.             XP_FREE(ndata);
  4030.         }
  4031.     }
  4032.  
  4033.     /* XXX This is pretty convoluted how this just all falls through
  4034.        to here. Clean it up sometime... */
  4035.     np_deleteapp(cx, app);                        /* unlink app from context and delete app */
  4036. }
  4037.  
  4038.  
  4039.  
  4040. /*
  4041.  * Get all the embeds in this context to save themselves in the
  4042.  * designated saved data list so we can reuse them when printing.
  4043.  * (Except hidden ones!)
  4044.  */
  4045. void
  4046. NPL_PreparePrint(MWContext* context, SHIST_SavedData* savedData)
  4047. {
  4048.     NPEmbeddedApp* app;
  4049.     
  4050.     XP_ASSERT(context && savedData);
  4051.     if (!context || !savedData)
  4052.         return;
  4053.     
  4054.     for (app = context->pluginList; app != NULL; app = app->next)
  4055.     {
  4056.         np_data* ndata = (np_data*)app->np_data;
  4057.         XP_ASSERT(ndata);
  4058.         if (ndata && ndata->lo_struct)
  4059.         {    
  4060.             /* ignore this assert if the plugin is hidden */
  4061.             XP_ASSERT(ndata->state == NPDataNormal);
  4062.             ndata->state = NPDataCached;
  4063.             LO_AddEmbedData(context, ndata->lo_struct, ndata);
  4064.         }    
  4065.     }
  4066.     
  4067.     LO_CopySavedEmbedData(context, savedData);
  4068. }
  4069.  
  4070.  
  4071.  
  4072. /*
  4073.  * This function should be moved to layembed.c so the TYPE
  4074.  * attribute is pulled out the same way as the SRC attribute.
  4075.  */
  4076. static char*
  4077. np_findTypeAttribute(LO_EmbedStruct* embed_struct)
  4078. {
  4079.     char* typeAttribute = NULL;
  4080.     int i;
  4081.  
  4082.     /* Look for the TYPE attribute */
  4083.     for (i = 0; i < embed_struct->attribute_cnt; i++)
  4084.     {
  4085.         if (XP_STRCASECMP(embed_struct->attribute_list[i], "TYPE") == 0)
  4086.         {
  4087.             typeAttribute = embed_struct->value_list[i];
  4088.             break;
  4089.         }
  4090.     }
  4091.     
  4092.     return typeAttribute;
  4093. }
  4094.  
  4095.  
  4096. /*
  4097.  * This is called by the front-end to create a new plug-in. It will
  4098.  * fill in the FE_Data member of the embed_struct with a pointer to
  4099.  * the NPEmbeddedApp that gets created.
  4100.  */
  4101. NPEmbeddedApp*
  4102. NPL_EmbedCreate(MWContext* cx, LO_EmbedStruct* embed_struct)
  4103. {
  4104.     NPEmbeddedApp* app = NULL;
  4105.     np_data* ndata = NULL;
  4106.     
  4107.     XP_ASSERT(cx && embed_struct);
  4108.     if (!cx || !embed_struct)
  4109.         goto error;
  4110.         
  4111.     /*
  4112.      * Check the contents of the session data. If we have a cached
  4113.      * app in the session data, we can short-circuit this function
  4114.      * and just return the app we cached earlier.  If we have saved
  4115.      * data in the session data, keep that np_data object but 
  4116.      * attach it to a new app.  If there is nothing in the session
  4117.      * data, then we must create both a np_data object and an app.
  4118.      */
  4119.     if (embed_struct->session_data)
  4120.     {
  4121.         ndata = (np_data*) embed_struct->session_data;
  4122.         embed_struct->session_data = NULL;
  4123.  
  4124.         if (ndata->state == NPDataCached)            /* We cached this app, so don't create another */
  4125.         {
  4126.             XP_ASSERT(ndata->app);
  4127.             if (cx->type == MWContextPrint ||
  4128.                 cx->type == MWContextMetaFile ||
  4129.                 cx->type == MWContextPostScript)
  4130.             {
  4131.                 /* This is a printing "instance" that we're restoring
  4132.                    from the session data */
  4133.                 if (ndata->app->pagePluginType == NP_FullPage)
  4134.                 {
  4135.                     np_reconnect* reconnect;
  4136.                     if (!cx->pluginReconnect)
  4137.                         cx->pluginReconnect = XP_NEW_ZAP(np_reconnect);
  4138.                     reconnect = (np_reconnect*) cx->pluginReconnect;
  4139.                     if (reconnect)
  4140.                         reconnect->app = ndata->app;
  4141.                 }
  4142.  
  4143. #ifdef LAYERS
  4144.                 if ((cx->compositor) && ndata->instance) {
  4145.                     LO_SetEmbedType(embed_struct, (PRBool)ndata->instance->windowed);
  4146.                 }
  4147. #endif /* LAYERS */
  4148.             }
  4149.             else
  4150.             {
  4151.                 /* It's a real instance that we're restoring from the
  4152.                    session data */
  4153.                    ndata->lo_struct = embed_struct;        /* Set reference to new layout structure */
  4154.                    np_bindContext(ndata->app, cx);            /* Set reference to (potentially) new context */
  4155.                 ndata->state = NPDataNormal;
  4156. #ifdef LAYERS
  4157.                 if (ndata->instance) {
  4158.                     ndata->instance->layer = embed_struct->layer;
  4159.                     LO_SetEmbedType(ndata->lo_struct, 
  4160.                                     (PRBool)ndata->instance->windowed);
  4161.                 }
  4162. #endif /* LAYERS */
  4163.             }
  4164.             
  4165.             /*
  4166.              * For full-page/frame plug-ins, make sure scroll
  4167.              * bars are off in the (potentially) new context.
  4168.              */
  4169.             if (ndata->app->pagePluginType == NP_FullPage)
  4170.                 FE_ShowScrollBars(cx, FALSE);
  4171.                 
  4172.             /*
  4173.              * Increment the refcount since this app is now in use.
  4174.              * Currently the most refs we can have will be 2, if
  4175.              * this app is being displayed in one context and 
  4176.              * printed in another.
  4177.              */
  4178.             ndata->refs++;
  4179.             XP_ASSERT(ndata->refs == 1 || ndata->refs == 2);
  4180.  
  4181.             /* Make the front-end restore the embedded window from
  4182.                it's saved context. */
  4183.             if (! (embed_struct->ele_attrmask & LO_ELE_HIDDEN))
  4184.                 FE_RestoreEmbedWindow(cx, ndata->app);
  4185.  
  4186.             /* Tie the app to the layout struct. */
  4187.             embed_struct->FE_Data = ndata->app;
  4188.             return ndata->app;
  4189.         }
  4190.  
  4191.         /* If not cached, it's just saved data. (XXX NPL_StartPlugin
  4192.            will take care of re-constituting it?) */
  4193.         XP_ASSERT(ndata->state == NPDataSaved);
  4194.         XP_ASSERT(ndata->app == NULL);
  4195.         XP_ASSERT(ndata->instance == NULL);
  4196.         XP_ASSERT(ndata->lo_struct == NULL);
  4197.         XP_ASSERT(ndata->streamStarted == FALSE);
  4198.         XP_ASSERT(ndata->refs == 0);
  4199.     }
  4200.  
  4201.     /* So now we either have a "saved" pre-5.0 style plugin, or a
  4202.        brand new plugin. */
  4203.     if (!ndata)
  4204.     {
  4205.         ndata = XP_NEW_ZAP(np_data);
  4206.         if (!ndata)
  4207.             goto error;
  4208.     }
  4209.     ndata->state = NPDataNormal;
  4210.     ndata->lo_struct = embed_struct;
  4211.  
  4212.     /*
  4213.      * Create the NPEmbeddedApp and attach it to its context.
  4214.      */
  4215.     app = XP_NEW_ZAP(NPEmbeddedApp);
  4216.     if (!app)
  4217.         goto error;
  4218.     app->np_data = (void*) ndata;
  4219.     app->type = NP_Untyped;
  4220.     ndata->refs = 1;
  4221.     ndata->app = app;
  4222.     np_bindContext(app, cx);
  4223.  
  4224.     /* Tell the front-end to create the plugin window for us. */
  4225.     if (! (embed_struct->ele_attrmask & LO_ELE_HIDDEN))
  4226.         FE_CreateEmbedWindow(cx, app);
  4227.     
  4228.     /* Attach the app to the layout info */
  4229.     embed_struct->FE_Data = ndata->app;
  4230.     return app;
  4231.     
  4232. error:    
  4233.     if (app)
  4234.         np_deleteapp(cx, app);            /* Unlink app from context and delete app */
  4235.     if (ndata)
  4236.         XP_FREE(ndata);
  4237.     return NULL;
  4238. }
  4239.  
  4240.  
  4241. NPError
  4242. NPL_EmbedStart(MWContext* cx, LO_EmbedStruct* embed_struct, NPEmbeddedApp* app)
  4243. {
  4244.     np_handle* handle;
  4245.     np_mimetype* mimetype;
  4246.     char* typeAttribute;
  4247.     np_data* ndata = NULL;
  4248.     
  4249.     if (!cx || !embed_struct || !app)
  4250.         goto error;
  4251.         
  4252.     ndata = (np_data*) app->np_data;
  4253.     if (!ndata)
  4254.         goto error;
  4255.     
  4256.     /*
  4257.      * Don't do all the work in this function multiple times for the
  4258.      * same NPEmbeddedApp.  For example, we could be reusing this 
  4259.      * app in a new context (when resizing or printing) or just re-
  4260.      * creating the app multiple times (when laying out complex tables),
  4261.      * so we don't want to be creating another stream, etc. each
  4262.      * time. 
  4263.      */
  4264.     if (ndata->streamStarted)
  4265.         return NPERR_NO_ERROR;
  4266.     ndata->streamStarted = TRUE;            /* Remember that we've been here */
  4267.     
  4268.     /*
  4269.      * First check for a TYPE attribute.  The type specified
  4270.      * will override the MIME type of the SRC (if present).
  4271.      */
  4272.     typeAttribute = np_findTypeAttribute(embed_struct);
  4273.     if (typeAttribute)
  4274.     {
  4275.         /* Only embedded plug-ins can have a TYPE attribute */
  4276.         app->pagePluginType = NP_Embedded;
  4277.  
  4278.         /* Found the TYPE attribute, so look for a matching handler */
  4279.         mimetype = NULL;
  4280.         for (handle = np_plist; handle; handle = handle->next)
  4281.         {
  4282.             mimetype = np_getmimetype(handle, typeAttribute, FALSE);
  4283.             if (mimetype) break;
  4284.         }
  4285.  
  4286.         /* No handler with an exactly-matching name, so check for a wildcard */ 
  4287.         if (!mimetype) 
  4288.         {
  4289.             for (handle = np_plist; handle; handle = handle->next)
  4290.             {
  4291.                 mimetype = np_getmimetype(handle, typeAttribute, TRUE);
  4292.                 if (mimetype) break;
  4293.             }
  4294.         }
  4295.  
  4296.         /*
  4297.          * If we found a handler, now we can create an instance.
  4298.          * If we didn't find a handler, we have to use the SRC
  4299.          * to determine the MIME type later (so there better be
  4300.          * SRC, or it's an error).
  4301.          */
  4302.         if (mimetype)
  4303.         {
  4304.             ndata->instance = np_newinstance(handle, cx, app, mimetype, typeAttribute);
  4305.             if (ndata->instance == NULL)
  4306.                 goto error;
  4307.  
  4308. #ifdef LAYERS
  4309.             LO_SetEmbedType(ndata->lo_struct, (PRBool) ndata->instance->windowed);
  4310. #endif
  4311.         }
  4312.     }
  4313.      
  4314.     /*
  4315.      * Now check for the SRC attribute.
  4316.      * - If it's full-page, create a instance now since we already 
  4317.      *     know the MIME type (NPL_NewStream has already happened).
  4318.      * - If it's embedded, create a stream for the URL (we'll create 
  4319.      *     the instance when we get the stream in NPL_NewStream).
  4320.      */
  4321.     if (embed_struct->embed_src)
  4322.     {
  4323.         char* theURL;
  4324.         PA_LOCK(theURL, char*, embed_struct->embed_src);
  4325.         XP_ASSERT(theURL);
  4326.         if (XP_STRCMP(theURL, "internal-external-plugin") == 0)
  4327.         {
  4328.             /*
  4329.              * Full-page case: Stream already exists, so now
  4330.              * we can create the instance.
  4331.              */
  4332.             np_reconnect* reconnect;
  4333.             np_mimetype* mimetype;
  4334.             np_handle* handle;
  4335.             np_instance* instance;
  4336.             char* requestedtype;
  4337.             
  4338.             app->pagePluginType = NP_FullPage;
  4339.  
  4340.             reconnect = (np_reconnect*) cx->pluginReconnect;
  4341.             XP_ASSERT(reconnect); 
  4342.             if (!reconnect)
  4343.             {
  4344.                 PA_UNLOCK(embed_struct->embed_src); 
  4345.                 goto error;
  4346.             }
  4347.             
  4348.             mimetype = reconnect->mimetype;
  4349.             requestedtype = reconnect->requestedtype;
  4350.             handle = mimetype->handle;
  4351.             
  4352.             /* Now we can create the instance */
  4353.             XP_ASSERT(ndata->instance == NULL);
  4354.             instance = np_newinstance(handle, cx, app, mimetype, requestedtype);
  4355.             if (!instance)
  4356.             {
  4357.                 PA_UNLOCK(embed_struct->embed_src); 
  4358.                 goto error;
  4359.             }
  4360.         
  4361.             reconnect->app = app;
  4362.             ndata->instance =  instance;
  4363.             ndata->handle = handle;
  4364.             ndata->instance->app = app;
  4365.             FE_ShowScrollBars(cx, FALSE);
  4366. #ifdef LAYERS
  4367.             LO_SetEmbedType(ndata->lo_struct, (PRBool) ndata->instance->windowed);
  4368. #endif
  4369.         }
  4370.         else
  4371.         {
  4372.             /*
  4373.              * Embedded case: Stream doesn't exist yet, so
  4374.              * we need to create it before we can make the
  4375.              * instance (exception: if there was a TYPE tag,
  4376.              * we already know the MIME type so the instance
  4377.              * already exists).
  4378.              */
  4379.             app->pagePluginType = NP_Embedded;
  4380.             
  4381.             if ((embed_struct->ele_attrmask & LO_ELE_STREAM_STARTED) == 0)
  4382.             {
  4383.                 URL_Struct* pURL;    
  4384.                 pURL = NET_CreateURLStruct(theURL, NET_DONT_RELOAD);
  4385.                 pURL->fe_data = (void*) app;
  4386.         
  4387.                 /* start a stream */
  4388.                 (void) NET_GetURL(pURL, FO_CACHE_AND_EMBED, cx, NPL_EmbedURLExit);
  4389.             }
  4390.         }
  4391.         
  4392.         PA_UNLOCK(embed_struct->embed_src); 
  4393.     }
  4394.     
  4395.     return NPERR_NO_ERROR;
  4396.  
  4397. error:
  4398.     if (cx && app)
  4399.         np_deleteapp(cx, app);            /* Unlink app from context and delete app */
  4400.     if (ndata)
  4401.         XP_FREE(ndata);
  4402.     return NPERR_GENERIC_ERROR;
  4403. }
  4404.  
  4405.  
  4406. /*
  4407.  * Called by the front-end via layout whenever layout information changes,
  4408.  * including size, visibility status, etc.
  4409.  */
  4410. void
  4411. NPL_EmbedSize(NPEmbeddedApp *app)
  4412. {
  4413.     if(app)
  4414.     {
  4415.         np_data *ndata = (np_data *)app->np_data;
  4416.         if(ndata && ndata->instance && app->wdata)
  4417.             np_setwindow(ndata->instance, app->wdata);
  4418.     }
  4419. }
  4420.  
  4421. /* the following is used in CGenericDoc::FreeEmbedElement */
  4422. int32
  4423. NPL_GetEmbedReferenceCount(NPEmbeddedApp *app)
  4424. {
  4425.   np_data *ndata = (np_data *)app->np_data;
  4426.   int32 iRet = ndata->refs;
  4427.   return iRet;
  4428. }
  4429.  
  4430. XP_Bool          
  4431. NPL_IsEmbedWindowed(NPEmbeddedApp *app)
  4432. {
  4433.     if(app)
  4434.     {
  4435.         np_data *ndata = (np_data *)app->np_data;
  4436.         if (ndata && ndata->instance)
  4437.             return ndata->instance->windowed;
  4438.         else
  4439.             return FALSE;
  4440.     }
  4441.     else
  4442.         return FALSE;
  4443. }
  4444.  
  4445.  
  4446. /*
  4447.  * This is called by layout when the context in which the embedded
  4448.  * object lives is finally decimated. We need to decide:
  4449.  *
  4450.  * 1. Exactly what kind of context is getting destroyed (e.g., we
  4451.  * could care less if it's a printing context, because it was a
  4452.  * "dummy" context, anyway).
  4453.  *
  4454.  * 2. whether or not we have left an embedded window lying around in
  4455.  * the front-end somewhere.
  4456.  */
  4457. void
  4458. NPL_DeleteSessionData(MWContext* context, void* sdata)
  4459. {
  4460.     XP_Bool bFreeSessionData = TRUE;
  4461.     np_data* ndata = (np_data*) sdata;
  4462.  
  4463.     /*
  4464.      * Printing Case
  4465.      *
  4466.      * Don't delete the data if we're printing, since
  4467.      * data really belongs to the original context (a
  4468.      * MWContextBrowser).  A more generic way to make
  4469.      * this check might be 'if (context != ndata->
  4470.      * instance->cx)'.
  4471.      */
  4472.     // XXX Ugh. Now the front-end thinks we've freed our session data, but
  4473.     // in reality we just leaked some memory and maybe a widget or two...
  4474.     if (ndata == NULL ||
  4475.         context->type == MWContextPrint ||
  4476.         context->type == MWContextMetaFile ||
  4477.         context->type == MWContextPostScript)
  4478.         return;
  4479.         
  4480.  
  4481.     if (ndata->state == NPDataCached) {
  4482.         if (ndata->instance != NULL && np_is50StylePlugin(ndata->instance->handle)) {
  4483.             /*
  4484.              * 5.0-style (C++) plugin case
  4485.              *
  4486.              * Since 5.0-style plugins aren't deleted and unloaded as
  4487.              * soon as the current context goes away, they lie around
  4488.              * in the history for a while with the data state as
  4489.              * NPDataCached. In this case, we've been called back to
  4490.              * let us know that it's time to clean up our act.
  4491.              */
  4492.             
  4493.             np_delete_instance(ndata->instance);
  4494.             return;
  4495.         }
  4496.  
  4497.         /*
  4498.          * Resize case 
  4499.          *
  4500.          * This case happens when we resize a page but must
  4501.          * delete the session history of the old page before
  4502.          * creating the new (resized) one.  Typically this
  4503.          * happens because the resized page isn't in the cache;
  4504.          * thus we must retrieve the document from the net and
  4505.          * can't use its session data because we don't know if
  4506.          * the document has changed or not.  In this case,
  4507.          * NPL_EmbedDelete was already called for the instances
  4508.          * of the original document, but we didn't delete the
  4509.          * instances because we were expecting to re-use them
  4510.          * in the resized document.  Since the session data is
  4511.          * going away, we won't have that opportunity, so we
  4512.          * must delete them here, or else the instances will be
  4513.          * left dangling, which is really bad.
  4514.          */
  4515.  
  4516.         /* Shouldn't have instance data when resizing */
  4517.         XP_ASSERT(ndata->sdata == NULL);
  4518.         XP_ASSERT(ndata->app != NULL);
  4519.  
  4520.         /*
  4521.          * Fall through to saved instance case so ndata and
  4522.          * plug-in's saved data and will be deleted.
  4523.          */
  4524.     }
  4525.  
  4526.  
  4527.     /* ndata could be already freed by this point in NPL_EmbedDelete call
  4528.      * so check session_data which is zeroed in this case
  4529.      */
  4530.     if(bFreeSessionData)
  4531.         {
  4532.             /*
  4533.              * Saved instance data case
  4534.              *
  4535.              * This case occurs when session history is deleted for
  4536.              * a document that previously contained a plug-in. 
  4537.              * The plug-in may have given us a NPSavedData structure
  4538.              * to store for it, which we must delete here.
  4539.              */
  4540.             XP_ASSERT(ndata->state == NPDataSaved);
  4541.             XP_ASSERT(ndata->app == NULL);
  4542.             XP_ASSERT(ndata->streamStarted == FALSE);
  4543.  
  4544.             // XXX I don't think we should ever get here with a
  4545.             // 5.0-style (C++) plugin since, by default, they cache
  4546.             // themselves. Throw in an assert just to make sure...
  4547.             XP_ASSERT(ndata->instance == NULL || !np_is50StylePlugin(ndata->instance->handle));
  4548.  
  4549.             if (ndata->sdata) {
  4550.                 if (ndata->sdata->buf)
  4551.                     XP_FREE(ndata->sdata->buf);
  4552.                 XP_FREE(ndata->sdata);
  4553.                 ndata->sdata = 0;
  4554.             }
  4555.  
  4556.             ndata->handle = NULL;
  4557.             XP_FREE(ndata);
  4558.         }
  4559.  
  4560.     // XXX Err...what's the point?
  4561.     ndata = NULL;
  4562. }
  4563.  
  4564.  
  4565. NPBool
  4566. NPL_IteratePluginFiles(NPReference* ref, char** name, char** filename, char** description)
  4567. {
  4568.     np_handle* handle;
  4569.     
  4570.     if (*ref == NPRefFromStart)
  4571.         handle = np_plist;
  4572.     else
  4573.         handle = ((np_handle*) *ref)->next;
  4574.  
  4575.     if (handle)
  4576.     {
  4577.         if (name)
  4578.             *name = handle->name;
  4579.         if (filename)
  4580.             *filename = handle->filename;
  4581.         if (description)
  4582.             *description = handle->description;
  4583.     }
  4584.     
  4585.     *ref = handle;
  4586.     return (handle != NULL);
  4587. }
  4588.  
  4589.  
  4590. NPBool
  4591. NPL_IteratePluginTypes(NPReference* ref, NPReference plugin, NPMIMEType* type, char*** extents,
  4592.          char** description, void** fileType)
  4593. {
  4594.     np_handle* handle = (np_handle*) plugin;
  4595.     np_mimetype* mimetype;
  4596.     
  4597.     if (*ref == NPRefFromStart)
  4598.         mimetype = handle->mimetypes;
  4599.     else    
  4600.         mimetype = ((np_mimetype*) *ref)->next;
  4601.         
  4602.     if (mimetype)
  4603.     {
  4604.         if (type)
  4605.             *type = mimetype->type;
  4606.         if (description)
  4607.             *description = mimetype->fassoc->description;
  4608.         if (extents)
  4609.             *extents = mimetype->fassoc->extentlist;
  4610.         if (fileType)
  4611.             *fileType = mimetype->fassoc->fileType;
  4612.     }
  4613.     
  4614.     *ref = mimetype;
  4615.     return (mimetype != NULL);
  4616.     
  4617. }
  4618.  
  4619.  
  4620.  
  4621.  
  4622. /*
  4623.  * Returns a null-terminated array of plug-in names that support the specified MIME type.
  4624.  * This function is called by the FEs to implement their MIME handler controls (they need
  4625.  * to know which plug-ins can handle a particular type to build their popup menu).
  4626.  * The caller is responsible for deleting the strings and the array itself. 
  4627.  */
  4628. char**
  4629. NPL_FindPluginsForType(const char* typeToFind)
  4630. {
  4631.     char** result;
  4632.     uint32 count = 0;
  4633.  
  4634.     /* First count plug-ins that support this type */
  4635.     {
  4636.         NPReference plugin = NPRefFromStart;
  4637.         while (NPL_IteratePluginFiles(&plugin, NULL, NULL, NULL))
  4638.         {
  4639.             char* type;
  4640.             NPReference mimetype = NPRefFromStart;
  4641.             while (NPL_IteratePluginTypes(&mimetype, plugin, &type, NULL, NULL, NULL))
  4642.             {
  4643.                 if (strcmp(type, typeToFind) == 0)
  4644.                     count++;
  4645.             }
  4646.         }
  4647.     }
  4648.  
  4649.     /* Bail if no plug-ins match this type */
  4650.     if (count == 0)
  4651.         return NULL;
  4652.         
  4653.     /* Make an array big enough to hold the plug-ins */
  4654.     result = (char**) XP_ALLOC((count + 1) * sizeof(char*));
  4655.     if (!result)
  4656.         return NULL;
  4657.  
  4658.     /* Look for plug-ins that support this type and put them in the array */
  4659.     count = 0;
  4660.     {
  4661.         char* name;
  4662.         NPReference plugin = NPRefFromStart;
  4663.         while (NPL_IteratePluginFiles(&plugin, &name, NULL, NULL))
  4664.         {
  4665.             char* type;
  4666.             NPReference mimetype = NPRefFromStart;
  4667.             while (NPL_IteratePluginTypes(&mimetype, plugin, &type, NULL, NULL, NULL))
  4668.             {
  4669.                 if (strcmp(type, typeToFind) == 0)
  4670.                     result[count++] = XP_STRDUP(name);
  4671.             }
  4672.         }
  4673.     }
  4674.     
  4675.     /* Null-terminate the array and return it */
  4676.     result[count] = NULL;
  4677.     return result;
  4678. }
  4679.  
  4680.  
  4681. /*
  4682.  * Returns the name of the plug-in enabled for the 
  4683.  * specified type, of NULL if no plug-in is enabled.
  4684.  * The caller is responsible for deleting the string. 
  4685.  */
  4686. char*
  4687. NPL_FindPluginEnabledForType(const char* typeToFind)
  4688. {
  4689.     np_handle* handle = np_plist;
  4690.     while (handle)
  4691.     {
  4692.         np_mimetype* mimetype = handle->mimetypes;
  4693.         while (mimetype)
  4694.         {
  4695.             if ((strcmp(mimetype->type, typeToFind) == 0) && mimetype->enabled)
  4696.                 return XP_STRDUP(handle->name);
  4697.             mimetype = mimetype->next;
  4698.         }
  4699.         
  4700.         handle = handle->next;
  4701.     }
  4702.     
  4703.     return NULL;
  4704. }
  4705.  
  4706.  
  4707.  
  4708. #if !defined(XP_MAC) && !defined(XP_UNIX)        /* plugins change */
  4709.  
  4710. /* put_block modifies input buffer. We cannot pass static data to it.
  4711.  * And hence the strdup.
  4712.  */
  4713. #define PUT(string) if(string) { \
  4714.     char *s = XP_STRDUP(string); \
  4715.     int ret; \
  4716.     ret = (*stream->put_block)(stream,s, XP_STRLEN(s)); \
  4717.        XP_FREE(s); \
  4718.     if (ret < 0) \
  4719.         return; \
  4720. }
  4721.  
  4722. void
  4723. NPL_DisplayPluginsAsHTML(FO_Present_Types format_out, URL_Struct *urls, MWContext *cx)
  4724. {
  4725.     NET_StreamClass * stream;
  4726.     np_handle *handle;
  4727.  
  4728.     StrAllocCopy(urls->content_type, TEXT_HTML);
  4729.     format_out = CLEAR_CACHE_BIT(format_out);
  4730.  
  4731.     stream = NET_StreamBuilder(format_out, urls, cx);
  4732.     if (!stream)
  4733.         return;
  4734.  
  4735.     if (np_plist)
  4736.     {
  4737.         PUT("<b><font size=+3>Installed plug-ins</font></b><br>");
  4738.     }
  4739.     else
  4740.     {
  4741.         PUT("<b><font size=+2>No plug-ins are installed.</font></b><br>");
  4742.     }
  4743.     
  4744.     PUT("For more information on plug-ins, <A HREF=http://home.netscape.com/comprod/products/navigator/version_2.0/plugins/index.html>click here</A>.<p><hr>");
  4745.     
  4746.     for (handle = np_plist; handle; handle = handle->next)
  4747.     {
  4748.         np_mimetype* mimetype;
  4749.         
  4750.         PUT("<b><font size=+2>");
  4751.         PUT(handle->name);
  4752.         PUT("</font></b><br>");
  4753.  
  4754.         PUT("File name: ");
  4755.         PUT(handle->filename);
  4756.         PUT("<br>");
  4757.         
  4758.         PUT("MIME types: <br>");
  4759.         PUT("<ul>");
  4760.         for (mimetype = handle->mimetypes; mimetype; mimetype = mimetype->next)
  4761.         {
  4762.             int index = 0;
  4763.             char** extents = mimetype->fassoc->extentlist;
  4764.             
  4765.             PUT("Type: ");
  4766.             PUT(mimetype->type);
  4767.             if (!mimetype->enabled)
  4768.                 PUT(" (disabled)");
  4769.             PUT("<br>");
  4770.             
  4771.             PUT("File extensions: ");
  4772.             while (extents[index])
  4773.             {
  4774.                 PUT(extents[index]);
  4775.                 index++;
  4776.                 if (extents[index])
  4777.                     PUT(", ");
  4778.             }
  4779.             PUT("<br>");
  4780.         }
  4781.         PUT("</ul>");
  4782.         
  4783.         PUT("<p>");
  4784.         PUT("<hr>");
  4785.     }
  4786.     
  4787.     (*stream->complete)(stream);
  4788. }
  4789.  
  4790. #endif
  4791.  
  4792. /* ANTHRAX PUBLIC FUNCTIONS */
  4793.  
  4794. /*
  4795.     NPL_FindAppletEnabledForMimetype()
  4796.     ----------------------------------
  4797.      Returns the name of the applet associated AND enabled for the particular mimetype.
  4798.     Returns NULL if no applet has been set to handle this mimetype.  This does not mean
  4799.     that no Applets have been _installed_ for this mimetype - just that none are enabled.
  4800.     
  4801.     mimetype : should be of the form "audio/basic", ect.
  4802.     
  4803.     NOTE: Caller must free returned string.
  4804.     
  4805.     11.15.97
  4806. */
  4807.  
  4808. #ifdef ANTHRAX
  4809. char* NPL_FindAppletEnabledForMimetype(const char* mimetype)
  4810. {
  4811.     char* prefName;
  4812.     char* temp;
  4813.     char* applet;
  4814.     uint32 len;
  4815.     int32 loadAction;
  4816.     
  4817.     prefName = np_CreateMimePref(mimetype, "applet");
  4818.  
  4819.     if(PREF_CopyCharPref(prefName, &applet) == PREF_OK)
  4820.         {
  4821.         /* also check the load action on Mac - this may be XP in the future */
  4822.         XP_FREE(prefName);
  4823.         prefName = np_CreateMimePref(mimetype, "load_action");
  4824.         if(PREF_GetIntPref(prefName, &loadAction) == PREF_OK)
  4825.             if(loadAction == 5)
  4826.                 {
  4827.                 XP_FREE(prefName);
  4828.                 return applet;
  4829.                 }
  4830.         }
  4831.         
  4832.     XP_FREE(prefName);
  4833.     return NULL;
  4834.  
  4835. }
  4836.  
  4837. /* 
  4838.     NPL_FindAppletsForType()
  4839.     ------------------------
  4840.     Returns an array of strings specifying the installed Applets for a particular
  4841.     mimetype.
  4842.     
  4843.     mimetype : should be of the form "audio/basic", ect.
  4844.  
  4845.     NOTE: Caller must free returned array and strings.
  4846.  
  4847.     11.10.97 
  4848. */
  4849.  
  4850. char**
  4851. NPL_FindAppletsForType(const char* mimetype)
  4852. {
  4853.     char** result;
  4854.     char* appletName;
  4855.     int32 numApplets;
  4856.     int32 i;
  4857.     
  4858.     numApplets = np_GetNumberOfInstalledApplets(mimetype);
  4859.     if(numApplets == 0)
  4860.         return NULL;
  4861.     
  4862.     result = (char**) XP_ALLOC(numApplets * sizeof(char*));
  4863.     if (!result)
  4864.         return NULL;
  4865.     
  4866.     for(i=1; i<=numApplets; i++)
  4867.         {
  4868.         if((appletName = np_FindAppletNForMimeType(mimetype, (char)i)) == NULL)
  4869.             return NULL;
  4870.         result[i-1] = appletName;
  4871.         }
  4872.     result[i-1] = NULL;
  4873.         
  4874.     return result;
  4875. }
  4876.  
  4877. /*
  4878.     NPL_RegisterAppletType()
  4879.     ------------------------
  4880.     Lets NetLib know that a particular mimetype should be handled by an Applet.
  4881.     
  4882.     11.10.97
  4883. */
  4884.  
  4885. NPError
  4886. NPL_RegisterAppletType(NPMIMEType type)
  4887. {
  4888.     /*
  4889.      * Is this Applet the wildcard (a.k.a. null) plugin?
  4890.      * If so, we don't want to register it for FO_PRESENT
  4891.      * or it will interfere with our normal unknown-mime-
  4892.      * type handling.
  4893.      */
  4894.     XP_Bool wildtype = (strcmp(type, "*") == 0);
  4895.     np_handle* handle = NULL;
  4896.     
  4897.     for(handle = np_alist; handle != NULL; handle = handle->next)
  4898.         {
  4899.         if(!XP_STRCMP(handle->name, type))
  4900.             break;
  4901.         }
  4902.  
  4903.     if(handle == NULL)
  4904.         {
  4905.         handle = XP_NEW_ZAP(np_handle);
  4906.         if (!handle)
  4907.             return NPERR_OUT_OF_MEMORY_ERROR;
  4908.         
  4909.         StrAllocCopy(handle->name, type);
  4910.         
  4911.         handle->pdesc = NULL;
  4912.         handle->next = np_alist;
  4913.            np_alist = handle;
  4914.         }
  4915.         
  4916. #ifdef XP_WIN
  4917.     /* EmbedStream does some Windows FE work and then calls NPL_NewStream */
  4918.     if (!wildtype)
  4919.         NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, EmbedStream);
  4920.     NET_RegisterContentTypeConverter(type, FO_EMBED, handle, EmbedStream); /* XXX I dont think this does anything useful */
  4921. #else
  4922.     if (!wildtype)
  4923.       {
  4924.         NET_RegisterContentTypeConverter(type, FO_PRESENT, handle, NPL_NewPresentStream);
  4925. #ifdef XP_UNIX
  4926.         /* While printing we use the FO_SAVE_AS_POSTSCRIPT format type. We want
  4927.          * plugin to possibly handle that case too. Hence this.
  4928.          */
  4929.         NET_RegisterContentTypeConverter(type, FO_SAVE_AS_POSTSCRIPT, handle,
  4930.                                          NPL_NewPresentStream);
  4931. #endif /* XP_UNIX */
  4932.       }
  4933.     NET_RegisterContentTypeConverter(type, FO_EMBED, handle, NPL_NewEmbedStream);
  4934. #endif
  4935.     NET_RegisterContentTypeConverter(type, FO_PLUGIN, handle, np_newpluginstream);
  4936.     NET_RegisterContentTypeConverter(type, FO_BYTERANGE, handle, np_newbyterangestream);
  4937.     
  4938.     return NPERR_NO_ERROR;
  4939. }
  4940.  
  4941. /* ANTHRAX STATIC FUNCTIONS */
  4942.  
  4943. /*
  4944.     np_FindAppletNForMimeType()
  4945.     ---------------------------
  4946.     Returns a string to the Nth installed applet as specified by index.
  4947.     Returns NULL if no applet is installed for that type.
  4948.  
  4949.     mimetype : should be of the form "audio/basic", ect.
  4950.  
  4951.     NOTE: Caller must free returned string.
  4952. */
  4953.  
  4954. static char* np_FindAppletNForMimeType(const char* mimetype, char index)
  4955. {
  4956.     char* prefName;
  4957.     char pref[] = { 'a', 'p', 'p', 'l', 'e', 't', '1', '\0'};
  4958.     char* applet;
  4959.     uint32 len;
  4960.  
  4961.     pref[6] = (index+48);
  4962.     prefName = np_CreateMimePref(mimetype, pref);
  4963.  
  4964.     if(PREF_CopyCharPref(prefName, &applet) == PREF_OK)
  4965.         {
  4966.         XP_FREE(prefName);
  4967.         return applet;
  4968.         }
  4969.     else
  4970.         {
  4971.         XP_FREE(prefName);
  4972.         return NULL;
  4973.         }
  4974. }
  4975.  
  4976. /*
  4977.     np_GetNumberOfInstalledApplets()
  4978.     --------------------------------
  4979.     Returns the number of Applets that have been installed for a particular
  4980.     mimetype.
  4981.     
  4982.     mimetype : should be of the form "audio/basic", ect.
  4983. */
  4984.  
  4985. static int32 np_GetNumberOfInstalledApplets(const char* mimetype)
  4986. {
  4987.     char* prefName;
  4988.     char* temp;
  4989.     uint32 len;
  4990.     int32 numApplets;
  4991.     
  4992.     numApplets = 0;
  4993.     
  4994.     prefName = np_CreateMimePref(mimetype, "num_applets");
  4995.     
  4996.     PREF_GetIntPref(prefName, &numApplets);
  4997.  
  4998.     XP_FREE(prefName);
  4999.     return numApplets;
  5000. }
  5001.  
  5002. /*
  5003.     np_CreateMimePref()
  5004.     -------------------
  5005.     Returns a string formatted in the following way:
  5006.     
  5007.     "mime.<mimetype>.<pref>"
  5008.     
  5009.     All '/' and '-' characters in <mimetype> and <pref> are converted to '_'
  5010.  
  5011.     Returns NULL if there's a faliure on the allocation of memory.
  5012.     
  5013.     12.8.97
  5014. */
  5015.  
  5016. static char* np_CreateMimePref(const char* mimetype, const char* pref)
  5017. {
  5018.     uint32 len;
  5019.     char* prefName;
  5020.     
  5021.     len = XP_STRLEN("mime..") + XP_STRLEN(mimetype) + XP_STRLEN(pref);
  5022.     
  5023.     prefName = XP_ALLOC((len+1)*sizeof(char));
  5024.     XP_ASSERT(prefName);
  5025.     if(!prefName)
  5026.         return NULL;
  5027.         
  5028.     prefName[0] = 0;
  5029.     
  5030.     XP_STRCAT(prefName, "mime.");
  5031.     XP_STRCAT(prefName, mimetype);
  5032.     XP_STRCAT(prefName, ".");
  5033.     XP_STRCAT(prefName, pref);
  5034.  
  5035.     np_ReplaceChars(prefName, '-', '_');
  5036.     np_ReplaceChars(prefName, '/', '_');
  5037.     
  5038.     return prefName;
  5039. }
  5040.  
  5041. /*
  5042.     np_ReplaceChars()
  5043.     -----------------
  5044.     Swaps all occurances of oldChar with newChar in word.
  5045.     Should this be inline?
  5046. */
  5047.  
  5048. static void np_ReplaceChars(char* word, char oldChar, char newChar)
  5049. {
  5050.     char* index;
  5051.     XP_ASSERT(word);
  5052.     for(index = word; *index != 0; ++index)
  5053.         if(*index == oldChar)
  5054.             *index = newChar;
  5055. }
  5056.  
  5057. #endif    /* ANTHRAX */
  5058.  
  5059.