home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / display.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  25.6 KB  |  913 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. // OK, so this module is horribly misnamed.  It contains all of the external
  20. //   streams defined in the front end
  21. //
  22. #include "stdafx.h"
  23.  
  24. #include "display.h"
  25.  
  26. #include "helper.h"
  27. #include "dialog.h"
  28. #include "ngdwtrst.h"
  29. #include "mainfrm.h"
  30. #include "cxsave.h"
  31. #include "errno.h"
  32. #include "prefapi.h"
  33. #include "extgen.h"
  34. #include "viewerse.h"
  35.  
  36. extern "C" int MK_DISK_FULL;  // defined in allxpstr.h
  37. extern "C" int MK_OUT_OF_MEMORY;  // defined in allxpstr.h
  38.  
  39. /*      Stream Object
  40. **      ------------
  41. */                   
  42.  
  43. extern NET_StreamClass *OLE_ViewStream(int format_out, void *pDataObj, URL_Struct *urls,
  44.               MWContext *pContext);
  45.  
  46.  
  47. extern char *FE_FindFileExt(char * path);
  48. extern void FE_LongNameToDosName(char* dest, char* source);
  49.  
  50. #define DEFAULT_BUFFER_SZ 30000
  51.  
  52. struct DataObject {
  53.     /* generic */
  54.     char      * address;
  55.     char      * format_in;
  56.     MWContext * context;
  57.   int         format_out;
  58.  
  59.     /* file stuff */
  60.     char * filename;
  61.     FILE * fp;
  62.  
  63.     /* memory stuff */
  64.     int32  sz;               /* size of buffer */
  65.     char * start;         /* start of buffer */
  66.     char * loc;           /* current posn in buffer */
  67.     int32  content_length; /* size if known */
  68.     int32  cur_loc;
  69.  
  70.     /* external object stuff */
  71.     char * command;       /* command to execute */
  72.     char * params;
  73.     int how_handle;
  74. };
  75.  
  76.  
  77. /****************************************************************************
  78. DISK STREAM DECLARATION
  79. *****************************************************************************/
  80.  
  81. /*  Buffer write.  
  82. **  ------------
  83. */
  84. extern "C"  int 
  85. disk_stream_write (NET_StreamClass *stream, CONST char* s, int32 len)
  86. {
  87.  
  88.     int32 status;
  89.  
  90.     DataObject * data = (DataObject *)stream->data_object;    
  91.  
  92.     if(!data || !data->fp || !len || !s)
  93.         return(0);
  94.  
  95.     status = XP_FileWrite(s, len, data->fp); 
  96.     if(len != status) {
  97.         if(errno == ENOSPC)
  98.             return(MK_DISK_FULL);
  99.         else
  100.             return(-1);
  101.     }
  102.  
  103.     data->cur_loc += len;
  104.  
  105.     float fPercent = 0.0f;
  106.  
  107.     if (data->content_length) 
  108.         fPercent = (float)data->cur_loc / (float)data->content_length;
  109.     if (data->cur_loc) 
  110.         FE_SetProgressBarPercent(data->context, (int)(fPercent * 100));
  111.  
  112.     return((int) status);
  113.  
  114. }
  115.  
  116.  
  117.  
  118. /*  Free the object
  119. **  ---------------
  120. **
  121. */
  122. extern "C"  void 
  123. disk_stream_complete (NET_StreamClass *stream)
  124. {
  125.     DataObject * data = (DataObject *)stream->data_object;    
  126.  
  127.     if(!data)
  128.         return;
  129.  
  130.     if(data->fp) {
  131.         fclose(data->fp);
  132.         data->fp = NULL;
  133.     }
  134.  
  135.     FE_Progress(data->context, szLoadString(IDS_DOC_LOAD_COMPLETE));
  136.  
  137.     if(FEU_Execute(data->context, data->command, data->params)) {
  138.         FE_Progress(data->context, szLoadString(IDS_SPAWNING_EXTERNAL_VIEWER));
  139.     }
  140.  
  141.     if(data->address) {
  142.         XP_FREE(data->address);
  143.         data->address = NULL;
  144.     }
  145.  
  146.     if(data->filename) {
  147.         XP_FREE(data->filename);
  148.         data->filename = NULL;
  149.     }
  150.  
  151.     if(data->params) {
  152.         XP_FREE(data->params);
  153.         data->params = NULL;
  154.     }
  155.  
  156.     delete data;
  157.     return;
  158. }
  159.  
  160. /*  End writing
  161. */
  162.        
  163. extern "C"  void 
  164. disk_stream_abort (NET_StreamClass *stream, int status)
  165. {
  166.     DataObject * data = (DataObject *)stream->data_object;    
  167.  
  168.     char * error_string = "<title>Error</title><H1>Error</h1>Unable to load requested item.";
  169.  
  170.     if (data->fp)
  171.         XP_FileWrite(error_string, XP_STRLEN(error_string), data->fp); 
  172.  
  173.     disk_stream_complete(stream);
  174.  
  175.     return;
  176. }
  177.  
  178.  
  179. //
  180. // Always assume we can write no matter what type of stream we are dealing with
  181. //
  182. static unsigned int 
  183. write_ready(NET_StreamClass *stream)
  184. {    
  185.   return((unsigned int) MAX_WRITE_READY);
  186. }
  187.  
  188. static NET_StreamClass *
  189. ExternalFileSave(int iFormatOut, URL_Struct *pUrl, MWContext *pContext)
  190. {
  191.     //
  192.     // While we have a pointer to the original frame window query
  193.     //   for a filename
  194.     //
  195.     char             *pDestination;
  196.     char             *pSuggested = NULL;
  197.     NET_StreamClass *pRetval = NULL;
  198.  
  199.     //    Prompt the user for a file name.
  200.     //  Security rist to let path information in externally provided
  201.     //      filename (content disposition, filename =)
  202.     if (pUrl->content_name != NULL &&
  203.         strstr(pUrl->content_name, "../") == NULL &&
  204.         strstr(pUrl->content_name, "..\\") == NULL) {
  205.         // Make a copy of the name, because that's what fe_URLtoLocalName() does
  206.         // and the code below is going to XP_FREE pSuggested
  207.         pSuggested = XP_STRDUP(pUrl->content_name);
  208.     }
  209.     if (!pSuggested)
  210.         pSuggested = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
  211. #ifdef XP_WIN16
  212.     char dosName[13];
  213.     FE_LongNameToDosName(dosName, pSuggested);
  214.     pDestination = wfe_GetSaveFileName(GetFrame(pContext)->GetFrameWnd()->m_hWnd, szLoadString(IDS_SAVE_AS), dosName, NULL);
  215. #else
  216.     pDestination = wfe_GetSaveFileName(GetFrame(pContext)->GetFrameWnd()->m_hWnd, szLoadString(IDS_SAVE_AS), pSuggested, NULL);
  217. #endif
  218.     if(pSuggested != NULL)    {
  219.         XP_FREE(pSuggested);
  220.     }
  221.     if(pDestination == NULL)    {
  222.         return(NULL);
  223.     }
  224.  
  225.     //    We're going to be saving this stream.
  226.     //    Check to see if we should attempt to save the file in the
  227.     //        old fashion, or in the new external contexts.
  228.     if(NET_IsSafeForNewContext(pUrl) != FALSE)    {
  229.         //    Attempt to split it off into a new context.
  230.         pRetval = CSaveCX::SaveUrlObject(pUrl, NULL, pDestination);
  231.  
  232.     } else {
  233.         //    We need to continue to use the old method of saving.
  234.  
  235.         //    We have a destination file name.
  236.         FILE *pSink = XP_FileOpen(pDestination, xpTemporary, "wb");
  237.         if(pSink == NULL)    {
  238.             FE_Alert(pContext, szLoadString(IDS_FAILED_CREATE_TEMP_FILE));
  239.             XP_FREE(pDestination);
  240.             return(NULL);
  241.         }
  242.  
  243.         //    Create the data object that will be passed along down
  244.         //        the stream.
  245.         DataObject *pMe = new DataObject;
  246.         if(!pMe)
  247.             return(NULL);
  248.  
  249.         memset(pMe, 0, sizeof(DataObject));
  250.         pMe->how_handle = HANDLE_SAVE;
  251.         pMe->fp = pSink;
  252.         pMe->context = pContext;
  253.         pMe->format_out = iFormatOut;
  254.         pMe->filename = pDestination;
  255.         pMe->content_length = pUrl->content_length < 0 ? 0 : pUrl->content_length;
  256.         pMe->cur_loc = 0;
  257.         StrAllocCopy(pMe->address, pUrl->address);
  258.         StrAllocCopy(pMe->format_in, pUrl->content_type);
  259.  
  260.         //    Progress.
  261.         FE_SetProgressBarPercent(pContext, 0);
  262.  
  263.         //    Set the waiting mode???
  264.         FE_EnableClicking(pContext);
  265.  
  266.         //    Create the stream.
  267.         pRetval = NET_NewStream("ServeAndSave",
  268.                                 disk_stream_write,
  269.                                 disk_stream_complete,
  270.                                 disk_stream_abort,
  271.                                 write_ready,
  272.                                 pMe,
  273.                                 pContext);
  274.  
  275.         if(!pRetval)
  276.             return(NULL);
  277.     }
  278.  
  279.     return pRetval;
  280. }
  281.  
  282. /*  Subclass-specific Methods
  283. **  -------------------------
  284. */
  285.  
  286. /* this is the main converter for external viewers.
  287.  * it returns the stream object as well
  288.  * as a data object that it can reference 
  289.  * internally to save the state of the document
  290.  */
  291. NET_StreamClass *external_viewer_disk_stream(int iFormatOut, void *pDataObj, URL_Struct *pUrl, MWContext *pContext)    
  292. {
  293.     ASSERT(pUrl);
  294.     ASSERT(pUrl->address);
  295.  
  296.     //    Lookup the helper app, if one exists.
  297.     //    If not found, create one on the fly.
  298.     CNetscapeApp *pNetscape = (CNetscapeApp *)AfxGetApp();
  299.     CHelperApp *pHelper;
  300.     XP_Bool isNewHelper = FALSE;
  301.  
  302.     if(0 == pNetscape->m_HelperListByType.Lookup(pUrl->content_type, (CObject *&)pHelper))    {
  303.         //    couldn't find one.
  304.         //    create the new mime type.
  305.         CString csText = pUrl->content_type;
  306.  
  307.         //    If there's no slash, just send the type as the file type
  308.         //        (this usually only happens on server error, but we
  309.         //        should still behave ourselves).
  310.         int iSlash = csText.Find('/');
  311.         if(iSlash != -1)    {
  312.             // this mess splits the string into the stuff before the slash and
  313.             //   the stuff after the slash
  314.             pHelper = fe_AddNewFileFormatType(csText.Left(iSlash),
  315.                 csText.Right(csText.GetLength() - iSlash - 1));
  316.             isNewHelper = TRUE;
  317.         }
  318.         else    {
  319.             pHelper = fe_AddNewFileFormatType(csText, "");
  320.             isNewHelper = TRUE;
  321.         }
  322.     }
  323.  
  324.     //    The helper app is now defined for the mime type in any case.
  325.     //    See how it is to be handled.
  326.     BOOL bExternal = FALSE;
  327.     BOOL bSave = FALSE;
  328.     BOOL bMoreInfo = FALSE;
  329.  
  330.     switch(pHelper->how_handle)    {
  331.     case HANDLE_UNKNOWN:    {
  332.         //    See what this is supposed to do via user input.
  333.         CUnknownTypeDlg dlgUnknown(GetFrame(pContext)->GetFrameWnd(), pUrl->content_type, pHelper);
  334.         int iDlg = dlgUnknown.DoModal();
  335.         if(iDlg == IDCANCEL)    {
  336.             //    User hit cancel.  Abort the load.
  337.             if (pHelper && pHelper->cd_item && isNewHelper) {
  338.                 if (XP_ListRemoveObject(cinfo_MasterListPointer(), pHelper->cd_item)) {
  339.                     if (pHelper->cd_item) {
  340.                         if (pHelper->cd_item->ci.type) {
  341.                             theApp.m_HelperListByType.RemoveKey(pHelper->cd_item->ci.type);
  342.                             XP_FREE( pHelper->cd_item->ci.type );
  343.                         }
  344.                         XP_FREE (pHelper->cd_item);
  345.                     }
  346.                     delete pHelper;
  347.                 }
  348.             }
  349.             return(NULL);
  350.         }
  351.         else if(iDlg == HANDLE_EXTERNAL)    {
  352.             char buf[256];
  353.  
  354.             bExternal = TRUE;
  355.  
  356.             // We need to indicate that this is a user-defined MIME type. If we
  357.             // don't, then we won't remember it the next time the Navigator is run
  358.             sprintf(buf,"TYPE%d",theApp.m_iNumTypesInINIFile);
  359.             theApp.m_iNumTypesInINIFile++;
  360.             theApp.WriteProfileString("Viewers", buf, pUrl->content_type);
  361.             pHelper->bNewType = FALSE;
  362.  
  363.         }
  364.         else if(iDlg == HANDLE_SAVE)    {
  365.             bSave = TRUE;
  366.         }
  367.         else if(iDlg == HANDLE_MOREINFO)    {
  368.             bMoreInfo = TRUE;
  369.         }
  370.         break;
  371.     }
  372.     case HANDLE_EXTERNAL:    
  373.     case HANDLE_BY_OLE: {
  374.         bExternal = TRUE;
  375.         break;
  376.     }
  377.     case HANDLE_SHELLEXECUTE:    {
  378.         bExternal = TRUE;
  379.         break;
  380.     }
  381.     case HANDLE_SAVE:    {
  382.         bSave = TRUE;
  383.         break;
  384.     }
  385.     default:    {
  386.         //    Shouldn't ever be other than the above types at this
  387.         //        point!
  388.         ASSERT(0);
  389.         return(NULL);
  390.     }
  391.     }
  392.  
  393.     //    We know that we are either saving or spawning an external
  394.     //        viewer at this point.
  395.     NET_StreamClass *pRetval = NULL;
  396.     if (bSave == TRUE)    {
  397.         return ExternalFileSave(iFormatOut, pUrl, pContext);
  398.     } else if (bExternal == TRUE)    {
  399.         //    Prompt the user for a file name.
  400.         //  Security rist to let path information in externally provided
  401.         //      filename (content disposition, filename =)
  402.         // XXX This code could be cleaned up -- eliminate aFileName 
  403.         // and just use what was allocated by WH_TempFileName.
  404.  
  405.         char aFileName[_MAX_PATH];
  406.         char *pSuggestedName = NULL;
  407.         BOOL bUseContentName = FALSE;
  408.         if (pUrl->content_name != NULL &&
  409.             strstr(pUrl->content_name, "../") == NULL &&
  410.             strstr(pUrl->content_name, "..\\") == NULL) {
  411.             bUseContentName = TRUE;
  412.         }
  413.         else {
  414.             pSuggestedName = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
  415.         }
  416.         char *pDestination;
  417.  
  418.         ASSERT(pNetscape->m_pTempDir);
  419.         if(pNetscape->m_pTempDir != NULL && pSuggestedName != NULL)    {
  420.             sprintf(aFileName, "%s\\%s", pNetscape->m_pTempDir, pSuggestedName);
  421.             XP_FREE(pSuggestedName);
  422.             pSuggestedName = NULL;
  423.             pDestination = aFileName;
  424.         }
  425.         else    {
  426.             char aExt[_MAX_EXT];
  427.             size_t stExt = 0;
  428.             DWORD dwFlags = 0;
  429.             const char *pName = pUrl->address;
  430.             
  431.             if(bUseContentName) {
  432.                 pName = pUrl->content_name;
  433.             }
  434. #ifdef XP_WIN16
  435.             dwFlags |= EXT_DOT_THREE;
  436. #endif
  437.             aExt[0] = '\0';
  438.             stExt = EXT_Invent(aExt, sizeof(aExt), dwFlags, pName, pUrl->content_type);
  439.             char *pTemp = WH_TempFileName(xpTemporary, "M", aExt);
  440.             if(pTemp) {
  441.                 strcpy(aFileName, pTemp);
  442.                 XP_FREE(pTemp);
  443.                 pTemp = NULL;
  444.             }
  445.             else {
  446.                 aFileName[0] = '\0';
  447.             }
  448.         }
  449.         pDestination = aFileName;
  450.  
  451.  
  452.         //    Figure out the application that we'll be spawning.
  453.         //    Strip off odd things at the right hand side.
  454.         CString csCommand;
  455.         if(pHelper->how_handle == HANDLE_EXTERNAL)  {
  456.             csCommand = pHelper->csCmd;
  457.             int iStrip = csCommand.ReverseFind('%');
  458.             if(iStrip > 0)    {
  459.                 csCommand = csCommand.Left(iStrip - 1);
  460.             }
  461.         }
  462.  
  463.         //    See if it's actually OK to spawn this application.
  464.         CString csSpawn = csCommand;
  465.         BOOL bShellExecute = FALSE;
  466.         if(pHelper->how_handle == HANDLE_SHELLEXECUTE ||
  467.             pHelper->how_handle == HANDLE_BY_OLE) {
  468.             //  Shell execute type, figure out the exe.
  469.             char aExe[_MAX_PATH];
  470.             memset(aExe, 0, sizeof(aExe));
  471.             if(FEU_FindExecutable(pDestination, aExe, FALSE)) {
  472.                 csSpawn = aExe;
  473.                 if(pHelper->how_handle == HANDLE_SHELLEXECUTE) {
  474.                     bShellExecute = TRUE;
  475.                 }
  476.             }
  477.             else     {
  478.                 csSpawn.Empty();
  479.             }
  480.         }
  481.  
  482.         // See whether the user wants to be prompted before we open the file
  483.         if (pContext->type != MWContextPrint && theApp.m_pSpawn->PromptBeforeOpening((LPCSTR)csSpawn)) {
  484.             BOOL    bFree = FALSE;
  485.             LPCSTR    lpszFilename = NULL;
  486.  
  487.             if (pUrl->content_name != NULL &&
  488.                 strstr(pUrl->content_name, "../") == NULL &&
  489.                 strstr(pUrl->content_name, "..\\") == NULL) {
  490.                 lpszFilename = pUrl->content_name;
  491.             }
  492.  
  493.             if (!lpszFilename) {
  494.                 lpszFilename = fe_URLtoLocalName(pUrl->address, pUrl->content_type);
  495.                 bFree = TRUE;
  496.             }
  497.             char* docExt[1];
  498.             const char * ptr1 = lpszFilename;
  499.             int type = NET_URL_Type(pUrl->address);
  500.             BOOL canHandleOLE = FALSE;
  501.  
  502.             if ((type != MAILBOX_TYPE_URL) && (type !=NEWS_TYPE_URL) && (type != IMAP_TYPE_URL) ) {
  503.                 docExt[0] = FE_FindFileExt((char*)ptr1);
  504.                 if (docExt[0])
  505.                     canHandleOLE = fe_CanHandleByOLE(docExt, 1);
  506.             }
  507.             CLaunchHelper    dlg(lpszFilename, (LPCSTR)csSpawn, canHandleOLE, GetFrame(pContext)->GetFrameWnd());
  508.     
  509.             if (bFree)
  510.                 XP_FREE((LPVOID)lpszFilename);
  511.  
  512.             // Initialize the dialog to some defaults.
  513.             dlg.m_bAlwaysAsk = TRUE;
  514.             //dlg.m_nAction = HELPER_SAVE_TO_DISK; //Old statement CRN_MIME
  515.             dlg.m_nAction = (pHelper->how_handle == HANDLE_SHELLEXECUTE) ? HELPER_OPEN_IT : HELPER_SAVE_TO_DISK; //New Statement. Set m_nAction based on pHelper->how_handle... CRN_MIME
  516.             dlg.m_bHandleByOLE = fe_IsHandleByOLE(pUrl->content_type);
  517.     
  518.             // Ask the user
  519.             if (dlg.DoModal() == IDCANCEL)
  520.                 return NULL;
  521.     
  522.             // See if they no longer want to be asked
  523.             if (!dlg.m_bAlwaysAsk) {
  524.                 if (dlg.m_nAction == HELPER_SAVE_TO_DISK) {
  525.                     // User wants to just save to disk
  526.                     pHelper->how_handle = HANDLE_SAVE;
  527.                     pHelper->csCmd = MIME_SAVE;
  528.                     pHelper->bChanged = TRUE;
  529.                 
  530.                 } else {
  531.                     ASSERT(dlg.m_nAction == HELPER_OPEN_IT);
  532.                     theApp.m_pSpawn->SetPromptBeforeOpening((LPCSTR)csSpawn, FALSE);
  533.                 }
  534.             }
  535.  
  536.             // Check whether the user wants to launch the application or save it
  537.             // do disk
  538.             if (dlg.m_nAction == HELPER_SAVE_TO_DISK)
  539.                 return ExternalFileSave(iFormatOut, pUrl, pContext);
  540.             else { // open it case.
  541.                 // user want to handle this by OLE.
  542.                 if (dlg.m_bHandleByOLE) {
  543.                     fe_SetHandleByOLE(pUrl->content_type, pHelper, TRUE);
  544.                 }
  545.                 // Since mail and new will not be able launch using OLE inplace server, so we should not try to change helper app
  546.                 // how_handle here.
  547.                 else if (pHelper->how_handle == HANDLE_BY_OLE) {
  548.                     fe_SetHandleByOLE(pUrl->content_type, pHelper, FALSE);
  549.                 }
  550.             }
  551.         }
  552.         // MWH -- see could we handle this via OLE.
  553.         if ((iFormatOut == FO_PRESENT || iFormatOut == FO_PRINT)  &&
  554.             (pHelper->how_handle == HANDLE_BY_OLE) &&
  555.                 FE_FileType(pUrl->address, pUrl->content_type, pUrl->content_encoding)) {
  556.  
  557.             // can be handle by OLE.
  558.                 return OLE_ViewStream(iFormatOut, pDataObj, pUrl,pContext);
  559.         }
  560.  
  561.         //    It's OK to spawn this application.
  562.         //    Attempt to split it off into a seperate context.
  563.         if(bShellExecute) {
  564.             pRetval = CSaveCX::ViewUrlObject(pUrl, NULL);
  565.         }
  566.         else {
  567.             pRetval = CSaveCX::ViewUrlObject(pUrl, csSpawn);
  568.         }
  569.         if(pRetval != NULL)    {
  570.             return(pRetval);
  571.         }
  572.         //    Couldn't split off into a new context.
  573.         //    Handle as was handled before.
  574.  
  575.         //    We have a destination file name.
  576.         FILE *pSink = XP_FileOpen(pDestination, xpTemporary, "wb");
  577.         if(pSink == NULL)    {
  578.             FE_Alert(pContext, szLoadString(IDS_FAILED_CREATE_TEMP_FILE));
  579.             XP_FREE(pDestination);
  580.             return(NULL);
  581.         }
  582.  
  583.         //    Create the data object that will be passed along down
  584.         //        the stream.
  585.         DataObject *pMe = new DataObject;
  586.         if(!pMe)
  587.             return(NULL);
  588.  
  589.         memset(pMe, 0, sizeof(DataObject));
  590.         pMe->how_handle = pHelper->how_handle;
  591.         pMe->fp = pSink;
  592.         pMe->context = pContext;
  593.         pMe->format_out = iFormatOut;
  594.         pMe->filename = pDestination;
  595.         pMe->content_length = pUrl->content_length < 0 ? 0 : pUrl->content_length;
  596.         pMe->cur_loc = 0;
  597.         StrAllocCopy(pMe->address, pUrl->address);
  598.         StrAllocCopy(pMe->format_in, pUrl->content_type);
  599.  
  600.         //    The spawn command.
  601.         if(pMe->how_handle == HANDLE_EXTERNAL)  {
  602.             pMe->params = XP_STRDUP(pDestination);
  603.         }
  604.         else if(pMe->how_handle == HANDLE_SHELLEXECUTE)    {
  605.             csCommand += pDestination;
  606.         }
  607.         else if(pMe->how_handle == HANDLE_BY_OLE)    {
  608.             csCommand += pDestination;
  609.         }
  610.         pMe->command = XP_STRDUP(csCommand);
  611.  
  612.         //    Progress.
  613.         FE_SetProgressBarPercent(pContext, 0);
  614.  
  615.         //    Delete the file on exit.
  616.         FE_DeleteFileOnExit(pDestination, pUrl->address);
  617.  
  618.         //    Set the waiting mode???
  619.         FE_EnableClicking(pContext);
  620.  
  621.         //    Create the stream.
  622.         pRetval = NET_NewStream("ServeAndView",
  623.                                 disk_stream_write,
  624.                                 disk_stream_complete,
  625.                                 disk_stream_abort,
  626.                                 write_ready,
  627.                                 pMe,
  628.                                 pContext);
  629.  
  630.     }
  631.     if(bMoreInfo == TRUE)    {
  632.         char * url = NULL;
  633.         PREF_CopyConfigString("internal_url.more_info_plugin.url",&url);
  634.         if (url) {
  635.             CString csUrlAddress = url;
  636.             csUrlAddress += "?";
  637.             csUrlAddress += pUrl->content_type;
  638.             (ABSTRACTCX(pContext))->NormalGetUrl(csUrlAddress, pUrl->address, csUrlAddress);
  639.             XP_FREE(url);
  640.         }
  641.     }
  642.  
  643.     //    Return the stream that was created.
  644.     return(pRetval);
  645. }
  646.  
  647. /****************************************************************************
  648. MEMORY STREAM DECLARATION
  649. *****************************************************************************/
  650.  
  651. /*  Buffer write.  
  652. **  ------------
  653. */
  654. extern "C"  int 
  655. memory_stream_write (NET_StreamClass *stream, const char* s, int32 l)
  656. {
  657.     DataObject * data = (DataObject *)stream->data_object;    
  658.  
  659.     ASSERT(data);
  660.     ASSERT(s);
  661.  
  662.     if(!data || !data->start || !data->loc)
  663.         return(MK_OUT_OF_MEMORY);
  664.  
  665.     /* check the sizes - make bigger and recopy if needed */
  666.     if(((unsigned long)(data->loc - data->start))  + l > (unsigned long)data->sz) {
  667.     char * buffer;
  668.         int oldcontents = data->loc - data->start;
  669.  
  670.         data->sz += DEFAULT_BUFFER_SZ;
  671.         buffer = (char *) XP_REALLOC(data->start, data->sz);
  672.         if(!buffer) {
  673.           XP_FREE(data->start);
  674.           data->start = NULL;
  675.           data->loc = NULL;
  676.           return(MK_OUT_OF_MEMORY);
  677.         }
  678.           
  679.         data->start = buffer;
  680.         data->loc = data->start + oldcontents;     
  681.     }
  682.     
  683.     /* copy the stuff over and update the pointer */
  684.     XP_BCOPY(s, data->loc, l);
  685.     data->loc += l;
  686.  
  687.     data->cur_loc += l;
  688.  
  689.     float fPercent = 0.0f;
  690.  
  691.     if (data->content_length) 
  692.         fPercent = (float)data->cur_loc / (float)data->content_length;
  693.     if (data->cur_loc) 
  694.         FE_SetProgressBarPercent(data->context, (int)(fPercent * 100));
  695.  
  696.     return((int) l);
  697. }
  698.  
  699. /* 
  700.  *  Do something interesting with the object and free it
  701.  *  ----------------------------------------------------
  702.  */
  703. extern "C"  void 
  704. memory_stream_complete (NET_StreamClass *stream)
  705. {
  706.     DataObject * data = (DataObject *)stream->data_object;    
  707.  
  708.     if(data->address)
  709.         XP_FREE(data->address);
  710.  
  711.     // Make sure we are text and NULL terminated
  712.     if(data->loc)
  713.         *(data->loc) = '\0';
  714.     
  715.     if(data->start) { 
  716.         XP_FREE(data->start);
  717.         data->start = NULL;
  718.     }
  719.         
  720.     if(data->params) {
  721.         XP_FREE(data->params);
  722.         data->params = NULL;
  723.     }
  724.  
  725.     delete data;
  726.     return;
  727. }
  728.  
  729. /*  End writing
  730. */
  731.  
  732. extern "C"  void 
  733. memory_stream_abort (NET_StreamClass *stream, int status)
  734. {    
  735.     memory_stream_complete(stream);
  736. }
  737.  
  738.  
  739. /*  Subclass-specific Methods
  740. **  -------------------------
  741. */
  742.  
  743. /* this is the main converter.
  744.  * it returns the stream object as well
  745.  * as a data object that it can reference 
  746.  * internally to save the state of the document
  747.  */
  748.  
  749. NET_StreamClass* 
  750. memory_stream (int     format_out,
  751.            void       *data_object,
  752.            URL_Struct *URL_s,
  753.            MWContext  *context)
  754. {
  755.     DataObject* me;
  756.     NET_StreamClass* stream;
  757.  
  758.     //
  759.     // If we are a view source stream and the user wants an external view source
  760.     //   application send it there instead
  761.     //
  762.     const char * html = theApp.m_pHTML;
  763.     if((format_out == FO_VIEW_SOURCE) && html && * html)    {
  764.         return (view_source_disk_stream(format_out, data_object, URL_s, context));
  765.     }
  766.     else if(format_out & FO_VIEW_SOURCE)    {
  767.         //    Otherwise, use our colored syntax HTML viewer for view source.
  768.         return(INTL_ConvCharCode(format_out, URL_s->content_type, URL_s, context));
  769.     }
  770.  
  771.     me = new DataObject;
  772.     if(!me)
  773.         return NULL;
  774.     memset(me, 0, sizeof(DataObject));
  775.  
  776.     stream = NET_NewStream("MemoryWriter",
  777.                             memory_stream_write,
  778.                             memory_stream_complete,
  779.                             memory_stream_abort,
  780.                             write_ready,
  781.                             me,
  782.                             context);
  783.  
  784.     if(stream == NULL) {
  785.         delete me;
  786.         return NULL;
  787.     }
  788.  
  789.     me->context = context;
  790.     me->address = me->filename = me->format_in = NULL;
  791.     me->format_out = format_out;
  792.     StrAllocCopy(me->address, URL_s->address);
  793.     StrAllocCopy(me->format_in, URL_s->content_type);
  794.  
  795.     /* set up the buffer fields */
  796.     me->sz = DEFAULT_BUFFER_SZ;
  797.     me->start = me->loc = (char *)XP_ALLOC(sizeof(char) * me->sz);
  798.  
  799.     if(!me->start) {
  800.         delete me;
  801.         XP_FREE(stream);
  802.         return NULL;
  803.     }
  804.  
  805.     if (URL_s->content_length > 0)
  806.         me->content_length = URL_s->content_length;
  807.     else 
  808.         me->content_length = 0;
  809.  
  810.     me->cur_loc =0;    
  811.     FE_SetProgressBarPercent(context, 0);
  812.  
  813.     return stream;
  814. }
  815.  
  816.  
  817. /* this is the main converter for saving files
  818.  * it returns the stream object as well
  819.  * as a data object that it can reference 
  820.  * internally to save the state of the document
  821.  */
  822. PUBLIC NET_StreamClass*
  823. view_source_disk_stream(int         format_out,
  824.            void       *lous_new_stuff,
  825.            URL_Struct *URL_s,
  826.            MWContext  * context)
  827. {
  828.     DataObject* me;
  829.     NET_StreamClass* stream;
  830.     FILE * fp = NULL;
  831.     BOOL bPromptUserForName =FALSE;
  832.     BOOL bDeleteFile = TRUE;
  833.  
  834.     ASSERT(context);
  835.  
  836.     me = new DataObject;
  837.     if (me == NULL) 
  838.         return NULL;
  839.     memset(me, 0, sizeof(DataObject));
  840.                                                                             
  841.     stream = NET_NewStream("FileWriter", 
  842.                             disk_stream_write,        
  843.                             disk_stream_complete,
  844.                             disk_stream_abort,
  845.                             write_ready,
  846.                             me,
  847.                             context);
  848.  
  849.     if(stream == NULL) {
  850.         delete me;
  851.         return NULL;
  852.     }
  853.     
  854.     // user selected save to disk
  855.     me->how_handle = HANDLE_EXTERNAL; 
  856.  
  857.     //
  858.     // Get a filename with an extension cuz stupid old notepad assumes one
  859.     //
  860.     char* fname = WH_TempFileName(xpTemporary, NULL, ".txt");
  861.     if(!fname)
  862.         return(NULL);
  863.     
  864.     //
  865.     // Open the file in text mode so that will get return translation
  866.     // Why in the world are we doing this AnsiToOemBuff stuff???
  867.     //  
  868. #ifdef XP_WIN32
  869.     fp = fopen(fname, "wt");
  870. #else
  871.     char oemBuff[254];
  872.     AnsiToOemBuff(fname, oemBuff, strlen(fname)+1);
  873.     fp = fopen(oemBuff, "wt");
  874. #endif
  875.     if(!fp) {
  876.         XP_FREE(fname);
  877.         return NULL;
  878.     }
  879.  
  880.     // delete the file when we are done
  881.     FE_DeleteFileOnExit(fname, URL_s->address);
  882.  
  883.     int len = theApp.m_pHTML.GetLength() + XP_STRLEN(fname) + 10;
  884.     me->command = (char *) XP_ALLOC(len);
  885.     if(!me->command) {
  886.         fclose(fp);
  887.         XP_FREE(fname);
  888.         return NULL;
  889.     }
  890.     
  891.     sprintf(me->command, "%s %s", theApp.m_pHTML, fname);
  892.  
  893.     me->fp = fp;
  894.     me->address = me->filename = me->format_in = NULL;
  895.     me->context = context;
  896.     me->format_out = format_out;
  897.     me->filename = fname;
  898.     StrAllocCopy(me->address, URL_s->address);
  899.     StrAllocCopy(me->format_in, URL_s->content_type);
  900.  
  901.     FE_EnableClicking(context);
  902.  
  903.     if (URL_s->content_length > 0)
  904.         me->content_length = URL_s->content_length;
  905.     else 
  906.         me->content_length = 0;
  907.     
  908.     FE_SetProgressBarPercent(context, 0);
  909.   
  910.     return stream;
  911.  
  912. }
  913.