home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / ComposeAttachFolderView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  30.6 KB  |  1,102 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.    ComposeAttachFolderView.cpp -- compose window folder containing attachment panel
  20.    Created: Alastair Gourlay(SGI) c/o Dora Hsu<dora@netscape.com>, 26 Nov 1996
  21.  */
  22.  
  23.  
  24.  
  25. // Classes in this file:
  26. //      XFE_ComposeAttachFolderView
  27. //      XFE_ComposeAttachPanel
  28. //      XFE_ComposeAttachDrop
  29. //
  30.  
  31. #include "ComposeAttachFolderView.h"
  32.  
  33. #include <stdlib.h>
  34. #include <unistd.h>
  35.  
  36. #include "xfe.h"
  37. #include "net.h"
  38. #include "msgcom.h"
  39. #include "xp_mem.h"
  40. #include <xpgetstr.h>
  41. #include <Xm/Xm.h>
  42. #include <Xm/XmP.h> // need widget-writer call _XmSetDestination()
  43.  
  44. #include <Xm/XmAll.h>
  45. #include <Xfe/Xfe.h>
  46.  
  47. #include "ThreadView.h"
  48. #include "BrowserFrame.h"
  49. #include "BookmarkView.h"
  50. #include "HistoryView.h"
  51.  
  52. // from lib/libmsg
  53. extern "C" XP_Bool MSG_RequiresMailMsgWindow(const char*);
  54. extern "C" XP_Bool MSG_RequiresNewsMsgWindow(const char*);
  55.  
  56. // Use API from XmP.h - moderately naughty, but implicitly supported for
  57. // widget-writers and happy hackers everywhere.
  58. extern "C" void _XmSetDestination(Display*,Widget);
  59.  
  60. static int IsWebJumper(const char*);
  61.  
  62. //
  63. // XFE_ComposeAttachFolderView
  64. //
  65.  
  66.  
  67. #ifdef DEBUG_sgidev
  68. #define XDEBUG(x) x
  69. #else
  70. #define XDEBUG(x)
  71. #endif
  72.  
  73. // error messages
  74.  
  75. extern int XFE_INVALID_FILE_ATTACHMENT_IS_A_DIRECTORY;
  76. extern int XFE_INVALID_FILE_ATTACHMENT_NOT_READABLE;
  77. extern int XFE_INVALID_FILE_ATTACHMENT_DOESNT_EXIST;
  78. extern int XFE_MN_TOO_MANY_ATTACHMENTS;
  79. extern int XFE_MN_ITEM_ALREADY_ATTACHED;
  80. extern int XFE_MN_DELIVERY_IN_PROGRESS;
  81. extern int XFE_MN_INVALID_ATTACH_URL;
  82.  
  83. // popup menu for attach panel
  84. static MenuSpec attachPopupMenuSpec[] = {
  85.   { xfeCmdAttachFile,            PUSHBUTTON },
  86.   { xfeCmdAttachWebPage,        PUSHBUTTON },
  87.   { xfeCmdDeleteAttachment,        PUSHBUTTON },
  88.   MENU_SEPARATOR,
  89.   { xfeCmdAttachAddressBookCard,    TOGGLEBUTTON },
  90.   { NULL }
  91. };
  92.  
  93. // intialize static members
  94.  
  95. char *XFE_ComposeAttachFolderView::_lastAttachmentType=NULL;
  96. const int XFE_ComposeAttachFolderView::_maxAttachments=128;
  97.  
  98. #if !defined(USE_MOTIF_DND)
  99.  
  100. // callback stubs
  101.  
  102. void XFE_ComposeAttachFolderView::AttachDropCb(Widget,void* cd,fe_dnd_Event type,fe_dnd_Source *source,XEvent*) {
  103.     XFE_ComposeAttachFolderView *ad=(XFE_ComposeAttachFolderView*)cd;
  104.     
  105.     if (type==FE_DND_DROP && ad && source)
  106.         ad->attachDropCb(source);
  107. }
  108. #endif /* USE_MOTIF_DND */
  109.  
  110. // constructor
  111.  
  112. XFE_ComposeAttachFolderView::XFE_ComposeAttachFolderView(
  113.                                  XFE_Component *toplevel_component,
  114.                                  XFE_View *parent_view,
  115.                                  MSG_Pane *p,
  116.                                  MWContext *context) 
  117.     : XFE_MNView(toplevel_component, parent_view, context, p)
  118. {
  119.     setParent(parent_view);
  120.     _attachPanel=NULL;
  121.     _attachLocationDialog=NULL;
  122.     _attachFileDialog=NULL;
  123.     _xfePopup=NULL;
  124.     _context=context;
  125.     _attachments=new struct MSG_AttachmentData[_maxAttachments];
  126.     _numAttachments=0;
  127.  
  128.     _folderVisible=FALSE;
  129.     _deleteAttachButton=NULL;
  130.     _addedExistingAttachments=FALSE;
  131. }
  132.  
  133. // destructor
  134.  
  135. XFE_ComposeAttachFolderView::~XFE_ComposeAttachFolderView()
  136. {
  137.     if (_attachPanel)
  138.     delete _attachPanel;
  139.  
  140.     if (_attachLocationDialog)
  141.         delete _attachLocationDialog;
  142.     
  143.     if (_attachFileDialog)
  144.         delete _attachFileDialog;
  145.     
  146.     if (_xfePopup)
  147.         delete _xfePopup;
  148.     
  149.     if (_attachments) {
  150.         for (int i=0;i<_numAttachments;i++)
  151.             if (_attachments[i].url)
  152.                 XP_FREE(_attachments[i].url);
  153.  
  154.         delete [] _attachments;
  155.     }
  156. }
  157.  
  158. // create UI
  159.  
  160. void XFE_ComposeAttachFolderView::createWidgets(Widget parent)
  161. {
  162.     // create attachment folder form
  163.     Widget form=XmCreateForm(parent,"attachForm",NULL,0);
  164.  
  165.     // create attachment panel
  166.     _attachPanel=new XFE_ComposeAttachPanel(this,_context);
  167.     _attachPanel->createWidgets(form);
  168.     _attachPanel->show();
  169.     XtVaSetValues(_attachPanel->getBaseWidget(),
  170.                   XmNleftAttachment,XmATTACH_FORM,
  171.                   XmNrightAttachment,XmATTACH_FORM,
  172.                   XmNtopAttachment,XmATTACH_FORM,
  173.                   XmNbottomAttachment,XmATTACH_FORM,
  174.                   NULL);
  175.  
  176. #if !defined(USE_MOTIF_DND)
  177.     // create drop site for internal drop (message,news etc.)
  178.     fe_dnd_CreateDrop(_attachPanel->getBaseWidget(),AttachDropCb,this);
  179. #endif /* USE_MOTIF_DND */
  180.  
  181.     // create popup menu
  182.     _xfePopup = new XFE_PopupMenu("popup",(XFE_Frame*)m_toplevel,_attachPanel->pane(),NULL);
  183.     _xfePopup->addMenuSpec(attachPopupMenuSpec);
  184.  
  185.     // Remove the osfLeft and osfRight translations of the popup's children.
  186.     // For bug 71620.  See the bug description for details.  Basically, for
  187.     // some strange reason, motif assumes that either a left or a right 
  188.     // naviation widget exists for this popup menu and core dumps trying 
  189.     // to dereference a NULL widget.
  190.     _xfePopup->removeLeftRightTranslations();
  191.  
  192.     setBaseWidget(form);
  193.  
  194.     // Register this widget to have a tooltip.
  195.     fe_WidgetAddToolTips(form);
  196.     
  197.     // add existing attachments to the panel (e.g. for Forward)
  198.     addExistingAttachments();
  199. }
  200.  
  201. void XFE_ComposeAttachFolderView::show()
  202. {
  203.     XFE_MNView::show();
  204.     
  205.     // enable attachment panel's drop site
  206.     if (_attachPanel)
  207.         _attachPanel->show();
  208. }
  209.  
  210. void XFE_ComposeAttachFolderView::hide()
  211. {
  212.     XFE_MNView::hide();
  213.     
  214.     // disable attachment panel's drop site
  215.     if (_attachPanel)
  216.         _attachPanel->hide();
  217. }
  218.  
  219. // track viewable state of attachment folder tab
  220. void XFE_ComposeAttachFolderView::folderVisible(int visible)
  221. {
  222.     _folderVisible=visible;
  223.     
  224.     if (visible) {
  225.         // make sure pre-exisiting attachments are added
  226.         addExistingAttachments();
  227.  
  228.         // take Motif 'active' status away from Subject/text area so
  229.         // that xfeCmdDelete gets routed appropriately.
  230.         _XmSetDestination(XtDisplay(getBaseWidget()),NULL);
  231.     }
  232. }
  233.  
  234. Boolean
  235. XFE_ComposeAttachFolderView::isCommandEnabled(CommandType command, void*,
  236.                                               XFE_CommandInfo*)
  237. {
  238.     // return True for  all the commands that are handled in this class
  239.     if (command==xfeCmdAttachFile ||
  240.         command==xfeCmdAttachWebPage || 
  241.      command==xfeCmdShowPopup) { 
  242.         return True;
  243.     }
  244.  
  245.     if ((command==xfeCmdDelete || command==xfeCmdDeleteAttachment) &&
  246.         _folderVisible &&
  247.         _attachPanel &&
  248.         _attachPanel->currentSelection()) {
  249.         return True;
  250.     }
  251.     
  252.     // If we don't hande any command here, return False. Don't call parent
  253.     // because the container will decide who to dispatch this command to
  254.     return False;
  255. }
  256.  
  257. Boolean
  258. XFE_ComposeAttachFolderView::handlesCommand(CommandType command, void*,
  259.                                             XFE_CommandInfo*)
  260. {
  261.     // return True for  all the commands that are handled in this class
  262.     if (command==xfeCmdAttachFile ||
  263.         command==xfeCmdAttachWebPage ||
  264.         command==xfeCmdDeleteAttachment ||
  265.         command==xfeCmdDelete ||
  266.         command==xfeCmdShowPopup) {
  267.         return True;
  268.     }
  269.  
  270.     // If we don't hande any command here, return False. Don't call parent
  271.     // because the container will decide who to dispatch this command to
  272.     return False;
  273.     
  274. }
  275.  
  276. void XFE_ComposeAttachFolderView::doCommand(CommandType command, void*,XFE_CommandInfo* info)
  277. {
  278.     if (command==xfeCmdAttachFile) {
  279.         attachFile();
  280.     } else if (command==xfeCmdAttachWebPage) {
  281.         attachLocation();
  282.     } else if ((command==xfeCmdDelete || command==xfeCmdDeleteAttachment) &&
  283.                _folderVisible) {
  284.         deleteAttach();
  285.     } else if (command==xfeCmdShowPopup) {
  286.         // Handle popup menu
  287.         XEvent *event = info->event;
  288.         Widget w = XtWindowToWidget(event->xany.display, event->xany.window);
  289.  
  290.         if (w == NULL) w=getBaseWidget();
  291.  
  292.         if (_xfePopup) {
  293.             _xfePopup->position(event);
  294.             _xfePopup->show();
  295.         }
  296.     }
  297. }
  298.  
  299.  
  300. // update UI in response to selection change
  301. void XFE_ComposeAttachFolderView::updateSelectionUI()
  302. {
  303.     // take Motif 'active' status away from Subject/text area so
  304.     // that xfeCmdDelete gets routed appropriately.
  305.     if (getBaseWidget())
  306.         _XmSetDestination(XtDisplay(getBaseWidget()),NULL);
  307.  
  308.     // update Delete menu entry
  309.     getToplevel()->notifyInterested(XFE_View::chromeNeedsUpdating);
  310. }
  311.  
  312. //
  313. // attachment management
  314. //
  315.  
  316. void XFE_ComposeAttachFolderView::addExistingAttachments()
  317. {
  318.     // we're only going to do this once per window
  319.     if (_addedExistingAttachments)
  320.         return;
  321.     
  322.     // add pre-existing attachments to the icon panel (e.g. during msg forward)
  323.     const struct MSG_AttachmentData *al=MSG_GetAttachmentList(getPane());
  324.     if (al) {
  325.         while(al->url) {
  326.             addAttachment(al->url,TRUE); // set 'pre_exisiting' flag - don't add to internal list
  327.             al++;
  328.         }
  329.     }
  330. }
  331.  
  332. void XFE_ComposeAttachFolderView::updateAttachments()
  333. {
  334.     if (!getPane())
  335.         return;
  336.  
  337.     // abort if attachment adding or delivery is in progress
  338.     if (!verifySafeToAttach())
  339.         return;
  340.  
  341.     // add to list
  342.     _attachments[_numAttachments].url=NULL;
  343.     MSG_SetAttachmentList(getPane(),_attachments);
  344. }
  345.  
  346.  
  347. int XFE_ComposeAttachFolderView::addAttachment(const char *itemData,int pre_existing,Boolean attach_binary)
  348. {
  349.     // abort if attachment adding or delivery is in progress
  350.     // (and not adding a pre_exisiting attachment)
  351.     if (!pre_existing && !verifySafeToAttach())
  352.         return FALSE;
  353.  
  354.     int addStatus=FALSE;
  355.     const char **items=new const char*[1];
  356.     items[0]=itemData;
  357.     addStatus=addAttachments(items,1,pre_existing,attach_binary);
  358.     delete items;
  359.     
  360.     return addStatus;
  361. }
  362.  
  363. int XFE_ComposeAttachFolderView::addAttachments(const char **items,int numItems,int pre_existing,Boolean attach_binary)
  364. {
  365.     // lock out addition of existing attachments after first time through
  366.     _addedExistingAttachments=TRUE;
  367.     
  368.     // abort if attachment adding or delivery is in progress
  369.     // (and not adding pre_exisiting attachments)
  370.     if (!pre_existing && !verifySafeToAttach())
  371.         return FALSE;
  372.  
  373.     if (!items || numItems==0)
  374.         return FALSE;
  375.  
  376.     int addStatus=FALSE;
  377.     
  378.     // desired type is NULL == as-is (used to read from format toggle buttons.)
  379.     char *desiredType=NULL;
  380.  
  381.     // if an icon has focus, restore it when we remap the pane
  382.     Widget focusWidget=XmGetFocusWidget(getBaseWidget());
  383.     if (focusWidget && XtParent(focusWidget)!=_attachPanel->pane())
  384.         focusWidget=NULL;
  385.     
  386.     _attachPanel->unmapPane();
  387.     for (int i=0;i<numItems;i++) {
  388.         // is there space in the list?
  389.         if (_numAttachments>=_maxAttachments) {
  390.             char *msg=PR_smprintf(XP_GetString(XFE_MN_TOO_MANY_ATTACHMENTS));
  391.             if (msg) {
  392.                 fe_Alert_2(getBaseWidget(),msg);
  393.                 XP_FREE(msg);
  394.             }
  395.             break;
  396.         }
  397.  
  398.         // is the item already attached?
  399.         int duplicate=FALSE;
  400.         for (int j=0;j<_numAttachments;j++) {
  401.             if (strcmp(items[i],_attachments[j].url)==0) {
  402.                 char *msg=PR_smprintf(XP_GetString(XFE_MN_ITEM_ALREADY_ATTACHED),items[i]);
  403.                 if (msg) {
  404.                     fe_Alert_2(getBaseWidget(),msg);
  405.                     XP_FREE(msg);
  406.                 }
  407.                 duplicate=TRUE;
  408.                 break;
  409.             }
  410.         }
  411.         if (duplicate)
  412.             continue;
  413.  
  414.         // nyi - hack "addbook:add?vcard=" URL to be vcard data, and accept as attachment
  415.         // (then turn back on dragging of addbook:add URL's in XFE_HTMLDrag)
  416.         // WinFE does this already.
  417.  
  418.         // is it a valid attachment?
  419.         if ((!pre_existing) && (!validateAttachment(getBaseWidget(),items[i])))
  420.             continue;
  421.  
  422.         // at least one attachment was accepted, return success status
  423.         addStatus=TRUE;
  424.         
  425.         // add to internal attachment list
  426.         struct MSG_AttachmentData m = { 0 };
  427.         m.url=XP_STRDUP(items[i]);
  428.         m.desired_type=desiredType;
  429.         if (attach_binary)
  430.             m.real_type= "application/octet-stream";
  431.         else if (IsWebJumper(m.url))
  432.             m.real_type= "text/webjumper";
  433.         else
  434.             m.real_type=NULL;
  435.         _attachments[_numAttachments]=m;
  436.         _numAttachments++;
  437.  
  438.         char *itemLabel=parseItemLabel(items[i]);
  439.         
  440.         // add icon to attachment panel
  441.         _attachPanel->addItem(items[i],itemLabel);
  442.         XP_FREE(itemLabel);
  443.     }
  444.  
  445.     // always select last-added item
  446.     if (addStatus && _attachPanel->numItems()>0) {
  447.         _attachPanel->selectItem(_attachPanel->items()[_attachPanel->numItems()-1]);
  448.         if (!pre_existing) {
  449.             focusWidget=_attachPanel->items()[_attachPanel->numItems()-1]->image();
  450.         }
  451.     }
  452.     
  453.     // update attachment panel
  454.     _attachPanel->updateDisplay();
  455.     _attachPanel->mapPane();
  456.  
  457.     // restore focus if we had it before the unmapPane()
  458.     if (focusWidget)
  459.         XmProcessTraversal(focusWidget,XmTRAVERSE_CURRENT);
  460.  
  461.     // update internal attachment list, if not adding pre-exisiting attachments
  462.     if (addStatus && !pre_existing)
  463.         updateAttachments();    
  464.  
  465.     // pop attachment folder to top, if not adding pre-exisiting attachments
  466.     if (!pre_existing) {
  467.         getParent()->doCommand(xfeCmdViewAttachments);
  468.     }
  469.  
  470.     return addStatus;
  471. }
  472.  
  473. void XFE_ComposeAttachFolderView::deleteAttachment(int pos)
  474. {
  475.     if (pos<0 || pos>=_numAttachments)
  476.         return;
  477.  
  478.     // abort if attachment adding or delivery is in progress
  479.     if (!verifySafeToAttach())
  480.         return;
  481.     
  482.     if (_attachments[pos].url)
  483.         XP_FREE(_attachments[pos].url);
  484.  
  485.     // remove from internal attachment list
  486.     for (int i=pos;i<_numAttachments-1;i++)
  487.         _attachments[i]=_attachments[i+1];    
  488.     _numAttachments--;
  489.     updateAttachments();
  490.     
  491.     // remove icon from attach panel
  492.     if (_attachPanel) {
  493.         _attachPanel->removeItem(pos);
  494.         _attachPanel->updateDisplay();
  495.     }
  496. }
  497.  
  498.  
  499. int XFE_ComposeAttachFolderView::validateAttachment(Widget widget,const char *url)
  500. {
  501.     if (!url)
  502.         return FALSE;
  503.  
  504.     // strip off any file: prefix before validating
  505.     const char *data=url;
  506.     if (XP_STRNCASECMP(url,"file:",5)==0)
  507.         data=url+5;
  508.     
  509.     if (strlen(data)==0)
  510.         return FALSE;
  511.  
  512.     // accept only URL's that resolve to a document
  513.     // reject mailto:, mailbox: folders etc.
  514.     if (NET_URL_Type(data)!=0) {
  515.         // reject addressbook add command, without error dialog
  516.         if (XP_STRNCASECMP(url,"addbook:add?vcard=",18)==0)
  517.             return FALSE;
  518.         
  519.         // accept regular address book cards
  520.         if (XP_STRNCASECMP(url,"addbook:",8)==0)
  521.             return TRUE;
  522.  
  523.         // accept anything we know how to display as a document
  524.         if (MSG_RequiresMailMsgWindow(url) ||
  525.             MSG_RequiresNewsMsgWindow(url) ||
  526.             MSG_RequiresBrowserWindow(url))
  527.             return TRUE;
  528.         else {
  529.             char *msg=PR_smprintf(XP_GetString(XFE_MN_INVALID_ATTACH_URL),data);
  530.             if (msg) {
  531.                 fe_Alert_2(widget,msg);
  532.                 XP_FREE(msg);
  533.             }
  534.             return FALSE;
  535.         }
  536.     }
  537.     
  538.     // file must exist
  539.     if (!fe_isFileExist((char*)data)) {
  540.         char *msg=PR_smprintf(XP_GetString(XFE_INVALID_FILE_ATTACHMENT_DOESNT_EXIST),data);
  541.         if (msg) {
  542.             fe_Alert_2(widget,msg);
  543.             XP_FREE(msg);
  544.         }
  545.         return FALSE;
  546.     }
  547.  
  548.     // file must be readable
  549.     if (!fe_isFileReadable((char*)data)) {
  550.         char *msg=PR_smprintf(XP_GetString(XFE_INVALID_FILE_ATTACHMENT_NOT_READABLE),data);
  551.         if (msg) {
  552.             fe_Alert_2(widget,msg);
  553.             XP_FREE(msg);
  554.         }
  555.         return FALSE;
  556.     }
  557.  
  558.     // cannot attach directory
  559.     if (fe_isDir((char*)data)) {
  560.         char *msg=PR_smprintf(XP_GetString( XFE_INVALID_FILE_ATTACHMENT_IS_A_DIRECTORY ),data);
  561.         if (msg) {
  562.             fe_Alert_2(widget,msg);
  563.             if (msg) XP_FREE(msg);
  564.         }
  565.         return FALSE;
  566.     }
  567.  
  568.     return TRUE;
  569. }
  570.  
  571.     
  572. void XFE_ComposeAttachFolderView::scrollToItem(int pos)
  573. {
  574.     if (_attachPanel)
  575.         _attachPanel->scrollToItem(pos);
  576. }
  577.  
  578. // create short icon label from full path/url
  579. char *XFE_ComposeAttachFolderView::parseItemLabel(const char *url)
  580. {
  581.     // (alastair) code taken from libmsg/msgsend.cpp - be nice just to call into libmsg
  582.     // modified slightly to avoid bug of trailing / generating empty name
  583.     // modified to return truncated label for mail/news URL's
  584.  
  585.     if (!url || strlen(url)==0)
  586.         return XP_STRDUP("(null)");
  587.  
  588.     char *s;
  589.     char *s2;
  590.     char *s3;
  591.     
  592.     /* If we know the URL doesn't have a sensible file name in it,
  593.        don't bother emitting a content-disposition. */
  594.     if (!strncasecomp (url, "news:", 5))
  595.         return XP_STRDUP("news:");
  596.     if (!strncasecomp (url, "snews:", 6))
  597.         return XP_STRDUP("snews:");    
  598.     if (!strncasecomp (url, "mailbox:", 8))
  599.         return XP_STRDUP("mailbox:");
  600.  
  601.     char *tmpLabel = XP_STRDUP(url);
  602.  
  603.     s=tmpLabel;
  604.     /* remove trailing / or \ */
  605.     int len=strlen(s);
  606.     if (s[len-1]=='/' || s[len-1]=='\\')
  607.         s[len-1]='\0';
  608.     
  609.     s2 = XP_STRCHR (s, ':');
  610.     if (s2) s = s2 + 1;
  611.     /* Take the part of the file name after the last / or \ */
  612.     s2 = XP_STRRCHR (s, '/');
  613.     if (s2) s = s2+1;
  614.     s2 = XP_STRRCHR (s, '\\');
  615.     if (s2) s = s2+1;
  616.  
  617.     /* if it's a non-file url, strip off any named anchors or search data */
  618.     if (XP_STRNCASECMP(url,"file:",5)!=0 && url[0]!='/') {
  619.         /* Now trim off any named anchors or search data. */
  620.         s3 = XP_STRCHR (s, '?');
  621.         if (s3) *s3 = 0;
  622.         s3 = XP_STRCHR (s, '#');
  623.         if (s3) *s3 = 0;
  624.     }
  625.  
  626.     /* Now lose the %XX crap. */
  627.     NET_UnEscape (s);
  628.  
  629.     char *retLabel=XP_STRDUP(s);
  630.     XP_FREE(tmpLabel);
  631.     
  632.     return retLabel;
  633. }
  634.  
  635.  
  636.     
  637.  
  638. extern "C" XP_Bool MSG_DeliveryInProgress(MSG_Pane * composepane);
  639.  
  640. int XFE_ComposeAttachFolderView::verifySafeToAttach()
  641. {
  642. #if 0
  643.     // this check is no longer needed - back end can handle
  644.     // multiple simultaneous attachment operations
  645.     if (MSG_DeliveryInProgress(getPane())) {
  646.         char *msg=PR_smprintf(XP_GetString(XFE_MN_DELIVERY_IN_PROGRESS));
  647.         if (msg) {
  648.             fe_Alert_2(getBaseWidget(),msg);
  649.             XP_FREE(msg);
  650.         }
  651.         return FALSE;
  652.     }
  653. #endif
  654.     return TRUE;
  655. }
  656.  
  657.  
  658. //
  659. // entry points for external objects to control attachments
  660. //
  661.  
  662. void XFE_ComposeAttachFolderView::attachFile()
  663. {
  664.     if (_attachFileDialog==NULL) {
  665.         _attachFileDialog=new XFE_ComposeAttachFileDialog(this);
  666.         _attachFileDialog->createWidgets(getBaseWidget());
  667.     }
  668.     
  669.     _attachFileDialog->show();
  670. }
  671.  
  672. void XFE_ComposeAttachFolderView::attachLocation()
  673. {
  674.     if (_attachLocationDialog==NULL) {
  675.         _attachLocationDialog=new XFE_ComposeAttachLocationDialog(this);
  676.         _attachLocationDialog->createWidgets(getBaseWidget());
  677.     }
  678.     
  679.     _attachLocationDialog->show();
  680. }
  681.  
  682. void XFE_ComposeAttachFolderView::deleteAttach()
  683. {
  684.     int pos=_attachPanel->currentSelectionPos();
  685.  
  686.     if (pos>=0)
  687.         deleteAttachment(pos);
  688. }
  689.  
  690. void XFE_ComposeAttachFolderView::openAttachment(int pos)
  691. {
  692.     if (pos<0 || pos>=_attachPanel->numItems())
  693.         return;
  694.  
  695.     // Disable preview of previously attached item. Need to resolve
  696.     // inconsistency when attaching URL pointing to cgi. Preview
  697.     // will reload the URL, and the return data may differ from the
  698.     // data previously loaded by the mail back-end. i.e. it will
  699.     // not be a useful preview.
  700. #if 0
  701.     // ensure clicked item is selected
  702.     if (pos!=_attachPanel->currentSelectionPos() && _attachPanel->items())
  703.         _attachPanel->selectItem(_attachPanel->items()[pos]);
  704.  
  705.     XFE_AttachPanelItem *item=_attachPanel->currentSelection();
  706.     
  707.     if (!item || !item->data())
  708.         return;
  709.     
  710.     URL_Struct *url = NET_CreateURLStruct (item->data(),NET_DONT_RELOAD);
  711.     if (!MSG_RequiresBrowserWindow(url->address))
  712.         fe_GetURL(_context,url,FALSE);
  713.     else
  714.         fe_MakeWindow(XtParent(CONTEXT_WIDGET (_context)), _context, url, NULL,
  715.                       MWContextBrowser, FALSE);
  716.  
  717.     fe_UserActivity(_context);
  718. #endif
  719. }
  720.  
  721.  
  722. //
  723. // XFE_ComposeAttachPanel
  724. //
  725.  
  726. // constructor
  727.  
  728. XFE_ComposeAttachPanel::XFE_ComposeAttachPanel(XFE_ComposeAttachFolderView *folder,MWContext *context) :
  729.     XFE_AttachPanel(context)
  730. {
  731.     _attachFolder=folder;
  732.     _dropSite=NULL;
  733.     _iconTranslations=fe_globalData.mailcompose_global_translations;
  734. }
  735.  
  736. // destructor
  737.  
  738. XFE_ComposeAttachPanel::~XFE_ComposeAttachPanel()
  739. {
  740.     if (_dropSite)
  741.         delete _dropSite;
  742. }
  743.  
  744.  
  745. // create Motif UI
  746.  
  747. void XFE_ComposeAttachPanel::createWidgets(Widget parent)
  748. {
  749.     // create panel UI
  750.  
  751.     XFE_AttachPanel::createWidgets(parent);
  752.  
  753.     // register drop site
  754.  
  755.     _dropSite=new XFE_ComposeAttachDrop(_topClip,this);
  756. }
  757.  
  758. // manage button state
  759.  
  760. void XFE_ComposeAttachPanel::updateSelectionUI()
  761. {
  762.     // update attach folder UI - Delete menu item state depends on selection
  763.  
  764.     _attachFolder->updateSelectionUI();
  765. }
  766.  
  767. // handle double-click - open selected attachment
  768.  
  769. void XFE_ComposeAttachPanel::doubleClickCb(int pos)
  770. {
  771.     _attachFolder->openAttachment(pos);
  772. }
  773.  
  774. // panel management
  775.  
  776. void XFE_ComposeAttachPanel::show()
  777. {
  778.     XFE_AttachPanel::show();
  779.     if (_dropSite) _dropSite->enable();
  780. }
  781.  
  782. void XFE_ComposeAttachPanel::hide()
  783. {
  784.     XFE_AttachPanel::hide();
  785.     if (_dropSite) _dropSite->disable();
  786. }
  787.  
  788. void XFE_ComposeAttachPanel::setSensitive(Boolean sensitive)
  789. {
  790.     XFE_AttachPanel::setSensitive(sensitive);
  791.  
  792.     if (sensitive)
  793.         if (_dropSite) _dropSite->enable();
  794.     else
  795.         if (_dropSite) _dropSite->disable();
  796. }
  797.  
  798.  
  799. // drop management - pass through to XFE_ComposeAttachFolderView
  800.  
  801. int XFE_ComposeAttachPanel::dropAttachments(const char **item,int numItems)
  802. {
  803.     int dropStatus=_attachFolder->addAttachments(item,numItems);
  804.  
  805.     // ensure last-added item is visible
  806.     if (dropStatus)
  807.         scrollToItem(_numItems-1);
  808.     
  809.     return dropStatus;
  810. }
  811.  
  812. int XFE_ComposeAttachPanel::dropAttachment(const char *item)
  813. {
  814.     int dropStatus=_attachFolder->addAttachment(item);
  815.  
  816.     // ensure last item is visible
  817.     // ensure last-added item is visible
  818.     if (dropStatus)
  819.         scrollToItem(_numItems-1);
  820.  
  821.     return dropStatus;
  822. }
  823.  
  824. static int IsWebJumper(const char *url)
  825. {    
  826.     const char *filename=url;
  827.  
  828.     // make sure it's a file
  829.     if (XP_STRNCASECMP(url,"file:",5)==0)
  830.         filename=url+5;
  831.     if (strlen(filename)==0 || filename[0]!='/')
  832.         return FALSE;
  833.  
  834.     // check for SGI WebJumper
  835.     FILE *fp;
  836.     int retval=FALSE;
  837.     
  838.     if (fp=fopen(filename,"r")) {
  839.         const int MAX_LENGTH=4000;
  840.         char line[MAX_LENGTH+1];
  841.         line[MAX_LENGTH]='\0';
  842.         line[0]='\0'; // ensure string will be null-terminated
  843.         fgets(line,MAX_LENGTH,fp);
  844.  
  845.         if (XFE_WebJumperDesktopType::isDesktopType(line)) {
  846.             retval=TRUE;
  847.         }
  848.         
  849.         fclose(fp);
  850.     }
  851.     return retval;
  852. }
  853.     
  854.  
  855. //
  856. // XFE_ComposeAttachDrop
  857. //
  858.  
  859. // constructor
  860.  
  861. XFE_ComposeAttachDrop::XFE_ComposeAttachDrop(Widget parent,XFE_ComposeAttachPanel *attach)
  862.     : XFE_DropNetscape(parent)
  863. {
  864.     _attachPanel=attach;
  865. }
  866.  
  867.  
  868. // destructor
  869.  
  870. XFE_ComposeAttachDrop::~XFE_ComposeAttachDrop()
  871. {
  872. }
  873.  
  874. //
  875. // methods below override DragFile defaults
  876. //
  877.  
  878. // set _operations
  879.  
  880. void XFE_ComposeAttachDrop::operations()
  881. {
  882.     // restrict attachment drop site to copy-only
  883.     _operations=(unsigned int)XmDROP_COPY;
  884. }
  885.  
  886. // set _targets
  887.  
  888. void XFE_ComposeAttachDrop::targets()
  889. {
  890.     _numTargets=2;
  891.     _targets=new Atom[_numTargets];
  892.  
  893.     _targets[0]=_XA_NETSCAPE_URL;
  894.     _targets[1]=XA_STRING;
  895.  
  896.     acceptFileTargets();
  897. }
  898.  
  899. // process drop
  900.  
  901. int XFE_ComposeAttachDrop::processTargets(Atom *targets,const char **data,int numItems)
  902. {
  903.     XDEBUG(printf("XFE_ComposeAttachDrop::processTargets()\n"));
  904.     
  905.     if (!targets || !data || numItems==0)
  906.         return FALSE;
  907.  
  908.     // pass dropped data to attachment panel
  909.  
  910.     char **dropInfo=new char*[numItems];
  911.     int numDropInfo=0;
  912.     int i;
  913.     
  914.     for (i=0;i<numItems;i++) {
  915.         if (targets[i]==None || data[i]==NULL || strlen(data[i])==0)
  916.             continue;
  917.  
  918.         XDEBUG(printf("  [%d] %s: \"%s\"\n",i,XmGetAtomName(XtDisplay(_widget),targets[i]),data[i]));
  919.  
  920.         if (targets[i]==_XA_FILE_NAME) {
  921.             dropInfo[numDropInfo++]=XP_STRDUP(data[i]);
  922.         }
  923.         if (targets[i]==_XA_NETSCAPE_URL) {
  924.             XFE_URLDesktopType urlData(data[i]);
  925.             for (int j=0;j<urlData.numItems();j++) {
  926.                 dropInfo[numDropInfo++]=XP_STRDUP(urlData.url(j));
  927.             }
  928.         }
  929.         if (targets[i]==XA_STRING) {
  930.             dropInfo[numDropInfo++]=XP_STRDUP(data[i]);
  931.         }
  932.     }
  933.     
  934.     int dropStatus=_attachPanel->dropAttachments((const char **)dropInfo,numDropInfo);
  935.  
  936.     // free drop info
  937.     for(i=0;i<numDropInfo; i++)
  938.         if (dropInfo[i])
  939.             XP_FREE(dropInfo[i]);
  940.     delete dropInfo;
  941.     
  942.     return dropStatus;
  943. }
  944.  
  945. #if !defined(USE_MOTIF_DND)
  946. //
  947. // callback methods
  948. //
  949.  
  950.  
  951. void XFE_ComposeAttachFolderView::processBookmarkDrop(fe_dnd_Source *source)
  952. {
  953.     XFE_BookmarkView* bookmarkView=( XFE_BookmarkView*)source->closure;
  954.     if (!bookmarkView)
  955.         return;
  956.  
  957.     MWContext *context=bookmarkView->getContext();
  958.     XFE_Outliner *outliner=bookmarkView->getOutliner();
  959.     const int *selectedList;
  960.     int numSelected;
  961.  
  962.     if (outliner->getSelection(&selectedList, &numSelected)) {
  963.         char **items=new char*[numSelected];
  964.         int numItems=0;
  965.         int i;
  966.         
  967.         for (i=0; i<numSelected; i++) {
  968.             BM_Entry* entry=BM_AtIndex(context,selectedList[i]+1);
  969.             if (BM_GetType(entry)==BM_TYPE_URL ||
  970.                 BM_GetType(entry)==BM_TYPE_ALIAS) {
  971.                 const char *address=BM_GetAddress(entry);
  972.                 if (address) {
  973.                     XDEBUG(printf("    %d:%s\n",selectedList[i],address));
  974.                     items[numItems++]=XP_STRDUP(address);
  975.                 }
  976.             }
  977.         } 
  978.         if (numItems>0)
  979.             addAttachments((const char **) items,numItems);
  980.         
  981.         for (i=0; i<numItems; i++)
  982.             XP_FREE(items[i]);
  983.         delete items;
  984.     }
  985. }
  986.  
  987. void XFE_ComposeAttachFolderView::processHistoryDrop(fe_dnd_Source *source)
  988. {
  989.     XFE_HistoryView *historyView = (XFE_HistoryView*)source->closure;
  990.     if (!historyView)
  991.         return;
  992.  
  993.     MWContext *context=historyView->getContext();
  994.     XFE_Outliner *outliner=historyView->getOutliner();
  995.     const int *selectedList;
  996.     int numSelected;
  997.  
  998.     if (outliner->getSelection(&selectedList, &numSelected)) {
  999.         char **items=new char*[numSelected];
  1000.         int numItems=0;
  1001.         int i;
  1002.         
  1003.         for (i=0; i<numSelected; i++) {
  1004.             gh_HistEntry *entry=historyView->getEntry(selectedList[i]);
  1005.             if (entry && entry->address) {
  1006.                 XDEBUG(printf("    %d:%s\n",selectedList[i],entry->address));
  1007.                 items[numItems++]=XP_STRDUP(entry->address);
  1008.             }
  1009.         } 
  1010.         if (numItems>0)
  1011.             addAttachments((const char **) items,numItems);
  1012.         
  1013.         for (i=0; i<numItems; i++)
  1014.             XP_FREE(items[i]);
  1015.         delete items;
  1016.     }
  1017. }
  1018.  
  1019. void XFE_ComposeAttachFolderView::processMessageDrop(fe_dnd_Source *source)
  1020. {
  1021.     XFE_ThreadView *threadView=(XFE_ThreadView*)source->closure;
  1022.     XFE_Outliner *outliner=threadView->getOutliner();
  1023.     const int *selectedList;
  1024.     int numSelected;
  1025.     if (outliner->getSelection(&selectedList, &numSelected)) {
  1026.         char **items=new char*[numSelected];
  1027.         int numItems=0;
  1028.         int i;
  1029.         
  1030.         for (i=0; i<numSelected; i++) {
  1031.             MessageKey key=MSG_GetMessageKey(threadView->getPane(),selectedList[i]);
  1032.             URL_Struct *messageURL=MSG_ConstructUrlForMessage(threadView->getPane(),key);
  1033.             if (messageURL && messageURL->address) {
  1034.                 XDEBUG(printf("    %d:%s\n",selectedList[i],messageURL->address));
  1035.                 items[numItems++]=XP_STRDUP(messageURL->address);
  1036.             }
  1037.             if (messageURL)
  1038.                 NET_FreeURLStruct(messageURL);
  1039.         }
  1040.         
  1041.         if (numItems>0)
  1042.             addAttachments((const char **) items,numItems);
  1043.         
  1044.         for (i=0; i<numItems; i++)
  1045.             XP_FREE(items[i]);
  1046.         delete items;
  1047.     }
  1048. }
  1049.  
  1050.  
  1051. // internal drop management
  1052. void XFE_ComposeAttachFolderView::attachDropCb(fe_dnd_Source *source)
  1053. {
  1054.     XDEBUG(printf("XFE_ComposeAttachFolderView::attachDropCb()\n"));
  1055.     
  1056.     switch (source->type) {
  1057.  
  1058.     // Interesting
  1059.  
  1060.     case FE_DND_MAIL_MESSAGE:
  1061.     case FE_DND_NEWS_MESSAGE:
  1062.         processMessageDrop(source);
  1063.         break;
  1064.     case FE_DND_BOOKMARK:
  1065.         processBookmarkDrop(source);
  1066.         break;
  1067.     case FE_DND_HISTORY:
  1068.         processHistoryDrop(source);
  1069.         break;
  1070.  
  1071.     // maybe interesting
  1072.  
  1073.     case FE_DND_ADDRESSBOOK:
  1074.         XDEBUG(printf("  AddressBook\n"));
  1075.         break;
  1076.     case FE_DND_URL:
  1077.         XDEBUG(printf("  URL\n"));
  1078.         break;
  1079.  
  1080.     // Not interesting
  1081.  
  1082.     case FE_DND_MAIL_FOLDER:
  1083.         XDEBUG(printf("  Mail Folder\n"));
  1084.         break;
  1085.     case FE_DND_NEWS_FOLDER:
  1086.         XDEBUG(printf("  News Folder\n"));
  1087.         break;
  1088.     case FE_DND_NONE:
  1089.         XDEBUG(printf("  None\n"));
  1090.         break;
  1091.     case FE_DND_COLUMN:
  1092.         XDEBUG(printf("  Column\n"));
  1093.         break;
  1094.     default:
  1095.         XDEBUG(printf("  unknown type:%d\n",source->type));
  1096.         break;
  1097.     }
  1098. }
  1099.  
  1100.  
  1101. #endif /* !USE_MOTIF_DND */
  1102.