home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CBrowserView.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  21.8 KB  |  721 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. #include "CBrowserView.h"
  20.  
  21.     // need these for various routine calls
  22. #include "CHTMLClickrecord.h"
  23. #include "msgcom.h"
  24. #include "proto.h"
  25. #include "RandomFrontEndCrap.h"
  26. #include "CBrowserContext.h"
  27. #include "CBookmarksAttachment.h"
  28. #include "ufilemgr.h"
  29. #include "CURLDispatcher.h"
  30. #include "CEditorWindow.h"    // cmd_EditFrame
  31. #include "secnav.h"
  32. #include "ntypes.h"
  33. #include "shist.h"
  34. #include "macutil.h"
  35. #include "CViewUtils.h"
  36. #include "CApplicationEventAttachment.h"
  37. #include "uerrmgr.h"    // GetPString prototype
  38. #include "CTargetFramer.h"
  39.  
  40. extern "C" {
  41. #include "layout.h"
  42. }
  43.  
  44.     // ÑÑÑ I don't want to include this, but I need the ID of the popup menu
  45. #include "resgui.h"
  46.  
  47. #include "CMochaHacks.h"
  48.  
  49. class CBrowserViewDoDragReceiveMochaCallback;
  50.  
  51. void MochaDragDrop(MWContext* inContext, CBrowserViewDoDragReceiveMochaCallback * cb, Point inDragMouse, short inDragModifiers );
  52. Boolean HasFTPUpload(CBrowserContext * context);
  53.  
  54.  
  55. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  56. //    Ñ    
  57. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  58.         
  59. CBrowserView::CBrowserView(LStream* inStream)
  60.     : CHTMLView(inStream)
  61. {
  62. }
  63.  
  64. CBrowserView::~CBrowserView()
  65. {
  66. }
  67.  
  68. void        
  69. CBrowserView::MoveBy(
  70.                                 Int32                inHorizDelta,
  71.                                 Int32                inVertDelta,
  72.                                 Boolean                inRefresh)
  73. {
  74.     Inherited::MoveBy(inHorizDelta, inVertDelta, inRefresh);
  75.     if (mContext != NULL && (inHorizDelta || inVertDelta))
  76.     {
  77.         SPoint32 location;
  78.         GetFrameLocation(location);
  79.         CMochaHacks::SendMoveEvent(*mContext, location.h, location.v);
  80.     }
  81. }
  82.  
  83. /*    BeTarget and DontBeTarget enable and disable the drawing of the selection.
  84.     This has the effect of not drawing the text as selected when the view is
  85.     not currently the target.  Using LO_ClearSelection instead would have
  86.     the same effect, but the selection wouldn't be recovered when the target
  87.     is given back to the view (as in, when its window is deactivated then
  88.     reactivated).
  89. */
  90.  
  91. // ---------------------------------------------------------------------------
  92. //        Ñ BeTarget
  93. // ---------------------------------------------------------------------------
  94.  
  95. void
  96. CBrowserView::BeTarget() {
  97.  
  98.     LO_HighlightSelection (*mContext, TRUE);
  99.     ExecuteAttachments(CTargetFramer::msg_BecomingTarget, this);
  100. }
  101.  
  102. // ---------------------------------------------------------------------------
  103. //        Ñ DontBeTarget
  104. // ---------------------------------------------------------------------------
  105.  
  106. void
  107. CBrowserView::DontBeTarget() {
  108.  
  109. //    LO_ClearSelection (*mContext);
  110.     LO_HighlightSelection (*mContext, FALSE);
  111.     ExecuteAttachments(CTargetFramer::msg_ResigningTarget, this);
  112. }
  113.  
  114. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  115. //
  116. #pragma mark --- COMMANDER OVERRIDES ---
  117. //
  118. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  119.  
  120. void CBrowserView::FindCommandStatus(CommandT inCommand,
  121.                                     Boolean    &outEnabled,
  122.                                     Boolean    &outUsesMark,
  123.                                     Char16    &outMark,
  124.                                     Str255    outName)
  125. {
  126.     if (::StillDown())
  127.     {
  128.         if (FindCommandStatusForContextMenu(inCommand, outEnabled,outUsesMark, outMark, outName))
  129.             return;
  130.     }
  131.     MWContext *mwcontext;
  132.     outUsesMark = false;
  133.     
  134.     CBrowserWindow    *browserWindow = dynamic_cast<CBrowserWindow *>(CViewUtils::GetTopMostSuperView(this));
  135.     Boolean isHTMLHelp        = browserWindow ? browserWindow->IsHTMLHelp() : false;
  136.  
  137. // Restricted targets are Netcaster things, right?
  138. #ifdef MOZ_NETCAST
  139.     // Disable commands which don't apply to restricted targets, at the request of javascript.
  140.     // No special distinction needed for floaters here.
  141.     if (browserWindow && 
  142.         browserWindow->CommandsAreDisabled() &&
  143.         inCommand == cmd_EditFrame)
  144.     {
  145.         outEnabled = false;
  146.         return;
  147.     }
  148. #endif // MOZ_NETCAST
  149.     switch (inCommand)
  150.     {
  151. #ifdef EDITOR
  152.         case cmd_EditFrame:
  153.             mwcontext = *GetContext();
  154.             if (mwcontext && !(XP_IsContextBusy(mwcontext)) && !Memory_MemoryIsLow())
  155.             {
  156.                 // we must have a frameset if this context has a non-grid parent
  157.                 if ( XP_GetNonGridContext( mwcontext ) != mwcontext )
  158.                     outEnabled = true && !isHTMLHelp;
  159.             }
  160.             break;
  161. #endif // EDITOR
  162.  
  163. //        case cmd_SecurityInfo:
  164. //        case cmd_DocumentInfo:
  165. //            outEnabled = true;
  166. //            break;
  167.             
  168.         case cmd_FTPUpload:
  169.             outEnabled = HasFTPUpload( GetContext() ) && !isHTMLHelp;
  170.             break;
  171.  
  172.         default:
  173.             Inherited::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  174.             break;
  175.     }
  176. }
  177.  
  178. Boolean    CBrowserView::ObeyCommand(CommandT inCommand, void* ioParam)
  179. {
  180.     Boolean cmdHandled = false;
  181.     
  182.     switch (inCommand)
  183.     {
  184. #ifdef EDITOR
  185.         case cmd_EditFrame:
  186.             CEditorWindow::MakeEditWindowFromBrowser( *GetContext() );
  187.             break;
  188. #endif // EDITOR
  189.         
  190. //        case cmd_SecurityInfo:
  191. //            mwcontext = *GetContext();
  192. //            if (mwcontext)
  193. //            {
  194. //                URL_Struct* url =
  195. //                    SHIST_CreateURLStructFromHistoryEntry(
  196. //                        mwcontext,
  197. //                        GetContext()->GetCurrentHistoryEntry()
  198. //                        );
  199. //                if (url)
  200. //                    SECNAV_SecurityAdvisor(mwcontext,url);
  201. //            }
  202. //            break;
  203.  
  204.         case cmd_FTPUpload:
  205.             {
  206.                 // NOTE -     the backend currently only supports uploading the data fork
  207.                 //            of a file.  A planned feature of 5.0 is to support MacBinary
  208.                 //            encoding during the upload process.  To this end the routine
  209.                 //            UStdDialogs::AskUploadAsDataOrMacBin has been created to prompt
  210.                 //            for the desired upload mode in place of the call to
  211.                 //            StandardGetFile below.
  212.                 FSSpec spec;
  213.                 History_entry * he = GetContext()->GetCurrentHistoryEntry();
  214.                 char * fileURL  = CFileMgr::EncodedPathNameFromFSSpec(spec, TRUE);
  215.                 OSType myTypes[3];
  216.                 StandardFileReply myReply;
  217.                 UDesktop::Deactivate();
  218.                 StandardGetFile(NULL, -1, myTypes, &myReply);
  219.                 UDesktop::Activate();
  220.                 if (myReply.sfGood)
  221.                 {
  222.                     URL_Struct * request = NET_CreateURLStruct(he->address, NET_SUPER_RELOAD);
  223.                     char ** newFileList = (char **) XP_ALLOC(2 * sizeof(char*));
  224.                     ThrowIfNil_(request);
  225.                     ThrowIfNil_(newFileList);
  226.                     request->method = URL_POST_METHOD;
  227.  
  228.                     newFileList[0] = CFileMgr::EncodedPathNameFromFSSpec(myReply.sfFile, TRUE);
  229.                     ThrowIfNil_(newFileList[0]);
  230.                     newFileList[1] = NULL;
  231.                     request->files_to_post = newFileList;
  232.                     GetContext()->SwitchLoadURL( request, FO_CACHE_AND_PRESENT );
  233.                 }
  234.             }
  235.             break;
  236.  
  237. //        case cmd_DocumentInfo:
  238. //            URL_Struct* aboutURL = NET_CreateURLStruct( "about:document", NET_DONT_RELOAD );
  239. //            if ( aboutURL )
  240. //                CURLDispatcher::GetURLDispatcher()->DispatchToView(mContext, aboutURL, FO_CACHE_AND_PRESENT, false, 1010, false);
  241. //            break;
  242.         
  243.         default:
  244.             cmdHandled = Inherited::ObeyCommand(inCommand, ioParam);
  245.             break;
  246.     }
  247.     
  248.     return cmdHandled;
  249. }
  250.  
  251.  
  252.  
  253. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  254. //
  255. #pragma mark --- CONTEXTUAL POPUP ---
  256. //
  257. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  258.  
  259. Boolean CBrowserView::FindCommandStatusForContextMenu(
  260.     CommandT inCommand,
  261.     Boolean    &outEnabled,
  262.     Boolean    &/*outUsesMark*/,
  263.     Char16    &/*outMark*/,
  264.     Str255    /*outName*/)
  265. {
  266.     // We come here only if a CContextMenuAttachment is installed. (This is the new way).
  267.     // Return true if we want to bypass standard status processing.
  268.     if (!mCurrentClickRecord)
  269.         return false;
  270.     CHTMLClickRecord& cr = *mCurrentClickRecord; // for brevity.
  271.     Boolean isAnchor = FALSE;
  272.     Boolean isImage = FALSE;
  273.     if (cr.mElement)
  274.     {
  275.         isAnchor = cr.IsAnchor();
  276.         isImage = cr.mElement->type == LO_IMAGE
  277.                 && NET_URL_Type(mContext->GetCurrentURL()) != FTP_TYPE_URL;
  278.     }
  279.     
  280.     CBrowserWindow    *browserWindow = dynamic_cast<CBrowserWindow *>(CViewUtils::GetTopMostSuperView(this));
  281.     Boolean isHTMLHelp = browserWindow ? browserWindow->IsHTMLHelp() : false;
  282.     // We're overloading command disabling to handle menu items too.
  283.     Boolean commandsAreDisabled = browserWindow ? browserWindow->CommandsAreDisabled() : false;
  284.  
  285.     switch (inCommand)
  286.     {
  287.         case cmd_NEW_WINDOW_WITH_FRAME:
  288.             outEnabled = ((MWContext (*mContext)).is_grid_cell
  289.                                 && (mContext->GetCurrentHistoryEntry() != NULL)) && !isHTMLHelp;
  290.             return true;
  291.         case cmd_OPEN_LINK:
  292.             outEnabled = isAnchor && !commandsAreDisabled;
  293.             return true;
  294.         case cmd_AddToBookmarks:
  295.             if (isAnchor)
  296.                 outEnabled = !isHTMLHelp;
  297.             return true; // for now, only have a "add bookmark for this link" command.
  298. //            return isAnchor; // we don't know unless it's an anchor
  299.         case cmd_NEW_WINDOW:
  300. #ifdef MOZ_MAIL_NEWS
  301.             Boolean newWindowProhibited = ::MSG_NewWindowProhibited(*mContext, cr.mClickURL);
  302. #else
  303.             // MSG_NewWindowProhibited doesn't exist in a non-mail/news world so just say
  304.             // we don't prohibit creating a new window
  305.             Boolean newWindowProhibited = false;
  306. #endif // MOZ_MAIL_NEWS
  307.             outEnabled = !newWindowProhibited && isAnchor && !isHTMLHelp;
  308.             return true;
  309.         case cmd_SAVE_LINK_AS:
  310.             outEnabled = isAnchor && !IsMailToLink(cr.mClickURL) && !isHTMLHelp;
  311.             return true; // we don't know unless it's an anchor
  312.         case cmd_COPY_LINK_LOC:
  313.             outEnabled = (isAnchor && mCurrentClickRecord->mClickURL.length() > 0) && !isHTMLHelp;
  314.             return true;
  315.         case cmd_VIEW_IMAGE:
  316.             outEnabled = isImage && !isHTMLHelp && !commandsAreDisabled;
  317.             return true;
  318.         case cmd_SAVE_IMAGE_AS:
  319.         case cmd_COPY_IMAGE:
  320.         case cmd_COPY_IMAGE_LOC:
  321.             outEnabled = isImage && !isHTMLHelp;
  322.             return true;
  323.         case cmd_LOAD_IMAGE:
  324.             outEnabled = isImage && !commandsAreDisabled;
  325.             return true;
  326.     }
  327.     return false; // we don't know about it
  328. } // CBrowserView::FindCommandStatusForContextMenu
  329.  
  330.  
  331. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  332. //
  333. #pragma mark --- DRAG AND DROP ---
  334. //
  335. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  336.  
  337. // Drag and drop is now reflected into javascript. On drag drop, the browser view
  338. // packages the URLs received into a new event and sends it to javascript with a
  339. // callback. If javascript lets us have the drop, the callback dispatches the URLs.
  340.  
  341.  
  342.  
  343. Boolean CBrowserView::DragIsAcceptable(DragReference inDragRef)
  344. {
  345.     Boolean            doAccept = false;
  346.     DragAttributes    theAttributes = {0};
  347.     
  348.     (void) GetDragAttributes(inDragRef, &theAttributes);
  349.     doAccept = !(theAttributes & kDragInsideSenderWindow);
  350.     
  351.     if (doAccept)
  352.     {
  353.         doAccept = Inherited::DragIsAcceptable(inDragRef);
  354.     }
  355.     
  356.     return doAccept;
  357. }
  358.  
  359.  
  360.  
  361. Boolean CBrowserView::ItemIsAcceptable(DragReference inDragRef, ItemReference inItemRef)
  362. {
  363.     FlavorFlags        theFlags;
  364.     Boolean            doAccept = false;
  365.     
  366.     doAccept |= (::GetFlavorFlags(inDragRef, inItemRef, 'TEXT', &theFlags) == noErr);
  367.     doAccept |= (::GetFlavorFlags(inDragRef, inItemRef, flavorTypeHFS, &theFlags) == noErr);
  368.      
  369.     return doAccept;
  370. }
  371.  
  372.  
  373.  
  374. /*
  375. void CBrowserView::ReceiveDragItem(DragReference inDragRef,
  376.                                 DragAttributes inDragAttrs,
  377.                                 ItemReference inItemRef,
  378.                                 Rect& inItemBounds)            // In local coordinates
  379. {
  380.     FlavorFlags        theFlags;
  381.     OSErr            anError = noErr;
  382.     URL_Struct*        request = nil;
  383.     
  384.     anError = ::GetFlavorFlags(inDragRef, inItemRef, 'TEXT', &theFlags);
  385.     if (anError == noErr)
  386.     {
  387.         long        theDataSize = 0;
  388.         char*        theData = nil;
  389.         
  390.         ::GetFlavorDataSize(inDragRef, inItemRef, 'TEXT', &theDataSize);
  391.         if (theDataSize > 255)                // ÑÑÑ╩are there any limits to the URL string length?
  392.         {
  393.             theDataSize = 255;
  394.         }
  395.         
  396.         theData = (char*) ::NewPtr(theDataSize+1);
  397.         // assert(theData != nil);
  398.         
  399.         ::GetFlavorData(inDragRef, inItemRef, 'TEXT', theData, &theDataSize, nil);
  400.         theData[theDataSize] = 0;
  401.         
  402.         request = NET_CreateURLStruct(theData, NET_DONT_RELOAD);
  403.         // assert(request != nil);
  404.         
  405.         ::DisposePtr(theData);
  406.     }
  407.  
  408.     anError = ::GetFlavorFlags(inDragRef, inItemRef, flavorTypeHFS, &theFlags);
  409.     if (anError == noErr)
  410.     {
  411.         long        theDataSize = 0;
  412.         HFSFlavor    theData;
  413.         char*        localURL;
  414.         
  415.         ::GetFlavorDataSize(inDragRef, inItemRef, flavorTypeHFS, &theDataSize);
  416.         ::GetFlavorData(inDragRef, inItemRef, flavorTypeHFS, &theData, &theDataSize, nil);
  417.         localURL = CFileMgr::GetURLFromFileSpec(theData.fileSpec);
  418.         // assert(localURL != nil);
  419.         
  420.         request = NET_CreateURLStruct(localURL, NET_DONT_RELOAD);
  421.         // assert(request != nil);
  422.         
  423.         XP_FREE(localURL);
  424.     }
  425.     
  426.     if (request != nil)
  427.     {
  428.         XP_MEMSET(&request->savedData, 0, sizeof(SHIST_SavedData));
  429.         CURLDispatcher::GetURLDispatcher()->DispatchToView(mContext, request, FO_CACHE_AND_PRESENT, false);
  430.     }
  431. }
  432. */
  433.  
  434. /*
  435.  * CBrowserViewDoDragReceiveMochaCallback
  436.  * callback for DoDragReceive
  437.  */
  438. class CBrowserViewDoDragReceiveMochaCallback : public CMochaEventCallback
  439. {
  440. public:
  441.     CBrowserViewDoDragReceiveMochaCallback( CBrowserView * view, XP_List* inRequestList, char** inURLArray)
  442.         : fBrowserView(view), fRequestList(inRequestList), fURLArray(inURLArray) {}
  443.  
  444.     virtual void Complete(MWContext *, 
  445.                 LO_Element * , int32 /*type*/, ETEventStatus status)
  446.     {
  447.         if (status == EVENT_OK)
  448.         {
  449.             fBrowserView->DoDragReceiveCallback(fRequestList );
  450.         }
  451.         else if (status == EVENT_PANIC || status == EVENT_CANCEL)
  452.         {
  453.             // free the URL_Structs we created in DoDragReceive since they weren't dispatched.
  454.             for (int i = 1; i <= XP_ListCount(fRequestList); i++)
  455.             {
  456.                 URL_Struct* request = (URL_Struct *)XP_ListGetObjectNum(fRequestList, i);
  457.                 NET_FreeURLStruct(request);
  458.             }
  459.         }
  460.         XP_ListDestroy(fRequestList);
  461.         XP_FREE(fURLArray);
  462.     }
  463.     
  464.     int LengthURLArray() { return XP_ListCount(fRequestList); }
  465.     
  466.     char** GetURLArray() { return fURLArray; }
  467.     
  468. private:
  469.     CBrowserView * fBrowserView;
  470.     XP_List* fRequestList;
  471.     char** fURLArray;
  472. };
  473.  
  474. // This is handled through a callback from javascript now.
  475. // Creates a list of the URL_Structs to process in the callback because the DragReference
  476. // will no longer be valid.
  477. void            
  478. CBrowserView::DoDragReceive(DragReference    inDragRef)
  479. {
  480.     // This gets freed in the callback.
  481.     XP_List* requestList = XP_ListNew();
  482.     if ( !requestList ) return;
  483.     
  484.     FlavorFlags        theFlags;
  485.     OSErr            anError = noErr;
  486.     URL_Struct*        request = nil;
  487.     
  488.     Uint16    itemCount;                // Number of Items in Drag
  489.     ::CountDragItems(inDragRef, &itemCount);
  490.     
  491.     for (Uint16 item = 1; item <= itemCount; item++) 
  492.     {
  493.         ItemReference    itemRef;
  494.         ::GetDragItemReferenceNumber(inDragRef, item, &itemRef);
  495.         
  496.         // First check if this has a TEXT flavor. If so, this is either a URL dragged from 
  497.         // another app or a text clipping dragged from the desktop. Either way, we need
  498.         // to guarantee that we don't try below to read the drop as an HFSFlavor
  499.         // (which a clipping also has).
  500.         anError = ::GetFlavorFlags(inDragRef, itemRef, 'TEXT', &theFlags);
  501.         if (anError == noErr)
  502.         {
  503.             long        theDataSize = 0;
  504.             char*        theData = nil;
  505.             
  506.             ::GetFlavorDataSize(inDragRef, itemRef, 'TEXT', &theDataSize);
  507.             if (theDataSize > 255)                // ÑÑÑ╩are there any limits to the URL string length?
  508.                 theDataSize = 255;
  509.             
  510.             theData = (char*) ::NewPtr(theDataSize+1);
  511.             // assert(theData != nil);
  512.             
  513.             if (theData != NULL)
  514.             {
  515.                 ::GetFlavorData(inDragRef, itemRef, 'TEXT', theData, &theDataSize, nil);
  516.                 theData[theDataSize] = 0;
  517.             
  518.                 request = NET_CreateURLStruct(theData, NET_DONT_RELOAD);
  519.                 if (request != NULL) XP_ListAddObjectToEnd(requestList, request);
  520.                 // assert(request != nil);
  521.             
  522.                 ::DisposePtr(theData);
  523.             }
  524.             
  525.         } // if has TEXT flavor
  526.         else
  527.         {
  528.             // if this item was not a clipping or dragged text, then process it as an HTML
  529.             // file
  530.             long        theDataSize = 0;
  531.             HFSFlavor    theData;
  532.             char*        localURL;
  533.             Boolean        ignore1, ignore2;
  534.             
  535.             ::GetFlavorDataSize(inDragRef, itemRef, flavorTypeHFS, &theDataSize);
  536.             anError = ::GetFlavorData(inDragRef, itemRef, flavorTypeHFS, &theData, &theDataSize, nil);
  537.             if (anError == badDragFlavorErr)
  538.                 anError = GetHFSFlavorFromPromise (inDragRef, itemRef, &theData, true);
  539.             
  540.             if (anError == noErr)
  541.             {
  542.                 if (HasFTPUpload(GetContext()))
  543.                 {
  544.                     History_entry * he = GetContext()->GetCurrentHistoryEntry();
  545.  
  546.                     if (!request)
  547.                     {
  548.                         request = NET_CreateURLStruct(he->address, NET_SUPER_RELOAD);
  549.                         request->method = URL_POST_METHOD;
  550.                     }
  551.                     
  552.                     QueueFTPUpload(theData.fileSpec, request);
  553.                 }
  554.                 else
  555.                 {
  556.                     // if there's an error resolving the alias, the local file url will refer to the alias itself.
  557.                     ::ResolveAliasFile(&theData.fileSpec, true, &ignore1, &ignore2);
  558.                     localURL = CFileMgr::GetURLFromFileSpec(theData.fileSpec);
  559.                     // assert(localURL != nil);
  560.                     
  561.                     if (localURL != NULL)
  562.                     {
  563.                         request = NET_CreateURLStruct(localURL, NET_DONT_RELOAD);
  564.                         if (request != NULL) XP_ListAddObjectToEnd(requestList, request);
  565.                         // assert(request != nil);
  566.                         
  567.                         XP_FREE(localURL);
  568.                     }
  569.                 }
  570.  
  571.             } // if we are sure this is a file.
  572.             
  573.         } // if not a clipping or text
  574.         
  575.     } // for each drag item
  576.  
  577.     // After all that, do we have any files to post?
  578.     if (HasFTPUpload(GetContext()) && request->files_to_post)
  579.         XP_ListAddObjectToEnd(requestList, request);
  580.  
  581.     if (requestList != NULL)
  582.     {
  583.         int numItems = XP_ListCount(requestList);
  584.         int size = sizeof(char*) * (numItems + 1);
  585.         char ** urlArray = (char**)XP_ALLOC(size);
  586.         XP_ASSERT(urlArray);
  587.         
  588.         int i;
  589.         for (i = 0; i < numItems; i++)
  590.         {
  591.             // the URL_Struct already has the url allocated so use that.
  592.             URL_Struct* request = (URL_Struct *)XP_ListGetObjectNum(requestList, i+1); // XP_Lists are 1-indexed
  593.             urlArray[i] = request->address;
  594.         }
  595.         urlArray[i] = 0;
  596.         
  597.         Point dragMouse;
  598.         short dragModifiers;
  599.         
  600.         ::GetDragMouse(inDragRef, &dragMouse, NULL);
  601.         ::GetDragModifiers(inDragRef, &dragModifiers, NULL, NULL);
  602.         MochaDragDrop(*mContext,  
  603.                         new CBrowserViewDoDragReceiveMochaCallback(this, requestList, urlArray),
  604.                         dragMouse,
  605.                         dragModifiers);
  606.                         
  607.     } // if requestList has things to process
  608.  
  609. } // CBrowserView :: DoDragReceive
  610.  
  611.  
  612. // Dispatch the urls collected in DoDragReceive.
  613. // This is executed if javascript lets us have the event.
  614. void            
  615. CBrowserView::DoDragReceiveCallback(XP_List* inRequestList)
  616. {
  617.     for (int i = 1; i <= XP_ListCount(inRequestList); i++)
  618.     {
  619.         URL_Struct* request = (URL_Struct *)XP_ListGetObjectNum(inRequestList, i);
  620.         if (request != nil)
  621.         {
  622.             XP_MEMSET(&request->savedData, 0, sizeof(SHIST_SavedData));
  623.             //CURLDispatcher::GetURLDispatcher()->DispatchToView(mContext->GetTopContext(mContext),
  624.                     //request, FO_CACHE_AND_PRESENT, false);
  625.             
  626.             // We need this to be delayed so that we can confirm ftp drag & drop since we can't confirm
  627.             //inside the drag handler
  628. //            CURLDispatcher::GetURLDispatcher()->DispatchToView(mContext->GetTopContext(mContext),
  629.                     //request, FO_CACHE_AND_PRESENT, false, 1010, true);
  630.             CURLDispatcher::DispatchURL(request, mContext->GetTopContext(), true);
  631.         }
  632.     }
  633. }
  634.  
  635. // Mocha allows drag receive to be cancelled, so send a dragdrop message.
  636. void 
  637. MochaDragDrop(MWContext* inContext, CBrowserViewDoDragReceiveMochaCallback * cb, Point inDragMouse, short inDragModifiers)
  638. {
  639.     JSEvent* event = XP_NEW_ZAP(JSEvent);
  640.     
  641.     if (event != NULL)
  642.     {    
  643.         // event's data field is an array of urls.
  644.         
  645.         event->type = EVENT_DRAGDROP;
  646.         event->data = (void *)cb->GetURLArray();
  647.         event->dataSize = cb->LengthURLArray();
  648.         event->screenx = inDragMouse.h;
  649.         event->screeny = inDragMouse.v - ::GetMBarHeight();
  650.         event->modifiers = CMochaHacks::MochaModifiers(inDragModifiers);
  651.         ET_SendEvent( inContext, 0, event, CMochaEventCallback::MochaCallback, cb );
  652.     }
  653. }
  654.  
  655.  
  656. // True if we might be able to do FTP upload.
  657. Boolean HasFTPUpload(CBrowserContext * context)
  658. {
  659.     History_entry * he = context->GetCurrentHistoryEntry();
  660.     return (he &&
  661.             !strncasecomp(he->address, "ftp", 3) &&
  662.             he->address[strlen(he->address)-1] == '/' );
  663. }
  664.  
  665.  
  666. // Adds file for FTP file upload    
  667. void CBrowserView::QueueFTPUpload(const FSSpec & spec, URL_Struct* request)
  668. {
  669.     FSSpec theResolvedSpec = spec;
  670.     Boolean isFolder;
  671.     Boolean wasAliased;
  672.  
  673.     // If we drop the whole HD, allow bailout
  674.     if (CmdPeriod())    
  675.         return;
  676.  
  677.     // If it's an alias to a folder - skip it!
  678.     if (::ResolveAliasFile(&theResolvedSpec, TRUE, &isFolder, &wasAliased) == noErr && isFolder && wasAliased)
  679.         return;
  680.     
  681.     // If it is a folder, add it recursively
  682.     if (CFileMgr::IsFolder(spec))
  683.     {
  684.         FSSpec newSpec;
  685.         FInfo     dummy;
  686.         Boolean dummy2;
  687.         CFileIter    iter((FSSpec&)spec);
  688.         while (iter.Next(newSpec, dummy, dummy2))
  689.             QueueFTPUpload(newSpec, request);
  690.         return;
  691.     }
  692.     
  693.     // We want to use the resolved alias spec here so we get the right file name
  694.     char * fileURL  = CFileMgr::EncodedPathNameFromFSSpec(theResolvedSpec, TRUE);
  695.          
  696.      // Add file argument to the URL struct (queued up as the fLatentRequest
  697.     
  698.         // Duplicate the current file list
  699.         int newFilePos = 0;
  700.         char ** newFileList;
  701.         if (request->files_to_post)
  702.             while (request->files_to_post[newFilePos] != NULL)
  703.                 newFilePos++;
  704.  
  705.         newFileList = (char **) XP_ALLOC((newFilePos+2) * sizeof(char*));
  706.         ThrowIfNil_(newFileList);
  707.  
  708.         for (int i = 0; i < newFilePos; i++)
  709.             newFileList[i] = request->files_to_post[i];
  710.         
  711.         // Add the new member
  712.         newFileList[newFilePos] = fileURL;
  713.         newFileList[newFilePos + 1] = NULL;
  714.         
  715.         if (request->files_to_post)
  716.             XP_FREE(request->files_to_post);
  717.             
  718.         request->files_to_post = newFileList;
  719.         
  720. }
  721.