home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / msv2dsk.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  25.9 KB  |  989 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. // Macintosh front-end
  20.  
  21. #include "msv2dsk.h"
  22.  
  23. #include "earlmgr.h"
  24. #include "macutil.h"
  25. #include "uerrmgr.h"
  26. #include "uprefd.h"
  27. #include "ufilemgr.h"
  28. #include "ulaunch.h"
  29. #include "macutil.h"
  30. #include "resgui.h"
  31. #include "prefwutil.h"
  32. #include "uapp.h"
  33. #include "resae.h"
  34.  
  35. #include "CNSContext.h"
  36. #include "CDownloadProgressWindow.h"
  37.  
  38.     // Netscape
  39. #include "merrors.h"
  40. #include "xp_thrmo.h"
  41. #include "mkutils.h"
  42. #include "glhist.h"
  43. #include "xlate.h"
  44. #include "prefapi.h"
  45.  
  46. #include "BufferStream.h"
  47. #include "PascalString.h"
  48.  
  49.     // system
  50. #include <StandardFile.h>
  51. #include "merrors.h"
  52.  
  53.  
  54.  
  55. static Boolean    GetMacFileTypesFromMimeHeader(    const URL_Struct    *    fRequest, 
  56.                                                 OSType                *    fileCreator,
  57.                                                 OSType                *    fileType     );
  58.                                                 
  59. static OSType    TextToOSType(    const char*    text);
  60.                                                 
  61.  
  62.  
  63. extern int MK_DISK_FULL;
  64.  
  65.  
  66.  
  67. extern CMimeMapper * CreateUnknownMimeTypeMapper (URL_Struct * request);
  68. extern void GUI_PostAlertNoReply (const CStr255 & message);
  69. extern OSErr GUI_AskForFileSpec (StandardFileReply & reply);
  70.  
  71. /*------------------=----------------------------------------------------------
  72.     External function so everyone can start a progress load without having
  73.     to include the full .h file
  74. --------------------=--------------------------------------------------------*/
  75.  
  76. extern "C" void SaveAsCompletionProc( PrintSetup* p );
  77. extern "C" void SaveAsCompletionProc( PrintSetup* p )
  78. {
  79.     XP_FileClose (p->out);
  80.     CNSContext* theContext = (CNSContext*)p->url->fe_data;
  81.     
  82. // FIX ME!!! need to put this back in
  83. //    if (theContext != NULL)
  84. //        theContext->AllConnectionsComplete();
  85.         
  86.         
  87. }
  88.  
  89. extern int MK_OUT_OF_MEMORY;
  90.  
  91. int PROGRESS_GetUrl(
  92.     URL_Struct *,
  93.     int /*format_out*/,
  94.     const FSSpec * /*destination*/,
  95.     Boolean /*delayed*/)
  96. {
  97. Assert_(false); // NO LONGER VALID
  98. return 0;
  99. }
  100.  
  101.  
  102. /*-----------------------------------------------------------------------------
  103.     When we decide to do something with an url (such as save it to disk, print
  104.     it, mail it, etc), we sometimes have extra data which specializes the 
  105.     action. Save-to-disk is the best example: a destination file. We need a 
  106.     place to put it all.
  107.     
  108.     We have been putting this data in the context. This is a mistake because
  109.     the context is not specific to any particular url action, and multiple 
  110.     requests will cause a race condition.
  111.     
  112.     The url struct is where it belongs, since this object is created at that
  113.     time (making it like MacApp's Command class). It has an fe_data field,
  114.     but we need to put *lots* of data there. Argh.
  115.     
  116.     Things go to disk when we launch an external viewer (click -> download in
  117.     normal context) or explicitly request a download (SAVE_AS, SAVE_TO_DISK,
  118.     VIEW_SOURCE, and Drag&Drop).
  119.     FO_PRESENT            auto-launch external viewer (by normal click).
  120.     VIEW_SOURCE            auto-launch with view source application
  121.     SAVE_TO_DISK        prompt for location and save to disk
  122.     SAVE_AS                prompt for location and save to disk
  123.     INTERNAL_IMAGE        display internally.
  124.     Drag&Drop            Variant of SAVE_TO_DISK
  125.     SAVE_ALL            Save page & images. Like SAVE_AS.
  126. -----------------------------------------------------------------------------*/
  127.  
  128. class DownloadFilePipe: public Pipe
  129. {
  130. public:
  131.                     DownloadFilePipe (
  132.                             CNSContext*             progressContext,
  133.                             URL_Struct*                request);
  134.                     ~DownloadFilePipe ();
  135.     OSErr            Open ();
  136.     int                Write (const char *buffer, int len);
  137.     void             Complete ();
  138.     void             Abort (int reason);
  139.     
  140.     OSErr            GetFileSpec ();
  141.     inline Boolean    TranslateLinefeeds ();
  142.     Boolean            LaunchWhenDone ();
  143.     CNSContext*     mContext;
  144.     
  145. protected:
  146.     URL_Struct *     fRequest;
  147.     NET_StreamClass * fInput;
  148. // fFile logic gets complicated. There are two questions:
  149. // - where to create the file
  150. // - when should the file object be deleted
  151. // - when should the file be deleted
  152. // The answers depend upon the stream:
  153. //         case FO_PRESENT:
  154. //        ask mapper for the registered viewer file spec.
  155. //            if we get these specs, registered viewer will handle the physical file deletion
  156. //                we need to delete the fFile object
  157. //            else, do the same as 
  158. //        case FO_VIEW_SOURCE:
  159. //         register with the app, do not delete fFile yourself
  160. //        case FO_SAVE_AS:
  161. //         do not register, delete file object  - 
  162.  
  163.     LFileBufferStream *    fFile;
  164.     Boolean            fDeleteOnDestroy;    // Should we delete the file object?
  165.     int                fIntention;
  166.     CMimeMapper *     fHandler;
  167.     Boolean            fHasDestination;
  168.     FSSpec            fDestination;
  169.     
  170.     OSErr GetSilentFileSpec();
  171.     OSErr GetUserFileSpec();
  172.     
  173.     friend NET_StreamClass * NewFilePipe (int format_out, void *registration, URL_Struct * request, MWContext *context);
  174. };
  175.  
  176. static LArray DownloadList;    // Keeps track of all downloads, so that we can see if we are interrupting any
  177.  
  178. Boolean HasDownloads(MWContext * context)
  179. {
  180.     DownloadFilePipe * pipe;
  181.     LArrayIterator iter(DownloadList);
  182.     while (iter.Next(&pipe))
  183.         {
  184.         MWContext* theContext = *(pipe->mContext);
  185.         if (theContext == context)
  186.             return true;
  187.             
  188.         }
  189.     return false;
  190. }
  191.  
  192. //--------------------------------------------------------------------------------
  193. // DownloadFilePipe
  194. //--------------------------------------------------------------------------------
  195.  
  196. DownloadFilePipe::DownloadFilePipe (
  197.     CNSContext* progressContext,
  198.     URL_Struct* request)
  199. {
  200.     mContext = progressContext;
  201.     mContext->AddUser(this);
  202.     
  203.     fRequest = request;
  204.     fInput = nil;
  205.     fFile = nil;
  206.     fIntention = -1;
  207.     
  208.     fHandler = nil;
  209.     fHasDestination = false;
  210.     fDeleteOnDestroy = true;
  211.     DownloadList.InsertItemsAt(1,1,&this);
  212. }
  213.  
  214.  
  215. DownloadFilePipe::~DownloadFilePipe ()
  216. {
  217.     mContext->RemoveUser(this);
  218.  
  219.     if (fFile && fDeleteOnDestroy)
  220.     {
  221.         CFileMgr::sFileManager.CancelRegister(fFile);
  222.         delete fFile;
  223.     }
  224.     Int32 where = DownloadList.FetchIndexOf(&this);
  225.     DownloadList.RemoveItemsAt(1,where);
  226. }
  227.  
  228. OSErr DownloadFilePipe::GetSilentFileSpec()
  229. {
  230.     OSErr        err;
  231.     CStr31        defaultName;
  232.     FSSpec        defaultFolder;
  233.     
  234.     if ( fRequest->content_name )
  235.         defaultName = fRequest->content_name;
  236.     else
  237.          defaultName =  CFileMgr::FileNameFromURL( fRequest->address ) ;
  238.  
  239.     defaultFolder = CPrefs::GetFilePrototype( CPrefs::DownloadFolder );
  240.     err = CFileMgr::UniqueFileSpec( defaultFolder, defaultName, fDestination );
  241.     if ( err )
  242.         return err;
  243.     fDeleteOnDestroy = FALSE;
  244.     fHasDestination = TRUE;
  245.     return noErr;
  246. }
  247.  
  248. // Get specs from the user
  249. OSErr DownloadFilePipe::GetUserFileSpec()
  250. {
  251.     OSErr                err;
  252.     CStr31                defaultName;
  253.     StandardFileReply     reply;
  254.  
  255.     if ( fRequest->content_name )
  256.         defaultName = fRequest->content_name;
  257.     else
  258.          defaultName =  CFileMgr::FileNameFromURL( fRequest->address ) ;
  259.  
  260.     (CStr63&)reply.sfFile.name = defaultName;
  261.     err = GUI_AskForFileSpec( reply );
  262.  
  263.     if ( err )
  264.         return err;
  265.  
  266.     fDestination = reply.sfFile;
  267.     fHasDestination = TRUE;
  268.     fDeleteOnDestroy = TRUE;    // do not delete automatically
  269.  
  270.     return noErr;
  271. }
  272.  
  273. // Obtain the location of where the stream should be downloaded to
  274. OSErr DownloadFilePipe::GetFileSpec ()
  275. {
  276.     OSErr err = noErr;
  277.     if (fHasDestination)
  278.         fDeleteOnDestroy = true;
  279.     else
  280.     {
  281. //         case FO_PRESENT:
  282. //        ask mapper for the registered viewer file spec.
  283. //            if we get these specs, registered viewer will handle the physical file deletion
  284. //                we need to delete the fFile object
  285. //            else, do the same as 
  286. //        case FO_VIEW_SOURCE:
  287. //         register with the app, do not delete fFile yourself
  288. //        case FO_SAVE_AS:
  289. //            we should have the spec already, die otherwise
  290.  
  291.         switch (fIntention)    {
  292.             case FO_PRESENT:
  293.                 
  294.                 
  295.                 if (fHandler)
  296.                 {
  297.                     // See if the helper app is already running and 
  298.                     // has registered with us at runtime.  If so,
  299.                     // give it a chance to tell us where to put the file.
  300.                     //
  301.                     err = fHandler->GetFileSpec(fRequest, fDestination);
  302.                 
  303.                     // tj, with mourey and timm:
  304.                     //
  305.                     // This wasn't guarded by fHandler but we're sure it should be.
  306.                     // We should only delete on destroy if the helper app has registered
  307.                     // with us at runtime and tells us where to save the file. Otherwise,
  308.                     // we need to prompt for the file name/location.
  309.                     //
  310.                     // This never used to be a problem because fHandler was never NULL.
  311.                     // Now with support for mac type/creator from the mime header, fHandler
  312.                     // may be NULL.
  313.                     
  314.                      if (err == noErr)
  315.                      {
  316.                          fDeleteOnDestroy = true;
  317.                          break;
  318.                      }
  319.                 }
  320.                 
  321.                 if (LaunchWhenDone())
  322.                     err = GetSilentFileSpec();
  323.                 else
  324.                     err = GetUserFileSpec();
  325.                     
  326.                 break;
  327.             case FO_SAVE_AS:
  328.                 err = GetUserFileSpec();
  329.                 break;
  330.             case FO_VIEW_SOURCE:
  331.                 err = GetSilentFileSpec();
  332.                 break;
  333.             default:
  334.                 Assert_(false);
  335.         }
  336.     }
  337.     if (err == noErr)    // No error in creating the spec, make the stream
  338.     {
  339.         try
  340.         {
  341.             fFile = new LFileBufferStream (fDestination);
  342.         }
  343.         catch (OSErr err)
  344.         {
  345.             return err;
  346.         }
  347.  
  348.         fFile->DoUseBuffer();
  349.         if (fRequest && fRequest->address)
  350.             fFile->SetURL(XP_STRDUP(fRequest->address));
  351.         
  352.         if (fDeleteOnDestroy == false)    // If we are not taking care of the file, file manager is
  353.             CFileMgr::sFileManager.RegisterFile(fFile);
  354.     }
  355.     return err;
  356. }
  357.  
  358. inline Boolean DownloadFilePipe::TranslateLinefeeds ()
  359. {
  360.     return (fIntention == FO_VIEW_SOURCE);
  361. }
  362.  
  363. Boolean DownloadFilePipe::LaunchWhenDone ()
  364. {
  365. /*
  366.     For view source we always want to launch the viewer.
  367.     For saving HTML, don't launch it, just save.
  368.     For drag&drop, we want to launch Stuffit (for FTP convenience) but not
  369.         a text viewer, so text/html->false, the rest according to mime mapper
  370. */
  371.     if (fIntention == FO_VIEW_SOURCE)
  372.         return true;
  373.     if (fIntention == FO_SAVE_AS)
  374.         return false;
  375.     if (strcmp(fRequest->content_type, "text/html") == 0) // LAM need entry for text/html!
  376.         return false;
  377.         
  378.     if (fHandler != NULL)
  379.         return fHandler->GetLoadAction() == CMimeMapper::Launch;
  380.     else
  381.         return false;
  382. }
  383.  
  384.  
  385. OSErr DownloadFilePipe::Open ()
  386. {
  387. /*
  388.     If this is a drag&drop or SAVE_AS then we already have a filespec.
  389.     If the helper application is set to "launch" then we automatically
  390.     choose a filespec. Otherwise we have to ask.
  391. */
  392.     OSErr             err;
  393.     cstring            appName     = "\0";        // app that can open the attachment
  394.     CMimeMapper *     mapper        = nil;        // mime-type -> mac-type mapper
  395.     OSType            fileType     = 0;        // mac file type of the attachment
  396.     OSType             fileCreator    = 0;        // mac creator type of the attachment
  397.     
  398.     
  399.     //
  400.     // Figure out the appropriate file type and creator
  401.     //
  402.         
  403.     if (fIntention == FO_VIEW_SOURCE || strcmp(fRequest->content_type,"text/html") == 0)
  404.         mapper = CPrefs::sMimeTypes.FindMimeType (CMimeList::HTMLViewer);
  405.     
  406.     if (mapper == NULL)
  407.     {
  408.         //
  409.         // If we have content of application/octet-stream, look for the mac file type
  410.         // and creator in the URL struct (from the mime header).
  411.         //
  412.         // If we find valid mac file type/creator data, or if the content_type
  413.         // isn't octet-stream, then we attempt content_type -> mime-type mapping
  414.         //
  415.         if (     (strcmp(fRequest->content_type, APPLICATION_OCTET_STREAM) != 0)    ||
  416.                 !GetMacFileTypesFromMimeHeader(fRequest, &fileCreator, &fileType)    )
  417.         {        
  418.             mapper = CPrefs::sMimeTypes.FindMimeType (fRequest->content_type);
  419.     
  420.             if (mapper && mapper->GetLoadAction() == CMimeMapper::Unknown)
  421.             {
  422.                 //
  423.                 // If they specified "Unknown" in the prefs, then we have an existing
  424.                 // mapper that tells us this fact.  To know how to handle the stream
  425.                 // this time, we need to ask them what to do and create a new mapper.
  426.                 //
  427.                 mapper = CreateUnknownMimeTypeMapper (fRequest);
  428.                 if (!mapper)
  429.                     return userCanceledErr;
  430.             }
  431.             else if (mapper == NULL)
  432.             {
  433.                 if (!GetMacFileTypesFromMimeHeader(fRequest, &fileCreator, &fileType))
  434.                 {
  435.                     if (fIntention != FO_SAVE_AS)
  436.                     {
  437.                         mapper = CreateUnknownMimeTypeMapper (fRequest);
  438.                         if (!mapper)
  439.                             return userCanceledErr;
  440.                     }
  441.                     else
  442.                     {
  443.                         fileType = 'TEXT';
  444.                         fileCreator = emSignature;
  445.                     }
  446.                 }        
  447.             }
  448.         }
  449.     }
  450.     
  451.     //
  452.     // If fHandler is NULL, then fileType and fileCreator have been set
  453.     // from the mime header via GetMacFileTypesFromMimeHeader.
  454.     // 
  455.     // When fHandler is NULL, appName will be empty because we're not
  456.     // doing anything further to match the file to its application
  457.     //
  458.     fHandler = mapper;
  459.     if (fHandler != NULL)
  460.     {
  461.         fileCreator    = fHandler->GetAppSig();
  462.         fileType    = fHandler->GetDocType();
  463.         appName        = fHandler->GetAppName();
  464.     }
  465.     
  466.     // Additional little hack to make sure if we've got a text/html type file and we're supposed
  467.     // to view it internally we set it to our creator code
  468.     if (strcmp(fRequest->content_type,"text/html") == 0 &&
  469.         mapper->GetLoadAction() == CMimeMapper::Internal)
  470.     {
  471.         fileType = 'TEXT';
  472.         fileCreator = emSignature;
  473.     }
  474.     
  475.     Assert_(fileCreator != (OSType) 0 && fileType != (OSType) 0);
  476.     
  477.     
  478.     //
  479.     // Figure out the appropriate file type and creator
  480.     //
  481.     
  482.     err = GetFileSpec ();
  483.     if (err)
  484.         return err;    
  485.     // Make a file object, file stream, and stream buffer.
  486.     Try_
  487.     {
  488.         // Open an existing file before creating because for drag&drop we will have
  489.         // created a Bookmark file as a placeholder. For all other cases, we have
  490.         // a unique filespec.
  491.         fFile->OpenDataFork (fsRdWrPerm);
  492.         err = CFileMgr::SetFileTypeCreator(fileCreator, fileType, &fDestination);
  493.         ThrowIfOSErr_ (err);
  494.     }
  495.     Catch_ (openErr)
  496.     {
  497.         if (openErr == fnfErr) {
  498.             fFile->CreateNewDataFile (fileCreator, fileType, smSystemScript);
  499.             fFile->OpenDataFork (fsRdWrPerm);
  500.         }
  501.         else
  502.             Throw_ (openErr);
  503.     }
  504.     EndCatch_
  505.     
  506.     if (fFile && fRequest && fRequest->address)
  507.     {
  508.         FSSpec macSpec;
  509.         fFile->GetSpecifier(macSpec);
  510.         CFileMgr::FileSetComment (macSpec, CStr255(fRequest->address));
  511.     }
  512.     CStr255 message;
  513.     StringHandle messageHdl = ::GetString(SAVE_QUOTE_RESID);
  514.     
  515.     if(messageHdl && *messageHdl) {
  516.         ::HLock((Handle) messageHdl);
  517.         CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
  518.         ::HUnlock((Handle) messageHdl);
  519.     }
  520.     message += CStr255(fDestination.name);
  521.     message += "\"";
  522.     
  523.     CContextProgress* theProgress = mContext->GetCurrentProgressStats();
  524.     Assert_(theProgress != NULL);
  525.     StSharer theShareLock(theProgress);
  526.  
  527.     theProgress->mAction = message;
  528.  
  529.     if (LaunchWhenDone()) {
  530.     
  531.         messageHdl = ::GetString(WILL_OPEN_WITH_RESID);
  532.         if(messageHdl && *messageHdl) {
  533.             ::HLock((Handle) messageHdl);
  534.             CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
  535.             ::HUnlock((Handle) messageHdl);
  536.         }
  537.         message += appName;
  538.         message += GetCString(WILL_OPEN_TERM_RESID);
  539.     }
  540.     else {
  541.         message = "";
  542.         messageHdl = ::GetString(SAVE_AS_A_RESID);
  543.         if(messageHdl && *messageHdl) {
  544.             ::HLock((Handle) messageHdl);
  545.             CopyString((unsigned char *) message, (const unsigned char *) *messageHdl);
  546.             ::HUnlock((Handle) messageHdl);
  547.         }
  548.         message += appName;
  549.         message += GetCString(FILE_RESID);
  550.     }
  551.  
  552.     theProgress->mComment = message;
  553.     mContext->UpdateCurrentProgressStats();
  554.         
  555.     if( fRequest->server_can_do_byteranges || fRequest->server_can_do_restart )
  556.         fRequest->must_cache = TRUE;
  557.  
  558.     return noErr;
  559. }
  560.  
  561. int
  562. DownloadFilePipe::Write (const char *buffer, int len)
  563. {
  564.     int written = 0;
  565.     Try_
  566.     {
  567.         if (TranslateLinefeeds()) {
  568.             for (int i = 0; i < len; i++) {
  569.                 char c = buffer[i];
  570.                 if (c == LF)
  571.                     c = CR;
  572.                 fFile->WriteData (&c, 1);
  573.             }
  574.             written = len;
  575.         }
  576.         else
  577.             written = fFile->WriteData (buffer, len);
  578.     }
  579.     Catch_ (writeErr)
  580.     {
  581.         CStr255 message = (const char*) GetCString(COULD_NOT_SAVE_RESID);
  582.         message += CStr63(fDestination.name);
  583.         if (writeErr == dskFulErr)
  584.             message += CStr255((const char*)GetCString(DISK_FULL_RESID));
  585.         else
  586.             message += CStr255((const char*)GetCString(DISK_ERR_RESID));
  587.         ErrorManager::PlainAlert(message);
  588.         return MK_DISK_FULL;
  589.     }
  590.     EndCatch_
  591.     
  592.     return written;
  593. }
  594.  
  595. //    Close the file
  596. //    Launch the helper application if necessary
  597. void DownloadFilePipe::Complete ()
  598. {
  599.     if (fRequest)
  600.         GH_UpdateGlobalHistory(fRequest);
  601.     if (fFile)
  602.     Try_
  603.     {
  604.         fFile->CloseDataFork();
  605.         CFileMgr::UpdateFinderDisplay(fDestination);
  606.     }
  607.     Catch_(inErr){}
  608.     EndCatch_
  609.  
  610.     NET_RemoveURLFromCache(fRequest);
  611.     NET_RemoveDiskCacheObjects(0);
  612.  
  613.     Try_
  614.     {
  615.     if (LaunchWhenDone() && fHandler && fFile)
  616.     
  617. //        fHandler->LaunchFile(fFile, fRequest, fCppContext->GetContextUniqueID());
  618. // FIX ME!!! we need to implement the unique ID stuff in the CNSContext
  619.         fHandler->LaunchFile(fFile, fRequest, 69);
  620.     }
  621.     Catch_(inErr){}
  622.     EndCatch_
  623. }
  624.  
  625. void DownloadFilePipe::Abort (int /*reason*/)
  626. {
  627.     if (fFile)
  628.     {
  629.         Try_
  630.         {
  631.             fFile->CloseDataFork();
  632.         }
  633.         Catch_(inErr)
  634.         {}
  635.         EndCatch_
  636.         FSSpec fileSpec;
  637.         fFile->GetSpecifier (fileSpec);
  638.         FSpDelete (&fileSpec);
  639.     }
  640.     fDeleteOnDestroy = true;
  641. }
  642.  
  643. /*-----------------------------------------------------------------------------
  644.     C++ URL Streams
  645.     
  646.     Streams are responsible for reading data in to memory/disk
  647.     They will also get "hinting" information and be responsible for
  648.     ultimately deciding where to direct the data.
  649.     
  650.     display_converter and Pipe::Handle* are called from C code. They cannot
  651.     pass any exceptions up.
  652. -----------------------------------------------------------------------------*/
  653.  
  654. int Pipe::HandleProcess (NET_StreamClass *stream, const char *buffer, int32 buffLen)
  655. {
  656.     void *streamData=stream->data_object;
  657.     volatile int result = -1;
  658.     Try_ {
  659.         Pipe *self = (Pipe*) streamData;
  660.         result = self->Write (buffer, buffLen);
  661.     }
  662.     Catch_ (err) {
  663.         XP_TRACE(("*** Caught an error (%i) in Pipe::HandleProcess", err));
  664.         result = -1;
  665.     }
  666.     EndCatch_
  667.     return result;
  668. }
  669.  
  670. void Pipe::HandleComplete (NET_StreamClass *stream)
  671. {
  672.     void *streamData=stream->data_object;
  673.     Try_ {
  674.         Pipe *self = (Pipe*) streamData;
  675.         self->Complete ();
  676.         delete self;
  677.     }
  678.     Catch_ (err) {
  679.         XP_TRACE(("*** Caught an error (%i) in Pipe::HandleComplete but can't return it", err));
  680.     }
  681.     EndCatch_
  682. }
  683.  
  684. void Pipe::HandleAbort (NET_StreamClass *stream, int reason)
  685. {
  686.     void *streamData=stream->data_object;
  687.     Try_ {
  688.         XP_TRACE(("*** HandleAbort %i", reason));
  689.         Pipe *self = (Pipe*) streamData;
  690.         self->Abort (reason);
  691.         delete self;
  692.     }
  693.     Catch_ (err) {
  694.         XP_TRACE(("*** Caught an error (%i) in Pipe::HandleAbort but can't return it", err));
  695.     }
  696.     EndCatch_
  697. }
  698.  
  699. unsigned int Pipe::HandleWriteReady (NET_StreamClass * /*stream*/)
  700. {
  701.     return 32765;
  702. }
  703.  
  704. //
  705. //
  706. //
  707.  
  708. OSErr
  709. Pipe::Open ()
  710. {
  711.     return noErr;
  712. }
  713.  
  714. int
  715. Pipe::Write (const char */*buffer*/, int buffLen)
  716. {
  717.     return buffLen;
  718. }
  719.  
  720. void 
  721. Pipe::Complete ()
  722. {
  723. }
  724.  
  725. void
  726. Pipe::Abort (int /*reason*/)
  727. {
  728. }
  729.  
  730. //
  731. // api
  732. //
  733.  
  734. NET_StreamClass * 
  735. Pipe::MakeStreamObject (char * name, MWContext * context)
  736. {
  737.     NET_StreamClass * stream = NET_NewStream (
  738.             name, 
  739.             Pipe::HandleProcess,
  740.             Pipe::HandleComplete, 
  741.             Pipe::HandleAbort, 
  742.             Pipe::HandleWriteReady, 
  743.             this, 
  744.             context);
  745.     return stream;
  746. }
  747.  
  748. //
  749. // Construction & Stuff
  750. //
  751.  
  752. Pipe::Pipe ()
  753. {
  754. }
  755.  
  756. Pipe::~Pipe ()
  757. {
  758. }
  759.  
  760.  
  761. CMimeMapper * CreateUnknownMimeTypeMapper(URL_Struct * request);
  762. // After receiving the request for unknown mime type, this routine is called
  763. // to create a mapper for an unknown MIME type
  764. CMimeMapper* CreateUnknownMimeTypeMapper( URL_Struct* request )
  765. {
  766.     CStr255        fileName;
  767.     CStr255        content_type;
  768.     CStr31        newName;
  769.     int            result;
  770.     CMimeMapper*    mapper = NULL;
  771.     
  772.     if (!ErrorManager::TryToInteract(900))
  773.         return NULL;
  774.     // Notify the user with nice names
  775.     newName = CFileMgr::FileNameFromURL( request->address );
  776.     fileName = newName;
  777.     content_type = NET_URLStruct_ContentType( request );
  778.     
  779.     ::ParamText( newName, content_type, CStr255::sEmptyString, CStr255::sEmptyString );
  780.  
  781.     UDesktop::Deactivate();
  782.     result = ::CautionAlert( ALRT_UnknownMimeType, NULL );
  783.     UDesktop::Activate();
  784.     
  785.     // What does user want?
  786.     switch ( result )
  787.     {
  788.         case ALRT_UnknownMimeType_Cancel:
  789.             return NULL;
  790.         case ALRT_UnknownMimeType_Save:
  791.             mapper = CPrefs::CreateDefaultUnknownMapper( NET_URLStruct_ContentType(request), TRUE );
  792.             mapper->SetLoadAction( CMimeMapper::Save );
  793.             return mapper;
  794.         case ALRT_UnknownMimeType_PickApp:
  795.             StandardFileReply reply;
  796.             CFilePicker::DoCustomGetFile( reply, CFilePicker::Applications, FALSE );
  797.             if ( reply.sfGood )
  798.                 mapper = CPrefs::CreateDefaultAppMapper( reply.sfFile,NET_URLStruct_ContentType(request), TRUE );
  799.             return mapper;
  800.         case ALRT_UnknownMimeType_MoreInfo:
  801.         {
  802.             char* string;
  803.             if (PREF_CopyConfigString("internal_url.more_info_plugin.url", &string) != PREF_NOERROR)
  804.                 return NULL;
  805.                 
  806.             cstring url;
  807.             url = (const char*) string;        // cstringâ•’s operator= expects unsigned char* to be a P string, so we have to cast
  808.             url += "?";
  809.             url += NET_URLStruct_ContentType( request );
  810.  
  811.             AppleEvent getURLEvent;
  812.             UAppleEventsMgr::MakeAppleEvent( AE_url_suite, AE_url_getURL, getURLEvent );
  813.  
  814.             OSErr err = ::AEPutParamPtr( &getURLEvent, keyDirectObject, typeChar, url.data(), strlen(url.data()) );
  815.             
  816.             if ( err == noErr )
  817.                 err = ::AEPutParamPtr( &getURLEvent, AE_url_getURLname, typeChar, url.data(), strlen(url.data()) );
  818.  
  819.             if ( err == noErr )
  820.                 UAppleEventsMgr::SendAppleEvent (getURLEvent );
  821.  
  822.             return NULL;
  823.         }
  824.         default:
  825.             return NULL;
  826.     }
  827.     return NULL;    
  828. }
  829.  
  830. NET_StreamClass * NewFilePipe (
  831.     int                 format_out,
  832.     void *                /*registration*/,
  833.     URL_Struct *         request,
  834.     MWContext*            context)
  835. {
  836.     CNSContext* theContext = ExtractNSContext(context);
  837.     Assert_(theContext != NULL);
  838.  
  839.     GH_UpdateGlobalHistory(request);
  840.  
  841.     // 97-06-15 pkc -- We really should make a function to determine if a URL is a
  842.     // mail attachment instead of duplicating this code.
  843.     const char* urlAddress = request ? NET_URLStruct_Address(request) : nil;
  844.     Boolean isMailMessage = false;
  845.     if (urlAddress)
  846.         {
  847.         // check to see if this is a mail or news messages
  848.         if (!strncasecomp (urlAddress, "mailbox:", 8) || !strncasecomp (urlAddress, "news:", 5))
  849.             {
  850.                 {
  851.                 // this is a mail message
  852.                 isMailMessage = true;
  853.                 }
  854.             }
  855.         }
  856.  
  857.     // 97-06-15 pkc -- The bug is that when you close the browser
  858.     // window for the mail message, the MimeObject* in the context is freed. That pointer is also
  859.     // referenced somewhere else and used by libnet. Whoops. So, since we're trying to ship, don't
  860.     // spawn a seperate progress context for mail messages.
  861.     // 97-08-15 sdagley - Removing check for theContext->IsCloneRequired() as it won't be set to true
  862.     // in frames which is the cause of bug #75288.  The alternative fix is to change the CNSContext constructors
  863.     // to initialize mRequiresClone to true instead of the current default of false.
  864.     if (/*theContext->IsCloneRequired() &&*/ !isMailMessage)
  865.         {
  866.         CNSContext* theProgressContext = NULL;
  867.         CDownloadProgressWindow* theProgressWindow = NULL;
  868.         try
  869.             {
  870.             theProgressContext = new CNSContext(*theContext);
  871.             StSharer theShareLock(theProgressContext);
  872.             
  873.             // 97-06-12 pkc -- Move call to NET_SetNewContext here so that if it fails
  874.             // (which can happen if mocha calls us) we still use context
  875.             if(NET_SetNewContext(request, *theProgressContext, EarlManager::DispatchFinishLoadURL) == 0)
  876.                 theContext = theProgressContext;
  877.  
  878.             theProgressWindow = dynamic_cast<CDownloadProgressWindow*>(LWindow::CreateWindow(WIND_DownloadProgress, LCommander::GetTopCommander()));
  879.             ThrowIfNULL_(theProgressWindow);
  880.             theProgressWindow->Show();
  881.             
  882. //            theProgressWindow->SetWindowContext(theProgressContext);
  883.             theProgressWindow->SetWindowContext(theContext);
  884.             // the window will be shown upon progress initialization
  885.             
  886.             }
  887.         catch(...)
  888.             {
  889.             delete theProgressWindow;
  890.             return NULL;
  891.             }
  892.         }
  893.  
  894.     DownloadFilePipe* thePipe = NULL;
  895.     NET_StreamClass* theStream = NULL;
  896.  
  897.     try
  898.         {
  899.         // 97-06-05 pkc -- if theContext doesn't have ContextProgress, make one now
  900.         if (!theContext->GetContextProgress())
  901.             theContext->EnsureContextProgress();
  902.         thePipe = new DownloadFilePipe(theContext, request);
  903.  
  904.         thePipe->fIntention = CLEAR_CACHE_BIT(format_out);    
  905.         if (request->fe_data) 
  906.             {
  907.             thePipe->fDestination = *(FSSpec*)request->fe_data;
  908.             thePipe->fHasDestination = true;
  909.             XP_FREE(request->fe_data);
  910.             }
  911.  
  912.         OSErr theErr = thePipe->Open();
  913.         ThrowIfOSErr_(theErr);
  914.  
  915.         theStream = thePipe->MakeStreamObject("Download File", *theContext);
  916.         thePipe->fInput = theStream;
  917.         }
  918.     catch (...)
  919.         {
  920.         if (thePipe != NULL)
  921.             thePipe->Abort (-1);
  922.         delete thePipe;
  923.  
  924.         XP_DELETE(theStream);
  925.         theStream = NULL;
  926.         }
  927.  
  928.     return theStream;
  929. }
  930.  
  931.  
  932. //
  933. // Snarf the mac file type and creator out of the mime header.
  934. //
  935. // Returns true if valid data is found, false if not.
  936. //
  937. static Boolean
  938. GetMacFileTypesFromMimeHeader(    const URL_Struct    *    fRequest, 
  939.                                 OSType                *    fileCreator,
  940.                                 OSType                *    fileType     )
  941. {
  942.     *fileCreator     = 0;
  943.     *fileType         = 0;
  944.     
  945.     Assert_(fRequest != NULL);
  946.     
  947.     if (    fRequest->x_mac_creator == NULL    ||
  948.             fRequest->x_mac_type    == NULL        )
  949.     {
  950.         return false;
  951.     }
  952.         
  953.     *fileCreator = TextToOSType(fRequest->x_mac_creator);
  954.     *fileType     = TextToOSType(fRequest->x_mac_type);
  955.     
  956.     return (*fileCreator != 0 && *fileType != 0);
  957. }    
  958.  
  959.  
  960. static OSType
  961. TextToOSType(    const char*    text)
  962. {
  963.     OSType    result = 0;
  964.     UInt32    len;
  965.     
  966.     //
  967.     // If the text is 4-characters long, we treat it
  968.     // as a raw OSType.
  969.     //
  970.     // If it is 8-characters, it is hex-encoded.
  971.     //
  972.     // If it's not 4 or 8, we return 0;
  973.     //
  974.     
  975.     len = strlen(text);
  976.     
  977.     if (len == 4)
  978.         result =  * ((OSType *) text);
  979.     else
  980.     if (len == 8)
  981.         sscanf(text, "%lx", &result);
  982.     
  983.     return result;
  984. }                        
  985.  
  986.  
  987.  
  988.  
  989.