home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / DownloadFrame.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  33.1 KB  |  1,256 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.    DownloadFrame.cpp -- class definition for the save to disk window.
  20.    Created: Chris Toshok <toshok@netscape.com>, 21-Feb-97
  21.  */
  22.  
  23.  
  24.  
  25. #include "DownloadFrame.h"
  26. #include "MozillaApp.h"
  27. #include "Dashboard.h"
  28. #include "ViewGlue.h"
  29. #include "Logo.h"
  30.  
  31. #include "xlate.h"
  32.  
  33. #include <Xm/XmP.h>
  34. #include <Xm/LabelG.h>
  35. #include <Xm/TextF.h>
  36. #include <Xm/Form.h>
  37. #include <Xm/MessageB.h>
  38. #include <Xm/PushB.h>
  39.  
  40. #include <Xfe/Xfe.h>
  41.  
  42. #include "xpgetstr.h"
  43. #include "felocale.h"
  44.  
  45. extern int XFE_SAVE_AS_TYPE_ENCODING;
  46. extern int XFE_SAVE_AS_TYPE;
  47. extern int XFE_SAVE_AS_ENCODING;
  48. extern int XFE_SAVE_AS;
  49. extern int XFE_ERROR_OPENING_FILE;
  50. extern int XFE_ERROR_READ_ONLY;
  51. extern int XFE_COMMANDS_SAVE_AS_USAGE;
  52. extern int XFE_COMMANDS_SAVE_AS_USAGE_TWO;
  53.  
  54. #ifdef DEBUG_toshok
  55. #define D(x) x
  56. #else
  57. #define D(x)
  58. #endif
  59.  
  60. /* Externs from dialog.c: */
  61. extern "C" {
  62.   void fe_set_scrolled_default_size(MWContext *context);
  63.   int fe_await_synchronous_url (MWContext *context);
  64.   int fe_GetSynchronousURL(MWContext *context,
  65.                            Widget widget_to_grab,
  66.                            const char *title,
  67.                            URL_Struct *url,
  68.                            int output_format,
  69.                            void *call_data);
  70.   void fe_save_top_frame_as_cb (Widget widget, XtPointer closure,
  71.                                 XtPointer call_data);
  72. }
  73.  
  74. // Note:  isFileP - if true and the file_name is a directory,
  75. //                  we return False...
  76. //
  77. //        existsP - if true, the file_name must exist or we return False,
  78. //                  otherwise we just make sure we can read/write into the 
  79. //                  directory specified in file_name...
  80. //
  81. XP_Bool
  82. XFE_StatReadWrite(const char *file_name, XP_Bool isFileP, XP_Bool existsP) 
  83. {
  84.     // NOTE:  let's get the directory that this file resides in...
  85.     //
  86.     XP_StatStruct  dir_info;
  87.     XP_StatStruct  file_info;
  88.     XP_Bool        isDir = False;
  89.     char*          p;
  90.     char*          base_name = (char *) XP_ALLOC(XP_STRLEN(file_name) + 1);
  91.     
  92.     p = XP_STRRCHR(file_name, '/');
  93.     
  94.     if (p) {
  95.         if (p == file_name) {
  96.             XP_STRCPY(base_name, "/");
  97.         }
  98.         else {
  99.             int32 len = p - file_name;
  100.  
  101.             if (len == XP_STRLEN(file_name)) {
  102.                 isDir = True;
  103.                 XP_STRCPY(base_name, file_name);
  104.             }
  105.             else {
  106.                 XP_MEMCPY(base_name, file_name, len);
  107.                 base_name[len] = '\0';
  108.             }
  109.         }
  110.     }
  111.     else {
  112.         // WARNING... [ we may get into some trouble with this one ]
  113.         //
  114.         XP_STRCPY(base_name, ".");
  115.     }
  116.     
  117.     // NOTE:  we need to verify that we can read/write the directory
  118.     //        before we check the file...
  119.     //
  120.     //        - need to check all three mode groups... [ owner, group, other ]
  121.     //
  122.     if ( stat(base_name, &dir_info) >= 0 ) {
  123.         XP_Bool gotcha = False;
  124.         
  125.         if ( isFileP && 
  126.              isDir
  127.             ) {
  128.             // NOTE:  the specifed file_name is a directory... [ fail ]
  129.             //
  130.             XP_FREE(base_name);
  131.  
  132.             return False;
  133.         }
  134.  
  135.         if (dir_info.st_uid == getuid()) {
  136.             if ((dir_info.st_mode & S_IRUSR) &&
  137.                 (dir_info.st_mode & S_IWUSR)) {
  138.                 gotcha = True;
  139.             }
  140.         }
  141.         
  142.         if (!gotcha) {
  143.             if (dir_info.st_gid == getgid()) {
  144.                 if ((dir_info.st_mode & S_IRGRP) &&
  145.                     (dir_info.st_mode & S_IWGRP)) {
  146.                     gotcha = True;
  147.                 }
  148.             }
  149.             
  150.             if (!gotcha) {
  151.                 if ((dir_info.st_mode & S_IROTH) &&
  152.                     (dir_info.st_mode & S_IWOTH)) {
  153.                     gotcha = True;
  154.                 }
  155.             }
  156.         }
  157.  
  158.         if (gotcha) {
  159.             if (isDir) {
  160.                 // NOTE: we're done... [ we can read/write this directory ]
  161.                 //
  162.                 XP_FREE(base_name);
  163.  
  164.                 return True;
  165.             }
  166.             else {
  167.                 // NOTE:  let's do the same thing for the file...
  168.                 //
  169.                 if ( stat(file_name, &file_info) >= 0 ) {
  170.                     gotcha = False;
  171.                     
  172.                     if (isFileP &&
  173.                         (file_info.st_mode & S_IFDIR)) {
  174.                         // NOTE:  the specifed file_name is a directory...
  175.                         //
  176.                         XP_FREE(base_name);
  177.  
  178.                         return False;
  179.                     }
  180.  
  181.                     if (file_info.st_uid == getuid()) {
  182.                         if ((file_info.st_mode & S_IRUSR) &&
  183.                             (file_info.st_mode & S_IWUSR)) {
  184.                             gotcha = True;
  185.                         }
  186.                     }
  187.                     
  188.                     if (!gotcha) {
  189.                         if (file_info.st_gid == getgid()) {
  190.                             if ((file_info.st_mode & S_IRGRP) &&
  191.                                 (file_info.st_mode & S_IWGRP)) {
  192.                                 gotcha = True;
  193.                             }
  194.                         }
  195.                         
  196.                         if (!gotcha) {
  197.                             if ((file_info.st_mode & S_IROTH) &&
  198.                                 (file_info.st_mode & S_IWOTH)) {
  199.                                 gotcha = True;
  200.                             }
  201.                         }
  202.                     }
  203.  
  204.                     if (gotcha) {
  205.                         // NOTE:  we can read/write this directory/file...
  206.                         //
  207.                         XP_FREE(base_name);
  208.                         
  209.                         return True;
  210.                     }
  211.                     else {
  212.                         // NOTE:  we failed the file check...
  213.                         //
  214.                         XP_FREE(base_name);
  215.                         
  216.                         return False;
  217.                     }
  218.                 }
  219.                 else {
  220.                     if (existsP) {
  221.                         // NOTE:  failed to stat the file...
  222.                         //
  223.                         XP_FREE(base_name);
  224.                     
  225.                         return False;
  226.                     }
  227.                     else {
  228.                         // NOTE:  we can read/write this directory...
  229.                         //
  230.                         XP_FREE(base_name);
  231.                     
  232.                         return True;
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.         else {
  238.             // NOTE:  we failed the directory check...
  239.             //
  240.             XP_FREE(base_name);
  241.  
  242.             return False;
  243.         }
  244.     }
  245.     else {
  246.         // NOTE:  failed to stat the directory...
  247.         //
  248.         XP_FREE(base_name);
  249.  
  250.         return False;
  251.     }
  252. }
  253.  
  254.  
  255. //////////////////////////////////////////////////////////////////////////
  256. //
  257. // XFE_DownloadView
  258. //
  259. //////////////////////////////////////////////////////////////////////////
  260.  
  261. XFE_DownloadFrame::XFE_DownloadFrame(Widget toplevel, XFE_Frame *parent_frame)
  262.     : XFE_Frame("Download",            // name
  263.                 toplevel,            // top level
  264.                 parent_frame,        // parent frame
  265.                 FRAME_DOWNLOAD,        // frame type
  266.                 NULL,                // chrome
  267.                 False,                // have html display
  268.                 False,                // have menu bar
  269.                 False,                // have toolbar
  270.                 False,                // have dashboard (we'll make our own)
  271.                 True)                // destroy on close
  272. {
  273.     Widget msgb;
  274.     XFE_Component *belowView;
  275.     Arg av[10];
  276.     int ac;
  277.  
  278.     XFE_DownloadView *v = new XFE_DownloadView(this, getViewParent(),
  279.                                                NULL, m_context);
  280.  
  281.     ac = 0;
  282.     XtSetArg(av[ac], XmNdialogType, XmDIALOG_TEMPLATE); ac++;
  283.     msgb = XmCreateMessageBox(getChromeParent(), "messagebox", av, ac);
  284.  
  285.     /* We have to do this explicitly because of AIX versions come
  286.        with these buttons by default */
  287.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msgb, XmDIALOG_SEPARATOR));
  288.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msgb, XmDIALOG_OK_BUTTON));
  289.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msgb, XmDIALOG_CANCEL_BUTTON));
  290.     fe_UnmanageChild_safe(XmMessageBoxGetChild(msgb, XmDIALOG_HELP_BUTTON));
  291.  
  292.     m_stopButton = XtVaCreateManagedWidget("stopLoading",
  293.                                            xmPushButtonWidgetClass,
  294.                                            msgb,
  295.                                            NULL);
  296.  
  297.     XtAddCallback(m_stopButton, XmNactivateCallback, activate_cb, this);
  298.  
  299.     belowView = new XFE_Component(msgb);
  300.  
  301.     setView(v);
  302.     setBelowViewArea(belowView);
  303.  
  304.     m_dashboard = new XFE_Dashboard(this,                // top level
  305.                                     getChromeParent(),    // parent
  306.                                     this,                // parent frame
  307.                                     False);                // have task bar
  308.  
  309.     m_dashboard->setShowStatusBar(True);
  310.     m_dashboard->setShowProgressBar(True);
  311.  
  312.     fe_set_scrolled_default_size(m_context);
  313.     v->show();
  314.     belowView->show();
  315.  
  316.  
  317.     m_dashboard->show();
  318.  
  319.     // Register the logo animation notifications with ourselves
  320.     // We need to do this, cause the XFE_Frame class only does so
  321.     // if the have_toolbars ctor parameter is true and in our case
  322.     // it is not.
  323.     registerInterest(XFE_Frame::logoStartAnimation,
  324.                      this,
  325.                      &XFE_Frame::logoAnimationStartNotice_cb);
  326.     
  327.     registerInterest(XFE_Frame::logoStopAnimation,
  328.                      this,
  329.                      &XFE_Frame::logoAnimationStopNotice_cb);
  330. }
  331.  
  332. XFE_DownloadFrame::~XFE_DownloadFrame()
  333. {
  334.     // Unregister the logo animation notifications with ourselves
  335.     // We need to do this, cause the XFE_Frame class only does so
  336.     // if the have_toolbars ctor parameter is true and in our case
  337.     // it is not.
  338.     unregisterInterest(XFE_Frame::logoStartAnimation,
  339.                        this,
  340.                        &XFE_Frame::logoAnimationStartNotice_cb);
  341.     
  342.     unregisterInterest(XFE_Frame::logoStopAnimation,
  343.                        this,
  344.                        &XFE_Frame::logoAnimationStopNotice_cb);
  345. }
  346.  
  347. XP_Bool
  348. XFE_DownloadFrame::isCommandEnabled(CommandType cmd,
  349.                                     void */*calldata*/, XFE_CommandInfo*)
  350. {
  351.     if (cmd == xfeCmdStopLoading)
  352.         return fe_IsContextStoppable(m_context);
  353.     else
  354.         return False;
  355. }
  356.  
  357. void
  358. XFE_DownloadFrame::doCommand(CommandType cmd,
  359.                              void */*calldata*/, XFE_CommandInfo*)
  360. {
  361.     if (cmd == xfeCmdStopLoading)
  362.         {
  363.             D( printf ("Canceling.\n"); )
  364.             XP_InterruptContext(m_context);
  365.             // allConnectionsComplete will destroy this frame.
  366.         }
  367. }
  368.  
  369. XP_Bool
  370. XFE_DownloadFrame::handlesCommand(CommandType cmd,
  371.                                   void */*calldata*/, XFE_CommandInfo*)
  372. {
  373.     if (cmd == xfeCmdStopLoading)
  374.         return True;
  375.     else
  376.         return False;
  377. }
  378.  
  379. void
  380. XFE_DownloadFrame::activate_cb(Widget w, XtPointer clientData, XtPointer)
  381. {
  382.     CommandType cmd = Command::intern(XtName(w));
  383.     XFE_DownloadFrame *obj = (XFE_DownloadFrame*)clientData;
  384.  
  385.     if (obj->handlesCommand(cmd) && obj->isCommandEnabled(cmd))
  386.         obj->doCommand(cmd);
  387. }
  388.  
  389. void
  390. XFE_DownloadFrame::allConnectionsComplete()
  391. {
  392.     D( printf ("in allConnectionsComplete\n");)
  393.     XP_InterruptContext(m_context);
  394.  
  395.     delete_response();
  396. }
  397.  
  398. void
  399. XFE_DownloadFrame::setAddress(char *address)
  400. {
  401.     XFE_DownloadView *v = (XFE_DownloadView*)m_view;
  402.  
  403.     v->setAddress(address);
  404. }
  405.  
  406. void
  407. XFE_DownloadFrame::setDestination(char *destination)
  408. {
  409.     XFE_DownloadView *v = (XFE_DownloadView*)m_view;
  410.  
  411.     v->setDestination(destination);
  412. }
  413. //////////////////////////////////////////////////////////////////////////
  414. XFE_Logo *
  415. XFE_DownloadFrame::getLogo()
  416. {
  417.     XFE_Logo *            logo = NULL;
  418.     XFE_DownloadView *    view = (XFE_DownloadView *) getView();
  419.     
  420.     if (view)
  421.     {
  422.         logo = view->getLogo();
  423.     }
  424.  
  425.     return logo;
  426. }
  427. //////////////////////////////////////////////////////////////////////////
  428. void
  429. XFE_DownloadFrame::configureLogo()
  430. {
  431. }
  432.  
  433. //////////////////////////////////////////////////////////////////////////
  434. //
  435. // XFE_DownloadView
  436. //
  437. //////////////////////////////////////////////////////////////////////////
  438. XFE_DownloadView::XFE_DownloadView(XFE_Component *toplevel, Widget parent,
  439.                                    XFE_View *parent_view, MWContext *context)
  440.     : XFE_View (toplevel, parent_view, context)
  441. {
  442.     Widget form;
  443.     Widget   pane = 0;
  444.     Widget    saving_label, url_label;
  445.     Arg av[10];
  446.     int ac;
  447.  
  448.     form = XtVaCreateWidget("topArea",
  449.                             xmFormWidgetClass,
  450.                             parent,
  451.                             XmNrightAttachment,        XmATTACH_FORM,
  452.                             XmNtopAttachment,        XmATTACH_FORM,
  453.                             XmNleftAttachment,        XmATTACH_FORM,
  454.                             XmNbottomAttachment,    XmATTACH_NONE,
  455.                             NULL);
  456.  
  457.     CONTEXT_DATA(m_contextData)->top_area = form;
  458.     
  459.  
  460.     m_logo = new XFE_Logo((XFE_Frame *) toplevel,form,"logo");
  461.     
  462.     pane = XtVaCreateManagedWidget("pane",
  463.                                    xmFormWidgetClass,
  464.                                    form,
  465.                                    NULL);
  466.     url_label = XtVaCreateManagedWidget("downloadURLLabel",
  467.                                         xmLabelGadgetClass,
  468.                                         pane,
  469.                                         NULL);
  470.     ac = 0;
  471.     XtSetArg (av [ac], XmNeditable, False); ac++;
  472.     m_url_value = fe_CreateTextField (pane, "downloadURLValue", av, ac);
  473.     XtManageChild(m_url_value);
  474.  
  475.     saving_label = XtVaCreateManagedWidget("downloadFileLabel",
  476.                                            xmLabelGadgetClass,
  477.                                            pane,
  478.                                            NULL);
  479.     ac = 0;
  480.     XtSetArg (av [ac], XmNeditable, False); ac++;
  481.     m_saving_value = fe_CreateTextField(pane, "downloadFileValue", av, ac);
  482.     XtManageChild(m_saving_value);
  483.  
  484.     /* =======================================================================
  485.        Attachments.  This has to be done after the widgets are created,
  486.        since they're interdependent, sigh.
  487.        =======================================================================
  488.        */
  489.     XtVaSetValues(url_label,
  490.                   XmNleftAttachment, XmATTACH_FORM,
  491.                   XmNtopAttachment, XmATTACH_FORM,
  492.                   0);
  493.     XtVaSetValues(m_url_value,
  494.                   XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  495.                   XmNtopWidget, url_label,
  496.                   XmNrightAttachment, XmATTACH_FORM,
  497.                   XmNleftAttachment, XmATTACH_WIDGET,
  498.                   XmNleftWidget, url_label,
  499.                   0);
  500.     XtVaSetValues(saving_label,
  501.                   XmNleftAttachment, XmATTACH_FORM,
  502.                   XmNtopAttachment, XmATTACH_WIDGET,
  503.                   XmNtopWidget, m_url_value,
  504.                   0);
  505.     XtVaSetValues(m_saving_value,
  506.                   XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  507.                   XmNtopWidget, saving_label,
  508.                   XmNleftAttachment, XmATTACH_WIDGET,
  509.                   XmNleftWidget, saving_label,
  510.                   XmNrightAttachment, XmATTACH_FORM,
  511.                   0);
  512.     XP_ASSERT(XfeWidth(url_label) > 0 && XfeWidth(saving_label) > 0);
  513.     if (XfeWidth(url_label) < XfeWidth(saving_label))
  514.         XtVaSetValues (url_label, XmNwidth, XfeWidth(saving_label), 0);
  515.     else
  516.         XtVaSetValues (saving_label, XmNwidth, XfeWidth(url_label), 0);
  517.     
  518.     XtVaSetValues (url_label, XmNheight, XfeHeight(m_url_value), 0);
  519.     XtVaSetValues (saving_label, XmNheight, XfeHeight(m_saving_value), 0);
  520.  
  521.     XtVaSetValues (pane,
  522.                    XmNtopAttachment, XmATTACH_FORM,
  523.                    XmNleftAttachment, XmATTACH_FORM,
  524.                    XmNbottomAttachment, XmATTACH_FORM,
  525.                    XmNrightAttachment, XmATTACH_WIDGET,
  526.                    XmNrightWidget, m_logo->getBaseWidget(),
  527.                    0);
  528.     XtVaSetValues (m_logo->getBaseWidget(),
  529.                    XmNtopAttachment, XmATTACH_FORM,
  530.                    XmNrightAttachment, XmATTACH_FORM,
  531.                    XmNleftAttachment, XmATTACH_NONE,
  532.                    XmNbottomAttachment, XmATTACH_NONE,
  533.                    0);
  534.  
  535.     m_logo->show();
  536.     setBaseWidget(form);
  537. }
  538.  
  539. XFE_DownloadView::~XFE_DownloadView()
  540. {
  541.     // nothing to do here.
  542. }
  543.  
  544. void
  545. XFE_DownloadView::setAddress(char *address)
  546. {
  547.     fe_SetTextFieldAndCallBack(m_url_value, address);
  548. }
  549.  
  550. void
  551. XFE_DownloadView::setDestination(char *destination)
  552. {
  553.     fe_SetTextFieldAndCallBack(m_saving_value, destination);
  554. }
  555.  
  556. XFE_Logo *
  557. XFE_DownloadView::getLogo()
  558. {
  559.     return m_logo;
  560. }
  561.  
  562. MWContext*
  563. fe_showDownloadWindow(Widget toplevel, XFE_Frame *parent_frame)
  564. {
  565.     XFE_DownloadFrame *frame = new XFE_DownloadFrame(toplevel, parent_frame);
  566.  
  567.     frame->show();
  568.  
  569.     return frame->getContext();
  570. }
  571.  
  572.  
  573. /* here is the stuff ripped out of commands.c, which is used to actually
  574.    set up the stream.  It needs to be here instead of commands.c because
  575.    we have do set values of the text fields, through member functions. */
  576. extern char **fe_encoding_extensions; /* gag.  used by mkcache.c. */
  577.  
  578. static struct save_as_data *
  579. make_save_as_data (MWContext *context, Boolean allow_conversion_p,
  580.            int type, URL_Struct *url, const char *output_file)
  581. {
  582.   const char *file_name;
  583.   struct save_as_data *sad;
  584.   FILE *file = NULL;
  585.   char *suggested_name = 0;
  586.   Boolean use_dialog_p = False;
  587.   Boolean exists_p = False;
  588.   Boolean nuke_p = True;
  589.   const char *address = url ? url->address : 0;
  590.   const char *content_type = url ? url->content_type : 0;
  591.   const char *content_encoding = url ? url->content_encoding : 0;
  592.   const char *title;
  593.   char buf [255];
  594.  
  595.   if (url)
  596.     {
  597. #ifdef MOZ_MAIL_NEWS
  598.       if (!url->content_name)
  599.     url->content_name = MimeGuessURLContentName(context, url->address);
  600. #endif
  601.       if (url->content_name)
  602.     address = url->content_name;
  603.     }
  604.  
  605.   if (output_file)
  606.     file_name = output_file;
  607.   else
  608.     {
  609.       Boolean really_allow_conversion_p = allow_conversion_p;
  610.       if (content_type &&
  611.       (!strcasecomp (content_type, UNKNOWN_CONTENT_TYPE) || 
  612.        !strcasecomp (content_type, INTERNAL_PARSER)))
  613.     content_type = 0;
  614.  
  615.       if (content_type && !*content_type) content_type = 0;
  616.       if (content_encoding && !*content_encoding) content_encoding = 0;
  617.       if (content_type && content_encoding)
  618.     PR_snprintf (buf, sizeof (buf), XP_GetString(XFE_SAVE_AS_TYPE_ENCODING),
  619.          content_type, content_encoding);
  620.       else if (content_type)
  621.     PR_snprintf (buf, sizeof (buf),
  622.         XP_GetString(XFE_SAVE_AS_TYPE), content_type);
  623.       else if (content_encoding)
  624.     PR_snprintf (buf, sizeof (buf),
  625.         XP_GetString(XFE_SAVE_AS_ENCODING), content_encoding);
  626.       else
  627.     PR_snprintf (buf, sizeof (buf), XP_GetString(XFE_SAVE_AS));
  628.       title = buf;
  629.  
  630.       if (fe_encoding_extensions)
  631.     {
  632.       int L = strlen (address);
  633.       int i = 0;
  634.       while (fe_encoding_extensions [i])
  635.         {
  636.           int L2 = strlen (fe_encoding_extensions [i]);
  637.           if (L2 < L &&
  638.           !strncmp (address + L - L2,
  639.                 fe_encoding_extensions [i],
  640.                 L2))
  641.         {
  642.  
  643.           /* The URL ends in ".Z" or ".gz" (or whatever.)
  644.              Take off that extension, and ask netlib what the type
  645.              of the resulting file is - if it is text/html or
  646.              text/plain (meaning it ends in ".html" or ".htm" or
  647.              ".txt" or god-knows-what-else) then (and only then)
  648.              strip off the .Z or .gz.  That we need to check the
  649.              extension like that is a kludge, but since we haven't
  650.              opened the URL yet, we don't have a content-type to
  651.              know for sure.  And it's just for the default file name
  652.              anyway...
  653.            */
  654. #ifdef NEW_DECODERS
  655.           NET_cinfo *cinfo;
  656.  
  657.           /* If the file ends in .html.Z, the suggested file
  658.              name is .html, but we will allow it to be saved
  659.              as .txt (uncompressed.)
  660.  
  661.              If the file ends in .ps.Z, the suggested file name
  662.              is .ps.Z, and we will ignore a selection which says
  663.              to save it as text. */
  664.           really_allow_conversion_p = False;
  665.  
  666.           suggested_name = strdup (address);
  667.           suggested_name [L - L2] = 0;
  668.           /* don't free cinfo. */
  669.           cinfo = NET_cinfo_find_type (suggested_name);
  670.           if (cinfo &&
  671.               cinfo->type &&
  672.               (!strcasecomp (cinfo->type, TEXT_PLAIN) ||
  673.                !strcasecomp (cinfo->type, TEXT_HTML) ||
  674.                !strcasecomp (cinfo->type, TEXT_MDL) ||
  675.                /* always treat unknown content types as text/plain */
  676.                !strcasecomp (cinfo->type, UNKNOWN_CONTENT_TYPE)))
  677.             {
  678.               /* then that's ok */
  679.               really_allow_conversion_p = allow_conversion_p;
  680.               break;
  681.             }
  682.  
  683.           /* otherwise, continue. */
  684.           free (suggested_name);
  685.           suggested_name = 0;
  686. #else  /* !NEW_DECODERS */
  687.           suggested_name = strdup (address);
  688.           suggested_name [L - L2] = 0;
  689.           break;
  690. #endif /* !NEW_DECODERS */
  691.         }
  692.           i++;
  693.         }
  694.     }
  695.  
  696.       file_name = fe_ReadFileName (context, title,
  697.                    (suggested_name ? suggested_name : address),
  698.                    False,
  699.                    (really_allow_conversion_p ? &type : 0));
  700.  
  701.       if (suggested_name)
  702.     free ((char *) suggested_name);
  703.  
  704.       use_dialog_p = True;
  705.     }
  706.  
  707.   if (! file_name)
  708.     return 0;
  709.  
  710. #ifdef EDITOR 
  711.   if (context->type == MWContextEditor) {
  712.       // NOTE:  let's check to make sure we can write into this file/directory
  713.       //        before we start nuking data...
  714.       //
  715.       if ( !XFE_StatReadWrite(file_name, True, False) ) {
  716.           // NOTE:  we can't write into this directory or file... [ PUNT ]
  717.           //
  718.           char buf [1024];
  719.           PR_snprintf (buf, sizeof (buf),
  720.                        XP_GetString(XFE_ERROR_READ_ONLY), file_name);
  721.           fe_perror (context, buf);
  722.           
  723.           return 0;
  724.       }
  725.   }
  726. #endif
  727.   
  728.   /* If the file exists, confirm overwriting it. */
  729.   {
  730.     XP_StatStruct st;
  731.     if (!stat (file_name, &st))
  732.       {
  733.     char *bp;
  734.     int size;
  735.  
  736.     exists_p = True;
  737.  
  738.     size = XP_STRLEN (file_name) + 1;
  739.     size += XP_STRLEN (fe_globalData.overwrite_file_message) + 1;
  740.     bp = (char *) XP_ALLOC (size);
  741.     if (!bp) return 0;
  742.     PR_snprintf (bp, size,
  743.             fe_globalData.overwrite_file_message, file_name);
  744.     if (!FE_Confirm (context, bp))
  745.       {
  746.         XP_FREE (bp);
  747.         return 0;
  748.       }
  749.     XP_FREE (bp);
  750.       }
  751.   }
  752.  
  753. #ifdef EDITOR 
  754.   if (exists_p && (context->type == MWContextEditor)) {
  755.       // NOTE:  don't open the file or we'll destroy the ability to 
  756.       //        create the backup file in EDT...
  757.       //
  758.       nuke_p = False;
  759.   }
  760. #endif
  761.  
  762.   if (nuke_p) {
  763.       file = fopen (file_name, "w");
  764.   }
  765.  
  766.   if (!file && nuke_p)
  767.     {
  768.       char buf [1024];
  769.       PR_snprintf (buf, sizeof (buf),
  770.             XP_GetString(XFE_ERROR_OPENING_FILE), file_name);
  771.       fe_perror (context, buf);
  772.       sad = 0;
  773.     }
  774.   else
  775.     {
  776.       sad = (struct save_as_data *) malloc (sizeof (struct save_as_data));
  777.       sad->context = context;
  778.       sad->name = (char *) file_name;
  779.       sad->file = file;
  780.       sad->type = type;
  781.       sad->done = NULL;
  782.       sad->insert_base_tag = FALSE;
  783.       sad->use_dialog_p = use_dialog_p;
  784.       sad->content_length = 0;
  785.       sad->bytes_read = 0;
  786.       sad->url = url;
  787.     }
  788.   return sad;
  789. }
  790.  
  791. static void
  792. fe_save_as_complete (PrintSetup *ps)
  793. {
  794.   MWContext *context = (MWContext *) ps->carg;
  795.  
  796.   fclose(ps->out);
  797.  
  798.   fe_LowerSynchronousURLDialog (context);
  799.  
  800.   free (ps->filename);
  801.   NET_FreeURLStruct (ps->url);
  802. }
  803.  
  804.  
  805. static int
  806. fe_save_as_stream_write_method (NET_StreamClass *stream, const char *str, int32 len)
  807. {
  808.   struct save_as_data *sad = (struct save_as_data *) stream->data_object;
  809.   fwrite ((char *) str, 1, len, sad->file);
  810.  
  811.   sad->bytes_read += len;
  812.  
  813.   if (sad->content_length > 0)
  814.     FE_SetProgressBarPercent (sad->context,
  815.                   (sad->bytes_read * 100) /
  816.                   sad->content_length);
  817. #if 0
  818.   /* Oops, this makes the size twice as large as it should be. */
  819.   FE_GraphProgress (sad->context, 0 /* #### url_s */,
  820.             sad->bytes_read, len, sad->content_length);
  821. #endif
  822.   return 1;
  823. }
  824.  
  825. static unsigned int
  826. fe_save_as_stream_write_ready_method (NET_StreamClass *stream)
  827. {
  828.   return(MAX_WRITE_READY);
  829. }
  830.  
  831. static void
  832. fe_save_as_stream_complete_method (NET_StreamClass *stream)
  833. {
  834.   struct save_as_data *sad = (struct save_as_data *) stream->data_object;
  835.   fclose (sad->file);
  836.   if (sad->done)
  837.     (*sad->done)(sad);
  838.   sad->file = 0;
  839.   if (sad->name)
  840.     {
  841.       free (sad->name);
  842.       sad->name = 0;
  843.     }
  844.   if (sad->use_dialog_p)
  845.     fe_LowerSynchronousURLDialog (sad->context);
  846.  
  847.   FE_GraphProgressDestroy (sad->context, 0 /* #### url */,
  848.                sad->content_length, sad->bytes_read);
  849.   NET_RemoveURLFromCache(sad->url); /* cleanup */
  850.   NET_RemoveDiskCacheObjects(0); /* kick the cache to notice the cleanup */
  851.   free (sad);
  852.   return;
  853. }
  854.  
  855. static void
  856. fe_save_as_stream_abort_method (NET_StreamClass *stream, int /*status*/)
  857. {
  858.   struct save_as_data *sad = (struct save_as_data *) stream->data_object;
  859.   fclose (sad->file);
  860.   sad->file = 0;
  861.   if (sad->name)
  862.     {
  863.       if (!unlink (sad->name))
  864.     {
  865. #if 0
  866.       char buf [1024];
  867.       PR_snprintf (buf, sizeof (buf),
  868.             XP_GetString(XFE_ERROR_DELETING_FILE), sad->name);
  869.       fe_perror (sad->context, buf);
  870. #endif
  871.     }
  872.       free (sad->name);
  873.       sad->name = 0;
  874.     }
  875.   if (sad->use_dialog_p)
  876.     fe_LowerSynchronousURLDialog (sad->context);
  877.  
  878.   FE_GraphProgressDestroy (sad->context, 0 /* #### url */,
  879.                sad->content_length, sad->bytes_read);
  880.   /* We do *not* remove the URL from the cache at this point. */
  881.   free (sad);
  882. }
  883.  
  884. /* Creates and returns a stream object which writes the data read to a
  885.    file.  If the file has not been prompted for / opened, it prompts the
  886.    user.
  887.  */
  888. extern "C" NET_StreamClass *
  889. fe_MakeSaveAsStream (int /*format_out*/, void */*data_obj*/,
  890.              URL_Struct *url_struct, MWContext *context)
  891. {
  892.     struct save_as_data *sad;
  893.     NET_StreamClass* stream;
  894.     
  895.     if (url_struct->fe_data)
  896.         {
  897.             sad = (struct save_as_data*)url_struct->fe_data;
  898.         }
  899.     else
  900.         {
  901.             Boolean text_p = (url_struct->content_type &&
  902.                               (!strcasecomp (url_struct->content_type, TEXT_HTML) ||
  903.                                !strcasecomp (url_struct->content_type, TEXT_MDL) ||
  904.                                !strcasecomp (url_struct->content_type, TEXT_PLAIN)));
  905.             sad = make_save_as_data (context, text_p, fe_FILE_TYPE_HTML, url_struct,
  906.                                      0);
  907.             if (! sad) return 0;
  908.         }
  909.  
  910.     url_struct->fe_data = 0;
  911.     
  912.     stream = (NET_StreamClass *) calloc (sizeof (NET_StreamClass), 1);
  913.     if (!stream) return 0;
  914.     
  915.     stream->name           = "SaveAs";
  916.     stream->complete       = fe_save_as_stream_complete_method;
  917.     stream->abort          = fe_save_as_stream_abort_method;
  918.     stream->put_block      = fe_save_as_stream_write_method;
  919.     stream->is_write_ready = fe_save_as_stream_write_ready_method;
  920.     stream->data_object    = sad;
  921.     stream->window_id      = context;
  922.     
  923.     if (sad->insert_base_tag && XP_STRCMP(url_struct->content_type, TEXT_HTML)
  924.         == 0)
  925.         {
  926.             /*
  927.             ** This is here to that any relative URL's in the document
  928.             ** will continue to work even though we are moving the document
  929.             ** to another world.
  930.             */
  931.             fe_save_as_stream_write_method(stream, "<BASE HREF=", 11);
  932.             fe_save_as_stream_write_method(stream, url_struct->address,
  933.                                            XP_STRLEN(url_struct->address));
  934.             fe_save_as_stream_write_method(stream, ">\n", 2);
  935.         }
  936.  
  937.     sad->content_length = url_struct->content_length;
  938.     FE_SetProgressBarPercent (context, -1);
  939.     if( url_struct->server_can_do_byteranges || url_struct->server_can_do_restart )
  940.         url_struct->must_cache = TRUE;
  941. #if 0
  942.     /* Oops, this makes the size twice as large as it should be. */
  943.     FE_GraphProgressInit (context, url_struct, sad->content_length);
  944. #endif
  945.     
  946.     if (sad->use_dialog_p)
  947.         {
  948.             /* make sure it is safe to open a new context */
  949.             if (NET_IsSafeForNewContext(url_struct))
  950.                 {
  951.                     /* create a download frame here */
  952.                     XFE_Frame *parent;
  953.                     XFE_DownloadFrame *new_frame;
  954.                     MWContext *new_context;
  955.  
  956.                     parent = ViewGlue_getFrame(XP_GetNonGridContext(context));
  957.  
  958.                     new_frame = new XFE_DownloadFrame(XtParent(parent->getBaseWidget()), parent);
  959.                     new_context = new_frame->getContext();
  960.  
  961.                     /* Set the values for location and filename */
  962.                     if (url_struct->address)
  963.                         new_frame->setAddress(url_struct->address);
  964.                     if (sad && sad->name)
  965.                         new_frame->setDestination(sad->name);
  966.  
  967.                     new_frame->show();
  968.  
  969.                     /* Set the url_count and enable all animation */
  970.                     CONTEXT_DATA (new_context)->active_url_count = 1;
  971.                     fe_StartProgressGraph (new_context);
  972.       
  973.                     /* register this new context associated with this stream
  974.                      * with the netlib
  975.                      */
  976.                     NET_SetNewContext(url_struct, new_context, fe_url_exit);
  977.  
  978.                     /* Change the fe_data's context */
  979.                     sad->context = new_context;
  980.                 }
  981.             else
  982.                 fe_RaiseSynchronousURLDialog (context, CONTEXT_WIDGET (context),
  983.                                               "saving");
  984.         }
  985.  
  986.   return stream;
  987. }
  988.  
  989. extern "C" NET_StreamClass *
  990. fe_MakeSaveAsStreamNoPrompt (int format_out, void *data_obj,
  991.                  URL_Struct *url_struct, MWContext *context)
  992. {
  993.   struct save_as_data *sad;
  994.  
  995.   assert (context->prSetup);
  996.   if (! context->prSetup)
  997.     return 0;
  998.  
  999.   sad = (struct save_as_data *) malloc (sizeof (struct save_as_data));
  1000.   sad->context = context;
  1001.   sad->name = strdup (context->prSetup->filename);
  1002.   sad->file = context->prSetup->out;
  1003.   sad->type = fe_FILE_TYPE_HTML;
  1004.   sad->done = 0;
  1005.   sad->insert_base_tag = FALSE;
  1006.   sad->use_dialog_p = FALSE;
  1007.  
  1008.   url_struct->fe_data = sad;
  1009.  
  1010.   sad->content_length = url_struct->content_length;
  1011.   FE_GraphProgressInit (context, url_struct, sad->content_length);
  1012.  
  1013.   return fe_MakeSaveAsStream (format_out, data_obj, url_struct, context);
  1014. }
  1015.  
  1016. static void
  1017. fe_save_as_nastiness (MWContext *context, URL_Struct *url,
  1018.               struct save_as_data *sad,int synchronous)
  1019. {
  1020.   SHIST_SavedData saved_data;
  1021.   assert (sad);
  1022.   if (! sad) return;
  1023.  
  1024.   /* Make sure layout saves the current state of form elements. */
  1025.   LO_SaveFormData(context);
  1026.  
  1027.   /* Hold on to the saved data. */
  1028.   XP_MEMCPY(&saved_data, &url->savedData, sizeof(SHIST_SavedData));
  1029.  
  1030.   /* make damn sure the form_data slot is zero'd or else all
  1031.    * hell will break loose
  1032.    */
  1033.   XP_MEMSET (&url->savedData, 0, sizeof (SHIST_SavedData));
  1034.  
  1035.   switch (sad->type)
  1036.     {
  1037.     case fe_FILE_TYPE_TEXT:
  1038.     case fe_FILE_TYPE_FORMATTED_TEXT:
  1039.       {
  1040.     PrintSetup p;
  1041.     fe_RaiseSynchronousURLDialog (context, CONTEXT_WIDGET (context),
  1042.                       "saving");
  1043.     XL_InitializeTextSetup (&p);
  1044.     p.out = sad->file;
  1045.     p.filename = sad->name;
  1046.     p.url = url;
  1047.     free(sad);
  1048.     p.completion = fe_save_as_complete;
  1049.     p.carg = context;
  1050.     XL_TranslateText (context, url, &p);
  1051.     fe_await_synchronous_url (context);
  1052.     break;
  1053.       }
  1054.     case fe_FILE_TYPE_PS:
  1055.       {
  1056.     PrintSetup p;
  1057.     fe_RaiseSynchronousURLDialog (context, CONTEXT_WIDGET (context),
  1058.                       "saving");
  1059.     XL_InitializePrintSetup (&p);
  1060.     p.out = sad->file;
  1061.     p.filename = sad->name;
  1062.     p.url = url;
  1063.     free (sad);
  1064.     p.completion = fe_save_as_complete;
  1065.     p.carg = context;
  1066.     XL_TranslatePostscript (context, url, &saved_data, &p);
  1067.     fe_await_synchronous_url (context);
  1068.     break;
  1069.       }
  1070.  
  1071.     case fe_FILE_TYPE_HTML:
  1072.       {
  1073.         if (!synchronous)
  1074.             fe_GetSecondaryURL (context, url, FO_CACHE_AND_SAVE_AS, sad, FALSE);
  1075.         else
  1076.             fe_GetSynchronousURL (context,
  1077.                                   CONTEXT_WIDGET (context),
  1078.                                   "saving",
  1079.                                   url,
  1080.                                   FO_CACHE_AND_SAVE_AS,
  1081.                                   (void *)sad);
  1082.     break;
  1083.       }
  1084. #ifdef SAVE_ALL
  1085.     case fe_FILE_TYPE_HTML_AND_IMAGES:
  1086.       {
  1087.     char *addr = strdup (url->address);
  1088.     char *filename = sad->name;
  1089.     FILE *file = sad->file;
  1090.     NET_FreeURLStruct (url);
  1091.     free (sad);
  1092.     SAVE_SaveTree (context, addr, filename, file);
  1093.     break;
  1094.       }
  1095. #endif /* SAVE_ALL */
  1096.     default:
  1097.       abort ();
  1098.     }
  1099. }
  1100.  
  1101.  
  1102. void
  1103. fe_SaveURL (MWContext *context, URL_Struct *url)
  1104. {
  1105.   struct save_as_data *sad;
  1106.   Boolean text_p = True;
  1107.  
  1108.   assert (url);
  1109.   if (!url) return;
  1110.  
  1111. #if 0
  1112.   if (url->content_type && *url->content_type)
  1113.     {
  1114.       if (! (!strcasecomp (url->content_type, TEXT_HTML) ||
  1115.          !strcasecomp (url->content_type, TEXT_MDL) ||
  1116.          !strcasecomp (url->content_type, TEXT_PLAIN)))
  1117.     text_p = False;
  1118.     }
  1119. #endif
  1120.  
  1121.   sad = (struct save_as_data*)make_save_as_data (context, text_p, fe_FILE_TYPE_HTML, url, 0);
  1122.   if (sad)
  1123.     fe_save_as_nastiness (context, url, sad, FALSE);
  1124.   else
  1125.     NET_FreeURLStruct (url);
  1126. }
  1127.  
  1128. void
  1129. fe_SaveSynchronousURL (MWContext *context, URL_Struct *url,const char *fname)
  1130. {
  1131.   struct save_as_data *sad;
  1132.   Boolean text_p = True;
  1133.  
  1134.   assert (url);
  1135.   if (!url) return;
  1136.  
  1137.   sad = (struct save_as_data*)make_save_as_data (context, text_p, fe_FILE_TYPE_HTML, url, fname);
  1138.   if (sad) {
  1139.       sad->use_dialog_p=FALSE;
  1140.       if (fname && strlen(fname)>0)
  1141.           sad->name = strdup((char *)fname);
  1142.       fe_save_as_nastiness (context, url, sad, TRUE);
  1143.   }
  1144.   else {
  1145.       NET_FreeURLStruct (url);
  1146.   }
  1147. }
  1148.  
  1149. #ifdef EDITOR
  1150.  
  1151. extern "C" Boolean
  1152. fe_SaveAsDialog(MWContext* context, char* buf, int type)
  1153. {
  1154.     URL_Struct*          url;
  1155.     struct save_as_data* sad;
  1156.     
  1157.     url = SHIST_CreateURLStructFromHistoryEntry(
  1158.                     context,
  1159.                     SHIST_GetCurrent(&context->hist)
  1160.                     );
  1161.  
  1162.     if (url) 
  1163.         {
  1164.             sad = (struct save_as_data*)make_save_as_data(context, FALSE, type, url, 0);
  1165.             
  1166.             if (sad) 
  1167.                 {
  1168.                     // NOTE:  check to see if they opened the file...
  1169.                     //
  1170.                     if (sad->file) {
  1171.                         fclose(sad->file);
  1172.                     }
  1173.                     
  1174.                     strcpy(buf, sad->name);
  1175.                     
  1176.                     free(sad);
  1177.                     
  1178.                     return TRUE;
  1179.                 }
  1180.         }
  1181.     
  1182.     return FALSE;
  1183. }
  1184.  
  1185. #endif
  1186.  
  1187. extern "C" void
  1188. fe_save_as_action (Widget widget, MWContext *context,
  1189.                    String *av, Cardinal *ac)
  1190. {
  1191.   /* See also fe_open_url_action() */
  1192.   XP_ASSERT (context);
  1193.   if (!context) return;
  1194.   fe_UserActivity (context);
  1195.   if (*ac && av[*ac-1] && !strcmp (av[*ac-1], "<remote>"))
  1196.     (*ac)--;
  1197.   if ((*ac == 1 || *ac == 2) && av[0])
  1198.     {
  1199.       URL_Struct *url;
  1200.       struct save_as_data *sad;
  1201.       char *file;
  1202.       int type = fe_FILE_TYPE_HTML;
  1203.  
  1204.       if (*ac == 2 && av[1])
  1205.     {
  1206.       if (!XP_STRCASECMP(av[1], "source"))
  1207.         type = fe_FILE_TYPE_HTML;
  1208.       else if (!XP_STRCASECMP(av[1], "html"))
  1209.         type = fe_FILE_TYPE_HTML;
  1210. #ifdef SAVE_ALL
  1211.       else if (!XP_STRCASECMP(av[1], "tree"))
  1212.         type = fe_FILE_TYPE_HTML_AND_IMAGES;
  1213.       else if (!XP_STRCASECMP(av[1], "html-and-images"))
  1214.         type = fe_FILE_TYPE_HTML_AND_IMAGES;
  1215.       else if (!XP_STRCASECMP(av[1], "source-and-images"))
  1216.         type = fe_FILE_TYPE_HTML_AND_IMAGES;
  1217. #endif /* SAVE_ALL */
  1218.       else if (!XP_STRCASECMP(av[1], "text"))
  1219.         type = fe_FILE_TYPE_TEXT;
  1220.       else if (!XP_STRCASECMP(av[1], "formatted-text"))
  1221.         type = fe_FILE_TYPE_FORMATTED_TEXT;
  1222.       else if (!XP_STRCASECMP(av[1], "ps"))
  1223.         type = fe_FILE_TYPE_PS;
  1224.       else if (!XP_STRCASECMP(av[1], "postscript"))
  1225.         type = fe_FILE_TYPE_PS;
  1226.       else
  1227.         {
  1228.           fprintf (stderr, 
  1229.                XP_GetString(XFE_COMMANDS_SAVE_AS_USAGE),
  1230.                fe_progname);
  1231.           return;
  1232.         }
  1233.     }
  1234.  
  1235.       url = SHIST_CreateWysiwygURLStruct (context,
  1236.                                           SHIST_GetCurrent (&context->hist));
  1237.       file = strdup (av[0]);
  1238.       sad = make_save_as_data (context, False, type, url, file);
  1239.       if (sad)
  1240.     fe_save_as_nastiness (context, url, sad, TRUE);
  1241.       else
  1242.     NET_FreeURLStruct (url);
  1243.     }
  1244.   else if (*ac > 2)
  1245.     {
  1246.         fprintf (stderr, 
  1247.                  XP_GetString(XFE_COMMANDS_SAVE_AS_USAGE_TWO),
  1248.                  fe_progname);
  1249.     }
  1250.   else
  1251.     {
  1252.       fe_save_top_frame_as_cb (widget, (XtPointer)context, (XtPointer)0);
  1253.     }
  1254. }
  1255.  
  1256.