home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / dialogs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  194.8 KB  |  6,577 lines

  1. /* -*- Mode: C++; tab-width: 8; 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.    dialogs.c --- General UI functions used elsewhere.
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 23-Jun-94.
  21.  */
  22.  
  23.  
  24. /* #define DOCINFO_SOURCE_TEXT */
  25. #define DOCINFO_VISUAL_TEXT
  26.  
  27. #include "mozilla.h"
  28. #include "net.h"             /* for fe_makeSecureTitle */
  29. #include "xlate.h"
  30. #include "xfe.h"
  31. #include "felocale.h"
  32. #include "outline.h"
  33. #include "mailnews.h"
  34.  
  35. #include <Xm/FileSBP.h>      /* for hacking FS lossage */
  36.  
  37. #include <Xm/XmAll.h>
  38. #include <Xm/CascadeB.h>
  39.  
  40. #include <Xfe/XfeP.h>            /* for xfe widgets and utilities */
  41.  
  42. #include "libi18n.h"
  43. #include "intl_csi.h"
  44.  
  45. #include "np.h"
  46. #include "xp_trace.h"
  47. #include <layers.h>
  48. #include "xeditor.h"
  49. #include "xp_qsort.h"
  50.  
  51. /* for XP_GetString() */
  52. #include <xpgetstr.h>
  53. extern int XFE_OPEN_FILE;
  54. extern int XFE_ERROR_OPENING_FILE;
  55. extern int XFE_ERROR_OPENING_PIPE;
  56. extern int XFE_NO_SUBJECT;
  57. extern int XFE_UNKNOWN_ERROR_CODE;
  58. extern int XFE_INVALID_FILE_ATTACHMENT_DOESNT_EXIST;
  59. extern int XFE_INVALID_FILE_ATTACHMENT_NOT_READABLE;
  60. extern int XFE_INVALID_FILE_ATTACHMENT_IS_A_DIRECTORY;
  61. extern int XFE_ERROR_SAVING_OPTIONS;
  62. extern int XFE_X_RESOURCES_NOT_INSTALLED_CORRECTLY;
  63. extern int XFE_OUTBOX_CONTAINS_MSG;
  64. extern int XFE_OUTBOX_CONTAINS_MSGS;
  65. extern int XFE_CONTINUE_MOVEMAIL;
  66. extern int XFE_CANCEL_MOVEMAIL;
  67. extern int XFE_MOVEMAIL_EXPLANATION;
  68. extern int XFE_SHOW_NEXT_TIME;
  69. extern int XFE_MAIL_SPOOL_UNKNOWN;
  70. extern int XFE_CANT_SAVE_PREFS;
  71. extern int XFE_JAVASCRIPT_APP;
  72. extern int XFE_DIALOGS_PRINTING;
  73. extern int XFE_DIALOGS_DEFAULT_VISUAL_AND_COLORMAP;
  74. extern int XFE_DIALOGS_DEFAULT_VISUAL_AND_PRIVATE_COLORMAP;
  75. extern int XFE_DIALOGS_NON_DEFAULT_VISUAL;
  76. extern int XFE_DIALOGS_FROM_NETWORK;
  77. extern int XFE_DIALOGS_FROM_DISK_CACHE;
  78. extern int XFE_DIALOGS_FROM_MEMORY_CACHE;
  79. extern int XFE_DIALOGS_DEFAULT;
  80.  
  81. #if XmVersion >= 2000
  82. extern void _XmOSBuildFileList(String,String,unsigned char,String * *,
  83.                    unsigned int *,unsigned int *);
  84.  
  85. extern char * _XmStringGetTextConcat(XmString);
  86.  
  87. extern int _XmOSFileCompare(XmConst void *,XmConst void *);
  88.  
  89. extern String _XmOSFindPatternPart(String);
  90.  
  91. extern void _XmOSQualifyFileSpec(String,String,String *,String *);
  92.  
  93. extern XmGeoMatrix _XmGeoMatrixAlloc(unsigned int,unsigned int,unsigned int);
  94.  
  95. extern Boolean _XmGeoSetupKid(XmKidGeometry,Widget);
  96.  
  97. extern void _XmMenuBarFix(XmGeoMatrix,int,XmGeoMajorLayout,XmKidGeometry);
  98.  
  99. extern void _XmSeparatorFix(XmGeoMatrix,int,XmGeoMajorLayout,XmKidGeometry);
  100.  
  101. extern void _XmDestroyParentCallback(Widget,XtPointer,XtPointer);
  102.  
  103. #endif /* XmVersion >= 2000 */
  104.  
  105.  
  106. #define DOCINFO_CHARSET_TEXT
  107.  
  108. /* Kludge around conflicts between Motif and xp_core.h... */
  109. #undef Bool
  110. #define Bool char
  111.  
  112. typedef enum {
  113.   Answer_Invalid = -1,
  114.   Answer_Cancel = 0,
  115.   Answer_OK,
  116.   Answer_Apply,
  117.   Answer_Destroy } Answers;
  118.  
  119. struct fe_confirm_data {
  120.   MWContext *context;
  121.   Answers answer;
  122.   void *return_value;
  123.   void *return_value_2;
  124.   Widget widget;
  125.   Widget text, text2;
  126.   Boolean must_match;
  127. };
  128.  
  129. #ifdef MOZ_MAIL_NEWS
  130. extern void fe_getMessageBody(MWContext *context, char **pBody, uint32 *body_size, MSG_FontCode **font_changes);
  131. extern void fe_doneWithMessageBody(MWContext *context, char *pBody, uint32 body_size);
  132. #endif
  133.  
  134. extern const char* FE_GetFolderDirectory(MWContext* context);
  135.  
  136. /*static void fe_confirm_cb (Widget, XtPointer, XtPointer);*/
  137. static void fe_clear_text_cb (Widget, XtPointer, XtPointer);
  138. static void fe_destroy_cb (Widget, XtPointer, XtPointer);
  139. static void fe_destroy_ok_cb (Widget, XtPointer, XtPointer);
  140. static void fe_destroy_apply_cb (Widget, XtPointer, XtPointer);
  141. static void fe_destroy_cancel_cb (Widget, XtPointer, XtPointer);
  142. static void fe_destroy_finish_cb (Widget, XtPointer, XtPointer);
  143.  
  144. static void fe_destroy_snarf_text_cb (Widget, XtPointer, XtPointer);
  145. static void fe_destroy_snarf_pw_cb (Widget, XtPointer, XtPointer);
  146. static void fe_destroy_snarf_pw2_cb (Widget, XtPointer, XtPointer);
  147.  
  148. void fe_browse_file_of_text (MWContext *context, Widget text_field, Boolean dirp);
  149.  
  150. /*
  151.  *    A real Info dialog - with ! instead of error icon.
  152.  *    Now we don't have to have "error: no new messages on server"
  153.  */
  154. void
  155. FE_Message(MWContext * context, const char* message)
  156. {
  157.     if (context && context->type != MWContextBiff)
  158.         fe_Message(context, message);
  159. }
  160.  
  161. /* FE_Alert is no longer defined in fe_proto.h */
  162. void
  163. FE_Alert (MWContext *context, const char *message)
  164. {
  165.   if (context && context->type == MWContextBiff)
  166.     return;
  167.  
  168.   if (context)
  169.       XFE_Alert (context, message);
  170.   else
  171.     {
  172.       Widget toplevel = FE_GetToplevelWidget();
  173.       if ( toplevel ) {
  174.           fe_Alert_2(toplevel, message);
  175.       } else {
  176.       /* So that didn't even work. Write to stdout and
  177.        * exit.
  178.        */
  179.       XP_ABORT((message));
  180.     }
  181.     }
  182. }
  183.  
  184. /* Lame hack to get the right title for javascript dialogs.
  185.  * This should be instead added to the call arguments.
  186.  */
  187. static MWContext *javaScriptCallingContextHack = 0;
  188.  
  189. /* Display a message, and wait for the user to click "Ok".
  190.    A pointer to the string is not retained.
  191.    The call to FE_Alert() returns immediately - it does not
  192.    wait for the user to click OK.
  193.  */
  194. void
  195. XFE_Alert (MWContext *context, const char *message)
  196. {
  197.   /* Keep the context around, so we can pull the domain name
  198.    * full the dialog title.
  199.    */
  200.   if (context->bJavaScriptCalling)
  201.     javaScriptCallingContextHack = context;
  202.  
  203.   fe_Alert_2 (CONTEXT_WIDGET (context), message);
  204. }
  205.  
  206. /* Just like XFE_Alert, but with a different dialog title. */
  207. void
  208. fe_stderr (MWContext *context, const char *message)
  209. {
  210.   (void) fe_dialog (CONTEXT_WIDGET (context),
  211.             (fe_globalData.stderr_dialog_p &&
  212.              fe_globalData.stdout_dialog_p
  213.              ? "stdout_stderr"
  214.              : fe_globalData.stderr_dialog_p ? "stderr"
  215.              : fe_globalData.stdout_dialog_p ?  "stdout"  : "???" ),
  216.             message, FALSE, 0, FALSE, FALSE, 0);
  217. }
  218.  
  219.  
  220. /* Let the user confirm or deny assertion `message' (returns True or False.)
  221.    A pointer to the prompt-string is not retained.
  222.  */
  223. XP_Bool
  224. XFE_Confirm (MWContext *context, const char *message)
  225. {
  226.   return fe_Confirm_2 (CONTEXT_WIDGET (context), message);
  227. }
  228.  
  229. Boolean
  230. fe_Confirm_2 (Widget parent, const char *message)
  231. {
  232.   return (Bool) ((int) fe_dialog (parent, "question", message,
  233.                   TRUE, 0, TRUE, FALSE, 0));
  234. }
  235.  
  236. void
  237. fe_Alert_2 (Widget parent, const char *message)
  238. {
  239.   (void) fe_dialog (parent, "error", message, FALSE, 0, FALSE, FALSE, 0);
  240. }
  241.  
  242. #if !defined(__FreeBSD__) && !defined(MACLINUX) && !defined(LINUX_GLIBC_2)
  243. #include <sys/errno.h>
  244. extern char *sys_errlist[];
  245. extern int sys_nerr;
  246. #endif
  247.  
  248. /* Like perror, but with a dialog.
  249.  */
  250. void
  251. fe_perror (MWContext *context, const char *message)
  252. {
  253.   fe_perror_2 (CONTEXT_WIDGET (context), message);
  254. }
  255.  
  256. void
  257. fe_perror_2 (Widget parent, const char *message)
  258. {
  259.   int e = errno;
  260.   char *es = 0;
  261.   char buf1 [2048];
  262.   char buf2 [512];
  263.   char *b = buf1;
  264.   if (e >= 0 && e < sys_nerr)
  265.     {
  266.       es = sys_errlist [e];
  267.     }
  268.   else
  269.     {
  270.       PR_snprintf (buf2, sizeof (buf2), XP_GetString( XFE_UNKNOWN_ERROR_CODE ),
  271.         errno);
  272.       es = buf2;
  273.     }
  274.   if (message)
  275.     PR_snprintf (buf1, sizeof (buf1), "%.900s\n%.900s", message, es);
  276.   else
  277.     b = buf2;
  278.   fe_Alert_2 (parent, b);
  279. }
  280.  
  281. void
  282. fe_UnmanageChild_safe (Widget w)
  283. {
  284.   if (w) XtUnmanageChild (w);
  285. }
  286.  
  287.  
  288. void
  289. fe_NukeBackingStore (Widget widget)
  290. {
  291.   XSetWindowAttributes attrs;
  292.   unsigned long attrmask;
  293.  
  294.   if (!XtIsTopLevelShell (widget))
  295.     widget = XtParent (widget);
  296.   XtRealizeWidget (widget);
  297.  
  298.   attrmask = CWBackingStore | CWSaveUnder;
  299.   attrs.backing_store = NotUseful;
  300.   attrs.save_under = False;
  301.   XChangeWindowAttributes (XtDisplay (widget), XtWindow (widget),
  302.                attrmask, &attrs);
  303. }
  304.  
  305.  
  306. Widget
  307.  
  308. #ifdef OSF1
  309. fe_CreateTextField (Widget parent, char *name, Arg *av, int ac)
  310. #else
  311. fe_CreateTextField (Widget parent, const char *name, Arg *av, int ac)
  312. #endif
  313. {
  314.   Widget w;
  315.  
  316. #if 1
  317.   w = XmCreateTextField (parent, (char *) name, av, ac);
  318. #else
  319.   XtSetArg (av[ac], XmNeditMode, XmSINGLE_LINE_EDIT); ac++;
  320.   w = XmCreateTextField (parent, (char *) name, av, ac);
  321. #endif
  322.  
  323.   fe_HackTextTranslations (w);
  324.   return w;
  325. }
  326.  
  327. Widget
  328. fe_CreateText (Widget parent, const char *name, Arg *av, int ac)
  329. {
  330.   Widget w = XmCreateText (parent, (char *) name, av, ac);
  331.   fe_HackTextTranslations (w);
  332.   return w;
  333. }
  334.  
  335.  
  336. static void
  337. fe_select_text(Widget text)
  338. {
  339.   XmTextPosition first = 0;
  340.   XmTextPosition last = XmTextGetLastPosition (text);
  341.   XP_ASSERT (XtIsRealized(text));
  342.   XmTextSetSelection (text, first, last,
  343.               XtLastTimestampProcessed (XtDisplay (text)));
  344. }
  345.  
  346.  
  347. /* The purpose of this function is try disable all grabs and settle
  348.  * focus issues. This will be called before we popup a dialog
  349.  * (modal or non-modal). This needs to do all these:
  350.  *    - if a menu was posted, unpost it.
  351.  *    - if a popup menu was up, pop it down.
  352.  *    - if an option menu, pop it down.
  353.  */
  354. void fe_fixFocusAndGrab(MWContext *context)
  355. {
  356.   Widget focus_w;
  357.   Widget mainw;
  358.   XEvent event;
  359.   int i;
  360.  
  361.   mainw = CONTEXT_WIDGET(context);
  362.   focus_w = XmGetFocusWidget(mainw);
  363.  
  364.   /* Unpost Menubar */
  365.   if (focus_w && XmIsCascadeButton(focus_w) &&
  366.       XmIsRowColumn(XtParent(focus_w))) {
  367.     /* 1. Found the menubar. Unpost it.
  368.      *        To do that, we makeup a dummy event and use it with the
  369.      *        CleanupMenuBar() action.
  370.      * WARNING: if focus_w was a XmCascadeButtonGadget we wont be able to
  371.      *        do this.
  372.      */
  373.     event.xany.type = 0;
  374.     event.xany.serial = 0;
  375.     event.xany.send_event = 0;
  376.     event.xany.display = fe_display;
  377.     event.xany.window = XtWindow(focus_w);
  378.     XtCallActionProc(focus_w, "CleanupMenuBar", &event, NULL, 0);
  379.   }
  380.  
  381.   /* Identify and Popdown any OptionMenu that was active */
  382.   if (focus_w && XmIsRowColumn(XtParent(focus_w))) {
  383.     unsigned char type;
  384.     Widget w;
  385.     XtVaGetValues(XtParent(focus_w), XmNrowColumnType, &type, 0);
  386.     if (type == XmMENU_OPTION) {
  387.       XtVaGetValues(focus_w, XmNsubMenuId, &w, 0);
  388.       if (w) XtUnmanageChild(w);
  389.     }
  390.   }
  391.   
  392.   /* Identify and Popdown any popup menus that were active */
  393.   for (i=0; i < XfeNumPopups(mainw); i++) {
  394.     Widget popup = XfePopupListIndex(mainw,i);
  395.     if (XtIsShell(popup) && XmIsMenuShell(popup))
  396.       if (XfeShellIsPoppedUp(popup)) {
  397. #ifdef DEBUG_dora
  398.       printf("popdown... name %s shell is popped up\n", XtName(popup));
  399. #endif
  400.     XtPopdown(popup);
  401.       }
  402.   }
  403. }
  404.  
  405. static char *fe_makeSecureTitle( MWContext *context )
  406. {
  407.   History_entry *h;
  408.   char *domain = 0;
  409.   char *title = 0;
  410.  
  411.   if( !context )
  412.     {
  413.       return title;
  414.     }
  415.   
  416.   h = SHIST_GetCurrent (&context->hist);
  417.   
  418.   if (!h || !h->address) return title;
  419.   
  420.   domain = NET_ParseURL(h->address, GET_HOST_PART);
  421.  
  422.   if (domain) {
  423.     title = PR_smprintf("%s - %s", domain, XP_GetString(XFE_JAVASCRIPT_APP));
  424.     XP_FREE(domain);
  425.   } else {
  426.     title = PR_smprintf("%s", XP_GetString(XFE_JAVASCRIPT_APP));
  427.   }
  428.   
  429.   return title;
  430. }
  431.  
  432. void *
  433. fe_prompt (MWContext *context, Widget mainw,
  434.        const char *title, const char *message,
  435.        XP_Bool question_p, const char *default_text,
  436.        XP_Bool wait_p, XP_Bool select_p,
  437.        char **passwd)
  438. {
  439.   /* Keep the context around, so we can pull the domain name
  440.    * full the dialog title.
  441.    */
  442.   if (context->bJavaScriptCalling)
  443.     javaScriptCallingContextHack = context;
  444.  
  445.   return fe_dialog(mainw, title, message, question_p,
  446.                    default_text, wait_p, select_p, passwd);
  447. }
  448.  
  449. /* This function is complete madness - it takes a billion flags
  450.    and does everything in the world because somehow I thought it would save
  451.    me a bunch of lines of code but it's just a MESS!
  452.  */
  453. void *
  454. fe_dialog (Widget mainw,
  455.        const char *title, const char *message,
  456.        XP_Bool question_p, const char *default_text,
  457.        XP_Bool wait_p, XP_Bool select_p,
  458.        char **passwd)
  459. {
  460.   Widget shell, dialog;
  461.   Widget text = 0, pwtext = 0;
  462.   XmString xm_message = 0;
  463.   Arg av [20];
  464.   int ac;
  465.   Visual *v = 0;
  466.   Colormap cmap = 0;
  467.   Cardinal depth = 0;
  468.   char title2 [255];
  469.   struct fe_MWContext_cons *cons;
  470.   int i;
  471.   char *javaScriptTitle = 0;  /* dialog title when javascript calls */
  472.   XP_Bool javaScriptCalling = FALSE;
  473.     
  474.   strcpy (title2, title);
  475.   strcat (title2, "_popup");
  476.  
  477.   /* Use this global variable hackery to get the context */
  478.   if (javaScriptCallingContextHack) {
  479.     javaScriptTitle = fe_makeSecureTitle(javaScriptCallingContextHack);
  480.     javaScriptCallingContextHack = NULL;
  481.     javaScriptCalling = TRUE;
  482.   }
  483.  
  484.   if (!mainw) {
  485.     /* Yikes.  Well, this can happen if someone calls FE_Alert() on a biff
  486.        context or some other context without a window.  We could ignore it,
  487.        but I think it better to try and put the dialog up *someplace*.  So,
  488.        look for some context with a reasonable window. */
  489.     for (cons = fe_all_MWContexts ; cons && !mainw; cons = cons->next) {
  490.       mainw = CONTEXT_WIDGET(cons->context);
  491.     }
  492.     if (!mainw) return NULL;
  493.   }
  494.  
  495.   while(!XtIsWMShell(mainw) && (XtParent(mainw)!=0))
  496.     mainw = XtParent(mainw);
  497.  
  498.   /* so, if the context that is popping up the dialog is hidden, we need
  499.      to pop it up _somewhere_, so we run down the list of contexts *again*,
  500.      and pop it up over one of them.  This should work.  I think. */
  501.   if (!XfeIsViewable(mainw))
  502.       {
  503.           Widget attempt = mainw;
  504.           /* instead of popping up the dialog at (0,0) pop it up over
  505.              the active context */
  506.           for (cons = fe_all_MWContexts ; 
  507.                cons && !XfeIsViewable(attempt); 
  508.                cons = cons->next) 
  509.               {
  510.                   attempt = CONTEXT_WIDGET(cons->context);
  511.  
  512.                   while(!XtIsWMShell(attempt) && (XtParent(attempt)!=0))
  513.                       attempt = XtParent(attempt);
  514.               }
  515.  
  516.           /* oh well, we tried. */
  517.           if (attempt)
  518.               mainw = attempt;
  519.       }
  520.  
  521.   /* If any dialog is already up we will cascade these dialogs. Thus this
  522.    * dialog will be the child of the last popped up dialog.
  523.    */
  524.   i = XfeNumPopups(mainw);
  525.   while (i>0)
  526.     if (XmIsDialogShell(XfePopupListIndex(mainw,i-1)) &&
  527.         (XfeIsViewable(XfePopupListIndex(mainw,i-1)))) {
  528.       /* Got a new mainw */
  529.       Widget newmainw = XfePopupListIndex(mainw,i-1);
  530. #ifdef DEBUG_dp
  531.       fprintf(stderr, "Using mainw: %s[%x] (%s[%x] num_popup=%d)\n",
  532.           XtName(newmainw), newmainw,
  533.           XtName(mainw), mainw, i);
  534. #endif /* DEBUG_dp */
  535.       mainw = newmainw;
  536.       i = XfeNumPopups(mainw);
  537.     }
  538.   else i--;
  539.  
  540.   /* Popdown any popup menu that was active. If not, this could get motif
  541.    * motif really confused as to who has focus as the new dialog that we
  542.    * are going to popup will undo a grab that the popup did without the
  543.    * popup's knowledge.
  544.    */
  545.   for (cons = fe_all_MWContexts ; cons; cons = cons->next)
  546.     fe_fixFocusAndGrab(cons->context);
  547.  
  548.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  549.          XtNdepth, &depth, 0);
  550.  
  551.   ac = 0;
  552.   XtSetArg (av[ac], XmNvisual, v); ac++;
  553.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  554.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  555.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  556.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  557.   shell = XmCreateDialogShell (mainw, title2, av, ac);
  558.  
  559.   /* If it is java script that is posting this, use this special title */
  560.   if (javaScriptTitle) {
  561.     XtVaSetValues (shell, XmNtitle, javaScriptTitle, 0);
  562.     free(javaScriptTitle);
  563.   }
  564.  
  565.   ac = 0;
  566.   if (message)
  567.     xm_message = XmStringCreateLtoR ((char *) message,
  568.                      XmFONTLIST_DEFAULT_TAG);
  569.   XtSetArg (av[ac], XmNdialogStyle, (wait_p
  570.                      ? XmDIALOG_FULL_APPLICATION_MODAL
  571.                      : XmDIALOG_MODELESS)); ac++;
  572.   XtSetArg (av[ac], XmNdialogType,
  573.             (default_text
  574.              ? XmDIALOG_MESSAGE
  575.              : (question_p
  576.                 ? XmDIALOG_QUESTION
  577.                 : (javaScriptCalling
  578.                    ? XmDIALOG_WARNING
  579.                    : XmDIALOG_ERROR)))); ac++;
  580.   if (xm_message) XtSetArg (av[ac], XmNmessageString, xm_message), ac++;
  581.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  582.   dialog = XmCreateMessageBox (shell, "dialog", av, ac);
  583.   if (xm_message) XmStringFree (xm_message);
  584.  
  585. #ifdef NO_HELP
  586.   fe_UnmanageChild_safe (XtNameToWidget (dialog, "*Help"));
  587. #endif
  588.  
  589.  
  590.   if (! question_p )
  591.     {
  592.       Widget cancel = 0;
  593.       XtVaGetValues (dialog, XmNcancelButton, &cancel, 0);
  594.       if (! cancel) abort ();
  595.       XtUnmanageChild (cancel);
  596.     }
  597.  
  598.   if (default_text)
  599.     {
  600.       Widget clear;
  601.       Widget text_parent = dialog;
  602.       Widget ulabel = 0, plabel = 0;
  603.  
  604.       text = 0;
  605.       pwtext = 0;
  606.  
  607.       if (passwd && passwd != (char **) 1)
  608.     {
  609.       ac = 0;
  610.       text_parent = XmCreateForm (dialog, "dialogform", av, ac);
  611.       ulabel = XmCreateLabelGadget (text_parent, "userLabel", av, ac);
  612.       plabel = XmCreateLabelGadget (text_parent, "passwdLabel", av, ac);
  613.       XtVaSetValues (ulabel,
  614.              XmNtopAttachment, XmATTACH_FORM,
  615.              XmNbottomAttachment, XmATTACH_WIDGET,
  616.              XmNbottomWidget, plabel,
  617.              XmNleftAttachment, XmATTACH_FORM,
  618.              XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
  619.              XmNrightWidget, plabel,
  620.              0);
  621.       XtVaSetValues (plabel,
  622.              XmNtopAttachment, XmATTACH_NONE,
  623.              XmNbottomAttachment, XmATTACH_FORM,
  624.              XmNleftAttachment, XmATTACH_FORM,
  625.              XmNrightAttachment, XmATTACH_NONE,
  626.              0);
  627.     }
  628.  
  629.       if (passwd != (char **) 1)
  630.     {
  631.       ac = 0;
  632.       text = fe_CreateTextField (text_parent, "text", av, ac);
  633.       fe_SetTextField(text, default_text);
  634.       XtVaSetValues (text, XmNcursorPosition, 0, 0);
  635.     }
  636.  
  637.       if (passwd)
  638.     {
  639.       ac = 0;
  640.       pwtext = fe_CreateTextField (text_parent, "pwtext", av, ac);
  641.     }
  642.  
  643.       if (text && pwtext)
  644.     {
  645.       if (fe_globalData.nonterminal_text_translations)
  646.         XtOverrideTranslations (text, fe_globalData.
  647.                     nonterminal_text_translations);
  648.                     
  649.       XtVaSetValues (text,
  650.              XmNtopAttachment, XmATTACH_FORM,
  651.              XmNbottomAttachment, XmATTACH_WIDGET,
  652.              XmNbottomWidget, pwtext,
  653.              XmNleftAttachment, XmATTACH_WIDGET,
  654.              XmNleftWidget, ulabel,
  655.              XmNrightAttachment, XmATTACH_FORM,
  656.              0);
  657.       XtVaSetValues (pwtext,
  658.              XmNtopAttachment, XmATTACH_NONE,
  659.              XmNbottomAttachment, XmATTACH_FORM,
  660.              XmNleftAttachment, XmATTACH_WIDGET,
  661.              XmNleftWidget, plabel,
  662.              XmNrightAttachment, XmATTACH_FORM,
  663.              0);
  664.       XtManageChild (ulabel);
  665.       XtManageChild (plabel);
  666.     }
  667.  
  668.       if (text)
  669.     XtManageChild (text);
  670.       if (pwtext)
  671.     XtManageChild (pwtext);
  672.  
  673.       if (text && pwtext)
  674.     XtManageChild (text_parent);
  675.  
  676.       XtVaSetValues (text_parent, XmNinitialFocus, (text ? text : pwtext), 0);
  677.       XtVaSetValues (dialog, XmNinitialFocus, (text ? text : pwtext), 0);
  678.  
  679.       ac = 0;
  680.       clear = XmCreatePushButtonGadget (dialog, "clear", av, ac);
  681.       if (pwtext)
  682.     XtAddCallback (clear, XmNactivateCallback, fe_clear_text_cb, pwtext);
  683.       if (text)
  684.     XtAddCallback (clear, XmNactivateCallback, fe_clear_text_cb, text);
  685.       XtManageChild (clear);
  686.     }
  687.  
  688.   if (! wait_p)
  689.     {
  690.       XtAddCallback (dialog, XmNokCallback, fe_destroy_cb, shell);
  691.       XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cb, shell);
  692.       XtManageChild (dialog);
  693.       if (text && select_p)
  694.     fe_select_text (text);
  695.       return False;
  696.     }
  697.   else
  698.     {
  699.       struct fe_confirm_data data;
  700.       void *ret_val = 0;
  701.       
  702.       /*      data.context = context; */
  703.       data.answer = Answer_Invalid;
  704.       data.widget = shell;
  705.       data.text  = (text ? text : pwtext);
  706.       data.text2 = ((text && pwtext) ? pwtext : 0);
  707.       data.return_value = 0;
  708.       data.return_value_2 = 0;
  709.  
  710.       XtVaSetValues (shell, XmNdeleteResponse, XmDESTROY, 0);
  711.       XtAddCallback (dialog, XmNokCallback, fe_destroy_ok_cb, &data);
  712.       XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cancel_cb, &data);
  713.       XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  714.  
  715.       if (text)
  716.     XtAddCallback (text, XmNdestroyCallback, fe_destroy_snarf_text_cb,
  717.                &data);
  718.  
  719.       if (text && pwtext)
  720.     XtAddCallback (pwtext, XmNdestroyCallback, fe_destroy_snarf_pw2_cb,
  721.                &data);
  722.       else if (pwtext)
  723.     XtAddCallback (pwtext, XmNdestroyCallback, fe_destroy_snarf_pw_cb,
  724.                &data);
  725.  
  726.       if (pwtext)
  727.     fe_SetupPasswdText (pwtext, 1024);
  728.  
  729.       fe_NukeBackingStore (dialog);
  730.       XtManageChild (dialog);
  731.  
  732.       if (text)
  733.     {
  734.       XtVaSetValues (text, XmNcursorPosition, 0, 0);
  735.       XtVaSetValues (text, XmNcursorPositionVisible, True, 0);
  736.       if (select_p)
  737.         fe_select_text (text);
  738.     }
  739.  
  740.       while (data.answer == Answer_Invalid)
  741.     fe_EventLoop ();
  742.  
  743.       if (default_text)
  744.     {
  745.       if (data.answer == Answer_OK)    /* user clicked OK at the text */
  746.         {
  747.           if (text && pwtext)
  748.         {
  749.           if (!data.return_value || !data.return_value_2) abort ();
  750.           *passwd = data.return_value_2;
  751.           ret_val = data.return_value;
  752.         }
  753.           else if (text || pwtext)
  754.         {
  755.           if (! data.return_value) abort ();
  756.           ret_val = data.return_value;
  757.         }
  758.           else
  759.         abort ();
  760.         }
  761.       else            /* user clicked cancel */
  762.         {
  763.           if (data.return_value)
  764.         free (data.return_value);
  765.           if (data.return_value_2)
  766.         free (data.return_value_2);
  767.           ret_val = 0;
  768.         }
  769.     }
  770.       else
  771.     {
  772.       ret_val = (data.answer == Answer_OK
  773.              ? (void *) True
  774.              : (void *) False);
  775.     }
  776.  
  777.       /* We need to suck the values out of the widgets before destroying them.
  778.        */
  779.       /* Ok, with the new way, it got destroyed by the callbacks on the
  780.      OK and Cancel buttons. */
  781.       /* XtDestroyWidget (shell); */
  782.       return ret_val;
  783.     }
  784. }
  785.  
  786.  
  787. void
  788. fe_Message (MWContext *context, const char *message)
  789. {
  790.   Widget mainw = CONTEXT_WIDGET (context);
  791.   Widget shell, dialog;
  792.   XmString xm_message;
  793.   Arg av [20];
  794.   int ac;
  795.   Visual *v = 0;
  796.   Colormap cmap = 0;
  797.   Cardinal depth = 0;
  798.  
  799.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  800.          XtNdepth, &depth, 0);
  801.  
  802.   ac = 0;
  803.   XtSetArg (av[ac], XmNvisual, v); ac++;
  804.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  805.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  806.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  807.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  808.   shell = XmCreateDialogShell (mainw, "message_popup", av, ac);
  809.   ac = 0;
  810.   xm_message = XmStringCreateLtoR ((char *) message, XmFONTLIST_DEFAULT_TAG);
  811.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  812.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_MESSAGE); ac++;
  813.   XtSetArg (av[ac], XmNmessageString, xm_message); ac++;
  814.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  815.   dialog = XmCreateMessageBox (shell, "message", av, ac);
  816.   XmStringFree (xm_message);
  817.  
  818. #ifdef NO_HELP
  819.   fe_UnmanageChild_safe (XtNameToWidget (dialog, "*Help"));
  820. #endif
  821.  
  822.   {
  823.     Widget cancel = 0;
  824.     XtVaGetValues (dialog, XmNcancelButton, &cancel, 0);
  825.     if (! cancel) abort ();
  826.     XtUnmanageChild (cancel);
  827.   }
  828.   XtAddCallback (dialog, XmNokCallback, fe_destroy_cb, shell);
  829.   XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cb, shell);
  830.   fe_NukeBackingStore (dialog);
  831.   XtManageChild (dialog);
  832. }
  833.  
  834. static void
  835. fe_destroy_ok_cb (Widget widget, XtPointer closure, XtPointer call_data)
  836. {
  837.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  838.   data->answer = Answer_OK;
  839.   XtDestroyWidget(data->widget);
  840. }
  841.  
  842. static void
  843. fe_destroy_cancel_cb (Widget widget, XtPointer closure, XtPointer call_data)
  844. {
  845.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  846.   data->answer = Answer_Cancel;
  847.   XtDestroyWidget(data->widget);
  848. }
  849.  
  850. static void
  851. fe_destroy_apply_cb (Widget widget, XtPointer closure, XtPointer call_data)
  852. {
  853.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  854.   data->answer = Answer_Apply;
  855.   XtDestroyWidget(data->widget);
  856. }
  857.  
  858. static void
  859. fe_destroy_finish_cb (Widget widget, XtPointer closure, XtPointer call_data)
  860. {
  861.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  862.   if (data->answer == Answer_Invalid)
  863.     data->answer = Answer_Destroy;
  864. }
  865.  
  866. static void
  867. fe_destroy_snarf_text_cb (Widget widget, XtPointer closure,XtPointer call_data)
  868. {
  869.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  870.   Widget text = data->text;
  871.   if (text)
  872.     {
  873.         char *plaintext = 0;
  874.         data->return_value = 0;
  875.         plaintext = fe_GetTextField(text);
  876.         data->return_value = XP_STRDUP(plaintext ? plaintext : "");
  877.     }
  878. }
  879.  
  880. static void
  881. fe_destroy_snarf_pw_cb (Widget widget, XtPointer closure, XtPointer call_data)
  882. {
  883.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  884.   Widget text = data->text;
  885.   if (text)
  886.     data->return_value = fe_GetPasswdText (text);
  887. }
  888.  
  889. static void
  890. fe_destroy_snarf_pw2_cb (Widget widget, XtPointer closure, XtPointer call_data)
  891. {
  892.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  893.   Widget text = data->text2;
  894.   if (text)
  895.     data->return_value_2 = fe_GetPasswdText (text);
  896. }
  897.  
  898.  
  899. /* Callback used by the clear button to nuke the contents of the text field. */
  900. static void
  901. fe_clear_text_cb (Widget widget, XtPointer closure, XtPointer call_data)
  902. {
  903.   Widget text = (Widget) closure;
  904.   fe_SetTextField (text, "");
  905.   /* Focus on the text widget after this, since otherwise you have to
  906.      click again. */
  907.   XmProcessTraversal (text, XmTRAVERSE_CURRENT);
  908. }
  909.  
  910. /* When we are not blocking waiting for a response to a dialog, this is used
  911.    by the buttons to make it get lost when no longer needed (the default would
  912.    otherwise be to merely unmanage it instead of destroying it.) */
  913. static void
  914. fe_destroy_cb (Widget widget, XtPointer closure, XtPointer call_data)
  915. {
  916.   Widget shell = XtParent (widget);
  917.   while (!XmIsDialogShell (shell))
  918.     shell = XtParent (shell);
  919.   XtDestroyWidget (shell);
  920. }
  921.  
  922.  
  923.  
  924. /* Create a XmString that will render in the given width or less.  If
  925.    the given string is too big, then chop out stuff by clipping out the
  926.    center and replacing it with "...". */
  927. XmString
  928. fe_StringChopCreate(char* message, char* tag, XmFontList font_list,
  929.             int maxwidth)
  930. {
  931.   XmString label = XmStringCreate ((char *) message, tag);
  932.   int string_width;
  933.   uint16 csid;
  934.  
  935.   if (!font_list) return label;
  936.  
  937.   string_width = XmStringWidth(font_list, label);
  938.   if (string_width >= maxwidth) {
  939.     /* The string is bigger than the label.  Mid-truncate it. */
  940.  
  941.     XmString try;
  942.     int length = 0;
  943.     int maxlength = XP_STRLEN(message);
  944.     char* text = XP_ALLOC(maxlength + 10);
  945.     if (!text) return label;
  946.       
  947.     csid = INTL_CharSetNameToID(tag);
  948.     if (csid==CS_UNKNOWN) {
  949.       csid = INTL_CharSetNameToID(INTL_ResourceCharSet());
  950.     }
  951.     string_width = 0;
  952.     while (string_width < maxwidth && length < maxlength) {
  953.       length++;
  954.       INTL_MidTruncateString(csid, message, text, length);
  955.       try = XmStringCreate(text, tag);
  956.       if (!try) break;
  957.       string_width = XmStringWidth(font_list, try);
  958.       if (string_width >= maxwidth) {
  959.     XmStringFree(try);
  960.       } else {
  961.     XmStringFree(label);
  962.     label = try;
  963.       }
  964.       try = 0;
  965.     }
  966.  
  967.     free (text);
  968.   }
  969.  
  970.   return label;
  971. }
  972.  
  973. /* Dealing with field/value pairs.
  974.  
  975.    This takes a "value" widget and an arbitrary number of "label" widgets.
  976.    It finds the widest label, and attaches the "value" widget to the left
  977.    edge of its parent with an offset such that it falls just beyond the
  978.    right edge of the widest label widget.
  979.  
  980.    The argument list is expected to be NULL-terminated.
  981.  */
  982.  
  983. /* #ifdef AIXV3 */
  984. /*    I don't understand - this seems not to be broken any more, and now
  985.       the "hack" way doesn't compile either.  Did someone upgrade me?? */
  986. /* # define BROKEN_VARARGS */
  987. /* #endif */
  988.  
  989. #ifdef BROKEN_VARARGS
  990. /* Sorry, we can't be bothered to implement varargs correctly. */
  991. # undef va_list
  992. # undef va_start
  993. # undef va_arg
  994. # undef va_end
  995. # define va_list int
  996. # define va_start(list,first_arg) list = 0
  997. # define va_arg(list, type) (++list, (type) (list == 1 ? varg0 : \
  998.                              list == 2 ? varg1 : \
  999.                              list == 3 ? varg2 : \
  1000.                              list == 4 ? varg3 : \
  1001.                              list == 5 ? varg4 : \
  1002.                              list == 6 ? varg5 : \
  1003.                              list == 7 ? varg6 : \
  1004.                              list == 8 ? varg7 : \
  1005.                              list == 9 ? varg8 : 0))
  1006. # define va_end(list)
  1007. #endif
  1008.  
  1009.  
  1010. void
  1011. #ifdef BROKEN_VARARGS
  1012. fe_attach_field_to_labels (Widget value_field,
  1013.                void *varg0, void *varg1, void *varg2, void *varg3,
  1014.                void *varg4, void *varg5, void *varg6, void *varg7,
  1015.                void *varg8)
  1016. #else
  1017. fe_attach_field_to_labels (Widget value_field, ...)
  1018. #endif
  1019. {
  1020.   va_list vargs;
  1021.   Widget current;
  1022.   Widget widest = 0;
  1023.   Position left = 0;
  1024.   long max_width = -1;
  1025.  
  1026.   va_start (vargs, value_field);
  1027.   while ((current = va_arg (vargs, Widget)))
  1028.     {
  1029.       Dimension width = 0;
  1030.       Position left = 0;
  1031.       Position right = 10;
  1032.  
  1033. #ifdef Motif_doesnt_suck
  1034.       /* Getting the leftOffset of a Gadget may randomly dump core */
  1035.       if (XmIsGadget (current))
  1036.     abort ();
  1037.       XtVaGetValues (current,
  1038.              XmNwidth, &width,
  1039.              XmNleftOffset, &left,
  1040. /*             XmNrightOffset, &right,*/
  1041.              0);
  1042.  
  1043. #else
  1044.       width = XfeWidth(current);
  1045. #endif
  1046.  
  1047.       width += (left + right);
  1048.       if (((long) width) > max_width)
  1049.     {
  1050.       widest = current;
  1051.       max_width = (long) width;
  1052.     }
  1053.     }
  1054.   va_end (vargs);
  1055.  
  1056.   if (! widest)
  1057.     abort ();
  1058. #ifdef Motif_doesnt_suck
  1059.   XtVaGetValues (value_field, XmNleftOffset, &left, 0);
  1060. #endif
  1061.   XtVaSetValues (value_field,
  1062.          XmNleftAttachment, XmATTACH_FORM,
  1063.          XmNleftOffset, max_width + left,
  1064.          0);
  1065. }
  1066.  
  1067.  
  1068. /* Files
  1069.  */
  1070. static XmString fe_file_selection_directory;
  1071.  
  1072. /*
  1073.  * This code tried to make some minor improvements to the standard
  1074.  * Motif 1.2* File Selection Box dialog. The code here attempts
  1075.  * to use the existing Motif code for the bulk of the work, and to
  1076.  * replace some parts of Motif's behavior with something simpler.
  1077.  * I've also added some nice things conceptually lifted from the Mac
  1078.  * file picker, and at the request of users. In hindsight it might
  1079.  * have been easier to just write a new file picker widget, preferably
  1080.  * one that is semantically compatible with the Motif widget. Next time.
  1081.  *
  1082.  * Anyway, this stuff is conditionally compiled. Most of this is
  1083.  * controlled by the USE_WINNING_FILE_SELECTION define. When
  1084.  * you turn this guy on, it enables a bunch of hacks to the standard
  1085.  * Motif behavior. Best to take a look, but below is a snippet from
  1086.  * the resource file. Note that some of the hacks (the simple layout
  1087.  * hacks) require Motif source knowledge because they must attack the
  1088.  * FSB class record directly. We've moved that code out (see the
  1089.  * define FEATURE_MOTIF_FSB_CLASS_HACKING) because we can't make the
  1090.  * Motif code public.
  1091.  *
  1092.  * Related to these hacks, but somewhat orthogonal to them, we try to
  1093.  * save the last accessed directory. This makes life a little easier
  1094.  * than always going back to (say) HOME.
  1095.  *
  1096.  * From the resource file:
  1097.  *
  1098.  * This resource enables some hacks to the File Selection Box
  1099.  * which use a simpler layout algorithm than the standard Motif
  1100.  * code. The directory and file listings are always maintained
  1101.  * as equal size. We don't do this for SGI, as they have solved
  1102.  * the problem. See *useEnhancedFSB above.
  1103.  * @NOTSGI@*nsMotifFSBHacks: True
  1104.  *
  1105.  * This resource enables the CDE mode of the File Selection Box.
  1106.  * You must be running a CDE enhanced Motif library for this
  1107.  * option to work. This resource will apply pathMode=1 to the
  1108.  * File Selection Box. If you specify nsMotifFSBHacks and
  1109.  * nsMotifFSBCdeMode, some of the keyboard and filter enhancements
  1110.  * of nsMotifFSBHacks will also be applied, the layout hacks will not.
  1111.  * *nsMotifFSBCdeMode: False
  1112.  *
  1113.  * ...djw
  1114.  */
  1115. #define USE_WINNING_FILE_SELECTION win
  1116.  
  1117. #ifdef USE_WINNING_FILE_SELECTION
  1118.  
  1119. #include <Xm/XmP.h>
  1120. #include <Xm/XmosP.h>
  1121.  
  1122. static void
  1123. fe_force_configure(Widget widget)
  1124. {
  1125.     Dimension width = _XfeWidth(widget);
  1126.     Dimension height = _XfeHeight(widget);
  1127.     Dimension border_width = _XfeBorderWidth(widget);
  1128.  
  1129.     _XfeHeight(widget) += 1;
  1130.     XtResizeWidget(widget, width, height, border_width);
  1131. }
  1132.  
  1133. static void
  1134. fe_file_selection_get_dir_entries(String directory, String pattern,
  1135.                                   unsigned type,
  1136.                                   String** file_list_r, unsigned int* nfiles_r)
  1137. {
  1138.     unsigned int n;
  1139.     unsigned len = strlen(directory);
  1140.  
  1141.     *file_list_r = NULL;
  1142. #ifdef XM_GET_DIR_ENTRIES_OK
  1143.     _XmOSGetDirEntries(directory, pattern, type, FALSE, FALSE,
  1144.                        file_list_r, nfiles_r, &n);
  1145. #else
  1146.     _XmOSBuildFileList(directory, pattern, type,
  1147.                        file_list_r, nfiles_r, &n);
  1148.  
  1149.     for (n = 0; n < *nfiles_r; n++) {
  1150.         String old_s = (*file_list_r)[n];
  1151.         String new_s;
  1152.  
  1153.         if (strncmp(directory, old_s, len) == 0) {
  1154.             new_s = (String)XtNewString(&old_s[len]);
  1155.             XtFree(old_s);
  1156.             (*file_list_r)[n] = new_s;
  1157.         }
  1158.     }
  1159. #endif
  1160. }
  1161.  
  1162. static void 
  1163. fe_file_selection_file_search_proc(Widget widget, XtPointer call_data)
  1164. {
  1165.     XmFileSelectionBoxCallbackStruct* search_data
  1166.         = (XmFileSelectionBoxCallbackStruct *)call_data;
  1167.     String    directory;
  1168.     String    pattern;
  1169.     String*   file_list;
  1170.     unsigned int nfiles;
  1171.     Arg       args[10];
  1172.     Cardinal  n;
  1173.     Cardinal  nn;
  1174.     XmString* xm_string_file_list;
  1175.     XmString  xm_directory;
  1176.  
  1177.     if (!(directory = _XmStringGetTextConcat(search_data->dir))) {
  1178.         return;
  1179.     }
  1180.  
  1181.     if (!(pattern = _XmStringGetTextConcat(search_data->pattern))) {
  1182.         XtFree(directory);
  1183.         return;
  1184.     }
  1185.  
  1186.     /*
  1187.      *    _XmOSGetDirEntries() is being really wierd! Use this guy
  1188.      *    instead..djw
  1189.      */
  1190.     file_list = NULL;
  1191.     fe_file_selection_get_dir_entries(directory, pattern, XmFILE_REGULAR,
  1192.                                       &file_list, &nfiles);
  1193.  
  1194.     for (n = 0, nn = 0; n < nfiles; n++) {
  1195.         if (file_list[n][0] == '.') /* no more dot files ! */
  1196.             continue;
  1197.         
  1198.         file_list[nn++] = file_list[n];
  1199.     }
  1200.     nfiles = nn;
  1201.     
  1202.     if (nfiles != 0) {
  1203.         if (nfiles > 1)
  1204.             XP_QSORT((void *)file_list, nfiles, sizeof(char *), _XmOSFileCompare);
  1205.         
  1206.         xm_string_file_list = (XmString*)XtMalloc(nfiles * sizeof(XmString));
  1207.  
  1208.         for (n = 0; n < nfiles; n++) {
  1209.             xm_string_file_list[n] = XmStringLtoRCreate(file_list[n],
  1210.                                                     XmFONTLIST_DEFAULT_TAG);
  1211.         }
  1212.     } else {
  1213.         xm_string_file_list = NULL;
  1214.     }
  1215.  
  1216.     /* The Motif book says update the XmNdirectory */
  1217.     xm_directory = XmStringLtoRCreate(directory, XmFONTLIST_DEFAULT_TAG);
  1218.  
  1219.     /* Update the list widget */
  1220.     n = 0;
  1221.     XtSetArg(args[n], XmNfileListItems, xm_string_file_list); n++;
  1222.     XtSetArg(args[n], XmNfileListItemCount, nfiles); n++;
  1223.     XtSetArg(args[n], XmNlistUpdated, TRUE); n++;
  1224.     XtSetArg(args[n], XmNdirectory, xm_directory); n++;
  1225. #if 0
  1226.     XtSetArg(args[n], XmNdirectoryValid, TRUE); n++;
  1227. #endif
  1228.     XtSetValues(widget, args, n);
  1229.  
  1230. #if 1
  1231.     fe_force_configure(widget);
  1232. #endif
  1233.  
  1234.     /* And save directory default for next time */
  1235.     if (fe_file_selection_directory)
  1236.         XmStringFree(fe_file_selection_directory);
  1237.     fe_file_selection_directory = xm_directory;
  1238.  
  1239.     if (nfiles != 0) {
  1240.         /*
  1241.          *    Cleanup.
  1242.          */
  1243.         for (n = 0; n < nfiles; n++) {
  1244.             XmStringFree(xm_string_file_list[n]);
  1245.             XtFree(file_list[n]);
  1246.         }
  1247.         XtFree((char *)xm_string_file_list);
  1248.     }
  1249.  
  1250.     XtFree((char *)directory);
  1251.     XtFree((char *)pattern);
  1252.     
  1253.     if (file_list)
  1254.         XtFree((char *)file_list);
  1255. }
  1256.  
  1257. static void 
  1258. fe_file_selection_dir_search_proc(Widget widget, XtPointer call_data)
  1259. {
  1260.     XmFileSelectionBoxCallbackStruct* search_data
  1261.         = (XmFileSelectionBoxCallbackStruct *)call_data;
  1262.     String            directory;
  1263.     Arg             args[10];
  1264.     Cardinal        n;
  1265.     Cardinal        m;
  1266.     String *        dir_list;
  1267.     unsigned int    ndirs;
  1268.     unsigned int    mdirs;
  1269.     XmString *      xm_string_dir_list;
  1270.     XmString        xm_directory;
  1271.     int attempts;
  1272.     char* p;
  1273.  
  1274.     XtVaGetValues(widget, XmNdirectory, &xm_directory, 0);
  1275.  
  1276.     if (XmStringByteCompare(xm_directory, search_data->dir) == True) {
  1277.         /* Update the list widget */
  1278.         n = 0;
  1279.         XtSetArg(args[n], XmNlistUpdated, FALSE); n++;
  1280.         XtSetArg(args[n], XmNdirectoryValid, TRUE); n++;
  1281.         XtSetValues(widget, args, n);
  1282.         return;
  1283.     }
  1284.  
  1285.     directory = _XmStringGetTextConcat(search_data->dir);
  1286.  
  1287.     ndirs = 0;
  1288.     for (attempts = 0; ndirs == 0; attempts++) {
  1289.         dir_list = NULL;
  1290.         fe_file_selection_get_dir_entries(directory, "*", XmFILE_DIRECTORY,
  1291.                                           &dir_list, &ndirs);
  1292.         if (ndirs) {
  1293.             if (attempts != 0) {
  1294.                 XmFileSelectionBoxCallbackStruct new_data;
  1295.                 XmQualifyProc q_proc;
  1296.  
  1297.                 /*
  1298.                  *    Cleanup old stuff that won't be re-used.
  1299.                  */
  1300.                 XmStringFree(search_data->dir);
  1301.                 if (search_data->mask)
  1302.                     XmStringFree(search_data->mask);
  1303.  
  1304.                 memset(&new_data, 0, sizeof(XmFileSelectionBoxCallbackStruct));
  1305.                 new_data.reason = search_data->reason;
  1306.                 new_data.event = search_data->event;
  1307.                 new_data.dir = XmStringLtoRCreate(directory,
  1308.                                                   XmFONTLIST_DEFAULT_TAG);
  1309.                 new_data.dir_length = XmStringLength(new_data.dir);
  1310.                 new_data.pattern = search_data->pattern;
  1311.                 new_data.pattern_length = search_data->pattern_length;
  1312.  
  1313.                 /*
  1314.                  *    Reset the spec, because we may get called 50M
  1315.                  *    times if this broken state.
  1316.                  */
  1317.                 XtVaSetValues(widget,
  1318.                               XmNdirectory, new_data.dir,
  1319.                               XmNdirSpec, new_data.dir,
  1320.                               0);
  1321.  
  1322.                 /*
  1323.                  *    Call qualify proc to install new directory
  1324.                  *    into widget.
  1325.                  */
  1326.                 XtVaGetValues(widget, XmNqualifySearchDataProc, &q_proc, 0);
  1327.                 (*q_proc)(widget, (XtPointer)&new_data,
  1328.                           (XtPointer)search_data);
  1329.             }
  1330.         } else {
  1331.             if (attempts == 0) {
  1332. #ifdef DEBUG
  1333.                 char   buf[1024];
  1334.         
  1335.                 sprintf(buf, "Unable to access directory:\n  %.900s\n",
  1336.                         directory);
  1337.                 fprintf(stderr, buf);
  1338. #endif
  1339.                 XBell(XtDisplay(widget), 0); /* emulate Motif */
  1340.             }
  1341.  
  1342.             if (dir_list)
  1343.                 XtFree((char *) dir_list);
  1344.  
  1345.             if (directory[0] == '\0' || strcmp(directory, "/") == 0)
  1346.                 return; /* I give in! */
  1347.  
  1348.             while ((p = strrchr(directory, '/')) != NULL) {
  1349.                 if (p[1] == '\0') { /* "/" at end */
  1350.                     p[0] = '\0';
  1351.                 } else {
  1352.                     p[1] = '\0';
  1353.                     break;
  1354.                 }
  1355.             }
  1356.         }
  1357.     }
  1358.  
  1359.     if (ndirs > 1)
  1360.         XP_QSORT((void *)dir_list, ndirs, sizeof(char *), _XmOSFileCompare);
  1361.     
  1362.     xm_string_dir_list = (XmString *)XtMalloc(ndirs * sizeof(XmString));
  1363.  
  1364.     for (m = n = 0; n < ndirs; n++) {
  1365.         if (strcmp(dir_list[n], ".") == 0) /* don't want that */
  1366.             continue;
  1367.         xm_string_dir_list[m++] = XmStringLtoRCreate(dir_list[n],
  1368.                                                      XmFONTLIST_DEFAULT_TAG);
  1369.     } 
  1370.     mdirs = m;
  1371.  
  1372.     /* Update the list widget */
  1373.     n = 0;
  1374.     XtSetArg(args[n], XmNdirListItems, xm_string_dir_list); n++;
  1375.     XtSetArg(args[n], XmNdirListItemCount, mdirs); n++;
  1376.     XtSetArg(args[n], XmNlistUpdated, TRUE); n++;
  1377.     XtSetArg(args[n], XmNdirectoryValid, TRUE); n++;
  1378.     XtSetValues(widget, args, n);
  1379.  
  1380.     /* And save directory default for next time */
  1381.     xm_directory = XmStringLtoRCreate(directory, XmFONTLIST_DEFAULT_TAG);
  1382.     if (fe_file_selection_directory)
  1383.         XmStringFree(fe_file_selection_directory);
  1384.     fe_file_selection_directory = xm_directory;
  1385.  
  1386.     /*
  1387.      *    Cleanup.
  1388.      */
  1389.     for (n = 0; n < mdirs; n++) {
  1390.         XmStringFree(xm_string_dir_list[n]);
  1391.     }    
  1392.     for (n = 0; n < ndirs; n++) {
  1393.         XtFree(dir_list[n]);
  1394.     } 
  1395.  
  1396.     XtFree((char *)xm_string_dir_list);
  1397.     XtFree((char *)directory);
  1398. }
  1399.  
  1400. static void
  1401. fe_file_selection_qualify_search_data_proc(Widget widget,
  1402.                        XtPointer sd, XtPointer qsd)
  1403. {
  1404.     XmFileSelectionBoxCallbackStruct* s_data
  1405.         = (XmFileSelectionBoxCallbackStruct *)sd;
  1406.     XmFileSelectionBoxCallbackStruct* qs_data
  1407.         = (XmFileSelectionBoxCallbackStruct *)qsd;
  1408.     String mask_string = _XmStringGetTextConcat(s_data->mask);
  1409.     String dir_string = _XmStringGetTextConcat(s_data->dir);
  1410.     String pattern_string = _XmStringGetTextConcat(s_data->pattern);
  1411.     String dir_part = NULL;
  1412.     String pattern_part = NULL;
  1413.     String q_dir_string = NULL;
  1414.     String q_mask_string = NULL;
  1415.     String q_pattern_string = NULL;
  1416.     String dir_free_string = NULL;
  1417.     String pattern_free_string = NULL;
  1418.     String p;
  1419.     XmString xm_directory;
  1420.     XmString xm_pattern;
  1421.     XmString xm_dir_spec;
  1422.  
  1423.     if (dir_string != NULL) {
  1424.         if (dir_string[0] == '/') {
  1425.             dir_part = dir_string;
  1426.         } else {
  1427.             XtVaGetValues(widget, XmNdirectory, &xm_directory, 0);
  1428.             if (xm_directory != NULL) {
  1429.                 dir_part = _XmStringGetTextConcat(xm_directory);
  1430.                 p = (String)XtMalloc(strlen(dir_part) +
  1431.                                      strlen(dir_string) + 2);
  1432.                 strcpy(p, dir_part);
  1433.                 strcat(p, dir_string);
  1434.                 XtFree(dir_string);
  1435.                 XtFree(dir_part);
  1436.                 dir_part = dir_string = p;
  1437.             }
  1438.         }
  1439.     } else {
  1440.         if (mask_string != NULL) { /* use filter value */
  1441.             pattern_part = _XmOSFindPatternPart(mask_string);
  1442.  
  1443.             if (pattern_part != mask_string) {
  1444.                 pattern_part[-1] =  '\0'; /* zap dir trailing '/' */
  1445.                 /* "" or "/" */
  1446.                 if (*mask_string == '\0') {
  1447.                     dir_part = "/";
  1448.                 } else if (*mask_string == '/' && mask_string[1] == '\0') {
  1449.                     dir_part = "//";
  1450.                 } else {
  1451.                     dir_part = mask_string;
  1452.                 }
  1453.             }
  1454.         } else { /* use XmNdirectory */
  1455.             XtVaGetValues(widget, XmNdirectory, &xm_directory, 0);
  1456.             if (xm_directory != NULL) {
  1457.                 dir_part = _XmStringGetTextConcat(xm_directory);
  1458.                 dir_free_string = dir_part; /* to force free */
  1459.             }
  1460.         }
  1461.     }
  1462.  
  1463.     if (pattern_string != NULL) {
  1464.         pattern_part = pattern_string;
  1465.     } else {
  1466.         if (mask_string != NULL) {
  1467.             if (!pattern_part)
  1468.                 pattern_part = _XmOSFindPatternPart(mask_string);
  1469.         } else {
  1470.             XtVaGetValues(widget, XmNpattern, &xm_pattern, 0);
  1471.             if (xm_pattern != NULL) {
  1472.                 pattern_part = _XmStringGetTextConcat(xm_pattern);
  1473.                 pattern_free_string = pattern_part; /* so it gets freed */
  1474.             }
  1475.         }
  1476.     }
  1477.  
  1478.     /*
  1479.      *    It's ok for dir_part to be NULL, as _XmOSQualifyFileSpec
  1480.      *    will just use the cwd.
  1481.      */
  1482.     _XmOSQualifyFileSpec(dir_part, pattern_part,
  1483.                          &q_dir_string, &q_pattern_string);
  1484.  
  1485.     qs_data->reason = s_data->reason ;
  1486.     qs_data->event = s_data->event ;
  1487.     if (s_data->value) {
  1488.         qs_data->value = XmStringCopy(s_data->value);
  1489.     } else {
  1490.         XtVaGetValues(widget, XmNdirSpec, &xm_dir_spec, 0);
  1491.         qs_data->value = XmStringCopy(xm_dir_spec);
  1492.     }
  1493.     qs_data->length = XmStringLength(qs_data->value) ;
  1494.     q_mask_string = (String)XtMalloc(strlen(q_dir_string) +
  1495.                                      strlen(q_pattern_string) + 1);
  1496.     strcpy(q_mask_string, q_dir_string);
  1497.     strcat(q_mask_string, q_pattern_string);
  1498.     qs_data->mask = XmStringLtoRCreate(q_mask_string, XmFONTLIST_DEFAULT_TAG);
  1499.     qs_data->mask_length = XmStringLength(qs_data->mask);
  1500.     qs_data->dir = XmStringLtoRCreate(q_dir_string, XmFONTLIST_DEFAULT_TAG);
  1501.     qs_data->dir_length = XmStringLength(qs_data->dir) ;
  1502.     qs_data->pattern = XmStringLtoRCreate(q_pattern_string,
  1503.                                           XmFONTLIST_DEFAULT_TAG);
  1504.     qs_data->pattern_length = XmStringLength(qs_data->pattern);
  1505.  
  1506.     if (dir_free_string)
  1507.         XtFree(dir_free_string);
  1508.     if (pattern_free_string)
  1509.         XtFree(pattern_free_string);
  1510.     if (dir_string)
  1511.         XtFree(dir_string);
  1512.     if (pattern_string)
  1513.         XtFree(pattern_string);
  1514.     if (mask_string)
  1515.         XtFree(mask_string);
  1516.     if (q_dir_string)
  1517.         XtFree(q_dir_string);
  1518.     if (q_pattern_string)
  1519.         XtFree(q_pattern_string);
  1520.     if (q_mask_string)
  1521.         XtFree(q_mask_string);
  1522. }
  1523.  
  1524. static char* fe_file_selection_home = 0;
  1525.  
  1526. static char*
  1527. fe_file_selection_gethome()
  1528. {
  1529.     if (!fe_file_selection_home) {
  1530.         char* foo = getenv("HOME");
  1531.         char* p;
  1532.  
  1533.         if (!foo)
  1534.             foo = "/"; /* hah */
  1535.  
  1536.         fe_file_selection_home = XP_STRDUP(foo);
  1537.         
  1538.         p = strrchr(fe_file_selection_home, '/');
  1539.         if (p != NULL && p != fe_file_selection_home && p[1] == '\0')
  1540.             *p = '\0';
  1541.     }
  1542.  
  1543.     return fe_file_selection_home;
  1544. }
  1545.  
  1546. static void
  1547. fe_file_selection_dirspec_cb(Widget widget, XtPointer closure, XtPointer cb)
  1548. {
  1549.     XmTextVerifyCallbackStruct* vd = (XmTextVerifyCallbackStruct*)cb;
  1550.     Widget fsb = (Widget)closure;
  1551.     XmString xm_directory;
  1552.     String directory;
  1553.     String ptr;
  1554.  
  1555.     if (vd->startPos == 0 && vd->text->ptr != NULL) {
  1556.         if (vd->text->ptr[0] == '~') { /* expand $HOME */
  1557.  
  1558.             char* home = fe_file_selection_gethome();
  1559.  
  1560.             ptr = (String)XtMalloc(strlen(home) + strlen(vd->text->ptr) + 2);
  1561.  
  1562.             strcpy(ptr, home);
  1563.             strcat(ptr, "/");
  1564.             if (vd->text->length > 1)
  1565.                 strcat(ptr, &vd->text->ptr[1]);
  1566.  
  1567.             XtFree(vd->text->ptr);
  1568.             vd->text->ptr = ptr;
  1569.             vd->text->length = strlen(ptr);
  1570.             
  1571.         } else if (vd->text->ptr[0] != '/') {
  1572.             XtVaGetValues(fsb, XmNdirectory, &xm_directory, 0);
  1573.             if (xm_directory != NULL) {
  1574.                 directory = _XmStringGetTextConcat(xm_directory);
  1575.                 
  1576.                 ptr = (String)XtMalloc(strlen(directory) +
  1577.                                        strlen(vd->text->ptr) + 2);
  1578.                 strcpy(ptr, directory);
  1579.                 strcat(ptr, vd->text->ptr);
  1580.                 
  1581.                 XtFree(vd->text->ptr);
  1582.                 vd->text->ptr = ptr;
  1583.                 vd->text->length = strlen(ptr);
  1584.             }
  1585.         }
  1586.     }
  1587. }
  1588.  
  1589. static void
  1590. fe_file_selection_filter_cb(Widget apply, XtPointer closure, XtPointer cbd)
  1591. {
  1592.     Widget fsb = (Widget)closure;
  1593.     Widget dir = XmFileSelectionBoxGetChild(fsb, XmDIALOG_DIR_LIST);
  1594.     int*   position_list;
  1595.     int    position_count;
  1596.  
  1597.     if (XmListGetSelectedPos(dir, &position_list, &position_count)) {
  1598.  
  1599.         if (position_count == 1 && position_list[0] == 1)
  1600.             XmListSelectPos(dir, 1, True);
  1601.             
  1602.         if (position_count > 0 && position_list != NULL)
  1603.             XtFree((char*)position_list);
  1604.     }
  1605. }
  1606.  
  1607. static void
  1608. fe_file_selection_directory_up_action(Widget widget,
  1609.                                       XEvent* event,
  1610.                                       String* av, Cardinal* ac)
  1611. {
  1612.     XmString xm_directory;
  1613.     String   directory;
  1614.     String   p;
  1615.  
  1616.     while (!XtIsSubclass(widget, xmFileSelectionBoxWidgetClass)) {
  1617.         widget = XtParent(widget);
  1618.         if (!widget)
  1619.             return;
  1620.     }
  1621.  
  1622.     XtVaGetValues(widget, XmNdirectory, &xm_directory, 0);
  1623.  
  1624.     if (xm_directory != NULL) {
  1625.         int len;
  1626.  
  1627.         directory = _XmStringGetTextConcat(xm_directory);
  1628.  
  1629.         len = XP_STRLEN(directory);
  1630.  
  1631.         if (len > 0 && directory[len-1] == '/')
  1632.             directory[len-1] = '\0';
  1633.  
  1634.         if ((p = XP_STRRCHR(directory, '/')) != NULL) {
  1635.             p[1] = '\0';
  1636.  
  1637.             xm_directory = XmStringCreateSimple(directory);
  1638.  
  1639.             XtVaSetValues(widget, XmNdirectory, xm_directory, 0);
  1640.  
  1641.             XmStringFree(xm_directory);
  1642.         }
  1643.         XtFree(directory);
  1644.     }
  1645. }
  1646.  
  1647. static XtActionsRec fe_file_selection_actions[] =
  1648. {
  1649.     { "FileSelectionBoxCdDotDot", fe_file_selection_directory_up_action },
  1650. };
  1651.  
  1652. static _XmConst char fe_file_selection_accelerators[] =
  1653. "~Alt Meta<Key>osfUp:   FileSelectionBoxCdDotDot()\n"
  1654. "Alt ~Meta<Key>osfUp:   FileSelectionBoxCdDotDot()";
  1655.  
  1656. static unsigned fe_file_selection_add_actions_done;
  1657.  
  1658. static XtPointer
  1659. fe_file_selection_register_actions_mappee(Widget widget, XtPointer data)
  1660. {
  1661.     XtOverrideTranslations(widget, (XtTranslations)data);
  1662.     return 0;
  1663. }
  1664.  
  1665. static void
  1666. fe_file_selection_register_actions(Widget widget)
  1667. {
  1668.     if (!fe_file_selection_add_actions_done) {
  1669.         XtAppAddActions(fe_XtAppContext,
  1670.                         fe_file_selection_actions,
  1671.                         countof(fe_file_selection_actions));
  1672.         fe_file_selection_add_actions_done++;
  1673.     }
  1674.  
  1675.     fe_WidgetTreeWalk(widget,
  1676.                       fe_file_selection_register_actions_mappee,
  1677.                       (XtPointer) XtParseTranslationTable(fe_file_selection_accelerators));
  1678. }
  1679.  
  1680. typedef struct {
  1681.     Boolean hack;
  1682.     Boolean cde;
  1683. } fe_fsb_res_st;
  1684.  
  1685. static XtResource fe_fsb_resources[] =
  1686. {
  1687.     {
  1688.         "nsMotifFSBHacks", XtCBoolean, XtRBoolean, sizeof(Boolean),
  1689.         XtOffset(fe_fsb_res_st *, hack), XtRImmediate,
  1690. #ifdef IRIX    
  1691.         /* Irix has the nice enhanced FSB, so they don't need it */
  1692.         (XtPointer)False
  1693. #else
  1694.         (XtPointer)True
  1695. #endif
  1696.     },
  1697.     {
  1698.         "nsMotifFSBCdeMode", XtCBoolean, XtRBoolean, sizeof(Boolean),
  1699.         XtOffset(fe_fsb_res_st *, cde), XtRImmediate, (XtPointer)False
  1700.     }
  1701. };
  1702.  
  1703. typedef enum {
  1704.     FSB_LOSING,
  1705.     FSB_HACKS,
  1706.     FSB_CDE,
  1707.     FSB_CDE_PLUS
  1708. } fe_fsb_mode;
  1709.  
  1710. static fe_fsb_mode
  1711. fe_file_selection_box_get_resources(Widget parent)
  1712. {
  1713.     static Boolean done;
  1714.     static fe_fsb_res_st result;
  1715.  
  1716.     if (!done) {
  1717.         
  1718.         while (!XtIsTopLevelShell(parent))
  1719.             parent = XtParent(parent);
  1720.  
  1721.         XtGetApplicationResources(parent,
  1722.                                   (XtPointer)&result,
  1723.                                   fe_fsb_resources, XtNumber(fe_fsb_resources),
  1724.                                   0, 0);
  1725.         done++;
  1726.     }
  1727.  
  1728.     if (result.hack && result.cde)
  1729.         return FSB_CDE_PLUS;
  1730.     else if (result.hack && !result.cde)
  1731.         return FSB_HACKS;
  1732.     else if (!result.hack && result.cde)
  1733.         return FSB_CDE;
  1734.     else
  1735.         return FSB_LOSING;
  1736. }
  1737. #endif /*USE_WINNING_FILE_SELECTION*/
  1738.  
  1739. static void
  1740. fe_file_selection_save_directory_cb(Widget widget, XtPointer a, XtPointer b)
  1741. {
  1742.     XmString  xm_directory;
  1743.     XmString  xm_dirspec;
  1744.     /* And save directory default for next time */
  1745.     XtVaGetValues(widget,
  1746.                   XmNdirectory, &xm_directory,
  1747.                   XmNdirSpec, &xm_dirspec,
  1748.                   0);
  1749.  
  1750.     if (xm_dirspec != 0) {
  1751.         char* directory = _XmStringGetTextConcat(xm_dirspec);
  1752.  
  1753.         if (directory != NULL) {
  1754.             if (directory[0] == '/') {
  1755.                 
  1756.                 char* end = strrchr(directory, '/');
  1757.                 
  1758.                 if (end != NULL) {
  1759.                     if (end != directory)
  1760.                         *end = '\0';
  1761.                     
  1762.                     if (xm_directory != NULL)
  1763.                         XmStringFree(xm_directory);
  1764.                     
  1765.                     xm_directory = XmStringCreateLocalized(directory);
  1766.                 }
  1767.             }
  1768.             XtFree(directory);
  1769.         }
  1770.     }
  1771.  
  1772.     if (xm_directory != 0) {
  1773.         if (fe_file_selection_directory)
  1774.             XmStringFree(fe_file_selection_directory);
  1775.         fe_file_selection_directory = xm_directory;
  1776.     }
  1777. }
  1778.  
  1779. Widget
  1780. fe_CreateFileSelectionBox(Widget parent, char* name,
  1781.                           Arg* p_args, Cardinal p_n)
  1782. {
  1783.     Arg      args[32];
  1784.     Cardinal n;
  1785.     Cardinal i;
  1786.     Widget   fsb;
  1787.     Boolean  directory_set = FALSE;
  1788. #ifdef USE_WINNING_FILE_SELECTION
  1789.     Boolean  dir_search_set = FALSE;
  1790.     Boolean  file_search_set = FALSE;
  1791.     Boolean  qualify_set = FALSE;
  1792.     Widget   dir_list;
  1793.     Widget   file_list;
  1794.     Widget   dirspec;
  1795.     Widget   filter;
  1796.     Widget   filter_button;
  1797.     fe_fsb_mode  mode = fe_file_selection_box_get_resources(parent);
  1798. #endif /*USE_WINNING_FILE_SELECTION*/
  1799.  
  1800.     for (n = 0, i = 0; i < p_n && i < 30; i++) {    
  1801.         if (p_args[i].name == XmNdirectory)
  1802.             directory_set = TRUE;
  1803.  
  1804. #ifdef USE_WINNING_FILE_SELECTION
  1805.         if (mode == FSB_HACKS) {
  1806.             if (p_args[i].name == XmNdirSearchProc)
  1807.                 dir_search_set = TRUE;
  1808.             else if (p_args[i].name == XmNfileSearchProc)
  1809.                 file_search_set = TRUE;
  1810.             else if (p_args[i].name == XmNqualifySearchDataProc)
  1811.                 qualify_set = TRUE;
  1812.             else
  1813.                 args[n++] = p_args[i];
  1814.         }
  1815.         else
  1816. #endif /*USE_WINNING_FILE_SELECTION*/
  1817.         {
  1818.             args[n++] = p_args[i];
  1819.         }
  1820.     }
  1821.  
  1822.     /*
  1823.      *    Add last visited directory
  1824.      */
  1825.     if (!directory_set) {
  1826.         XtSetArg(args[n], XmNdirectory, fe_file_selection_directory); n++;
  1827.     }
  1828.  
  1829. #ifdef USE_WINNING_FILE_SELECTION
  1830.     if (mode == FSB_CDE || mode == FSB_CDE_PLUS) {
  1831.         XtSetArg(args[n], "pathMode", 1); n++;
  1832.     }
  1833.  
  1834.     if (mode == FSB_HACKS) {
  1835.  
  1836.         if (!dir_search_set) {
  1837.             XtSetArg(args[n], XmNdirSearchProc,
  1838.                      fe_file_selection_dir_search_proc); n++;
  1839.         }
  1840.         
  1841.         if (!file_search_set) {
  1842.             XtSetArg(args[n], XmNfileSearchProc,
  1843.                      fe_file_selection_file_search_proc); n++;
  1844.         }
  1845.         
  1846.         if (!qualify_set) {
  1847.             XtSetArg(args[n], XmNqualifySearchDataProc,
  1848.                      fe_file_selection_qualify_search_data_proc); n++;
  1849.         }
  1850.     
  1851. #ifdef FEATURE_MOTIF_FSB_CLASS_HACKING
  1852.         /*
  1853.          *    This routine is now in the Xm patches tree, as it requires
  1854.          *    access to the Motif source...djw
  1855.          */
  1856.         fe_FileSelectionBoxHackClassRecord(parent);
  1857. #endif /*FEATURE_MOTIF_FSB_CLASS_HACKING*/
  1858.  
  1859.         fsb = XmCreateFileSelectionBox(parent, name, args, n);
  1860.     
  1861.         /*
  1862.          *    XmCreateFileSelectionBox() sets directory list
  1863.          *    XmNscrollBarDisplayPolicy to STATIC which always shows
  1864.          *    the horizontal scrollbar. Bye...
  1865.          */
  1866.         dir_list = XmFileSelectionBoxGetChild(fsb, XmDIALOG_DIR_LIST);
  1867.         XtVaSetValues(dir_list, XmNscrollBarDisplayPolicy, XmAS_NEEDED, 0);
  1868.         file_list = XmFileSelectionBoxGetChild(fsb, XmDIALOG_LIST);
  1869.         XtVaSetValues(file_list, XmNscrollBarDisplayPolicy, XmAS_NEEDED, 0);
  1870.         dirspec = XmFileSelectionBoxGetChild(fsb, XmDIALOG_TEXT);
  1871.         XtAddCallback(dirspec, XmNmodifyVerifyCallback,
  1872.                       fe_file_selection_dirspec_cb, (XtPointer)fsb);
  1873.         filter = XmFileSelectionBoxGetChild(fsb, XmDIALOG_FILTER_TEXT);
  1874.         XtAddCallback(filter, XmNmodifyVerifyCallback,
  1875.                       fe_file_selection_dirspec_cb, (XtPointer)fsb);
  1876.  
  1877.     }
  1878.     else
  1879. #endif /*USE_WINNING_FILE_SELECTION*/
  1880.     {
  1881.         fsb = XmCreateFileSelectionBox(parent, name, args, n);
  1882.     }
  1883.  
  1884. #ifdef IRIX
  1885. #ifndef IRIX5_3
  1886.     /* FIX 98019
  1887.      *
  1888.      * For IRIX 6.2 and later:
  1889.      *      Reset filetype mask to suit custom Sgm file dialog.
  1890.      *      (otherwise directories don't show up in the list.)
  1891.      */
  1892.     XtVaSetValues(fsb,XmNfileTypeMask,XmFILE_ANY_TYPE,NULL);
  1893. #endif
  1894. #endif
  1895.  
  1896.  
  1897. #ifdef USE_WINNING_FILE_SELECTION
  1898.     if (mode == FSB_HACKS || mode == FSB_CDE_PLUS) {
  1899.         filter_button = XmFileSelectionBoxGetChild(fsb, XmDIALOG_APPLY_BUTTON);
  1900.         XtAddCallback(filter_button, XmNactivateCallback,
  1901.                       fe_file_selection_filter_cb, fsb);
  1902.         
  1903.         fe_file_selection_register_actions(fsb);
  1904.     }
  1905. #endif /*USE_WINNING_FILE_SELECTION*/
  1906.  
  1907.     XtAddCallback(fsb, XmNokCallback,
  1908.                   fe_file_selection_save_directory_cb, NULL);
  1909.  
  1910.     return fsb;
  1911. }
  1912.  
  1913. Widget 
  1914. fe_CreateFileSelectionDialog(Widget   parent,
  1915.                              String   name,
  1916.                              Arg*     fsb_args,
  1917.                              Cardinal fsb_n)
  1918. {   
  1919.     Widget  fsb;       /*  new fsb widget      */
  1920.     Widget  ds;        /*  DialogShell         */
  1921.     ArgList ds_args;   /*  arglist for shell  */
  1922.     char    ds_name[256];
  1923.  
  1924.     /*
  1925.      *    Create DialogShell parent.
  1926.      */
  1927.     XP_STRCPY(ds_name, name);
  1928.     XP_STRCAT(ds_name, "_popup"); /* motif compatible */
  1929.  
  1930.     ds_args = (ArgList)XtMalloc(sizeof(Arg) * (fsb_n + 1));
  1931.     XP_MEMCPY(ds_args, fsb_args, (sizeof(Arg) * fsb_n));
  1932.     XtSetArg(ds_args[fsb_n], XmNallowShellResize, True); 
  1933.     ds = XmCreateDialogShell(parent, ds_name, ds_args, fsb_n + 1);
  1934.  
  1935.     XtFree((char*)ds_args);
  1936.  
  1937.     /*
  1938.      *    Create FileSelectionBox.
  1939.      */
  1940.     fsb = fe_CreateFileSelectionBox(ds, name, fsb_args, fsb_n);
  1941.     XtAddCallback(fsb, XmNdestroyCallback, _XmDestroyParentCallback, NULL);
  1942.  
  1943.     return(fsb) ;
  1944. }
  1945.  
  1946. static void fe_file_cb (Widget, XtPointer, XtPointer);
  1947. static void fe_file_destroy_cb (Widget, XtPointer, XtPointer);
  1948. static void fe_file_type_cb (Widget, XtPointer, XtPointer);
  1949.  
  1950. #ifdef NEW_DECODERS
  1951. static void fe_file_type_hack_extension (struct fe_file_type_data *ftd);
  1952. #endif /* NEW_DECODERS */
  1953.  
  1954. /*
  1955.  * fe_ReadFilename_2
  1956.  * context:
  1957.  *    If context is non-null, it uses context's data to display the fsb.
  1958.  * iparent, filebp, ftdp:
  1959.  *    If context is NULL, then this uses these to create the file
  1960.  *    selection box.
  1961.  *    'iparent' is the parent shell under which the FSB will be created.
  1962.  *    'filebp' is a pointer to the file selection box widget. [CANT BE NULL]
  1963.  *    'ftdp' is a pointer to file type data used by FSB code. [CANT BE NULL]
  1964.  *        We allocate one and return it back to the caller.
  1965.  *        Everytime we are called with the same filebp, we need to
  1966.  *         be called with the same ftdp.
  1967.  *
  1968.  * WARNING:    1. Allocates *ftdp
  1969.  *        2. filebp and ftdp go together. For every filebp we need to
  1970.  *           use the ftdp that was created with it.
  1971.  *
  1972.  * Just another form of fe_ReadFileName() so that other parts of fe
  1973.  * eg. bookmarks can use this as they dont have a context and I
  1974.  * think making a dummy context is bad.
  1975.  * - dp
  1976.  *
  1977.  * Akkana note: bug 82924 was fixed in FE_PromptForFileName()
  1978.  * (in src/context_funcs.cpp), but has not yet been fixed here.
  1979.  * The three filename prompting routines need to be integrated into one;
  1980.  * see comment under FE_PromptForFileName().
  1981.  */
  1982. char *
  1983. fe_ReadFileName_2 (    MWContext* context,
  1984.             Widget iparent, Widget* filebp,
  1985.             struct fe_file_type_data **ftdp,
  1986.             const char *title, const char *default_url,
  1987.             Boolean must_match, int *save_as_type)
  1988. {
  1989.   Widget fileb;
  1990.   struct fe_file_type_data *ftd;
  1991.   struct fe_confirm_data data;
  1992.   Widget sabox, samenu, sabutton;
  1993.  
  1994.   if (context) {
  1995.     fileb = CONTEXT_DATA (context)->file_dialog;
  1996.     ftd = CONTEXT_DATA (context)->ftd;
  1997.   }
  1998.   else {
  1999.     fileb = *filebp;
  2000.     ftd = *ftdp;
  2001.   }
  2002.  
  2003.   if (! title) title = XP_GetString(XFE_OPEN_FILE);
  2004.  
  2005.   if (! fileb)
  2006.     {
  2007.       Arg av [20];
  2008.       int ac, i;
  2009.       Widget shell;
  2010.       Widget parent;
  2011.       Visual *v = 0;
  2012.       Colormap cmap = 0;
  2013.       Cardinal depth = 0;
  2014.  
  2015.       if (context) parent = CONTEXT_WIDGET (context);
  2016.       else parent = iparent;
  2017.  
  2018.       XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  2019.              XtNdepth, &depth, 0);
  2020.  
  2021.       ac = 0;
  2022.       XtSetArg (av[ac], XmNvisual, v); ac++;
  2023.       XtSetArg (av[ac], XmNdepth, depth); ac++;
  2024.       XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  2025.       XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  2026. /*      XtSetArg (av[ac], XmNallowShellResize, True); ac++;*/
  2027.       shell = XmCreateDialogShell (parent, "fileSelector_popup", av, ac);
  2028.       ac = 0;
  2029.       XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);
  2030.       ac++;
  2031.       ftd = (struct fe_file_type_data *)
  2032.     calloc (sizeof (struct fe_file_type_data), 1);
  2033.       if (context) CONTEXT_DATA (context)->ftd = ftd;
  2034.       else *ftdp = ftd;
  2035.       XtSetArg (av[ac], XmNuserData, ftd); ac++;
  2036.       fileb = fe_CreateFileSelectionBox (shell, "fileSelector", av, ac);
  2037.  
  2038. #ifdef NO_HELP
  2039.       fe_UnmanageChild_safe (XtNameToWidget (fileb, "*Help"));
  2040. #endif
  2041.  
  2042.       ac = 0;
  2043.       XtSetArg (av[ac], XmNvisual, v); ac++;
  2044.       XtSetArg (av[ac], XmNdepth, depth); ac++;
  2045.       XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  2046.       sabox = XmCreateFrame (fileb, "frame", av, ac);
  2047.       samenu = XmCreatePulldownMenu (sabox, "formatType", av, ac);
  2048.       ac = 0;
  2049.  
  2050. #ifdef NEW_DECODERS
  2051.       ftd->fileb = fileb;
  2052. #endif /* NEW_DECODERS */
  2053.       ftd->options [fe_FILE_TYPE_TEXT] =
  2054.     XmCreatePushButtonGadget (samenu, "text", av, ac);
  2055.       ftd->options [fe_FILE_TYPE_HTML] =
  2056.     XmCreatePushButtonGadget (samenu, "html", av, ac);
  2057. #ifdef SAVE_ALL
  2058.       ftd->options [fe_FILE_TYPE_HTML_AND_IMAGES] =
  2059.     XmCreatePushButtonGadget (samenu, "tree", av, ac);
  2060. #endif /* SAVE_ALL */
  2061.       ftd->options [fe_FILE_TYPE_PS] =
  2062.     XmCreatePushButtonGadget (samenu, "ps", av, ac);
  2063. /*       ftd->selected_option = fe_FILE_TYPE_TEXT; */
  2064.       /* Make the default "save as" type html (ie, source) */
  2065.       ftd->selected_option = fe_FILE_TYPE_HTML;
  2066.       XtVaSetValues (samenu, XmNmenuHistory,
  2067.              ftd->options [ftd->selected_option], 0);
  2068.       ac = 0;
  2069.       XtSetArg (av [ac], XmNsubMenuId, samenu); ac++;
  2070.       sabutton = fe_CreateOptionMenu (sabox, "formatType", av, ac);
  2071.       for (i = 0; i < countof (ftd->options); i++)
  2072.     if (ftd->options[i])
  2073.       {
  2074.         XtAddCallback (ftd->options[i], XmNactivateCallback,
  2075.                fe_file_type_cb, ftd);
  2076.         XtManageChild (ftd->options[i]);
  2077.       }
  2078.       XtManageChild (sabutton);
  2079.  
  2080.       if (context) CONTEXT_DATA (context)->file_dialog = fileb;
  2081.       else *filebp = fileb;
  2082.  
  2083.       fe_HackDialogTranslations (fileb);
  2084.     }
  2085.   else
  2086.     {
  2087.       /* Without this the "*fileSelector.width:" resource doesn't work
  2088.      on subsequent invocations of this box.  Don't ask me why.  I
  2089.      tried permutations of allowShellResize as well with no effect.
  2090.      (It's better to keep the widgets themselves around, if not the
  2091.      windows, so that the default text is persistent.)
  2092.        */
  2093. #if 0
  2094.       XtUnrealizeWidget (fileb);
  2095. #endif
  2096.       sabox = XtNameToWidget (fileb, "*frame");
  2097.  
  2098.       /*
  2099.        *    Restore the values saved in fe_file_selection_save_directory_cb()
  2100.        */
  2101.       if (fe_file_selection_directory != 0) {
  2102.           XtVaSetValues(fileb, XmNdirectory, fe_file_selection_directory, 0);
  2103.       }
  2104.     }
  2105.  
  2106. #ifdef NEW_DECODERS
  2107.   ftd->orig_url = default_url;
  2108.   ftd->conversion_allowed_p = (save_as_type != 0);
  2109. #endif /* NEW_DECODERS */
  2110.  
  2111. #ifdef NO_HELP
  2112.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (fileb, XmDIALOG_HELP_BUTTON));
  2113. #endif
  2114.  
  2115.   XtRemoveAllCallbacks (fileb, XmNnoMatchCallback);
  2116.   XtRemoveAllCallbacks (fileb, XmNokCallback);
  2117.   XtRemoveAllCallbacks (fileb, XmNapplyCallback);
  2118.   XtRemoveAllCallbacks (fileb, XmNcancelCallback);
  2119.   XtRemoveAllCallbacks (fileb, XmNdestroyCallback);
  2120.  
  2121.   XtAddCallback (fileb, XmNnoMatchCallback, fe_file_cb, &data);
  2122.   XtAddCallback (fileb, XmNokCallback,      fe_file_cb, &data);
  2123.   XtAddCallback (fileb, XmNcancelCallback,  fe_file_cb, &data);
  2124.   XtAddCallback (fileb, XmNdestroyCallback, fe_file_destroy_cb, &data);
  2125.  
  2126.   XtVaSetValues (XtParent (fileb), XmNtitle, title, 0);
  2127. #if 0 /* mustMatch doesn't work! */
  2128.   XtVaSetValues (fileb, XmNmustMatch, must_match, 0);
  2129. #else
  2130.   XtVaSetValues (fileb, XmNmustMatch, False, 0);
  2131.   data.must_match = must_match;
  2132. #endif
  2133.  
  2134.   {
  2135.     String dirmask = 0;
  2136.     XmString xms;
  2137.     char *s, *tail;
  2138.     char buf [2048];
  2139.     const char *def;
  2140.  
  2141.     if (! default_url)
  2142.       def = 0;
  2143.     else if ((def = strrchr (default_url, '/')))
  2144.       def++;
  2145.     else
  2146.       def = default_url;
  2147.  
  2148.     XtVaGetValues (fileb, XmNdirSpec, &xms, 0);
  2149.     XmStringGetLtoR (xms, XmFONTLIST_DEFAULT_TAG, &s); /* s - is XtMalloc  */
  2150.     XmStringFree (xms);
  2151.  
  2152.     /* Take the file name part off of `s', leaving only the dir. */
  2153.     tail = strrchr (s, '/');
  2154.     if (tail) *tail = 0;
  2155.  
  2156.     PR_snprintf (buf, sizeof (buf), "%.900s/%.900s", s, (def ? def : ""));
  2157.     if (def)
  2158.       {
  2159.     /* Grab the file name part (it's sitting right after the end of `s')
  2160.        and map out the characters which ought not go into file names.
  2161.        Also, terminate the file name at ? or #, since those aren't
  2162.        really a part of the URL's file, but are modifiers to it.
  2163.      */
  2164.     for (tail = buf+strlen(s)+1; *tail; tail++)
  2165.       if (*tail == '?' || *tail == '#')
  2166.         *tail = 0;
  2167.       else if (*tail < '+' || *tail > 'z' ||
  2168.            *tail == ':' || *tail == ';' ||
  2169.            *tail == '<' || *tail == '>' ||
  2170.            *tail == '\\' || *tail == '^' ||
  2171.            *tail == '\'' || *tail == '`' ||
  2172.            *tail == ',')
  2173.         *tail = '_';
  2174.       }
  2175.     XtFree (s);
  2176.  
  2177.     /* If the dialog already existed, its data is out of date.  Resync. */
  2178.     XtVaGetValues (fileb, XmNdirMask, &dirmask, 0);
  2179.     XmFileSelectionDoSearch (fileb, dirmask);
  2180.  
  2181.     /* Change the default file name. */
  2182.     xms = XmStringCreate (buf, XmFONTLIST_DEFAULT_TAG);
  2183.     XtVaSetValues (fileb, XmNdirSpec, xms, 0);
  2184.     XmStringFree (xms);
  2185.  
  2186. #ifdef NEW_DECODERS
  2187.     fe_file_type_hack_extension (ftd);
  2188. #endif /* NEW_DECODERS */
  2189.   }
  2190.  
  2191.   data.context = context;
  2192.   data.answer = Answer_Invalid;
  2193.   data.return_value = 0;
  2194.  
  2195.   if (save_as_type)
  2196.     XtManageChild (sabox);
  2197.   else
  2198.     XtUnmanageChild (sabox);
  2199.  
  2200.   fe_NukeBackingStore (fileb);
  2201.   XtManageChild (fileb);
  2202.   /* #### check for unmanagement here */
  2203.   while (data.answer == Answer_Invalid)
  2204.     fe_EventLoop ();
  2205.  
  2206.   if (data.answer != Answer_Destroy) {
  2207.     /* Call the ok -> save directory callback because it's been removed */
  2208.     fe_file_selection_save_directory_cb(fileb, NULL, NULL);
  2209.     XtUnmanageChild(fileb);
  2210.     XtRemoveCallback(fileb, XmNdestroyCallback, fe_file_destroy_cb, &data);
  2211.   }
  2212.  
  2213.  
  2214.   if (save_as_type)
  2215.     *save_as_type = ftd->selected_option;
  2216.  
  2217.   if (data.answer == Answer_Destroy) {
  2218.     if (!data.context) {
  2219.       XP_ASSERT(filebp && ftdp);
  2220.       *filebp = 0;
  2221.       *ftdp = 0;
  2222.     }
  2223.     if (ftd) {
  2224.       /*
  2225.        * If the context got destroyed, this could have been freed by the
  2226.        * context. Our destroy routine checks for the parent context being
  2227.        * freed and sets the return_value to -1 if the context was destroyed.
  2228.        */
  2229.       if (data.return_value != (void *)-1)
  2230.     XP_FREE(ftd);
  2231.     }
  2232.     data.answer = Answer_Cancel; /* Simulate CANCEL */
  2233.     data.return_value = 0;
  2234.   }
  2235.  
  2236.   return (char *) data.return_value;
  2237. }
  2238.  
  2239. char *
  2240. fe_ReadFileName (MWContext *context, const char *title,
  2241.          const char *default_url,
  2242.          Boolean must_match,
  2243.          int *save_as_type)
  2244. {
  2245.   char *ret = NULL;
  2246.  
  2247.   fe_ProtectContext(context);
  2248.   ret = fe_ReadFileName_2( context, NULL, NULL, NULL,
  2249.                title, default_url, must_match, save_as_type);
  2250.   fe_UnProtectContext(context);
  2251.   if (fe_IsContextDestroyed(context)) {
  2252.     free(CONTEXT_DATA(context));
  2253.     free(context);
  2254.   }
  2255.   return ret;
  2256. }
  2257.  
  2258.  
  2259. static void 
  2260. fe_file_destroy_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2261. {
  2262.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  2263.   if (data->answer == Answer_Invalid) {
  2264.     data->answer = Answer_Destroy;
  2265.     /* Reset the context file dialog storage. Be sure that this destroy isnt
  2266.      * a result of the context itself being destroyed.
  2267.      */
  2268.     if (data->context)
  2269.     if (!XfeIsAlive(CONTEXT_WIDGET(data->context))) {
  2270.     /* Indicates the context was destroyed too */
  2271.     data->return_value = (void *)-1;
  2272.       }
  2273.       else {
  2274.     CONTEXT_DATA(data->context)->file_dialog = 0;
  2275.     CONTEXT_DATA(data->context)->ftd = 0;
  2276.       }
  2277.   }
  2278. }
  2279.  
  2280. static void 
  2281. fe_file_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2282. {
  2283.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  2284.   XmFileSelectionBoxCallbackStruct *sbc =
  2285.     (XmFileSelectionBoxCallbackStruct *) call_data;
  2286.  
  2287.   switch (sbc->reason)
  2288.     {
  2289.     case XmCR_NO_MATCH:
  2290.       {
  2291.     NOMATCH:
  2292.     XBell (XtDisplay (widget), 0);
  2293.     break;
  2294.       }
  2295.     case XmCR_OK:
  2296.       {
  2297.     XmStringGetLtoR (sbc->value, XmFONTLIST_DEFAULT_TAG,
  2298.              (char **) &data->return_value);
  2299. #if 1
  2300.     /* mustMatch doesn't work!! */
  2301.     {
  2302.       struct stat st;
  2303.       if (data->must_match &&
  2304.           data->return_value &&
  2305.           stat (data->return_value, &st))
  2306.         {
  2307.           free (data->return_value);
  2308.           data->return_value = 0;
  2309.           goto NOMATCH;
  2310.         }
  2311.     }
  2312. #endif
  2313.     data->answer = Answer_OK;
  2314.     break;
  2315.       }
  2316.     case XmCR_CANCEL:
  2317.       {
  2318.     data->answer = Answer_Cancel;
  2319.     data->return_value = 0;
  2320.     break;
  2321.       }
  2322.     default:
  2323.       abort ();
  2324.     }
  2325. }
  2326.  
  2327. static void
  2328. fe_file_type_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2329. {
  2330.   struct fe_file_type_data *ftd = (struct fe_file_type_data *) closure;
  2331.   int i;
  2332.   ftd->selected_option = -1;
  2333.   for (i = 0; i < countof (ftd->options); i++)
  2334.     if (ftd->options [i] == widget)
  2335.       {
  2336.     ftd->selected_option = i;
  2337.     break;
  2338.       }
  2339. #ifdef NEW_DECODERS
  2340.   fe_file_type_hack_extension (ftd);
  2341. #endif /* NEW_DECODERS */
  2342. }
  2343.  
  2344. #ifdef NEW_DECODERS
  2345. static void
  2346. fe_file_type_hack_extension_1 (struct fe_file_type_data *ftd,
  2347.                    Boolean dirspec_p)
  2348. {
  2349.   int desired_type;
  2350.   const char *default_file_name = "index.html";
  2351.   XmString xm_file = 0;
  2352.   char *file = 0;
  2353.   char *name_part = 0;
  2354.   char *ext = 0;
  2355.   char *orig_ext = 0;
  2356.   const char *new_ext = 0;
  2357.   char *orig_url_copy = 0;
  2358.  
  2359.   if (!ftd || !ftd->fileb)
  2360.     return;
  2361.  
  2362.   if (ftd->conversion_allowed_p)
  2363.     desired_type = ftd->selected_option;
  2364.   else
  2365.     desired_type = fe_FILE_TYPE_HTML;
  2366.  
  2367.   /* Find a default file name.
  2368.      If this URL ends in a file part, use that, otherwise, assume "index.html".
  2369.      Then, once we've got a default file name, set the default extension to
  2370.      use for "Save As Source" from that.
  2371.    */
  2372.   if (ftd->orig_url)
  2373.     {
  2374.       const char *orig_name_part;
  2375.       char *s;
  2376.  
  2377.       orig_url_copy = strdup (ftd->orig_url);
  2378.  
  2379.       /* take off form and anchor data. */
  2380.       if ((s = strchr (orig_url_copy, '?')))
  2381.     *s = 0;
  2382.       if ((s = strchr (orig_url_copy, '#')))
  2383.     *s = 0;
  2384.  
  2385.       orig_name_part = strrchr (orig_url_copy, '/');
  2386.       if (! orig_name_part)
  2387.     orig_name_part = strrchr (orig_url_copy, ':');
  2388.       if (orig_name_part)
  2389.     orig_name_part++;
  2390.       else if (orig_url_copy && *orig_url_copy)
  2391.     orig_name_part = orig_url_copy;
  2392.  
  2393.       if (orig_name_part && *orig_name_part)
  2394.     default_file_name = orig_name_part;
  2395.  
  2396.       orig_ext = strrchr (default_file_name, '.');
  2397.  
  2398.       if (!orig_ext && !dirspec_p)
  2399.     {
  2400.       /* If we're up in the filter area, and there is as yet no
  2401.          orig_ext, then that means that there was file name without
  2402.          an extension (as opposed to no file name, when we would
  2403.          have defaulted to "index.html".)  So, for the purposes
  2404.          of the filter, set the extension to ".*".
  2405.        */
  2406.       orig_ext = ".*";
  2407.     }
  2408.     }
  2409.  
  2410.   /* Get `file' from what's currently typed into the text field.
  2411.    */
  2412.   XtVaGetValues (ftd->fileb,
  2413.          (dirspec_p ? XmNdirSpec : XmNdirMask), &xm_file, 0);
  2414.   if (! xm_file) return;
  2415.   XmStringGetLtoR (xm_file, XmFONTLIST_DEFAULT_TAG, &file); /* file- XtMalloc */
  2416.   XmStringFree (xm_file);
  2417.  
  2418.   /* If the file ends in "/" then stick the default file name on the end. */
  2419.   if (dirspec_p && file && *file && file [strlen (file) - 1] == '/')
  2420.     {
  2421.       char *file2 = (char *) malloc (strlen (file) +
  2422.                      strlen (default_file_name) + 1);
  2423.       strcpy (file2, file);
  2424.       strcat (file2, default_file_name);
  2425.       XtFree (file);
  2426.       file = file2;
  2427.     }
  2428.  
  2429.   name_part = strrchr (file, '/');
  2430.   if (! name_part)
  2431.     name_part = strrchr (file, ':');
  2432.   if (name_part)
  2433.     name_part++;
  2434.  
  2435.   if (!name_part || !*name_part)
  2436.     name_part = 0;
  2437.  
  2438.   if (name_part)
  2439.     ext = strrchr (name_part, '.');
  2440.  
  2441.   switch (desired_type)
  2442.     {
  2443.     case fe_FILE_TYPE_HTML:
  2444.     case fe_FILE_TYPE_HTML_AND_IMAGES:
  2445.       new_ext = orig_ext;
  2446.       break;
  2447.     case fe_FILE_TYPE_TEXT:
  2448.     case fe_FILE_TYPE_FORMATTED_TEXT:
  2449.       /* The user has selected "text".  Change the extension to "txt"
  2450.      only if the original URL had extension "html" or "htm". */
  2451.       if (orig_ext &&
  2452.       (!strcasecomp (orig_ext, ".html") ||
  2453.        !strcasecomp (orig_ext, ".htm")))
  2454.     new_ext = ".txt";
  2455.       else
  2456.     new_ext = orig_ext;
  2457.       break;
  2458.     case fe_FILE_TYPE_PS:
  2459.       new_ext = ".ps";
  2460.       break;
  2461.     default:
  2462.       break;
  2463.     }
  2464.  
  2465.   if (ext && new_ext /* && !!strcasecomp (ext, new_ext) */ )
  2466.     {
  2467.       char *file2;
  2468.       *ext = 0;
  2469.       file2 = (char *) malloc (strlen (file) + strlen (new_ext) + 1);
  2470.       strcpy (file2, file);
  2471.       strcat (file2, new_ext);
  2472.       xm_file = XmStringCreateLtoR (file2, XmFONTLIST_DEFAULT_TAG);
  2473.  
  2474.       if (dirspec_p)
  2475.     {
  2476.       XtVaSetValues (ftd->fileb, XmNdirSpec, xm_file, 0);
  2477.     }
  2478.       else
  2479.     {
  2480.       XmString saved_value = 0;
  2481.  
  2482.       /* Don't let what's currently typed into the `Selection' field
  2483.          to change as a result of running this search again -- that's
  2484.          totally bogus. */
  2485.       XtVaGetValues (ftd->fileb, XmNdirSpec, &saved_value, 0);
  2486.  
  2487.       XtVaSetValues (ftd->fileb, XmNdirMask, xm_file, 0);
  2488.       XmFileSelectionDoSearch (ftd->fileb, xm_file);
  2489.       if (saved_value)
  2490.         {
  2491.           XtVaSetValues (ftd->fileb, XmNdirSpec, saved_value, 0);
  2492.           XmStringFree (saved_value);
  2493.         }
  2494.     }
  2495.  
  2496.       XmStringFree (xm_file);
  2497.       free (file2);
  2498.     }
  2499.  
  2500.   if (orig_url_copy)
  2501.     free (orig_url_copy);
  2502.  
  2503.   XtFree (file);
  2504. }
  2505.  
  2506.  
  2507. static void
  2508. fe_file_type_hack_extension (struct fe_file_type_data *ftd)
  2509. {
  2510.   fe_file_type_hack_extension_1 (ftd, False);
  2511.   fe_file_type_hack_extension_1 (ftd, True);
  2512. }
  2513.  
  2514. #endif /* NEW_DECODERS */
  2515.  
  2516.  
  2517.  
  2518. /* Open URL - prompts asynchronously
  2519.  */
  2520.  
  2521. static char *last_open_url_text = 0;
  2522.  
  2523. struct fe_open_url_data {
  2524.   MWContext *context;
  2525.   Widget widget;
  2526.   Widget text;
  2527. #ifdef EDITOR
  2528.   Widget in_editor;
  2529. #endif
  2530.   Widget in_browser;
  2531. };
  2532.  
  2533. static char*
  2534. cleanup_selection(char* target, char* source, unsigned max_size)
  2535. {
  2536.     char* p;
  2537.     char* q;
  2538.     char* end;
  2539.  
  2540.     for (p = source; isspace(*p); p++) /* skip beginning whitespace */
  2541.         ;
  2542.  
  2543.     end = &p[max_size-1];
  2544.     q = target;
  2545.  
  2546.     while (p < end) {
  2547.         /*
  2548.          *    Stop if we detect an unprintable, or newline.
  2549.          */
  2550.         if (!isprint(*p) || *p == '\n' || *p == '\r')
  2551.             break;
  2552.  
  2553.         if (isspace(*p))
  2554.             *q++ = ' ', p++;
  2555.         else
  2556.             *q++ = *p++;
  2557.     }
  2558.     /* strip trailing whitespace */
  2559.     while (q > target && isspace(q[-1]))
  2560.         q--;
  2561.      
  2562.     *q = '\0';
  2563.  
  2564.     return target;
  2565. }
  2566.  
  2567. static void
  2568. file_dialog_get_url(MWContext* context, char* address, MWContextType ge_type)
  2569. {
  2570.     if (address != NULL) {
  2571.         if (ge_type == MWContextBrowser) {
  2572.             fe_BrowserGetURL(context, address);
  2573.         }
  2574. #ifdef EDITOR
  2575.         else if (ge_type == MWContextEditor) {
  2576.             fe_EditorEdit(context, NULL, NULL, address); /* try to re-use */
  2577.         }
  2578. #endif
  2579.     }
  2580. }
  2581.  
  2582. static void
  2583. fe_open_url_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2584. {
  2585.     struct fe_open_url_data *data = (struct fe_open_url_data *) closure;
  2586.     char*  text = NULL;
  2587.     MWContext* context;
  2588.     MWContextType ge_type = MWContextAny;
  2589.  
  2590.     if (call_data == NULL ||    /* when it's a destroy callback */
  2591.         !XfeIsAlive(widget) || /* on it's way */
  2592.         data == NULL)                         /* data from hell */
  2593.         return;
  2594.     
  2595.     context = data->context;
  2596.  
  2597.     if (widget == data->in_browser
  2598. #ifdef EDITOR
  2599.         || widget == data->in_editor
  2600. #endif
  2601.         ) {
  2602.  
  2603.         text = fe_GetTextField(data->text);
  2604.  
  2605.         if (! text)
  2606.             return;
  2607.         
  2608.         cleanup_selection(text, text, strlen(text)+1);
  2609.  
  2610.         if (*text != '\0') {
  2611.  
  2612.             if (last_open_url_text)
  2613.                 XtFree(last_open_url_text);
  2614.  
  2615.             last_open_url_text = text;
  2616.             
  2617.             if (widget == data->in_browser) 
  2618.               ge_type = MWContextBrowser;
  2619. #ifdef EDITOR
  2620.             else if (widget == data->in_editor)
  2621.               ge_type = MWContextEditor;
  2622. #endif
  2623.         }
  2624.     }
  2625.  
  2626.     XtUnmanageChild(data->widget);
  2627.     XtDestroyWidget(data->widget);
  2628.     free(data);
  2629.  
  2630.     /*
  2631.      *    Call common routine to divert the get_url()
  2632.      */
  2633.     file_dialog_get_url(context, text, ge_type);
  2634. }
  2635.  
  2636. static void
  2637. fe_open_url_browse_cb(Widget widget, XtPointer closure, XtPointer call_data)
  2638. {
  2639.     struct fe_open_url_data* data = (struct fe_open_url_data *)closure;
  2640.  
  2641.     fe_browse_file_of_text(data->context, data->text, False);
  2642. }
  2643.  
  2644. void
  2645. fe_OpenURLDialog(MWContext* context)
  2646. {
  2647.     struct fe_open_url_data *data;
  2648.     Widget dialog;
  2649.     Widget label;
  2650.     Widget text;
  2651.     Widget in_browser;
  2652. #ifdef EDITOR
  2653.     Widget in_editor;
  2654. #endif
  2655.     Widget form;
  2656.     Widget browse;
  2657.     Arg    args[20];
  2658.     int    n;
  2659.     char*  string;
  2660.  
  2661.     dialog = fe_CreatePromptDialog(context, "openURLDialog",
  2662.                                    FALSE, TRUE, TRUE, TRUE, TRUE);
  2663.  
  2664.     n = 0;
  2665.     form = XmCreateForm(dialog, "form", args, n);
  2666.     XtManageChild(form);
  2667.  
  2668.     n = 0;
  2669.     XtSetArg(args [n], XmNleftAttachment, XmATTACH_FORM); n++;
  2670.     XtSetArg(args [n], XmNtopAttachment, XmATTACH_FORM); n++;
  2671.     XtSetArg(args [n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  2672.     label = XmCreateLabelGadget(form, "label", args, n);
  2673.     XtManageChild(label);
  2674.  
  2675.     n = 0;
  2676.     XtSetArg(args [n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  2677.     XtSetArg(args [n], XmNtopWidget, label); n++;
  2678.     XtSetArg(args [n], XmNrightAttachment, XmATTACH_FORM); n++;
  2679.     XtSetArg(args [n], XmNbottomAttachment, XmATTACH_FORM); n++;
  2680.     browse = XmCreatePushButtonGadget(form, "choose", args, n);
  2681.     XtManageChild(browse);
  2682.  
  2683.     string = last_open_url_text? last_open_url_text : "";
  2684.  
  2685.     n = 0;
  2686.     XtSetArg(args [n], XmNleftAttachment, XmATTACH_FORM); n++;
  2687.     XtSetArg(args [n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  2688.     XtSetArg(args [n], XmNtopWidget, label); n++;
  2689.     XtSetArg(args [n], XmNrightAttachment, XmATTACH_WIDGET); n++;
  2690.     XtSetArg(args [n], XmNrightWidget, browse); n++;
  2691.     XtSetArg(args [n], XmNbottomAttachment, XmATTACH_FORM); n++;
  2692.     XtSetArg(args [n], XmNeditable, True); n++;
  2693.     XtSetArg(args [n], XmNcursorPositionVisible, True); n++;
  2694.     text = fe_CreateTextField(form, "openURLText", args, n);
  2695.     fe_SetTextField(text, string);
  2696.     XtManageChild(text);
  2697.  
  2698.     n = 0;
  2699. #ifdef MOZ_MAIL_NEWS
  2700.     in_browser = XmCreatePushButtonGadget(dialog, "openInBrowser", args, n);
  2701. #else
  2702.     in_browser = XmCreatePushButtonGadget(dialog, "OK", args, n);
  2703. #endif
  2704.     XtManageChild(in_browser);
  2705.  
  2706. #ifdef EDITOR
  2707.     n = 0;
  2708.     XtSetArg(args[n], XmNsensitive, !fe_IsEditorDisabled()); n++;
  2709.     in_editor = XmCreatePushButtonGadget(dialog, "openInEditor", args, n);
  2710.     XtManageChild(in_editor);
  2711. #endif
  2712.  
  2713.     data = (struct fe_open_url_data *)calloc(sizeof(struct fe_open_url_data), 1);
  2714.     data->context = context;
  2715.     data->widget = dialog;
  2716.     data->text = text;
  2717.     data->in_browser = in_browser;
  2718. #ifdef EDITOR
  2719.     data->in_editor = in_editor;
  2720.  
  2721.     if (context->type == MWContextEditor)
  2722.         XtVaSetValues(dialog, XmNdefaultButton, in_editor, 0);
  2723.     else
  2724. #endif
  2725.         XtVaSetValues(dialog, XmNdefaultButton, in_browser, 0);
  2726.  
  2727.     XtAddCallback(browse, XmNactivateCallback,fe_open_url_browse_cb, data);
  2728. #ifdef EDITOR
  2729.     XtAddCallback(in_editor, XmNactivateCallback, fe_open_url_cb, data);
  2730. #endif
  2731.     XtAddCallback(in_browser, XmNactivateCallback, fe_open_url_cb, data);
  2732.     XtAddCallback(dialog, XmNcancelCallback, fe_open_url_cb, data);
  2733.     XtAddCallback(dialog, XmNdestroyCallback, fe_open_url_cb, data);
  2734.     XtAddCallback(dialog, XmNapplyCallback, fe_clear_text_cb, text);
  2735.     
  2736.     fe_NukeBackingStore (dialog);
  2737.     XtManageChild (dialog);
  2738. }
  2739.  
  2740. void
  2741. fe_OpenURLChooseFileDialog (MWContext *context)
  2742. {
  2743.     char *text;
  2744.  
  2745.     if (!context) return;
  2746.  
  2747.     text = fe_ReadFileName (context,         
  2748.                             XP_GetString(XFE_OPEN_FILE),
  2749.                             last_open_url_text,
  2750.                             FALSE, /* must match */
  2751.                             0); /* save_as_type */
  2752.  
  2753.     file_dialog_get_url(context, text, context->type);
  2754. }
  2755.  
  2756.  
  2757.  
  2758.  
  2759. /* Prompt the user for their password.  The message string is displayed
  2760.  * to the user so they know what they are giving their password for.
  2761.  * The characters of the password are not echoed.
  2762.  */
  2763. char *
  2764. XFE_PromptPassword (MWContext *context, const char *message)
  2765. {
  2766.   return (char *) fe_dialog (CONTEXT_WIDGET (context),
  2767.                  "password", message, TRUE, "", TRUE, FALSE,
  2768.                  ((char **) 1));
  2769. }
  2770.  
  2771. /* Prompt for a  username and password
  2772.  *
  2773.  * message is a prompt message.
  2774.  *
  2775.  * if username and password are not NULL they should be used
  2776.  * as default values and NOT MODIFIED.  New values should be malloc'd
  2777.  * and put in their place.
  2778.  *
  2779.  * If the User hit's cancel FALSE should be returned, otherwise
  2780.  * TRUE should be returned.
  2781.  */
  2782. XP_Bool
  2783. XFE_PromptUsernameAndPassword (MWContext *context, 
  2784.                   const char *message,
  2785.                   char **username,
  2786.                   char **password)
  2787.   char *pw = "";
  2788.   char *un = (char *) fe_dialog (CONTEXT_WIDGET (context),
  2789.                  "password", message, TRUE,
  2790.                  (*username ? *username : ""), TRUE, FALSE,
  2791.                  &pw);
  2792.   if (pw)
  2793.     {
  2794.       *username = un;
  2795.       *password = XP_STRDUP(pw);
  2796.       return(TRUE);
  2797.     }
  2798.   else
  2799.     {
  2800.       *username = 0;
  2801.       *password = 0;
  2802.       return(FALSE);
  2803.     }
  2804. }
  2805.  
  2806.  
  2807.  
  2808. /* Prompting for visuals
  2809.  */
  2810.  
  2811. static void fe_visual_cb (Widget, XtPointer, XtPointer);
  2812.  
  2813. Visual *
  2814. fe_ReadVisual (MWContext *context)
  2815. {
  2816.   Widget mainw = CONTEXT_WIDGET (context);
  2817.   Display *dpy = XtDisplay (mainw);
  2818.   Screen *screen = XtScreen (mainw);
  2819.   Arg av [20];
  2820.   int ac;
  2821.   int i;
  2822.   Widget shell;
  2823.   XmString *items;
  2824.   int item_count;
  2825.   int default_item = 0;
  2826.   XVisualInfo vi_in, *vi_out;
  2827.   struct fe_confirm_data data;
  2828.   Visual *v = 0;
  2829.   Colormap cmap = 0;
  2830.   Cardinal depth = 0;
  2831.  
  2832.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  2833.          XtNdepth, &depth, 0);
  2834.  
  2835.   vi_in.screen = fe_ScreenNumber (screen);
  2836.   vi_out = XGetVisualInfo (dpy, VisualScreenMask, &vi_in, &item_count);
  2837.   if (! vi_out) item_count = 0;
  2838.   items = (XmString *) calloc (sizeof (XmString), item_count + 1);
  2839.   for (i = 0; i < item_count; i++)
  2840.     {
  2841.       char *vdesc = fe_VisualDescription (screen, vi_out [i].visual);
  2842.       items[i] = XmStringCreate (vdesc, XmFONTLIST_DEFAULT_TAG);
  2843.       free (vdesc);
  2844.       if (vi_out [i].visual == v)
  2845.     default_item = i;
  2846.     }
  2847.  
  2848.   ac = 0;
  2849.   XtSetArg (av[ac], XmNvisual, v); ac++;
  2850.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  2851.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  2852.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  2853.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  2854.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  2855.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  2856. /*  XtSetArg (av[ac], XmNautoUnmanage, False); ac++;*/
  2857.   XtSetArg (av[ac], XmNlistItems, items); ac++;
  2858.   XtSetArg (av[ac], XmNlistItemCount, item_count); ac++;
  2859.   shell = XmCreateSelectionDialog (mainw, "visual", av, ac);
  2860.  
  2861.   XtAddCallback (shell, XmNokCallback, fe_visual_cb, &data);
  2862.   XtAddCallback (shell, XmNcancelCallback, fe_visual_cb, &data);
  2863.   XtAddCallback (shell, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  2864.  
  2865.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_APPLY_BUTTON));
  2866.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_SEPARATOR));
  2867.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_TEXT));
  2868.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell,
  2869.                         XmDIALOG_SELECTION_LABEL));
  2870.  
  2871.   {
  2872.     Widget list = XmSelectionBoxGetChild (shell, XmDIALOG_LIST);
  2873.     XtVaSetValues (list,
  2874.            XmNselectedItems, (items + default_item),
  2875.            XmNselectedItemCount, 1,
  2876.            0);
  2877.   }
  2878.  
  2879.   data.context = context;
  2880.   data.widget = shell;
  2881.   data.answer = Answer_Invalid;
  2882.   data.return_value = 0;
  2883.  
  2884.   fe_NukeBackingStore (shell);
  2885.   XtManageChild (shell);
  2886.  
  2887.   /* #### check for destruction here */
  2888.   while (data.answer == Answer_Invalid)
  2889.     fe_EventLoop ();
  2890.  
  2891.   for (i = 0; i < item_count; i++)
  2892.     XmStringFree (items [i]);
  2893.   free (items);
  2894.  
  2895.   if (vi_out)
  2896.     {
  2897.       int index = (int) data.return_value;
  2898.       Visual *v = (data.answer == 1 ? vi_out [index].visual : 0);
  2899.       XFree ((char *) vi_out);
  2900.       return v;
  2901.     }
  2902.   else
  2903.     {
  2904.       return 0;
  2905.     }
  2906. }
  2907.  
  2908. static void fe_visual_cb (Widget widget, XtPointer closure,
  2909.               XtPointer call_data)
  2910. {
  2911.   struct fe_confirm_data *data = (struct fe_confirm_data *) closure;
  2912.   XmSelectionBoxCallbackStruct *cb =
  2913.     (XmSelectionBoxCallbackStruct *) call_data;
  2914.   XmString *items;
  2915.   int count;
  2916.   int i;
  2917.   XtVaGetValues (data->widget,
  2918.          XmNlistItems, &items,
  2919.          XmNlistItemCount, &count,
  2920.          0);
  2921.   switch (cb->reason)
  2922.     {
  2923.     case XmCR_OK:
  2924.     case XmCR_APPLY:
  2925.       {
  2926.     data->answer = 1;
  2927.     data->return_value = (void *) -1;
  2928.     for (i = 0; i < count; i++)
  2929.       if (XmStringCompare (items[i], cb->value))
  2930.         data->return_value = (void *) i;
  2931.     if (data->return_value == (void *) -1)
  2932.       abort ();
  2933.     break;
  2934.       }
  2935.     case XmCR_CANCEL:
  2936.       data->answer = 0;
  2937.       break;
  2938.     default:
  2939.       abort ();
  2940.       break;
  2941.     }
  2942. }
  2943.  
  2944.  
  2945. /* Displaying source
  2946.  */
  2947.  
  2948. struct fe_source_data
  2949. {
  2950.   Widget dialog;
  2951.   Widget name, url, text;
  2952. };
  2953.  
  2954. #if 0
  2955. static void
  2956. fe_close_source_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2957. {
  2958.   MWContext *context = (MWContext *) closure;
  2959.   if (! CONTEXT_DATA (context)->sd) return;
  2960.   XtUnmanageChild (CONTEXT_DATA (context)->sd->dialog);
  2961. }
  2962.  
  2963. static void
  2964. fe_source_save_as_cb (Widget widget, XtPointer closure, XtPointer call_data)
  2965. {
  2966.   MWContext *context = (MWContext *) closure;
  2967.   char *url = 0;
  2968.   URL_Struct *url_struct;
  2969.   if (! CONTEXT_DATA (context)->sd) return;
  2970.   url = fe_GetTextField (CONTEXT_DATA (context)->sd->url);
  2971.   if (! url) return;
  2972.   url_struct = NET_CreateURLStruct (url, FALSE);
  2973.   fe_SaveURL (context, url_struct);
  2974. }
  2975. #endif
  2976.  
  2977. #if 0    /* This is history. Should remove this code out later. */
  2978. Widget
  2979. fe_ViewSourceDialog (MWContext *context, const char *title, const char *url)
  2980. {
  2981.   Widget mainw = CONTEXT_WIDGET (context);
  2982.   struct fe_source_data *sd = CONTEXT_DATA (context)->sd;
  2983.  
  2984.   if (! sd)
  2985.     {
  2986.       Widget shell, form, text;
  2987.       Widget url_label, url_text, title_label, title_text;
  2988.       Widget ok_button, save_button;
  2989.       Arg av [20];
  2990.       int ac;
  2991.       Visual *v = 0;
  2992.       Colormap cmap = 0;
  2993.       Cardinal depth = 0;
  2994.       sd = (struct fe_source_data *) calloc(sizeof (struct fe_source_data), 1);
  2995.  
  2996.       XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  2997.              XtNdepth, &depth, 0);
  2998.       ac = 0;
  2999.       XtSetArg (av[ac], XmNvisual, v); ac++;
  3000.       XtSetArg (av[ac], XmNdepth, depth); ac++;
  3001.       XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  3002.       XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  3003.       XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  3004.  
  3005.       XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  3006.  
  3007.       XtSetArg (av[ac], XmNdialogType, XmDIALOG_INFORMATION); ac++;
  3008.       XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  3009.       shell = XmCreateTemplateDialog (mainw, "source", av, ac);
  3010.  
  3011.       fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_SEPARATOR));
  3012.       fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_OK_BUTTON));
  3013.       fe_UnmanageChild_safe (XmMessageBoxGetChild (shell,
  3014.                           XmDIALOG_CANCEL_BUTTON));
  3015. /*      fe_UnmanageChild_safe (XmMessageBoxGetChild (shell,
  3016.                           XmDIALOG_APPLY_BUTTON));*/
  3017.       fe_UnmanageChild_safe (XmMessageBoxGetChild (shell,
  3018.                           XmDIALOG_DEFAULT_BUTTON));
  3019.       fe_UnmanageChild_safe (XmMessageBoxGetChild (shell,
  3020.                           XmDIALOG_HELP_BUTTON));
  3021.  
  3022.       ac = 0;
  3023.       save_button = XmCreatePushButtonGadget (shell, "save", av, ac);
  3024.       ok_button = XmCreatePushButtonGadget (shell, "OK", av, ac);
  3025.  
  3026.       ac = 0;
  3027.       form = XmCreateForm (shell, "form", av, ac);
  3028.  
  3029.       ac = 0;
  3030.       title_label = XmCreateLabelGadget (form, "titleLabel", av, ac);
  3031.       url_label = XmCreateLabelGadget (form, "urlLabel", av, ac);
  3032.       ac = 0;
  3033.       XtSetArg (av [ac], XmNeditable, False); ac++;
  3034.       XtSetArg (av [ac], XmNcursorPositionVisible, False); ac++;
  3035.       title_text = fe_CreateTextField (form, "titleText", av, ac);
  3036.       url_text   = fe_CreateTextField (form, "urlText", av, ac);
  3037.  
  3038.       ac = 0;
  3039.       XtSetArg (av [ac], XmNeditable, False); ac++;
  3040.       XtSetArg (av [ac], XmNcursorPositionVisible, False); ac++;
  3041.       XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
  3042.       text = XmCreateScrolledText (form, "text", av, ac);
  3043.       fe_HackDialogTranslations (text);
  3044.  
  3045.       XtVaSetValues (title_label,
  3046.              XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  3047.              XmNtopWidget, title_text,
  3048.              XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  3049.              XmNbottomWidget, title_text,
  3050.              XmNleftAttachment, XmATTACH_FORM,
  3051.              XmNrightAttachment, XmATTACH_WIDGET,
  3052.              XmNrightWidget, title_text,
  3053.              0);
  3054.       XtVaSetValues (url_label,
  3055.              XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  3056.              XmNtopWidget, url_text,
  3057.              XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  3058.              XmNbottomWidget, url_text,
  3059.              XmNleftAttachment, XmATTACH_FORM,
  3060.              XmNrightAttachment, XmATTACH_WIDGET,
  3061.              XmNrightWidget, url_text,
  3062.              0);
  3063.  
  3064.       XtVaSetValues (title_text,
  3065.              XmNtopAttachment, XmATTACH_FORM,
  3066.              XmNbottomAttachment, XmATTACH_NONE,
  3067.              XmNrightAttachment, XmATTACH_FORM,
  3068.              0);
  3069.       XtVaSetValues (url_text,
  3070.              XmNtopAttachment, XmATTACH_WIDGET,
  3071.              XmNtopWidget, title_text,
  3072.              XmNbottomAttachment, XmATTACH_NONE,
  3073.              XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  3074.              XmNleftWidget, title_text,
  3075.              XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
  3076.              XmNrightWidget, title_text,
  3077.              0);
  3078.       XtVaSetValues (XtParent (text),
  3079.              XmNtopAttachment, XmATTACH_WIDGET,
  3080.              XmNtopWidget, url_text,
  3081.              XmNbottomAttachment, XmATTACH_FORM,
  3082.              XmNleftAttachment, XmATTACH_FORM,
  3083.              XmNrightAttachment, XmATTACH_FORM,
  3084.              0);
  3085.  
  3086.       fe_attach_field_to_labels (title_text, title_label, url_label, 0);
  3087.  
  3088.       XtAddCallback (save_button, XmNactivateCallback,
  3089.              fe_source_save_as_cb, context);
  3090.       XtAddCallback (ok_button, XmNactivateCallback,
  3091.              fe_close_source_cb, context);
  3092.  
  3093.       XtVaSetValues (shell, XmNdefaultButton, save_button, 0);
  3094.  
  3095.       XtManageChild (title_label);
  3096.       XtManageChild (title_text);
  3097.       XtManageChild (url_label);
  3098.       XtManageChild (url_text);
  3099.       XtManageChild (text);
  3100.       XtManageChild (form);
  3101.       XtManageChild (save_button);
  3102.       XtManageChild (ok_button);
  3103.  
  3104.       sd->dialog = shell;
  3105.       sd->text = text;
  3106.       sd->url = url_text;
  3107.       sd->name = title_text;
  3108.       CONTEXT_DATA (context)->sd = sd;
  3109.     }
  3110.  
  3111.   XtVaSetValues (sd->text, XmNcursorPosition, 0);
  3112.   fe_SetTextField (sd->text, "");
  3113.   XtVaSetValues (sd->name, XmNcursorPosition, 0, 0);
  3114.   fe_SetTextField (sd->name, (title ? title : ""));
  3115.   XtVaSetValues (sd->url, XmNcursorPosition, 0, 0);
  3116.   fe_SetTextField (sd->url, (url ? url : ""));
  3117.  
  3118.   fe_NukeBackingStore (sd->dialog);
  3119.   XtManageChild (sd->dialog);
  3120.   return sd->text;
  3121. }
  3122. #endif /* 0 */
  3123.  
  3124.  
  3125. /* User information
  3126.  */
  3127.  
  3128. #include <pwd.h>
  3129. #include <netdb.h>
  3130.  
  3131. void
  3132. fe_DefaultUserInfo (char **uid, char **name, Boolean really_default_p)
  3133. {
  3134.   struct passwd *pw = getpwuid (geteuid ());
  3135.   char *user_name, *tmp;
  3136.   char *real_uid = (pw ? pw->pw_name : "");
  3137.   char *user_uid = 0;
  3138.  
  3139.   if (really_default_p)
  3140.     {
  3141.       user_uid = real_uid;
  3142.     }
  3143.   else
  3144.     {
  3145.       user_uid = getenv ("LOGNAME");
  3146.       if (! user_uid) user_uid = getenv ("USER");
  3147.       if (! user_uid) user_uid = real_uid;
  3148.  
  3149.       /* If the env vars claim a different user, get the real name of
  3150.      that user instead of the actual user. */
  3151.       if (strcmp (user_uid, real_uid))
  3152.     {
  3153.       struct passwd *pw2 = getpwnam (user_uid);
  3154.       if (pw2) pw = pw2;
  3155.     }
  3156.     }
  3157.  
  3158.   user_uid = strdup (user_uid);
  3159.   user_name = strdup ((pw && pw->pw_gecos ? pw->pw_gecos : "&"));
  3160.  
  3161.   /* Terminate the string at the first comma, to lose phone numbers and crap
  3162.      like that.  This may lose for "Jr."s, but who cares: Unix sucks. */
  3163.   if ((tmp = strchr (user_name, ',')))
  3164.     *tmp = 0;
  3165.  
  3166.   if ((tmp = strchr (user_name, '&')))
  3167.     {
  3168.       int i, j;
  3169.       char *new = (char *) malloc (strlen (user_name) + strlen (user_uid) + 1);
  3170.       for (i = 0, j = 0; user_name[i]; i++)
  3171.     if (tmp == user_name + i)
  3172.       {
  3173.         strcpy (new + j, user_uid);
  3174.         new[j] = toupper (new[j]);
  3175.         j += strlen (user_uid);
  3176.         tmp = 0;
  3177.       }
  3178.       else
  3179.     {
  3180.       new[j++] = user_name[i];
  3181.     }
  3182.       free (user_name);
  3183.       user_name = new;
  3184.     }
  3185.  
  3186.   *uid = user_uid;
  3187.   *name = user_name;
  3188. }
  3189.  
  3190.  
  3191. /* Synchronous loading of a URL
  3192.    Internally, we use the URL mechanism to do some things during which time
  3193.    we want the interface to be blocked - for example, formatting a document
  3194.    for inclusion in a mail window, and printing, and so on.  This code lets
  3195.    us put up a dialog box with a status message and a cancel button, and
  3196.    bring it down when the event is over.
  3197.  */
  3198.  
  3199. /* #define SYNCHRONOUS_URL_DIALOG_WORKS */
  3200.  
  3201.  
  3202. #ifdef SYNCHRONOUS_URL_DIALOG_WORKS
  3203. static void
  3204. fe_synchronous_url_cancel_cb (Widget widget, XtPointer closure,
  3205.                   XtPointer call_data)
  3206. {
  3207.   MWContext *context = (MWContext *) closure;
  3208.   XP_InterruptContext (context);
  3209. }
  3210.  
  3211. /*
  3212.  * Make sure the the popped up modal dialog receives at least
  3213.  * on FocusIn event, because Motif seems to expect/require it.
  3214.  */
  3215. static void
  3216. fe_dialog_expose_eh (Widget widget, XtPointer closure, XEvent *event)
  3217. {
  3218.   MWContext *context = (MWContext *) closure;
  3219.   Widget dialog = CONTEXT_DATA (context)->synchronous_url_dialog;
  3220.  
  3221.   XtRemoveEventHandler(dialog, ExposureMask, FALSE,
  3222.         (XtEventHandler)fe_dialog_expose_eh, context);
  3223.   XSetInputFocus(XtDisplay (dialog), XtWindow(dialog),
  3224.         RevertToParent, CurrentTime);
  3225.   XSync (XtDisplay (dialog), False);
  3226. }
  3227. #endif /* SYNCHRONOUS_URL_DIALOG_WORKS */
  3228.  
  3229. void
  3230. fe_LowerSynchronousURLDialog (MWContext *context)
  3231. {
  3232.   if (CONTEXT_DATA (context)->synchronous_url_dialog)
  3233.     {
  3234. #ifdef SYNCHRONOUS_URL_DIALOG_WORKS
  3235.       Widget shell = XtParent (CONTEXT_DATA (context)->synchronous_url_dialog);
  3236.  
  3237.       /* Don't call XP_InterruptContext a (possibly) second time. */
  3238.       XtRemoveCallback (CONTEXT_DATA (context)->synchronous_url_dialog,
  3239.             XtNdestroyCallback,
  3240.             fe_synchronous_url_cancel_cb, context);
  3241.       XtUnmanageChild (CONTEXT_DATA (context)->synchronous_url_dialog);
  3242.       XSync (XtDisplay (shell), False);
  3243.       XtDestroyWidget (shell);
  3244. #endif /* SYNCHRONOUS_URL_DIALOG_WORKS */
  3245.  
  3246.       CONTEXT_DATA (context)->synchronous_url_dialog = 0;
  3247.  
  3248.       /* If this context was destroyed, do not proceed furthur */
  3249.       if (fe_IsContextDestroyed(context))
  3250.     return;
  3251.  
  3252.       assert (CONTEXT_DATA (context)->active_url_count > 0);
  3253.       if (CONTEXT_DATA (context)->active_url_count > 0)
  3254.     CONTEXT_DATA (context)->active_url_count--;
  3255.       if (CONTEXT_DATA (context)->active_url_count <= 0)
  3256.     XFE_AllConnectionsComplete (context);
  3257.       fe_SetCursor (context, False);
  3258.     }
  3259. }
  3260.  
  3261. static void
  3262. fe_synchronous_url_exit (URL_Struct *url, int status, MWContext *context)
  3263. {
  3264.   if (status == MK_CHANGING_CONTEXT)
  3265.     return;
  3266.   fe_LowerSynchronousURLDialog (context);
  3267.   if (status < 0 && url->error_msg)
  3268.     {
  3269.       FE_Alert (context, url->error_msg);
  3270.     }
  3271.   NET_FreeURLStruct (url);
  3272.   CONTEXT_DATA (context)->synchronous_url_exit_status = status;
  3273. }
  3274.  
  3275. void
  3276. fe_RaiseSynchronousURLDialog (MWContext *context, Widget parent,
  3277.                   const char *title)
  3278. {
  3279. #ifdef SYNCHRONOUS_URL_DIALOG_WORKS
  3280.   Widget shell, dialog;
  3281.   Arg av [20];
  3282.   int ac;
  3283.   Visual *v = 0;
  3284.   Colormap cmap = 0;
  3285.   Cardinal depth = 0;
  3286.   char title2 [255];
  3287.   Boolean popped_up;
  3288. #endif /* SYNCHRONOUS_URL_DIALOG_WORKS */
  3289.  
  3290.   CONTEXT_DATA (context)->active_url_count++;
  3291.   if (CONTEXT_DATA (context)->active_url_count == 1)
  3292.     {
  3293.       CONTEXT_DATA (context)->clicking_blocked = True;
  3294.       fe_StartProgressGraph (context);
  3295.       fe_SetCursor (context, False);
  3296.     }
  3297.  
  3298. #ifndef SYNCHRONOUS_URL_DIALOG_WORKS
  3299.  
  3300.   CONTEXT_DATA (context)->synchronous_url_dialog = (Widget) ~0;
  3301.   CONTEXT_DATA (context)->synchronous_url_exit_status = 0;
  3302.  
  3303. #else /* SYNCHRONOUS_URL_DIALOG_WORKS */
  3304.  
  3305.   XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  3306.          XtNdepth, &depth, 0);
  3307.  
  3308.   strcpy (title2, title);
  3309.   strcat (title2, "_popup");
  3310.  
  3311.   ac = 0;
  3312.   XtSetArg (av[ac], XmNvisual, v); ac++;
  3313.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  3314.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  3315.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  3316.   XtSetArg (av[ac], XmNtransientFor, parent); ac++;
  3317.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  3318.   shell = XmCreateDialogShell (parent, title2, av, ac);
  3319.   ac = 0;
  3320.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  3321.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_WORKING); ac++;
  3322.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  3323.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  3324.   dialog = XmCreateMessageBox (shell, (char *) title, av, ac);
  3325.  
  3326.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON));
  3327. #ifdef NO_HELP
  3328.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
  3329. #endif
  3330.  
  3331.   XtAddCallback (dialog, XmNokCallback, fe_destroy_cb, shell);
  3332.   XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cb, shell);
  3333.   XtAddCallback (dialog, XmNdestroyCallback, fe_synchronous_url_cancel_cb,
  3334.          context);
  3335.   XtAddEventHandler(dialog, ExposureMask, FALSE,
  3336.             (XtEventHandler)fe_dialog_expose_eh, context);
  3337.  
  3338.   CONTEXT_DATA (context)->synchronous_url_dialog = dialog;
  3339.   CONTEXT_DATA (context)->synchronous_url_exit_status = 0;
  3340.  
  3341.   fe_NukeBackingStore (dialog);
  3342.   XtManageChild (dialog);
  3343.   XSync (XtDisplay (dialog), False);
  3344.  
  3345.   /*
  3346.    * We wait here until we KNOW the dialog is popped up,
  3347.    * otherwise Motif will misbehave.
  3348.    */
  3349.   popped_up = FALSE;
  3350.   while (!popped_up)
  3351.     {
  3352.       XEvent event;
  3353.  
  3354.       XtAppNextEvent(XtWidgetToApplicationContext(dialog), &event);
  3355.       if ((event.type == Expose)&&(event.xexpose.window == XtWindow(dialog)))
  3356.     {
  3357.       popped_up = TRUE;
  3358.     }
  3359.       XtDispatchEvent(&event);
  3360.     }
  3361. #endif /* SYNCHRONOUS_URL_DIALOG_WORKS */
  3362.  
  3363. }
  3364.  
  3365.  
  3366. int
  3367. fe_await_synchronous_url (MWContext *context)
  3368. {
  3369.   /* Loop dispatching X events until the dialog box goes down as a result
  3370.      of the exit routine being called (which may be a result of the Cancel
  3371.      button being hit. */
  3372.   int status;
  3373.   
  3374.   fe_ProtectContext(context);
  3375.   while (CONTEXT_DATA (context)->synchronous_url_dialog)
  3376.     fe_EventLoop ();
  3377.   fe_UnProtectContext(context);
  3378.   status = CONTEXT_DATA (context)->synchronous_url_exit_status;
  3379.   if (fe_IsContextDestroyed(context)) {
  3380.     free(CONTEXT_DATA(context));
  3381.     free(context);
  3382.   }
  3383.   return (status);
  3384. }
  3385.  
  3386.  
  3387. int
  3388. fe_GetSynchronousURL (MWContext *context,
  3389.               Widget widget_to_grab,
  3390.               const char *title,
  3391.               URL_Struct *url,
  3392.               int output_format,
  3393.               void *call_data)
  3394. {
  3395.   int status;
  3396.   url->fe_data = call_data;
  3397.   fe_RaiseSynchronousURLDialog (context, widget_to_grab, title);
  3398.   status = NET_GetURL (url, output_format, context, fe_synchronous_url_exit);
  3399.   if (status < 0)
  3400.     return status;
  3401.   else
  3402.     return fe_await_synchronous_url (context);
  3403. }
  3404.  
  3405.  
  3406. #ifdef MOZ_MAIL_NEWS
  3407.  
  3408. /* Sending mail
  3409.  */
  3410.  
  3411. void fe_mail_text_modify_cb (Widget, XtPointer, XtPointer);
  3412.  
  3413. Boolean
  3414. fe_CheckDeferredMail (void)
  3415. {
  3416.   struct fe_MWContext_cons* rest;
  3417.   Boolean haveQueuedMail = False;
  3418.   int numMsgs = 0;
  3419.   MSG_ViewIndex row = 0;
  3420.  
  3421.   for (rest = fe_all_MWContexts; rest; rest = rest->next) {
  3422.     MWContext* context = rest->context;
  3423.     fe_MailNewsContextData* d = MAILNEWS_CONTEXT_DATA(context);
  3424.     if (context->type == MWContextMail) {
  3425.       MSG_CommandStatus (d->folderpane, MSG_DeliverQueuedMessages, NULL, 0,
  3426.              &haveQueuedMail, NULL, NULL, NULL);
  3427.       if (haveQueuedMail) {
  3428.     MSG_FolderLine line;
  3429.     /* ###tw  This is just too vile for words.  */
  3430.     while (MSG_GetFolderLineByIndex(d->folderpane, row, 1, &line)) {
  3431.       if (line.flags & MSG_FOLDER_FLAG_QUEUE) {
  3432.         numMsgs = line.total;
  3433.         break;
  3434.       }
  3435.       row++;
  3436.     }
  3437.     if (numMsgs) {
  3438.       char buf [256];
  3439.       void * sendNow = 0;
  3440.       if (numMsgs == 1)
  3441.         sendNow = fe_dialog (CONTEXT_WIDGET (fe_all_MWContexts->context),
  3442.                  "sendNow",
  3443.                  XP_GetString (XFE_OUTBOX_CONTAINS_MSG),
  3444.                  TRUE, 0, TRUE, FALSE, 0);
  3445.       else {
  3446.         PR_snprintf (buf, 256, XP_GetString (XFE_OUTBOX_CONTAINS_MSGS), numMsgs);
  3447.         sendNow = fe_dialog (CONTEXT_WIDGET (fe_all_MWContexts->context),
  3448.                  "sendNow", buf, TRUE, 0, TRUE, FALSE, 0);
  3449.       }
  3450.       if (sendNow) {
  3451.         MSG_Command (d->folderpane, MSG_DeliverQueuedMessages, NULL, 0);
  3452.         return False;
  3453.       }
  3454.     }
  3455.       }
  3456.     }
  3457.   }
  3458.   /* return True means no mail - weird, but consistent
  3459.    * with fe_CheckUnsentMail below. We can change them
  3460.    * later.
  3461.    */
  3462.   return True;
  3463. }
  3464.  
  3465. Boolean
  3466. fe_CheckUnsentMail (void)
  3467. {
  3468.   struct fe_MWContext_cons* rest;
  3469.   for (rest = fe_all_MWContexts; rest; rest = rest->next) {
  3470.     MWContext* context = rest->context;
  3471.     if (context->type == MWContextMessageComposition) {
  3472.       return XFE_Confirm(fe_all_MWContexts->context,
  3473.              fe_globalData.unsent_mail_message);
  3474.     }
  3475.   }
  3476.   return TRUE;
  3477. }
  3478.  
  3479. #if 0
  3480. static char* fe_last_attach_type = NULL;
  3481.  
  3482. static void
  3483. fe_del_attachment(struct fe_mail_attach_data *mad, int pos)
  3484. {
  3485.   if (pos > mad->nattachments) return;
  3486.   else XP_ASSERT(pos <= mad->nattachments);
  3487.  
  3488.   pos--;
  3489.   if (mad->attachments[pos].url)
  3490.     XP_FREE((char *)mad->attachments[pos].url);
  3491.   pos++;
  3492.   while (pos < mad->nattachments) {
  3493.     mad->attachments[pos-1] = mad->attachments[pos];
  3494.     pos++;
  3495.   }
  3496.   mad->nattachments--;
  3497. }
  3498.  
  3499. static void
  3500. fe_add_attachmentData(struct fe_mail_attach_data *mad,
  3501.             const struct MSG_AttachmentData *data)
  3502. {
  3503.   struct MSG_AttachmentData *m;
  3504.   char *name = (char *)data->url;
  3505.   XmString xmstr;
  3506.  
  3507.   if (!name || !*name) return;
  3508.  
  3509.   if (mad->nattachments >= XFE_MAX_ATTACHMENTS) return;
  3510.   else XP_ASSERT(mad->nattachments < XFE_MAX_ATTACHMENTS);
  3511.  
  3512.   xmstr = XmStringCreate(name, XmFONTLIST_DEFAULT_TAG);
  3513.   XmListAddItem(mad->list, xmstr, 0);
  3514.  
  3515.   m = &mad->attachments[mad->nattachments];
  3516.   *m = *data;
  3517.   m->url = XP_STRDUP(data->url);
  3518.  
  3519.   mad->nattachments++;
  3520.   if (mad->nattachments == 1)
  3521.     XmListSelectPos(mad->list, 1, True);
  3522.  
  3523.   XmListSelectItem(mad->list, xmstr, TRUE);
  3524.   XmStringFree(xmstr);
  3525. }
  3526.  
  3527.  
  3528. static void
  3529. fe_add_attachment(struct fe_mail_attach_data *mad, char *name)
  3530. {
  3531.   struct MSG_AttachmentData m = {0};
  3532.   Boolean b;
  3533.   XmString xmstr;
  3534.  
  3535.   if (!name || !*name) return;
  3536.  
  3537.   if(mad->nattachments >= XFE_MAX_ATTACHMENTS) return;
  3538.   else XP_ASSERT(mad->nattachments < XFE_MAX_ATTACHMENTS);
  3539.  
  3540.   xmstr = XmStringCreate(name, XmFONTLIST_DEFAULT_TAG);
  3541.   XmListAddItem(mad->list, xmstr, 0);
  3542.  
  3543.   XtVaGetValues (mad->text_p, XmNset, &b, 0);
  3544.   if (b)
  3545.     m.desired_type = TEXT_PLAIN;
  3546.   else {
  3547.     XtVaGetValues (mad->postscript_p, XmNset, &b, 0);
  3548.     if (b)
  3549.       m.desired_type = APPLICATION_POSTSCRIPT;
  3550.   }
  3551.   m.url = name;
  3552.  
  3553.   mad->attachments[mad->nattachments] = m;
  3554.   mad->nattachments++;
  3555.  
  3556.   XmListSelectItem(mad->list, xmstr, TRUE);
  3557.   XmStringFree(xmstr);
  3558. }
  3559.  
  3560. /***********************************
  3561.  * Location popup related routines *
  3562.  ***********************************/
  3563.  
  3564. static void
  3565. fe_locationOk_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3566. {
  3567.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3568.   char *url = fe_GetTextField(mad->location_text);
  3569.  
  3570.   if (url && *url)
  3571.     fe_add_attachment(mad, url);
  3572.   else
  3573.     if (url) XtFree(url);
  3574.   XtUnmanageChild(mad->location_shell);
  3575. }
  3576. static void
  3577. fe_locationClear_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3578. {
  3579.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3580.   fe_SetTextField (mad->location_text, "");
  3581.   /* Focus on the text widget after this, since otherwise you have to
  3582.      click again. */
  3583.   XmProcessTraversal (mad->location_text, XmTRAVERSE_CURRENT);
  3584. }
  3585.  
  3586. static void
  3587. fe_locationCancel_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3588. {
  3589.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3590.   XtUnmanageChild(mad->location_shell);
  3591. }
  3592.  
  3593. static void
  3594. fe_attach_make_location(struct fe_mail_attach_data *mad)
  3595. {
  3596.   Arg av [20];
  3597.   int ac;
  3598.   Visual *v = 0;
  3599.   Colormap cmap = 0;
  3600.   Cardinal depth = 0;
  3601.  
  3602.   Widget shell;
  3603.   Widget parent;
  3604.   Widget form;
  3605.   Widget label, location_label, location_text;
  3606.   Widget ok_button, clear_button, cancel_button;
  3607.  
  3608.   Widget kids [20];
  3609.   int i;
  3610.  
  3611.   if (mad->location_shell) return;
  3612.  
  3613. #ifdef dp_DEBUG
  3614.   fprintf(stderr, "Making attach_location widgets : fe_attach_make_location().\n");
  3615. #endif
  3616.  
  3617.   parent = CONTEXT_WIDGET(mad->context);
  3618.  
  3619.   XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  3620.          XtNdepth, &depth, 0);
  3621.  
  3622.   ac = 0;
  3623.   XtSetArg (av[ac], XmNvisual, v); ac++;
  3624.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  3625.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  3626. /*  XtSetArg (av[ac], XmNallowShellResize, True); ac++; */
  3627. /*  XtSetArg (av[ac], XmNtransientFor, parent); ac++; */
  3628.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  3629.   XtSetArg (av[ac], XmNdeleteResponse, XmUNMAP); ac++;
  3630.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  3631.   shell = XmCreateTemplateDialog (parent, "location_popup", av, ac);
  3632.  
  3633.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_OK_BUTTON));
  3634.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_CANCEL_BUTTON));
  3635.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_DEFAULT_BUTTON));
  3636.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_HELP_BUTTON));
  3637.  
  3638.   ac = 0;
  3639.   ok_button = XmCreatePushButtonGadget (shell, "OK", av, ac);
  3640.   clear_button = XmCreatePushButtonGadget (shell, "clear", av, ac);
  3641.   cancel_button = XmCreatePushButtonGadget (shell, "cancel", av, ac);
  3642.  
  3643.   ac = 0;
  3644.   form = XmCreateForm(shell, "form", av, ac);
  3645.   label = XmCreateLabelGadget( form, "label", av, ac);
  3646.   location_label = XmCreateLabelGadget( form, "locationLabel", av, ac);
  3647.   location_text = fe_CreateTextField( form, "locationText", av, ac);
  3648.  
  3649.   if (fe_globalData.nonterminal_text_translations)
  3650.     XtOverrideTranslations (location_text, fe_globalData.
  3651.                 nonterminal_text_translations);
  3652.  
  3653.   XtVaSetValues (label,
  3654.          XmNtopAttachment, XmATTACH_FORM,
  3655.          XmNbottomAttachment, XmATTACH_NONE,
  3656.          XmNleftAttachment, XmATTACH_FORM,
  3657.          XmNrightAttachment, XmATTACH_FORM,
  3658.          0);
  3659.   XtVaSetValues (location_label,
  3660.          XmNtopAttachment, XmATTACH_WIDGET,
  3661.          XmNtopWidget, label,
  3662.          XmNbottomAttachment, XmATTACH_NONE,
  3663.          XmNleftAttachment, XmATTACH_FORM,
  3664.          XmNrightAttachment, XmATTACH_NONE,
  3665.          0);
  3666.   XtVaSetValues (location_text,
  3667.          XmNtopAttachment, XmATTACH_WIDGET,
  3668.          XmNtopWidget, label,
  3669.          XmNbottomAttachment, XmATTACH_NONE,
  3670.          XmNleftAttachment, XmATTACH_WIDGET,
  3671.          XmNleftWidget, location_label,
  3672.          XmNrightAttachment, XmATTACH_FORM,
  3673.          0);
  3674.  
  3675.   _XfeHeight(location_label) = _XfeHeight(location_text);
  3676.  
  3677.   XtAddCallback(ok_button, XmNactivateCallback, fe_locationOk_cb, mad);
  3678.   XtAddCallback(clear_button, XmNactivateCallback, fe_locationClear_cb, mad);
  3679.   XtAddCallback(cancel_button, XmNactivateCallback, fe_locationCancel_cb, mad);
  3680.  
  3681.   {
  3682.     const char *str = MSG_GetAssociatedURL (mad->comppane);
  3683.     fe_SetTextFieldAndCallBack (location_text, (char *) (str ? str : ""));
  3684.   }
  3685.  
  3686.   fe_HackDialogTranslations (form);
  3687.  
  3688.   mad->location_shell = shell;
  3689.   i = 0;
  3690.   kids[i++] = mad->location_text = location_text;
  3691.   kids[i++] = location_label;
  3692.   kids[i++] = label;
  3693.   XtManageChildren(kids, i);
  3694.   i = 0;
  3695.   kids[i++] = ok_button;
  3696.   kids[i++] = clear_button;
  3697.   kids[i++] = cancel_button;
  3698.   XtManageChildren(kids, i);
  3699.  
  3700.   XtManageChild(form);
  3701.   XtManageChild(shell);
  3702. }
  3703.  
  3704. /*************************
  3705.  * File Attachment popup *
  3706.  *************************/
  3707. static void 
  3708. fe_attachFile_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3709. {
  3710.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data *) closure;
  3711.   XmFileSelectionBoxCallbackStruct *sbc =
  3712.     (XmFileSelectionBoxCallbackStruct *) call_data;
  3713.   char *file;
  3714.   char *msg;
  3715.  
  3716.   switch (sbc->reason) {
  3717.     case XmCR_NO_MATCH:
  3718.     XBell (XtDisplay (widget), 0);
  3719.     break;
  3720.  
  3721.     case XmCR_OK:
  3722.     XmStringGetLtoR (sbc->value, XmFONTLIST_DEFAULT_TAG, &file);
  3723.     if (!fe_isFileExist(file)) {
  3724.         msg = PR_smprintf( XP_GetString( XFE_INVALID_FILE_ATTACHMENT_DOESNT_EXIST ), file);
  3725.         if (msg) {
  3726.         fe_Alert_2(XtParent(mad->file_shell), msg);
  3727.         XP_FREE(msg);
  3728.         }
  3729.     }
  3730.     else if (!fe_isFileReadable(file)) {
  3731.         msg = PR_smprintf( XP_GetString( XFE_INVALID_FILE_ATTACHMENT_NOT_READABLE ) , file);
  3732.         if (msg) {
  3733.         fe_Alert_2(XtParent(mad->file_shell), msg);
  3734.         XP_FREE(msg);
  3735.         }
  3736.     }
  3737.     else if (fe_isDir(file)) {
  3738.         msg = PR_smprintf( XP_GetString( XFE_INVALID_FILE_ATTACHMENT_IS_A_DIRECTORY ), file);
  3739.         if (msg) {
  3740.         fe_Alert_2(XtParent(mad->file_shell), msg);
  3741.         if (msg) XP_FREE(msg);
  3742.         }
  3743.     }
  3744.     else {
  3745.       fe_add_attachment(mad, file);
  3746.       XtUnmanageChild(mad->file_shell);
  3747.     }
  3748.     break;
  3749.  
  3750.     case XmCR_CANCEL:
  3751.     XtUnmanageChild(mad->file_shell);
  3752.     break;
  3753.     default:
  3754.       abort ();
  3755.   }
  3756. }
  3757.  
  3758. static void
  3759. fe_attach_make_file(struct fe_mail_attach_data *mad)
  3760. {
  3761.   Arg av [20];
  3762.   int ac;
  3763.   Visual *v = 0;
  3764.   Colormap cmap = 0;
  3765.   Cardinal depth = 0;
  3766.   Widget shell;
  3767.   Widget parent;
  3768.   Widget fileb;
  3769.   Boolean dirp = False;
  3770.  
  3771.   if (mad->file_shell) return;
  3772.  
  3773. #ifdef dp_DEBUG
  3774.   fprintf(stderr, "Making attach_file widgets : fe_attach_make_file().\n");
  3775. #endif
  3776.  
  3777.   parent = CONTEXT_WIDGET (mad->context);
  3778.  
  3779.   XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  3780.          XtNdepth, &depth, 0);
  3781.  
  3782.   ac = 0;
  3783.   XtSetArg (av[ac], XmNvisual, v); ac++;
  3784.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  3785.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  3786. /*  XtSetArg (av[ac], XmNallowShellResize, True); ac++;*/
  3787.   XtSetArg (av[ac], XmNdeleteResponse, XmUNMAP); ac++;
  3788.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  3789.   shell = XmCreateDialogShell (parent, "fileBrowser_popup", av, ac);
  3790.  
  3791.   ac = 0;
  3792.   XtSetArg (av[ac], XmNfileTypeMask,
  3793.         (dirp ? XmFILE_DIRECTORY : XmFILE_REGULAR)); ac++;
  3794.   fileb = fe_CreateFileSelectionBox (shell, "fileBrowser", av, ac);
  3795. #ifdef NO_HELP
  3796.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (fileb, XmDIALOG_HELP_BUTTON));
  3797. #endif
  3798.  
  3799.   XtAddCallback(fileb, XmNnoMatchCallback, fe_attachFile_cb, mad);
  3800.   XtAddCallback(fileb, XmNokCallback,      fe_attachFile_cb, mad);
  3801.   XtAddCallback(fileb, XmNcancelCallback,  fe_attachFile_cb, mad);
  3802.  
  3803.   mad->file_shell = fileb;
  3804.  
  3805.   fe_HackDialogTranslations (fileb);
  3806.  
  3807.   fe_NukeBackingStore (fileb);
  3808.   XtManageChild (fileb);
  3809. }
  3810.  
  3811. static void
  3812. fe_attach_doc_type_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3813. {
  3814.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3815.   int *poslist, npos;
  3816.   int attach_pos = -1;
  3817.  
  3818.   if (XmListGetSelectedPos(mad->list, &poslist, &npos)) {
  3819.     attach_pos = poslist[npos - 1] - 1;
  3820.     XP_FREE(poslist);
  3821.   }
  3822.  
  3823.   /*
  3824.    * my how intuitive, if the file is attach as source, desired type = NULL.
  3825.    */
  3826.   XtVaSetValues (widget, XmNset, True, 0);
  3827.   if (widget == mad->text_p) {
  3828.     XtVaSetValues (mad->source_p, XmNset, False, 0);
  3829.     XtVaSetValues (mad->postscript_p, XmNset, False, 0);
  3830.     if (attach_pos >= 0)
  3831.       mad->attachments[attach_pos].desired_type = TEXT_PLAIN;
  3832.   }
  3833.   else if (widget == mad->source_p) {
  3834.     XtVaSetValues (mad->text_p, XmNset, False, 0);
  3835.     XtVaSetValues (mad->postscript_p, XmNset, False, 0);
  3836.     if (attach_pos >= 0)
  3837.       mad->attachments[attach_pos].desired_type = NULL;
  3838.   }
  3839.   else if (widget == mad->postscript_p) {
  3840.     XtVaSetValues (mad->source_p, XmNset, False, 0);
  3841.     XtVaSetValues (mad->text_p, XmNset, False, 0);
  3842.     if (attach_pos >= 0)
  3843.       mad->attachments[attach_pos].desired_type = APPLICATION_POSTSCRIPT;
  3844.   }
  3845.   else
  3846.     abort ();
  3847. }
  3848.  
  3849. static void
  3850. fe_attachDestroy_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3851. {
  3852.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3853.   int i;
  3854.  
  3855. #ifdef dp_DEBUG
  3856.   fprintf(stderr, "fe_attachDestroy_cb()\n");
  3857.   fprintf(stderr, "Destroying fe_mail_attach_data...\n");
  3858. #endif
  3859.  
  3860.   /* Free the list of attachments too */
  3861.   for(i=0; i<mad->nattachments; i++) {
  3862.     XP_FREE((char *)mad->attachments[i].url);
  3863.   }
  3864.   if (mad->location_shell)
  3865.     XtDestroyWidget(mad->location_shell);
  3866.   if (mad->file_shell)
  3867.     XtDestroyWidget(XtParent(mad->file_shell));
  3868.   CONTEXT_DATA(mad->context) ->mad = NULL;
  3869.   free (mad);
  3870. }
  3871.  
  3872. static void
  3873. fe_attachCancel_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3874. {
  3875.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3876.  
  3877.   /* We dont need to delete all the attachments that we have as they will
  3878.      be deleted either the next time we show the attach window (or) when
  3879.      the message composition context gets destroyed */
  3880.  
  3881.   XtUnmanageChild(mad->shell);
  3882.   if (mad->location_shell)
  3883.     XtUnmanageChild(mad->location_shell);
  3884.   if (mad->file_shell)
  3885.     XtUnmanageChild(mad->file_shell);
  3886. }
  3887.  
  3888. static void
  3889. fe_attachOk_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3890. {
  3891.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3892.   const char* ptr;
  3893.  
  3894.   mad->attachments[mad->nattachments].url = NULL;
  3895.   MSG_SetAttachmentList(mad->comppane, mad->attachments);
  3896.   ptr = MSG_GetCompHeader(mad->comppane, MSG_ATTACHMENTS_HEADER_MASK);
  3897.   fe_SetTextFieldAndCallBack(CONTEXT_DATA(mad->context)->mcAttachments,
  3898.                ptr ? (char*) ptr : "");
  3899.  
  3900.   /* We dont need to delete all the attachments that we have as they will
  3901.      be deleted either the next time we show the attach window (or) when
  3902.      the message composition context gets destroyed */
  3903.  
  3904.   XtUnmanageChild(mad->shell);
  3905.   if (mad->location_shell)
  3906.     XtUnmanageChild(mad->location_shell);
  3907.   if (mad->file_shell)
  3908.     XtUnmanageChild(mad->file_shell);
  3909. }
  3910.  
  3911. static void
  3912. fe_attach_location_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3913. {
  3914.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3915.  
  3916.   if (!mad->location_shell) fe_attach_make_location(mad);
  3917.  
  3918.   XtManageChild(mad->location_shell);
  3919.   XMapRaised(XtDisplay(mad->location_shell), XtWindow(mad->location_shell));
  3920. }
  3921.  
  3922. static void
  3923. fe_attach_file_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3924. {
  3925.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3926.  
  3927.   if (!mad->file_shell) fe_attach_make_file(mad);
  3928.  
  3929.   XtManageChild(mad->file_shell);
  3930.   XMapRaised(XtDisplay(mad->file_shell), XtWindow(mad->file_shell));
  3931. }
  3932.  
  3933. static void
  3934. fe_attach_delete_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3935. {
  3936.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3937.   int *poslist, npos;
  3938.   int i, pos;
  3939.  
  3940.   if (XmListGetSelectedPos(mad->list, &poslist, &npos)) {
  3941.     for(i=0; i<npos; i++) {
  3942.       XmListDeletePos(mad->list, poslist[i]);
  3943.       fe_del_attachment(mad, poslist[i]);
  3944.     }
  3945.     /*
  3946.      * After deleting an item from the list, select the
  3947.      * previous item in the list (or the last if it was
  3948.      * the first.)
  3949.      */
  3950.     pos = poslist[npos - 1] - 1;
  3951.     if (pos < 0)
  3952.       pos = 0;
  3953.     XmListSelectPos(mad->list, pos, TRUE);
  3954.     XP_FREE(poslist);
  3955.   }
  3956.  
  3957.   /*
  3958.    * If nothing left in the list selected, desensitize
  3959.    * the delete button.
  3960.    */
  3961.   if (!XmListGetSelectedPos(mad->list, &poslist, &npos)) {
  3962.     XtVaSetValues(mad->delete, XmNsensitive, False, 0);
  3963.   }
  3964.   else XP_FREE(poslist);
  3965. }
  3966.  
  3967. static void
  3968. fe_attach_select_cb (Widget widget, XtPointer closure, XtPointer call_data)
  3969. {
  3970.   struct fe_mail_attach_data *mad = (struct fe_mail_attach_data  *) closure;
  3971.   XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
  3972.   const char *s;
  3973.   Widget which_w = 0;
  3974.  
  3975.   if (cbs->item_position > mad->nattachments) return;
  3976.   else XP_ASSERT(cbs->item_position <= mad->nattachments);
  3977.  
  3978.   s = mad->attachments[cbs->item_position-1].desired_type;
  3979.  
  3980.   if (!s || !*s)
  3981.     which_w = mad->source_p;
  3982.   else if (!XP_STRCMP(s, APPLICATION_POSTSCRIPT))
  3983.     which_w = mad->postscript_p;
  3984.   else if (!XP_STRCMP(s, TEXT_PLAIN))
  3985.     which_w = mad->text_p;
  3986.  
  3987.   if (which_w == 0) return;
  3988.   else XP_ASSERT (which_w != 0);
  3989.   fe_attach_doc_type_cb(which_w, mad, NULL);
  3990.  
  3991.   XtVaSetValues(mad->delete, XmNsensitive, True, 0);
  3992. }
  3993.  
  3994. static void
  3995. fe_make_attach_dialog(MWContext* context)
  3996. {
  3997.   fe_ContextData* data = CONTEXT_DATA(context);
  3998.   Widget shell, form;
  3999.   Widget list;
  4000.   Widget messb;
  4001.   Widget   attach_location, attach_file, delete;
  4002.   Widget label;
  4003.   Widget   text_p, source_p, postscript_p;
  4004.   Widget ok_button, cancel_button;
  4005.   Widget kids [50];
  4006.   Arg av [20];
  4007.   int ac;
  4008.   Visual *v = 0;
  4009.   Colormap cmap = 0;
  4010.   Cardinal depth = 0;
  4011.   struct fe_mail_attach_data *mad = data->mad;
  4012.  
  4013.   XP_ASSERT(context->type == MWContextMessageComposition);
  4014.  
  4015.   if (mad && mad->shell)
  4016.     return;
  4017.  
  4018.   XtVaGetValues (CONTEXT_WIDGET(context), XtNvisual, &v, XtNcolormap, &cmap,
  4019.          XtNdepth, &depth, 0);
  4020.   ac = 0;
  4021.   XtSetArg (av[ac], XmNvisual, v); ac++;
  4022.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  4023.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  4024.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  4025.   XtSetArg (av[ac], XmNtransientFor, CONTEXT_WIDGET(context)); ac++;
  4026.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  4027.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  4028.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  4029.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  4030.   shell = XmCreateTemplateDialog (CONTEXT_WIDGET(context), "attach", av, ac);
  4031. /*  fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_SEPARATOR)); */
  4032.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_OK_BUTTON));
  4033.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_CANCEL_BUTTON));
  4034. /*  fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_APPLY_BUTTON));*/
  4035.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_DEFAULT_BUTTON));
  4036.   fe_UnmanageChild_safe (XmMessageBoxGetChild (shell, XmDIALOG_HELP_BUTTON));
  4037.  
  4038.   ac = 0;
  4039.   ok_button = XmCreatePushButtonGadget (shell, "OK", av, ac);
  4040.   cancel_button = XmCreatePushButtonGadget (shell, "cancel", av, ac);
  4041.  
  4042.   ac = 0;
  4043.   XtSetArg (av[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  4044.   XtSetArg (av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  4045.   XtSetArg (av[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  4046.   XtSetArg (av[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
  4047.   form = XmCreateForm (shell, "form", av, ac);
  4048.  
  4049.   ac = 0;
  4050.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_WORK_AREA); ac++;
  4051.   XtSetArg (av[ac], XmNresizePolicy, XmRESIZE_GROW); ac++;
  4052.   messb = XmCreateMessageBox(form, "messagebox", av, ac);
  4053.   fe_UnmanageChild_safe(XmMessageBoxGetChild(messb, XmDIALOG_SEPARATOR));
  4054.   fe_UnmanageChild_safe(XmMessageBoxGetChild(messb, XmDIALOG_OK_BUTTON));
  4055.   fe_UnmanageChild_safe(XmMessageBoxGetChild(messb, XmDIALOG_CANCEL_BUTTON));
  4056.   fe_UnmanageChild_safe(XmMessageBoxGetChild(messb, XmDIALOG_HELP_BUTTON));
  4057.   ac = 0;
  4058.   list = XmCreateList(messb, "list", av, ac);
  4059.   attach_location = XmCreatePushButtonGadget(messb, "attachLocation", av, ac);
  4060.   attach_file = XmCreatePushButtonGadget(messb, "attachFile", av, ac);
  4061.   ac = 0;
  4062.   XtSetArg (av[ac], XmNsensitive, False); ac++;
  4063.   delete = XmCreatePushButtonGadget(messb, "delete", av, ac);
  4064.  
  4065.   ac = 0;
  4066.   label = XmCreateLabelGadget (form, "label", av, ac);
  4067.   ac = 0;
  4068.   XtSetArg (av[ac], XmNset, False); ac++;
  4069.   source_p = XmCreateToggleButtonGadget (form, "sourceToggle", av, ac);
  4070.   text_p = XmCreateToggleButtonGadget (form, "textToggle", av, ac);
  4071.   postscript_p = XmCreateToggleButtonGadget (form, "postscriptToggle", av, ac);
  4072.  
  4073.   /* Making the attachments in such a way that the list would grow is
  4074.      the height of the dialog is increased */
  4075.   XtVaSetValues (messb,
  4076.          XmNtopAttachment, XmATTACH_FORM,
  4077.          XmNbottomAttachment, XmATTACH_FORM,
  4078.          XmNleftAttachment, XmATTACH_FORM,
  4079.          XmNrightAttachment, XmATTACH_FORM,
  4080.          0);
  4081.   XtVaSetValues (label,
  4082.          XmNtopAttachment, XmATTACH_NONE,
  4083.          XmNbottomAttachment, XmATTACH_FORM,
  4084.          XmNleftAttachment, XmATTACH_FORM,
  4085.          XmNrightAttachment, XmATTACH_NONE,
  4086.          0);
  4087.   XtVaSetValues (source_p,
  4088.          XmNtopAttachment, XmATTACH_NONE,
  4089.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  4090.          XmNbottomWidget, label,
  4091.          XmNleftAttachment, XmATTACH_WIDGET,
  4092.          XmNleftWidget, label,
  4093.          XmNrightAttachment, XmATTACH_NONE,
  4094.          0);
  4095.   XtVaSetValues (text_p,
  4096.          XmNtopAttachment, XmATTACH_NONE,
  4097.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  4098.          XmNbottomWidget, label,
  4099.          XmNleftAttachment, XmATTACH_WIDGET,
  4100.          XmNleftWidget, source_p,
  4101.          XmNrightAttachment, XmATTACH_NONE,
  4102.          0);
  4103.   XtVaSetValues (postscript_p,
  4104.          XmNtopAttachment, XmATTACH_NONE,
  4105.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  4106.          XmNbottomWidget, label,
  4107.          XmNleftAttachment, XmATTACH_WIDGET,
  4108.          XmNleftWidget, text_p,
  4109.          XmNrightAttachment, XmATTACH_NONE,
  4110.          0);
  4111.  
  4112. #ifdef dp_DEBUG
  4113.   fprintf(stderr, "Creating new fe_mail_attach_data...\n");
  4114. #endif
  4115.   data->mad = mad = (struct fe_mail_attach_data *)
  4116.     calloc (sizeof (struct fe_mail_attach_data), 1);
  4117.   mad->nattachments = 0;
  4118.  
  4119.   mad->context = context;
  4120.   mad->shell = shell;
  4121.   mad->list = list;
  4122.   mad->comppane = data->comppane;
  4123.  
  4124.   XtManageChild(list);
  4125.   ac = 0;
  4126.   kids [ac++] = attach_location;
  4127.   kids [ac++] = mad->attach_file = attach_file;
  4128.   kids [ac++] = mad->delete = delete;
  4129.   XtManageChildren (kids, ac);
  4130.   ac = 0;
  4131.   kids [ac++] = messb;
  4132.   kids [ac++] = label;
  4133.   kids [ac++] = mad->source_p = source_p;
  4134.   kids [ac++] = mad->text_p = text_p;
  4135.   kids [ac++] = mad->postscript_p = postscript_p;
  4136.  
  4137.   XtManageChildren (kids, ac);
  4138.  
  4139.   XtManageChild (form);
  4140.   XtManageChild (ok_button);
  4141.   XtManageChild (cancel_button);
  4142.  
  4143.   XtAddCallback (ok_button, XmNactivateCallback, fe_attachOk_cb, mad);
  4144.   XtAddCallback (cancel_button, XmNactivateCallback, fe_attachCancel_cb, mad);
  4145.   XtAddCallback (shell, XtNdestroyCallback, fe_attachDestroy_cb, mad);
  4146.  
  4147.   XtAddCallback (attach_location, XmNactivateCallback,
  4148.                     fe_attach_location_cb, mad);
  4149.   XtAddCallback (attach_file, XmNactivateCallback, fe_attach_file_cb, mad);
  4150.   XtAddCallback (delete, XmNactivateCallback, fe_attach_delete_cb, mad);
  4151.   XtAddCallback (list, XmNbrowseSelectionCallback, fe_attach_select_cb, mad);
  4152.  
  4153.   XtAddCallback (text_p,   XmNvalueChangedCallback,
  4154.          fe_attach_doc_type_cb, mad);
  4155.   XtAddCallback (source_p, XmNvalueChangedCallback,
  4156.          fe_attach_doc_type_cb, mad);
  4157.   XtAddCallback (postscript_p, XmNvalueChangedCallback,
  4158.          fe_attach_doc_type_cb, mad);
  4159.  
  4160.   /* Remember the last attachment typed used. */
  4161.   XtVaSetValues((fe_last_attach_type == NULL ? source_p :
  4162.          strcmp(fe_last_attach_type, TEXT_PLAIN) == 0 ? text_p :
  4163.          strcmp(fe_last_attach_type,
  4164.             APPLICATION_POSTSCRIPT) == 0 ? postscript_p :
  4165.          source_p),
  4166.         XmNset, True, 0);
  4167.  
  4168. #if 0
  4169.   /* Decide whether to attach a file or a URL based on what the URL is.
  4170.      If there's something in the Attachement: field already, use that.
  4171.      Otherwise, use the document associated with this mail window.
  4172.    */
  4173.   {
  4174.     char *string = 0;
  4175.     const char *url = 0;
  4176.     const char *file;
  4177.  
  4178.     string = fe_GetTextField (data->mcAttachments);
  4179.  
  4180.     url = fe_StringTrim(string);
  4181.     if (url && !*url) {
  4182.       url = 0;
  4183.     }
  4184.  
  4185.     if (!url) {
  4186.       url = MSG_GetAssociatedURL(context);
  4187.     }
  4188.  
  4189.     if (! url)
  4190.       file = 0;
  4191.     else if (url[0] == '/')
  4192.       file = url;
  4193.     else if (!strncasecomp (url, "file://localhost/", 17))
  4194.       file = url + 16;
  4195.     else if (!strncasecomp (url, "file://", 7))
  4196.       file = 0;
  4197.     else if (!strncasecomp (url, "file:/", 6))
  4198.       file = url + 5;
  4199.     else
  4200.       file = 0;
  4201.  
  4202.     if (file)
  4203.       fe_SetTextField (file_text, file);
  4204.  
  4205.     XtVaSetValues (doc_p, XmNset, True, 0);
  4206.     fe_SetTextField (doc_text, url);
  4207.     if (string) free (string);
  4208.   }
  4209. #endif
  4210.  
  4211.   fe_NukeBackingStore (shell);
  4212.   XtManageChild (shell);
  4213. }
  4214.  
  4215.  
  4216. /* Prompts for attachment info.
  4217.  */
  4218. void
  4219. fe_mailto_attach_dialog(MWContext* context)
  4220. {
  4221.   struct fe_mail_attach_data *mad = CONTEXT_DATA(context)->mad;
  4222.   const struct MSG_AttachmentData *list;
  4223.   int i;
  4224.  
  4225.   XP_ASSERT(context->type == MWContextMessageComposition);
  4226.  
  4227.   if (!mad || !mad->shell) {
  4228.     fe_make_attach_dialog(context);
  4229.     mad = CONTEXT_DATA(context)->mad;
  4230.   }
  4231.  
  4232.   /* Free the existing list of attachments */
  4233.   XmListDeleteAllItems(mad->list);
  4234.   for(i=0; i<mad->nattachments; i++) {
  4235.     XP_FREE((char *)mad->attachments[i].url);
  4236.   }
  4237.   mad->nattachments = 0;
  4238.     
  4239.   /* Refresh the list of attachments */
  4240.   list = MSG_GetAttachmentList(mad->comppane);
  4241.   while (list && list->url != NULL) {
  4242.     fe_add_attachmentData(mad, list);
  4243.     list++;
  4244.   }
  4245.  
  4246.   XtManageChild(mad->shell);
  4247.   XMapRaised(XtDisplay(mad->shell), XtWindow(mad->shell));
  4248.   return;
  4249. }
  4250.  
  4251.  
  4252.  
  4253. void
  4254. fe_attach_dropfunc(Widget dropw, void* closure, fe_dnd_Event type,
  4255.            fe_dnd_Source* source, XEvent* event)
  4256. {
  4257.   MWContext *compose_context;
  4258.   MWContext *src_context;
  4259.   const struct MSG_AttachmentData *old_list, *a;
  4260.   struct MSG_AttachmentData *new_list;
  4261.   Boolean sensitive_p = False;
  4262.   char **urls, **ss;
  4263.   const char* s;
  4264.   int old_count = 0;
  4265.   int new_count = 0;
  4266.   int i;
  4267.  
  4268.   if (type != FE_DND_DROP)
  4269.     return;
  4270.  
  4271.   compose_context = (MWContext *) closure;
  4272.   if (!compose_context) return;
  4273.   XP_ASSERT(compose_context->type == MWContextMessageComposition);
  4274.   if (compose_context->type != MWContextMessageComposition)
  4275.     return;
  4276.  
  4277.   XtVaGetValues(CONTEXT_DATA(compose_context)->mcAttachments,
  4278.         XmNsensitive, &sensitive_p, 0);
  4279.   if (!sensitive_p)
  4280.     {
  4281.       /* If the Attachments field is not sensitive, then that means that
  4282.      an attachment (or delivery?) is in progress, and bad things would
  4283.      happen were we to try and attach things right now.  So just beep.
  4284.        */
  4285.       XBell (XtDisplay (CONTEXT_WIDGET(compose_context)), 0);
  4286.       return;
  4287.     }
  4288.  
  4289.   src_context = fe_WidgetToMWContext((Widget) source->closure);
  4290.   if (!src_context) return;
  4291.   switch (src_context->type)
  4292.     {
  4293.     case MWContextMail:
  4294.     case MWContextNews:
  4295.       /* ###tw  Should get a list of all the selected URLs from the mail/news
  4296.        window...*/
  4297.       urls = 0;
  4298.       break;
  4299.     case MWContextBookmarks:
  4300.       /* #### Get a list of all the selected URLs out of the bookmarks
  4301.      window... */
  4302.       urls = 0;
  4303.       break;
  4304.     default:
  4305.       XP_ASSERT(0);
  4306.       urls = 0;
  4307.       break;
  4308.     }
  4309.   if (!urls)
  4310.     {
  4311.       XBell (XtDisplay (CONTEXT_WIDGET(compose_context)), 0);
  4312.       return;
  4313.     }
  4314.  
  4315.   new_count = 0;
  4316.   for (ss = urls; *ss; ss++)
  4317.     new_count++;
  4318.   XP_ASSERT(new_count > 0);
  4319.   if (new_count <= 0) return; /* #### leaks `urls'; but it already asserted. */
  4320.  
  4321.   old_list = MSG_GetAttachmentList(CONTEXT_DATA(compose_context)->comppane);
  4322.   old_count = 0;
  4323.   if (old_list)
  4324.     for (a = old_list; a->url; a++)
  4325.       old_count++;
  4326.  
  4327.   new_list = (struct MSG_AttachmentData *)
  4328.     XP_ALLOC(sizeof(struct MSG_AttachmentData) * (old_count + new_count + 1));
  4329.  
  4330.   for (i = 0; i < old_count; i++)
  4331.     {
  4332.       XP_MEMSET(&new_list[i], 0, sizeof(new_list[i]));
  4333.       if (old_list[i].url)
  4334.     new_list[i].url = XP_STRDUP(old_list[i].url);
  4335.       if (old_list[i].desired_type)
  4336.     new_list[i].desired_type = XP_STRDUP(old_list[i].desired_type);
  4337.       if (old_list[i].real_type)
  4338.     new_list[i].real_type = XP_STRDUP(old_list[i].real_type);
  4339.       if (old_list[i].real_encoding)
  4340.     new_list[i].real_encoding = XP_STRDUP(old_list[i].real_encoding);
  4341.       if (old_list[i].real_name)
  4342.     new_list[i].real_name = XP_STRDUP(old_list[i].real_name);
  4343.       if (old_list[i].description)
  4344.     new_list[i].description = XP_STRDUP(old_list[i].description);
  4345.       if (old_list[i].x_mac_type)
  4346.     new_list[i].x_mac_type = XP_STRDUP(old_list[i].x_mac_type);
  4347.       if (old_list[i].x_mac_creator)
  4348.     new_list[i].x_mac_creator = XP_STRDUP(old_list[i].x_mac_creator);
  4349.     }
  4350.  
  4351.   if (new_count > 0)
  4352.     XP_MEMSET(new_list + old_count, 0,
  4353.           sizeof(struct MSG_AttachmentData) * (new_count + 1));
  4354.  
  4355.   i = old_count;
  4356.   for (ss = urls; *ss; ss++)
  4357.     new_list[i++].url = *ss;
  4358.  
  4359.   MSG_SetAttachmentList(CONTEXT_DATA(compose_context)->comppane, new_list);
  4360.  
  4361.   for (i = 0; i < old_count; i++)
  4362.     {
  4363.       if (new_list[i].url) XP_FREE((char*)new_list[i].url);
  4364.       if (new_list[i].desired_type) XP_FREE((char*)new_list[i].desired_type);
  4365.       if (new_list[i].real_type) XP_FREE((char*)new_list[i].real_type);
  4366.       if (new_list[i].real_encoding) XP_FREE((char*)new_list[i].real_encoding);
  4367.       if (new_list[i].real_name) XP_FREE((char*)new_list[i].real_name);
  4368.       if (new_list[i].description) XP_FREE((char*)new_list[i].description);
  4369.       if (new_list[i].x_mac_type) XP_FREE((char*)new_list[i].x_mac_type);
  4370.       if (new_list[i].x_mac_creator) XP_FREE((char*)new_list[i].x_mac_creator);
  4371.     }
  4372.   XP_FREE (new_list);
  4373.   for (ss = urls; *ss; ss++)
  4374.     XP_FREE(*ss);
  4375.   XP_FREE(urls);
  4376.  
  4377.   /* Now they're attached; update the display. */
  4378.   s = MSG_GetCompHeader(CONTEXT_DATA(compose_context)->comppane,
  4379.             MSG_ATTACHMENTS_HEADER_MASK);
  4380.   fe_SetTextFieldAndCallBack(CONTEXT_DATA(compose_context)->mcAttachments,
  4381.                s ? (char*) s : "");
  4382. }
  4383.  
  4384. #endif  /* 0 */
  4385.  
  4386. int
  4387. FE_GetMessageBody (MSG_Pane* comppane,
  4388.            char **body,
  4389.            uint32 *body_size,
  4390.            MSG_FontCode **font_changes)
  4391. {
  4392.   MWContext* context = MSG_GetContext(comppane);
  4393.   if (context->type != MWContextMessageComposition) return -1;
  4394.   fe_getMessageBody(context, body, body_size, font_changes);
  4395.   return 0;
  4396. }
  4397.  
  4398. void
  4399. FE_DoneWithMessageBody(MSG_Pane* comppane, char* body, uint32 body_size)
  4400. {
  4401.   MWContext* context = MSG_GetContext(comppane);
  4402.   fe_doneWithMessageBody(context, body, body_size);
  4403. }
  4404.  
  4405.  
  4406. void
  4407. fe_mail_text_modify_cb (Widget text, XtPointer client_data,
  4408.             XtPointer call_data)
  4409. {
  4410.   MWContext* context = (MWContext*) client_data;
  4411.   CONTEXT_DATA(context)->mcCitedAndUnedited = False;
  4412.   CONTEXT_DATA(context)->mcEdited = True;
  4413.   /*  MSG_MessageBodyEdited(CONTEXT_DATA(context)->comppane); */
  4414. }
  4415.  
  4416. #endif  /* MOZ_MAIL_NEWS */
  4417.  
  4418. #define cite_abort 0
  4419. #define cite_protect_me_from_myself 1
  4420. #define cite_let_me_be_a_loser 2
  4421.  
  4422. #if 0
  4423. static int
  4424. FE_BogusQuotationQuery (MWContext *context, Boolean double_p)
  4425. {
  4426.   struct fe_confirm_data data;
  4427.   Widget dialog;
  4428.   Arg av [20];
  4429.   int ac;
  4430.   Visual *v = 0;
  4431.   Colormap cmap = 0;
  4432.   Cardinal depth = 0;
  4433.   Widget parent = CONTEXT_WIDGET (context);
  4434.   XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  4435.          XtNdepth, &depth, 0);
  4436.   ac = 0;
  4437.   XtSetArg (av[ac], XmNvisual, v); ac++;
  4438.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  4439.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  4440.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  4441.   XtSetArg (av[ac], XmNtransientFor, parent); ac++;
  4442.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  4443.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  4444.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  4445.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  4446.   dialog = XmCreatePromptDialog (parent, (double_p ?
  4447.                       "citationQuery"
  4448.                       : "doubleCitationQuery")
  4449.                  , av, ac);
  4450.  
  4451. /*  fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_SEPARATOR));*/
  4452.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_TEXT));
  4453.   XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL));
  4454.   XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_APPLY_BUTTON));
  4455. #ifdef NO_HELP
  4456.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
  4457. #endif
  4458.  
  4459.   XtManageChild (dialog);
  4460.  
  4461.   XtAddCallback (dialog, XmNokCallback, fe_destroy_ok_cb, &data);
  4462.   XtAddCallback (dialog, XmNapplyCallback, fe_destroy_apply_cb, &data);
  4463.   XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cancel_cb, &data);
  4464.   XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  4465.  
  4466.   data.context = context;
  4467.   data.widget = dialog;
  4468.   data.answer = Answer_Invalid;
  4469.  
  4470.   while (data.answer == Answer_Invalid)
  4471.     fe_EventLoop ();
  4472.  
  4473.   return (data.answer == 0 ? cite_abort :
  4474.       data.answer == 1 ? cite_protect_me_from_myself :
  4475.       data.answer == 2 ? cite_let_me_be_a_loser : 99);
  4476. }
  4477. #endif
  4478.  
  4479.  
  4480. /* Print setup
  4481.  */
  4482.  
  4483. struct fe_print_data
  4484. {
  4485.   MWContext *context;
  4486.   History_entry *hist;
  4487.   Widget shell;
  4488.   Widget printer, file, command_text, file_text, browse;
  4489.   Widget first, last;
  4490.   Widget portrait, landscape;
  4491.   Widget grey, color;
  4492.   Widget letter, legal, exec, a4;
  4493. };
  4494.  
  4495. static void
  4496. fe_print_to_toggle_cb (Widget widget, XtPointer closure, XtPointer call_data)
  4497. {
  4498.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4499.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  4500.   if (!cb->set)
  4501.     XtVaSetValues (widget, XmNset, True, 0);
  4502.   else if (widget == fpd->printer)
  4503.     {
  4504.       XtVaSetValues (fpd->file, XmNset, False, 0);
  4505.       XtVaSetValues (fpd->browse, XmNsensitive, False, 0);
  4506.       XtVaSetValues (fpd->file_text, XmNsensitive, False, 0);
  4507.       XtVaSetValues (fpd->command_text, XmNsensitive, True, 0);
  4508.       XmProcessTraversal (fpd->command_text, XmTRAVERSE_CURRENT);
  4509.     }
  4510.   else if (widget == fpd->file)
  4511.     {
  4512.       XtVaSetValues (fpd->printer, XmNset, False, 0);
  4513.       XtVaSetValues (fpd->browse, XmNsensitive, True, 0);
  4514.       XtVaSetValues (fpd->file_text, XmNsensitive, True, 0);
  4515.       XtVaSetValues (fpd->command_text, XmNsensitive, False, 0);
  4516.       XmProcessTraversal (fpd->file_text, XmTRAVERSE_CURRENT);
  4517.     }
  4518.   else
  4519.     abort ();
  4520. }
  4521.  
  4522. static void
  4523. fe_print_order_toggle_cb (Widget widget, XtPointer closure,XtPointer call_data)
  4524. {
  4525.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4526.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  4527.   if (!cb->set)
  4528.     XtVaSetValues (widget, XmNset, True, 0);
  4529.   else if (widget == fpd->first)
  4530.     XtVaSetValues (fpd->last, XmNset, False, 0);
  4531.   else if (widget == fpd->last)
  4532.     XtVaSetValues (fpd->first, XmNset, False, 0);
  4533.   else
  4534.     abort ();
  4535. }
  4536.  
  4537. static void
  4538. fe_print_orientation_toggle_cb (Widget widget, XtPointer closure,
  4539.                 XtPointer call_data)
  4540. {
  4541.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4542.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  4543.   if (!cb->set)
  4544.     XtVaSetValues (widget, XmNset, True, 0);
  4545.   else if (widget == fpd->portrait)
  4546.     XtVaSetValues (fpd->landscape, XmNset, False, 0);
  4547.   else if (widget == fpd->landscape)
  4548.     XtVaSetValues (fpd->portrait, XmNset, False, 0);
  4549.   else
  4550.     abort ();
  4551. }
  4552.  
  4553. static void
  4554. fe_print_color_toggle_cb (Widget widget, XtPointer closure,
  4555.               XtPointer call_data)
  4556. {
  4557.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4558.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  4559.   if (!cb->set)
  4560.     XtVaSetValues (widget, XmNset, True, 0);
  4561.   else if (widget == fpd->grey)
  4562.     XtVaSetValues (fpd->color, XmNset, False, 0);
  4563.   else if (widget == fpd->color)
  4564.     XtVaSetValues (fpd->grey, XmNset, False, 0);
  4565.   else
  4566.     abort ();
  4567. }
  4568.  
  4569. static void
  4570. fe_print_paper_toggle_cb (Widget widget, XtPointer closure,
  4571.               XtPointer call_data)
  4572. {
  4573.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4574.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  4575.   if (!cb->set)
  4576.     XtVaSetValues (widget, XmNset, True, 0);
  4577.   else if (widget == fpd->letter)
  4578.     {
  4579.       XtVaSetValues (fpd->legal,  XmNset, False, 0);
  4580.       XtVaSetValues (fpd->exec,   XmNset, False, 0);
  4581.       XtVaSetValues (fpd->a4,     XmNset, False, 0);
  4582.     }
  4583.   else if (widget == fpd->legal)
  4584.     {
  4585.       XtVaSetValues (fpd->letter, XmNset, False, 0);
  4586.       XtVaSetValues (fpd->exec,   XmNset, False, 0);
  4587.       XtVaSetValues (fpd->a4,     XmNset, False, 0);
  4588.     }
  4589.   else if (widget == fpd->exec)
  4590.     {
  4591.       XtVaSetValues (fpd->letter, XmNset, False, 0);
  4592.       XtVaSetValues (fpd->legal,  XmNset, False, 0);
  4593.       XtVaSetValues (fpd->a4,     XmNset, False, 0);
  4594.     }
  4595.   else if (widget == fpd->a4)
  4596.     {
  4597.       XtVaSetValues (fpd->letter, XmNset, False, 0);
  4598.       XtVaSetValues (fpd->legal,  XmNset, False, 0);
  4599.       XtVaSetValues (fpd->exec,   XmNset, False, 0);
  4600.     }
  4601.   else
  4602.     abort ();
  4603. }
  4604.  
  4605. void
  4606. fe_browse_file_of_text (MWContext *context, Widget text_field, Boolean dirp)
  4607. {
  4608.   char *text = 0;
  4609.   XmString xmpat, xmfile;
  4610.   char buf [1024];
  4611.   Arg av [20];
  4612.   int ac;
  4613.   Visual *v = 0;
  4614.   Colormap cmap = 0;
  4615.   Cardinal depth = 0;
  4616.   Widget shell;
  4617.   Widget parent;
  4618.   Widget fileb;
  4619.   struct fe_confirm_data data;
  4620.   data.context = context;
  4621.  
  4622.   /* Find the top level window of which this text field is a descendant,
  4623.      and make the file requester be a transient for that. */
  4624.   parent = text_field;
  4625.   while (parent && !XtIsShell (parent))
  4626.     parent = XtParent (parent);
  4627.   assert (parent);
  4628.   if (! parent)
  4629.     parent = CONTEXT_WIDGET (context);
  4630.  
  4631.   XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  4632.          XtNdepth, &depth, 0);
  4633.   text = fe_GetTextField(text_field);
  4634.   text = fe_StringTrim (text);
  4635.  
  4636.  
  4637.   if ( text && *text )
  4638.       text = XP_STRTOK(text, " ");
  4639.  
  4640.   if (!text || !*text)
  4641.     {
  4642.       xmpat = 0;
  4643.       xmfile = 0;
  4644.     }
  4645.   else if (dirp)
  4646.     {
  4647.       if (text [strlen (text) - 1] == '/')
  4648.     text [strlen (text) - 1] = 0;
  4649.       PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4650.       xmpat = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4651.       xmfile = XmStringCreateLtoR (text, XmFONTLIST_DEFAULT_TAG);
  4652.     }
  4653.   else
  4654.     {
  4655.       char *f;
  4656.       if (text [strlen (text) - 1] == '/')
  4657.     PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4658.       else
  4659.     PR_snprintf (buf, sizeof (buf), "%.900s", text);
  4660.       xmfile = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4661.       if (text[0] == '/') /* only do this for absolute path */
  4662.       f = strrchr (text, '/');
  4663.       else
  4664.       f = NULL;
  4665.       if (f && f != text)
  4666.     *f = 0;
  4667.       if (f) {
  4668.         PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4669.         xmpat = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4670.       }
  4671.       else {
  4672.             /* do not change dirmask and pattern if input is a file;
  4673.              * otherwise, the text widget in the file selection box
  4674.              * will insert the file name at the wrong position.
  4675.              * Windows version has similar behavior if a relative file
  4676.              * is entered.
  4677.              */
  4678.           buf[0] = '\0';        /* input was just a file. no '/' in it. */
  4679.           xmpat = 0;
  4680.       }
  4681.     }
  4682.   if (text) free (text);
  4683.  
  4684.   ac = 0;
  4685.   XtSetArg (av[ac], XmNvisual, v); ac++;
  4686.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  4687.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  4688.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  4689. /*  XtSetArg (av[ac], XmNallowShellResize, True); ac++;*/
  4690.   shell = XmCreateDialogShell (parent, "fileBrowser_popup", av, ac);
  4691.   ac = 0;
  4692.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  4693.   XtSetArg (av[ac], XmNfileTypeMask,
  4694.         (dirp ? XmFILE_DIRECTORY : XmFILE_REGULAR)); ac++;
  4695.   fileb = fe_CreateFileSelectionBox (shell, "fileBrowser", av, ac);
  4696.  
  4697. #ifdef NO_HELP
  4698.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (fileb, XmDIALOG_HELP_BUTTON));
  4699. #endif
  4700.  
  4701.   if (xmpat)
  4702.     {
  4703.       XtVaSetValues (fileb,
  4704.              XmNdirMask, xmpat,
  4705.              XmNpattern, xmpat, 0);
  4706. #if 0
  4707.       /*
  4708.        *    The XtVaSetValues on dirMask/pattern will cause this anyway.
  4709.        */
  4710.       XmFileSelectionDoSearch (fileb, xmpat);
  4711. #endif
  4712.       XtVaSetValues (fileb, XmNdirSpec, xmfile, 0);
  4713.       XmStringFree (xmpat);
  4714.       XmStringFree (xmfile);
  4715.     }
  4716.  
  4717.   XtAddCallback (fileb, XmNnoMatchCallback, fe_file_cb, &data);
  4718.   XtAddCallback (fileb, XmNokCallback,      fe_file_cb, &data);
  4719.   XtAddCallback (fileb, XmNcancelCallback,  fe_file_cb, &data);
  4720.   XtAddCallback (fileb, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  4721.  
  4722.   data.answer = Answer_Invalid;
  4723.   data.return_value = 0;
  4724.  
  4725.   fe_HackDialogTranslations (fileb);
  4726.  
  4727.   fe_NukeBackingStore (fileb);
  4728.   XtManageChild (fileb);
  4729.   /* #### check for destruction here */
  4730.   while (data.answer == Answer_Invalid)
  4731.     fe_EventLoop ();
  4732.  
  4733.   if (data.answer == Answer_OK)
  4734.     if (data.return_value)
  4735.       {
  4736.     fe_SetTextField(text_field, data.return_value);
  4737.     free (data.return_value);
  4738.       }
  4739.   if (data.answer != Answer_Destroy)
  4740.     XtDestroyWidget(shell);
  4741. }
  4742.  
  4743. void
  4744. fe_browse_file_of_text_in_url (MWContext *context, Widget text_field, Boolean dirp)
  4745. {
  4746.     char *orig_text = 0;
  4747.     char *text = 0;
  4748.     XmString xmpat, xmfile;
  4749.     char buf [1024];
  4750.     Arg av [20];
  4751.     int ac;
  4752.     Visual *v = 0;
  4753.     Colormap cmap = 0;
  4754.     Cardinal depth = 0;
  4755.     Widget shell;
  4756.     Widget parent;
  4757.     Widget fileb;
  4758.     struct fe_confirm_data data;
  4759.     data.context = context;
  4760.  
  4761.     /* Find the top level window of which this text field is a descendant,
  4762.        and make the file requester be a transient for that. */
  4763.  
  4764.     parent = text_field;
  4765.     while (parent && !XtIsShell (parent))
  4766.         parent = XtParent (parent);
  4767.     assert (parent);
  4768.     if (! parent)
  4769.         parent = CONTEXT_WIDGET (context);
  4770.  
  4771.     XtVaGetValues (parent, XtNvisual, &v, XtNcolormap, &cmap,
  4772.                    XtNdepth, &depth, 0);
  4773.     text = fe_GetTextField(text_field);
  4774.     orig_text = text;
  4775.     text = fe_StringTrim (text);
  4776.  
  4777.     if (!strncasecomp (text, "http://", 7)) {
  4778.         /* ignore url using http */
  4779.         free(orig_text);
  4780.         orig_text = 0;
  4781.         text = 0;
  4782.     }
  4783.  
  4784.     if (text) {
  4785.         if (!strncasecomp (text, "file://", 7)) {
  4786.             /* get to the absolute file path */
  4787.             text += 7;
  4788.         }
  4789.     }
  4790.  
  4791.     if ( text && *text )
  4792.         text = XP_STRTOK(text, " ");
  4793.  
  4794.     if (!text || !*text){
  4795.         xmpat = 0;
  4796.         xmfile = 0;
  4797.     }
  4798.     else if (dirp){
  4799.         if (text [strlen (text) - 1] == '/')
  4800.             text [strlen (text) - 1] = 0;
  4801.         PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4802.         xmpat = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4803.         xmfile = XmStringCreateLtoR (text, XmFONTLIST_DEFAULT_TAG);
  4804.     }
  4805.     else {
  4806.         char *f;
  4807.         if (text [strlen (text) - 1] == '/')
  4808.             PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4809.         else
  4810.             PR_snprintf (buf, sizeof (buf), "%.900s", text);
  4811.         xmfile = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4812.         if (text[0] == '/') /* only do this for absolute path */
  4813.             f = strrchr (text, '/');
  4814.         else
  4815.             f = NULL;
  4816.         if (f && f != text)
  4817.             *f = 0;
  4818.         if (f) {
  4819.             PR_snprintf (buf, sizeof (buf), "%.900s/*", text);
  4820.             xmpat = XmStringCreateLtoR (buf, XmFONTLIST_DEFAULT_TAG);
  4821.         }
  4822.         else {
  4823.             /* Do not change dirmask and pattern if input is a file;
  4824.              * otherwise, the text widget in the file selection box
  4825.              * will insert the file name at the wrong position.
  4826.              * Windows version has similar behavior if a relative file
  4827.              * is entered.
  4828.              */
  4829.             buf[0] = '\0';        /* input was just a file. no '/' in it. */
  4830.             xmpat = 0;
  4831.         }
  4832.     }
  4833.     if (orig_text) free (orig_text);
  4834.  
  4835.     ac = 0;
  4836.     XtSetArg (av[ac], XmNvisual, v); ac++;
  4837.     XtSetArg (av[ac], XmNdepth, depth); ac++;
  4838.     XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  4839.     XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  4840.     /*  XtSetArg (av[ac], XmNallowShellResize, True); ac++;*/
  4841.     shell = XmCreateDialogShell (parent, "fileBrowser_popup", av, ac);
  4842.     ac = 0;
  4843.     XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  4844.     XtSetArg (av[ac], XmNfileTypeMask, (dirp ? XmFILE_DIRECTORY : XmFILE_REGULAR)); ac++;
  4845.     fileb = fe_CreateFileSelectionBox (shell, "fileBrowser", av, ac);
  4846.  
  4847. #ifdef NO_HELP
  4848.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (fileb, XmDIALOG_HELP_BUTTON));
  4849. #endif
  4850.  
  4851.     if (xmpat) {
  4852.         XtVaSetValues (fileb,
  4853.                        XmNdirMask, xmpat,
  4854.                        XmNpattern, xmpat, 0);
  4855. #if 0
  4856.         /*
  4857.          *    The XtVaSetValues on dirMask/pattern will cause this anyway.
  4858.          */
  4859.         XmFileSelectionDoSearch (fileb, xmpat);
  4860. #endif
  4861.         XtVaSetValues (fileb, XmNdirSpec, xmfile, 0);
  4862.         XmStringFree (xmpat);
  4863.         XmStringFree (xmfile);
  4864.     }
  4865.  
  4866.     XtAddCallback (fileb, XmNnoMatchCallback, fe_file_cb, &data);
  4867.     XtAddCallback (fileb, XmNokCallback,      fe_file_cb, &data);
  4868.     XtAddCallback (fileb, XmNcancelCallback,  fe_file_cb, &data);
  4869.     XtAddCallback (fileb, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  4870.  
  4871.     data.answer = Answer_Invalid;
  4872.     data.return_value = 0;
  4873.  
  4874.     fe_HackDialogTranslations (fileb);
  4875.  
  4876.     fe_NukeBackingStore (fileb);
  4877.     XtManageChild (fileb);
  4878.     /* #### check for destruction here */
  4879.     while (data.answer == Answer_Invalid)
  4880.         fe_EventLoop ();
  4881.  
  4882.     if (data.answer == Answer_OK)
  4883.         if (data.return_value) {
  4884.             /* prepend the answer with file url */
  4885.             char path[1025];
  4886.             sprintf(path, "file://%s", data.return_value);
  4887.             fe_SetTextField (text_field, path);
  4888.             free (data.return_value);
  4889.         }
  4890.     if (data.answer != Answer_Destroy)
  4891.         XtDestroyWidget(shell);
  4892. }
  4893.  
  4894.  
  4895. static void
  4896. fe_print_browse_cb (Widget widget, XtPointer closure, XtPointer call_data)
  4897. {
  4898.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  4899.   fe_browse_file_of_text (fpd->context, fpd->file_text, False);
  4900. }
  4901.  
  4902.  
  4903. #define XFE_DEFAULT_PRINT_FILENAME    "netscape.ps"
  4904. static char *last_print_file_name = 0;
  4905. static Boolean last_to_file_p = False;
  4906.  
  4907. static void
  4908. ps_pipe_close (PrintSetup *p)
  4909. {
  4910.   fe_synchronous_url_exit (p->url, 0, (MWContext *) p->carg);
  4911.   pclose (p->out);
  4912. }
  4913.  
  4914. static void
  4915. ps_file_close (PrintSetup *p)
  4916. {
  4917.   fe_synchronous_url_exit (p->url, 0, (MWContext *) p->carg);
  4918.   fclose (p->out);
  4919. }
  4920.  
  4921. void
  4922. XFE_InitializePrintSetup (PrintSetup *p)
  4923. {
  4924.   XL_InitializePrintSetup (p);
  4925.   p->reverse = fe_globalPrefs.print_reversed;
  4926.   p->color = fe_globalPrefs.print_color;
  4927.   p->landscape = fe_globalPrefs.print_landscape;
  4928. /*  #### p->n_up = fe_globalPrefs.print_n_up;*/
  4929.  
  4930.   /* @@@ need to fix this -- erik */
  4931.   p->bigger = 0; /* -1 = small, 0 = medium, 1 = large, 2 = huge */
  4932.  
  4933.   if (fe_globalPrefs.print_paper_size == 0)
  4934.     {
  4935.       p->width = 8.5 * 72;
  4936.       p->height = 11  * 72;
  4937.     }
  4938.   else if (fe_globalPrefs.print_paper_size == 1)
  4939.     {
  4940.       p->width = 8.5 * 72;
  4941.       p->height = 14  * 72;
  4942.     }
  4943.   else if (fe_globalPrefs.print_paper_size == 2)
  4944.     {
  4945.       p->width = 7.5 * 72;
  4946.       p->height = 10  * 72;
  4947.     }
  4948.   else if (fe_globalPrefs.print_paper_size == 3)
  4949.     {
  4950.       p->width = 210 * 0.039 * 72;
  4951.       p->height = 297 * 0.039 * 72;
  4952.     }
  4953. }
  4954.  
  4955.  
  4956. void
  4957. fe_Print(MWContext *context, URL_Struct *url, Boolean last_to_file_p,
  4958.         char *last_print_file_name)
  4959. {
  4960.   SHIST_SavedData saved_data;
  4961.   PrintSetup p;
  4962.   char *type = NULL;
  4963.   char name[1024];
  4964.   char clas[1024];
  4965.   char mimecharset[48];
  4966.   XrmValue value;
  4967.   XrmDatabase db = XtDatabase(XtDisplay(CONTEXT_WIDGET(context)));
  4968.   INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  4969.  
  4970.   XFE_InitializePrintSetup (&p);
  4971.  
  4972.   if (last_to_file_p)
  4973.     {
  4974.       if (! *last_print_file_name)
  4975.     {
  4976.       FE_Alert (context, fe_globalData.no_file_message);
  4977.       return;
  4978.     }
  4979.  
  4980.       /* If the file exists, confirm overwriting it. */
  4981.       {
  4982.     XP_StatStruct st;
  4983.     char buf [2048];
  4984.     if (!stat (last_print_file_name, &st))
  4985.       {
  4986.         PR_snprintf (buf, sizeof (buf),
  4987.             fe_globalData.overwrite_file_message,
  4988.             last_print_file_name);
  4989.         if (!FE_Confirm (context, buf))
  4990.           return;
  4991.       }
  4992.       }
  4993.  
  4994.       p.out = fopen (last_print_file_name, "w");
  4995.       if (! p.out)
  4996.     {
  4997.       char buf [2048];
  4998.       PR_snprintf (buf, sizeof (buf),
  4999.             XP_GetString(XFE_ERROR_OPENING_FILE),
  5000.                last_print_file_name);
  5001.       fe_perror (context, buf);
  5002.       return;
  5003.     }
  5004.     }
  5005.   else
  5006.     {
  5007.       fe_globalPrefs.print_command =
  5008.     fe_StringTrim (fe_globalPrefs.print_command);
  5009.       if (! *fe_globalPrefs.print_command)
  5010.     {
  5011.       FE_Alert (context, fe_globalData.no_print_command_message);
  5012.       return;
  5013.     }
  5014.       p.out = popen (fe_globalPrefs.print_command, "w");
  5015.       if (! p.out)
  5016.     {
  5017.       char buf [2048];
  5018.       PR_snprintf (buf, sizeof (buf),
  5019.             XP_GetString(XFE_ERROR_OPENING_PIPE),
  5020.             fe_globalPrefs.print_command);
  5021.       fe_perror (context, buf);
  5022.       return;
  5023.     }
  5024.     }
  5025.  
  5026.   /* Make sure layout saves the current state. */
  5027.   LO_SaveFormData(context);
  5028.  
  5029.   /* Hold on to the saved data. */
  5030.   XP_MEMCPY(&saved_data, &url->savedData, sizeof(SHIST_SavedData));
  5031.  
  5032.   /* make damn sure the form_data slot is zero'd or else all
  5033.    * hell will break loose
  5034.    */
  5035.   XP_MEMSET (&url->savedData, 0, sizeof (SHIST_SavedData));
  5036.   NPL_PreparePrint(context, &url->savedData);
  5037.  
  5038.   INTL_CharSetIDToName(INTL_GetCSIWinCSID(c), mimecharset);
  5039.  
  5040.   PR_snprintf(clas, sizeof (clas),
  5041.         "%s.DocumentFonts.Charset.PSName", fe_progclass);
  5042.   PR_snprintf(name, sizeof (name),
  5043.         "%s.documentFonts.%s.psname", fe_progclass, mimecharset);
  5044.   if (XrmGetResource(db, name, clas, &type, &value))
  5045.       p.otherFontName = value.addr;
  5046.   else
  5047.       p.otherFontName = NULL;
  5048.  
  5049.   PR_snprintf(clas, sizeof (clas),
  5050.         "%s.DocumentFonts.Charset.PSCode", fe_progclass);
  5051.   PR_snprintf(name, sizeof (name),
  5052.         "%s.documentFonts.%s.pscode", fe_progclass, mimecharset);
  5053.   if (XrmGetResource(db, name, clas, &type, &value))
  5054.       p.otherFontCharSetID = INTL_CharSetNameToID(value.addr);
  5055.  
  5056.   PR_snprintf(clas, sizeof (clas),
  5057.         "%s.DocumentFonts.Charset.PSWidth", fe_progclass);
  5058.   PR_snprintf(name, sizeof (name),
  5059.         "%s.documentFonts.%s.pswidth", fe_progclass, mimecharset);
  5060.   if (XrmGetResource(db, name, clas, &type, &value))
  5061.       p.otherFontWidth = atoi(value.addr);
  5062.  
  5063.   PR_snprintf(clas, sizeof (clas),
  5064.         "%s.DocumentFonts.Charset.PSAscent", fe_progclass);
  5065.   PR_snprintf(name, sizeof (name),
  5066.         "%s.documentFonts.%s.psascent", fe_progclass, mimecharset);
  5067.   if (XrmGetResource(db, name, clas, &type, &value))
  5068.       p.otherFontAscent = atoi(value.addr);
  5069.  
  5070.   if (last_to_file_p)
  5071.       p.completion = ps_file_close;
  5072.   else
  5073.       p.completion = ps_pipe_close;
  5074.   
  5075.   p.carg = context;
  5076.   fe_RaiseSynchronousURLDialog (context, CONTEXT_WIDGET (context),
  5077.                 XP_GetString(XFE_DIALOGS_PRINTING));
  5078.   XL_TranslatePostscript (context, url, &saved_data, &p);
  5079.   fe_await_synchronous_url (context);
  5080.  
  5081.   /* XXX do we need to delete the URL ? */
  5082. }
  5083.  
  5084.  
  5085. static void
  5086. fe_print_destroy_cb(Widget widget, XtPointer closure, XtPointer call_data)
  5087. {
  5088.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  5089.   if (!fpd) return;
  5090.  
  5091.   /* Remove this callback so that we make absolutely sure we wont
  5092.    * free the fpd again.
  5093.    */
  5094.   XtRemoveCallback(widget, XmNdestroyCallback, fe_print_destroy_cb, fpd);
  5095.   free(fpd);
  5096. }
  5097.  
  5098. static void
  5099. fe_print_cb (Widget widget, XtPointer closure, XtPointer call_data)
  5100. {
  5101.   struct fe_print_data *fpd = (struct fe_print_data *) closure;
  5102.   URL_Struct *url;
  5103.   Boolean b;
  5104.  
  5105.   /*
  5106.    * Pop down the print dialog immediately.
  5107.    */
  5108.   fe_UnmanageChild_safe (fpd->shell);
  5109.  
  5110.   XtVaGetValues (fpd->printer, XmNset, &b, 0);
  5111.   last_to_file_p = !b;
  5112.   if (fe_globalPrefs.print_command) free (fe_globalPrefs.print_command);
  5113.   XtVaGetValues (fpd->command_text, XmNvalue, &fe_globalPrefs.print_command,0);
  5114.   if (last_print_file_name) free (last_print_file_name);
  5115.   last_print_file_name = fe_GetTextField(fpd->file_text);
  5116.   XtVaGetValues (fpd->portrait, XmNset, &b, 0);
  5117.   fe_globalPrefs.print_landscape = !b;
  5118.   XtVaGetValues (fpd->last, XmNset, &b, 0);
  5119.   fe_globalPrefs.print_reversed = b;
  5120.   XtVaGetValues (fpd->grey, XmNset, &b, 0);
  5121.   fe_globalPrefs.print_color = !b;
  5122.   XtVaGetValues (fpd->letter, XmNset, &b, 0);
  5123.   if (b) fe_globalPrefs.print_paper_size = 0;
  5124.   XtVaGetValues (fpd->legal, XmNset, &b, 0);
  5125.   if (b) fe_globalPrefs.print_paper_size = 1;
  5126.   XtVaGetValues (fpd->exec, XmNset, &b, 0);
  5127.   if (b) fe_globalPrefs.print_paper_size = 2;
  5128.   XtVaGetValues (fpd->a4, XmNset, &b, 0);
  5129.   if (b) fe_globalPrefs.print_paper_size = 3;
  5130.  
  5131.   url = SHIST_CreateWysiwygURLStruct (fpd->context, fpd->hist);
  5132.   if (url) {
  5133.     last_print_file_name = fe_StringTrim (last_print_file_name);
  5134.     
  5135.     fe_Print(fpd->context, url, last_to_file_p, last_print_file_name);
  5136.   } else {
  5137.     FE_Alert(fpd->context, fe_globalData.no_url_loaded_message);
  5138.   }
  5139.   
  5140.   /* We need this check to see if this widget is being_destroyed
  5141.    * or not in its ok_callback because fe_Print() goes off and
  5142.    * calls fe_await_synchronous_url() while has a mini eventloop
  5143.    * in it. This could cause a destroy of this widget. Motif, in
  5144.    * all its smartness, keeps this widget's memory around. This
  5145.    * is the only think we can check. context, shell, fpd all might
  5146.    * have been destroyed and deallocated.
  5147.    */
  5148.   if (XfeIsAlive(widget)) {
  5149.     XtDestroyWidget (fpd->shell);
  5150.   }
  5151. }
  5152.  
  5153.  
  5154. void
  5155. fe_PrintDialog (MWContext *context)
  5156. {
  5157.   Widget mainw = CONTEXT_WIDGET (context);
  5158.   Widget kids [50];
  5159.   Arg av [20];
  5160.   int ac, i, labels_width;
  5161.   Widget shell, form;
  5162.   Widget print_to_label, print_command_label;
  5163.   Widget print_command_text, file_name_label, file_name_text;
  5164.   Widget browse_button, line, print_label;
  5165.   Widget first_first_toggle, last_first_toggle, orientation_label;
  5166.   Widget portrait_toggle, landscape_toggle;
  5167.   Widget print_color_label, greyscale_toggle;
  5168.   Widget color_toggle, paper_size_label, paper_size_radio_box, letter_toggle;
  5169.   Widget legal_toggle, executive_toggle, a4_toggle;
  5170.   Widget to_printer_toggle, to_file_toggle;
  5171.  
  5172.   Visual *v = 0;
  5173.   Colormap cmap = 0;
  5174.   Cardinal depth = 0;
  5175.  
  5176.   struct fe_print_data *fpd = (struct fe_print_data *)
  5177.     calloc (sizeof (struct fe_print_data), 1);
  5178.  
  5179.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  5180.          XtNdepth, &depth, 0);
  5181.  
  5182.   ac = 0;
  5183.   XtSetArg (av[ac], XmNvisual, v); ac++;
  5184.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  5185.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  5186.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  5187.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  5188.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  5189.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  5190.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  5191.   XtSetArg (av[ac], XmNuserData, False); ac++;
  5192.   shell = XmCreatePromptDialog (mainw, "printSetup", av, ac);
  5193.  
  5194.   XtAddCallback (shell, XmNokCallback, fe_print_cb, fpd);
  5195.   XtAddCallback (shell, XmNcancelCallback, fe_destroy_cb, shell);
  5196.  
  5197.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell,
  5198.                         XmDIALOG_SELECTION_LABEL));
  5199.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_TEXT));
  5200.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_APPLY_BUTTON));
  5201. #ifdef NO_HELP
  5202.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_HELP_BUTTON));
  5203. #endif
  5204.   XtAddCallback (shell, XmNdestroyCallback, fe_print_destroy_cb, fpd);
  5205.  
  5206.   i = 0;
  5207.   ac = 0;
  5208.   form = XmCreateForm (shell, "form", av, ac);
  5209.   kids [i++] = print_to_label =
  5210.     XmCreateLabelGadget (form, "printToLabel", av, ac);
  5211.   kids [i++] = to_printer_toggle =
  5212.     XmCreateToggleButtonGadget (form, "toPrinterToggle", av, ac);
  5213.   kids [i++] = to_file_toggle =
  5214.     XmCreateToggleButtonGadget (form, "toFileToggle", av, ac);
  5215.   kids [i++] = print_command_label =
  5216.     XmCreateLabelGadget (form, "printCommandLabel", av, ac);
  5217.   kids [i++] = print_command_text =
  5218.     fe_CreateTextField (form, "printCommandText", av, ac);
  5219.   kids [i++] = file_name_label =
  5220.     XmCreateLabelGadget (form, "fileNameLabel", av, ac);
  5221.   kids [i++] = file_name_text =
  5222.     fe_CreateTextField (form, "fileNameText", av, ac);
  5223.   kids [i++] = browse_button =
  5224.     XmCreatePushButtonGadget (form, "browseButton", av, ac);
  5225.   kids [i++] = line = XmCreateSeparator (form, "line", av, ac);
  5226.   kids [i++] = print_label = XmCreateLabelGadget (form, "printLabel", av, ac);
  5227.   kids [i++] = first_first_toggle =
  5228.     XmCreateToggleButtonGadget (form, "firstFirstToggle", av, ac);
  5229.   kids [i++] = last_first_toggle =
  5230.     XmCreateToggleButtonGadget (form, "lastFirstToggle", av, ac);
  5231.   kids [i++] = orientation_label =
  5232.     XmCreateLabelGadget (form, "orientationLabel", av, ac);
  5233.   kids [i++] = portrait_toggle =
  5234.     XmCreateToggleButtonGadget (form, "portraitToggle", av, ac);
  5235.   kids [i++] = landscape_toggle =
  5236.     XmCreateToggleButtonGadget (form, "landscapeToggle", av, ac);
  5237.   kids [i++] = print_color_label =
  5238.     XmCreateLabelGadget (form, "printColorLabel", av, ac);
  5239.   kids [i++] = greyscale_toggle =
  5240.     XmCreateToggleButtonGadget (form, "greyscaleToggle", av, ac);
  5241.   kids [i++] = color_toggle =
  5242.     XmCreateToggleButtonGadget (form, "colorToggle", av, ac);
  5243.   kids [i++] = paper_size_label =
  5244.     XmCreateLabelGadget (form, "paperSizeLabel", av, ac);
  5245.   kids [i++] = paper_size_radio_box =
  5246.     XmCreateRadioBox (form, "paperSizeRadioBox", av, ac);
  5247.   kids [i++] = letter_toggle =
  5248.     XmCreateToggleButtonGadget (form, "letterToggle", av, ac);
  5249.   kids [i++] = legal_toggle =
  5250.     XmCreateToggleButtonGadget (form, "legalToggle", av, ac);
  5251.   kids [i++] = executive_toggle =
  5252.     XmCreateToggleButtonGadget (form, "executiveToggle", av, ac);
  5253.   kids [i++] = a4_toggle =
  5254.     XmCreateToggleButtonGadget (form, "a4Toggle", av, ac);
  5255.  
  5256.   labels_width = XfeVaGetWidestWidget(print_to_label, print_command_label,
  5257.                  file_name_label, 0);
  5258.  
  5259.   XtVaSetValues (print_to_label,
  5260.            XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5261.            XmNtopWidget, to_printer_toggle,
  5262.            XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5263.            XmNbottomWidget, to_printer_toggle,
  5264.          RIGHT_JUSTIFY_VA_ARGS(print_to_label,labels_width),
  5265.            0);
  5266.   XtVaSetValues (to_printer_toggle,
  5267.            XmNtopAttachment, XmATTACH_FORM,
  5268.            XmNbottomAttachment, XmATTACH_NONE,
  5269.          XmNleftAttachment, XmATTACH_FORM,
  5270.                  XmNleftOffset, labels_width,
  5271.            XmNrightAttachment, XmATTACH_NONE,
  5272.            0);
  5273.   XtVaSetValues (to_file_toggle,
  5274.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5275.          XmNtopWidget, to_printer_toggle,
  5276.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5277.          XmNbottomWidget, to_printer_toggle,
  5278.          XmNleftAttachment, XmATTACH_WIDGET,
  5279.          XmNleftWidget, to_printer_toggle,
  5280.          XmNrightAttachment, XmATTACH_NONE,
  5281.          0);
  5282.   XtVaSetValues (print_command_label,
  5283.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5284.          XmNtopWidget, print_command_text,
  5285.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5286.          XmNbottomWidget, print_command_text,
  5287.          RIGHT_JUSTIFY_VA_ARGS(print_command_label,labels_width),
  5288.          0);
  5289.   XtVaSetValues (print_command_text,
  5290.          XmNtopAttachment, XmATTACH_WIDGET,
  5291.          XmNtopWidget, to_printer_toggle,
  5292.          XmNbottomAttachment, XmATTACH_NONE,
  5293.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5294.          XmNleftWidget, to_printer_toggle,
  5295.          XmNrightAttachment, XmATTACH_FORM,
  5296.          0);
  5297.   XtVaSetValues (file_name_label,
  5298.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5299.          XmNtopWidget, file_name_text,
  5300.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5301.          XmNbottomWidget, file_name_text,
  5302.          RIGHT_JUSTIFY_VA_ARGS(file_name_label,labels_width),
  5303.          0);
  5304.   XtVaSetValues (file_name_text,
  5305.          XmNtopAttachment, XmATTACH_WIDGET,
  5306.          XmNtopWidget, print_command_text,
  5307.          XmNbottomAttachment, XmATTACH_NONE,
  5308.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5309.          XmNleftWidget, print_command_text,
  5310.          XmNrightAttachment, XmATTACH_WIDGET,
  5311.          XmNrightWidget, browse_button,
  5312.          0);
  5313.   XtVaSetValues (browse_button,
  5314.          XmNtopAttachment, XmATTACH_WIDGET,
  5315.          XmNtopWidget, print_command_text,
  5316.          XmNbottomAttachment, XmATTACH_NONE,
  5317.          XmNleftAttachment, XmATTACH_NONE,
  5318.          XmNrightAttachment, XmATTACH_FORM,
  5319.          0);
  5320.  
  5321.   XtVaSetValues (browse_button, XmNheight, _XfeHeight(file_name_text), 0);
  5322.  
  5323.   XtVaSetValues (line,
  5324.          XmNtopAttachment, XmATTACH_WIDGET,
  5325.          XmNtopWidget, file_name_text,
  5326.          XmNbottomAttachment, XmATTACH_NONE,
  5327.          XmNleftAttachment, XmATTACH_FORM,
  5328.          XmNrightAttachment, XmATTACH_FORM,
  5329.          0);
  5330.  
  5331.   XtVaSetValues (print_label,
  5332.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5333.          XmNtopWidget, first_first_toggle,
  5334.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5335.          XmNbottomWidget, first_first_toggle,
  5336.          XmNleftAttachment, XmATTACH_FORM,
  5337.          XmNrightAttachment, XmATTACH_WIDGET,
  5338.          XmNrightWidget, first_first_toggle,
  5339.          0);
  5340.   XtVaSetValues (first_first_toggle,
  5341.          XmNtopAttachment, XmATTACH_WIDGET,
  5342.          XmNtopWidget, line,
  5343.          XmNbottomAttachment, XmATTACH_NONE,
  5344.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5345.          XmNleftWidget, print_command_text,
  5346.          XmNrightAttachment, XmATTACH_NONE,
  5347.          0);
  5348.   XtVaSetValues (last_first_toggle,
  5349.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5350.          XmNtopWidget, first_first_toggle,
  5351.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5352.          XmNbottomWidget, first_first_toggle,
  5353.          XmNleftAttachment, XmATTACH_WIDGET,
  5354.          XmNleftWidget, first_first_toggle,
  5355.          XmNrightAttachment, XmATTACH_NONE,
  5356.          0);
  5357.  
  5358.   XtVaSetValues (orientation_label,
  5359.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5360.          XmNtopWidget, portrait_toggle,
  5361.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5362.          XmNbottomWidget, portrait_toggle,
  5363.          XmNleftAttachment, XmATTACH_FORM,
  5364.          XmNrightAttachment, XmATTACH_WIDGET,
  5365.          XmNrightWidget, portrait_toggle,
  5366.          0);
  5367.   XtVaSetValues (portrait_toggle,
  5368.          XmNtopAttachment, XmATTACH_WIDGET,
  5369.          XmNtopWidget, first_first_toggle,
  5370.          XmNbottomAttachment, XmATTACH_NONE,
  5371.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5372.          XmNleftWidget, first_first_toggle,
  5373.          XmNrightAttachment, XmATTACH_NONE,
  5374.          0);
  5375.   XtVaSetValues (landscape_toggle,
  5376.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5377.          XmNtopWidget, portrait_toggle,
  5378.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5379.          XmNbottomWidget, portrait_toggle,
  5380.          XmNleftAttachment, XmATTACH_WIDGET,
  5381.          XmNleftWidget, portrait_toggle,
  5382.          XmNrightAttachment, XmATTACH_NONE,
  5383.          0);
  5384.  
  5385.   XtVaSetValues (print_color_label,
  5386.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5387.          XmNtopWidget, greyscale_toggle,
  5388.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5389.          XmNbottomWidget, greyscale_toggle,
  5390.          XmNleftAttachment, XmATTACH_FORM,
  5391.          XmNrightAttachment, XmATTACH_WIDGET,
  5392.          XmNrightWidget, greyscale_toggle,
  5393.          0);
  5394.   XtVaSetValues (greyscale_toggle,
  5395.          XmNtopAttachment, XmATTACH_WIDGET,
  5396.          XmNtopWidget, portrait_toggle,
  5397.          XmNbottomAttachment, XmATTACH_NONE,
  5398.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5399.          XmNleftWidget, portrait_toggle,
  5400.          XmNrightAttachment, XmATTACH_NONE,
  5401.          0);
  5402.   XtVaSetValues (color_toggle,
  5403.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5404.          XmNtopWidget, greyscale_toggle,
  5405.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5406.          XmNbottomWidget, greyscale_toggle,
  5407.          XmNleftAttachment, XmATTACH_WIDGET,
  5408.          XmNleftWidget, greyscale_toggle,
  5409.          XmNrightAttachment, XmATTACH_NONE,
  5410.          0);
  5411.  
  5412.   XtVaSetValues (paper_size_label,
  5413.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5414.          XmNtopWidget, letter_toggle,
  5415.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5416.          XmNbottomWidget, letter_toggle,
  5417.          XmNleftAttachment, XmATTACH_FORM,
  5418.          XmNrightAttachment, XmATTACH_WIDGET,
  5419.          XmNrightWidget, letter_toggle,
  5420.          0);
  5421.   XtVaSetValues (letter_toggle,
  5422.          XmNtopAttachment, XmATTACH_WIDGET,
  5423.          XmNtopWidget, greyscale_toggle,
  5424.          XmNbottomAttachment, XmATTACH_NONE,
  5425.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5426.          XmNleftWidget, greyscale_toggle,
  5427.          XmNrightAttachment, XmATTACH_NONE,
  5428.          0);
  5429.   XtVaSetValues (legal_toggle,
  5430.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5431.          XmNtopWidget, letter_toggle,
  5432.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5433.          XmNbottomWidget, letter_toggle,
  5434.          XmNleftAttachment, XmATTACH_WIDGET,
  5435.          XmNleftWidget, letter_toggle,
  5436.          XmNrightAttachment, XmATTACH_NONE,
  5437.          0);
  5438.   XtVaSetValues (executive_toggle,
  5439.          XmNtopAttachment, XmATTACH_WIDGET,
  5440.          XmNtopWidget, letter_toggle,
  5441.          XmNbottomAttachment, XmATTACH_NONE,
  5442.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5443.          XmNleftWidget, letter_toggle,
  5444.          XmNrightAttachment, XmATTACH_NONE,
  5445.          0);
  5446.   XtVaSetValues (a4_toggle,
  5447.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5448.          XmNtopWidget, executive_toggle,
  5449.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5450.          XmNbottomWidget, executive_toggle,
  5451.          XmNleftAttachment, XmATTACH_WIDGET,
  5452.          XmNleftWidget, executive_toggle,
  5453.          XmNrightAttachment, XmATTACH_NONE,
  5454.          0);
  5455.  
  5456.   XtAddCallback (to_printer_toggle, XmNvalueChangedCallback,
  5457.          fe_print_to_toggle_cb, fpd);
  5458.   XtAddCallback (to_file_toggle, XmNvalueChangedCallback,
  5459.          fe_print_to_toggle_cb, fpd);
  5460.  
  5461.   XtAddCallback (browse_button, XmNactivateCallback,
  5462.          fe_print_browse_cb, fpd);
  5463.  
  5464.   XtAddCallback (first_first_toggle, XmNvalueChangedCallback,
  5465.          fe_print_order_toggle_cb, fpd);
  5466.   XtAddCallback (last_first_toggle, XmNvalueChangedCallback,
  5467.          fe_print_order_toggle_cb, fpd);
  5468.  
  5469.   XtAddCallback (portrait_toggle, XmNvalueChangedCallback,
  5470.          fe_print_orientation_toggle_cb, fpd);
  5471.   XtAddCallback (landscape_toggle, XmNvalueChangedCallback,
  5472.          fe_print_orientation_toggle_cb, fpd);
  5473.  
  5474.   XtAddCallback (greyscale_toggle, XmNvalueChangedCallback,
  5475.          fe_print_color_toggle_cb, fpd);
  5476.   XtAddCallback (color_toggle, XmNvalueChangedCallback,
  5477.          fe_print_color_toggle_cb, fpd);
  5478.  
  5479.   XtAddCallback (letter_toggle, XmNvalueChangedCallback,
  5480.          fe_print_paper_toggle_cb, fpd);
  5481.   XtAddCallback (legal_toggle, XmNvalueChangedCallback,
  5482.          fe_print_paper_toggle_cb, fpd);
  5483.   XtAddCallback (executive_toggle, XmNvalueChangedCallback,
  5484.          fe_print_paper_toggle_cb, fpd);
  5485.   XtAddCallback (a4_toggle, XmNvalueChangedCallback,
  5486.          fe_print_paper_toggle_cb, fpd);
  5487.  
  5488.   XtVaSetValues (print_command_text, XmNvalue, fe_globalPrefs.print_command,0);
  5489.   if (!last_print_file_name || !*last_print_file_name) {
  5490.     /* Use a default file name. We need to strdup here as we free this
  5491.        later. */
  5492.     last_print_file_name = strdup( XFE_DEFAULT_PRINT_FILENAME );
  5493.   }
  5494.   fe_SetTextField(file_name_text, last_print_file_name);
  5495.   if (last_to_file_p)
  5496.     {
  5497.       XtVaSetValues (to_file_toggle, XmNset, True, 0);
  5498.       XtVaSetValues (print_command_text, XmNsensitive, False, 0);
  5499.       XtVaSetValues (shell, XmNinitialFocus, file_name_text, 0);
  5500.     }
  5501.   else
  5502.     {
  5503.       XtVaSetValues (to_printer_toggle, XmNset, True, 0);
  5504.       XtVaSetValues (file_name_text, XmNsensitive, False, 0);
  5505.       XtVaSetValues (browse_button, XmNsensitive, False, 0);
  5506.       XtVaSetValues (shell, XmNinitialFocus, print_command_text, 0);
  5507.     }
  5508.   XtVaSetValues ((fe_globalPrefs.print_reversed
  5509.           ? last_first_toggle : first_first_toggle),
  5510.          XmNset, True, 0);
  5511.   XtVaSetValues ((fe_globalPrefs.print_landscape
  5512.           ? landscape_toggle : portrait_toggle),
  5513.          XmNset, True, 0);
  5514.   XtVaSetValues ((fe_globalPrefs.print_color
  5515.           ? color_toggle : greyscale_toggle),
  5516.          XmNset, True, 0);
  5517.   XtVaSetValues ((fe_globalPrefs.print_paper_size == 0 ? letter_toggle :
  5518.           fe_globalPrefs.print_paper_size == 1 ? legal_toggle :
  5519.           fe_globalPrefs.print_paper_size == 2 ? executive_toggle :
  5520.           a4_toggle),
  5521.          XmNset, True, 0);
  5522.  
  5523.  
  5524.   XtManageChildren (kids, i);
  5525.   XtManageChild (form);
  5526.  
  5527.   fpd->context = context;
  5528.   fpd->hist = SHIST_GetCurrent (&context->hist);
  5529.   fpd->shell = shell;
  5530.   fpd->printer = to_printer_toggle;
  5531.   fpd->file = to_file_toggle;
  5532.   fpd->command_text = print_command_text;
  5533.   fpd->file_text = file_name_text;
  5534.   fpd->browse = browse_button;
  5535.   fpd->first = first_first_toggle;
  5536.   fpd->last = last_first_toggle;
  5537.   fpd->portrait = portrait_toggle;
  5538.   fpd->landscape = landscape_toggle;
  5539.   fpd->grey = greyscale_toggle;
  5540.   fpd->color = color_toggle;
  5541.   fpd->letter = letter_toggle;
  5542.   fpd->legal = legal_toggle;
  5543.   fpd->exec = executive_toggle;
  5544.   fpd->a4 = a4_toggle;
  5545.  
  5546.   fe_NukeBackingStore (shell);
  5547.   XtManageChild (shell);
  5548. }
  5549.  
  5550.  
  5551.  
  5552. /* Find dialog. */
  5553.  
  5554. static void
  5555. fe_find_refresh_data(fe_FindData *find_data)
  5556. {
  5557.   MWContext *focus_context;
  5558.   INTL_CharSetInfo c;
  5559.  
  5560.   if (!find_data)
  5561.     return;
  5562.  
  5563.   /* Decide which context to search in */
  5564.   focus_context = fe_findcommand_context();
  5565.   if (!focus_context)
  5566.     focus_context = fe_GetFocusGridOfContext(find_data->context);
  5567.   
  5568.   c = LO_GetDocumentCharacterSetInfo(find_data->context);
  5569.   if (focus_context) {
  5570.     if (focus_context != find_data->context_to_find)
  5571.       fe_FindReset(find_data->context);
  5572.   }
  5573.   find_data->context_to_find = focus_context;
  5574.  
  5575.   if (find_data->shell) {
  5576.     unsigned char *loc;
  5577.     char * tmp;
  5578.  
  5579.     if (find_data->string)
  5580.       XP_FREE (find_data->string);
  5581.     find_data->string = 0;
  5582.     XtVaGetValues (find_data->text, XmNvalue, &loc, 0);
  5583.     tmp = (char *) fe_ConvertFromLocaleEncoding (INTL_GetCSIWinCSID(c), loc);
  5584.     if (tmp) {
  5585.       int length;
  5586.       /*
  5587.        * We don't use XP_STRDUP here because it maps to strdup
  5588.        * which implies using free() when we're through.  We want
  5589.        * to allocate a string which is freed by XP_FREE()
  5590.        */
  5591.       length = XP_STRLEN(tmp);
  5592.       find_data->string = (char *)XP_ALLOC(length+1);
  5593.       XP_STRCPY(find_data->string, tmp);
  5594.     } else {
  5595.       find_data->string = 0;
  5596.     }
  5597.     if (find_data->string != (char *) loc) {
  5598.       XtFree (loc);
  5599.     }
  5600.     XtVaGetValues (find_data->case_sensitive, XmNset,
  5601.            &find_data->case_sensitive_p, 0);
  5602.     XtVaGetValues (find_data->backward,
  5603.            XmNset, &find_data->backward_p, 0);
  5604.     /* For mail/news contexts, the Search in Header/Body is loaded into the
  5605.        fe_FindData in the valueChangeCallback */
  5606.   }
  5607. }
  5608.  
  5609. #define FE_FIND_FOUND            0
  5610. #define FE_FIND_NOTFOUND        1
  5611. #define FE_FIND_CANCEL            2
  5612. #define FE_FIND_HEADER_FOUND        3
  5613. #define FE_FIND_HEADER_NOTFOUND        4
  5614. #define FE_FIND_NOSTRING        5
  5615.  
  5616. static int
  5617. fe_find (fe_FindData *find_data)
  5618. {
  5619.   Widget mainw;
  5620.   MWContext *context_to_find;
  5621.   XP_Bool hasRetried = FALSE;
  5622.   CL_Layer *layer;
  5623.  
  5624.   XP_ASSERT(find_data);
  5625.  
  5626.   /* Find a shell to use with all subsequent dialogs */
  5627.   if (find_data->shell && XtIsManaged(find_data->shell))
  5628.     mainw = find_data->shell;
  5629.   else
  5630.     mainw = CONTEXT_WIDGET(find_data->context);
  5631.   while(!XtIsWMShell(mainw) && (XtParent(mainw)!=0))
  5632.     mainw = XtParent(mainw);
  5633.  
  5634.   /* reload search parameters */
  5635.   fe_find_refresh_data(find_data);
  5636.  
  5637.   context_to_find = find_data->context;
  5638.   if (find_data->context_to_find)
  5639.     context_to_find = find_data->context_to_find;
  5640.  
  5641.   if (!find_data->string || !find_data->string[0]) {
  5642.     fe_Alert_2(mainw, fe_globalData.no_search_string_message);
  5643.     return (FE_FIND_NOSTRING);
  5644.   }
  5645.  
  5646.   if (find_data->find_in_headers) {
  5647.     XP_ASSERT(find_data->context->type == MWContextMail ||
  5648.           find_data->context->type == MWContextNews);
  5649.     if (find_data->context->type == MWContextMail ||
  5650.     find_data->context->type == MWContextNews) {
  5651.       int status = -1;        /* ###tw  Find needs to be hooked up in a brand
  5652.                    new way now### */
  5653. /*###tw      int status = MSG_DoFind(fj->context, fj->string, fj->case_sensitive_p); */
  5654.       if (status < 0) {
  5655.     /* mainw could be the find_data->shell. If status < 0 (find failed)
  5656.      * backend will bring the find window down. So use the context to
  5657.      * display the error message here.
  5658.      */
  5659.     FE_Alert(find_data->context, XP_GetString(status));
  5660.     return(FE_FIND_HEADER_NOTFOUND);
  5661.       }
  5662.       return (FE_FIND_HEADER_FOUND);
  5663.     }
  5664.   }
  5665.  
  5666. #ifdef EDITOR
  5667.   /* but I think you will want this in non-Gold too! */
  5668.   /*
  5669.    *    Start the search from the current selection location. Bug #29854.
  5670.    */
  5671.   LO_GetSelectionEndpoints(context_to_find,
  5672.                &find_data->start_element,
  5673.                &find_data->end_element,
  5674.                &find_data->start_pos,
  5675.                &find_data->end_pos,
  5676.                            &layer);
  5677. #endif
  5678.   AGAIN:
  5679.  
  5680.   if (LO_FindText (context_to_find, find_data->string,
  5681.            &find_data->start_element, &find_data->start_pos, 
  5682.            &find_data->end_element, &find_data->end_pos,
  5683.            find_data->case_sensitive_p, !find_data->backward_p))
  5684.     {
  5685.       int32 x, y;
  5686.       LO_SelectText (context_to_find,
  5687.              find_data->start_element, find_data->start_pos,
  5688.              find_data->end_element, find_data->end_pos,
  5689.              &x, &y);
  5690.  
  5691.       /* If the found item is not visible on the screen, scroll to it.
  5692.      If we need to scroll, attempt to position the destination
  5693.      coordinate in the middle of the window.
  5694.      */
  5695.       if (x >= CONTEXT_DATA (context_to_find)->document_x &&
  5696.       x <= (CONTEXT_DATA (context_to_find)->document_x +
  5697.         CONTEXT_DATA (context_to_find)->scrolled_width))
  5698.     x = CONTEXT_DATA (context_to_find)->document_x;
  5699.       else
  5700.     x = x - (CONTEXT_DATA (context_to_find)->scrolled_width / 2);
  5701.  
  5702.       if (y >= CONTEXT_DATA (context_to_find)->document_y &&
  5703.       y <= (CONTEXT_DATA (context_to_find)->document_y +
  5704.         CONTEXT_DATA (context_to_find)->scrolled_height))
  5705.     y = CONTEXT_DATA (context_to_find)->document_y;
  5706.       else
  5707.     y = y - (CONTEXT_DATA (context_to_find)->scrolled_height / 2);
  5708.  
  5709.       if (x + CONTEXT_DATA (context_to_find)->scrolled_width
  5710.       > CONTEXT_DATA (context_to_find)->document_width)
  5711.     x = (CONTEXT_DATA (context_to_find)->document_width -
  5712.          CONTEXT_DATA (context_to_find)->scrolled_width);
  5713.  
  5714.       if (y + CONTEXT_DATA (context_to_find)->scrolled_height
  5715.       > CONTEXT_DATA (context_to_find)->document_height)
  5716.     y = (CONTEXT_DATA (context_to_find)->document_height -
  5717.          CONTEXT_DATA (context_to_find)->scrolled_height);
  5718.  
  5719.       if (x < 0) x = 0;
  5720.       if (y < 0) y = 0;
  5721.  
  5722.       fe_ScrollTo (context_to_find, x, y);
  5723.     }
  5724.   else
  5725.     {
  5726.       if (hasRetried) {
  5727.     fe_Alert_2 (mainw, fe_globalData.wrap_search_not_found_message);
  5728.     return(FE_FIND_NOTFOUND);
  5729.       } else {
  5730.     if (fe_Confirm_2 (mainw,
  5731.               (find_data->backward_p
  5732.                ? fe_globalData.wrap_search_backward_message
  5733.                : fe_globalData.wrap_search_message)))    {
  5734.       find_data->start_element = 0;
  5735.       find_data->start_pos = 0;
  5736.       hasRetried = TRUE;
  5737.       goto AGAIN;
  5738.     }
  5739.     else
  5740.       return (FE_FIND_CANCEL);
  5741.       }
  5742.     }
  5743.   return(FE_FIND_FOUND);
  5744. }
  5745.  
  5746. static void
  5747. fe_find_destroy_cb (Widget widget, XtPointer closure, XtPointer call_data)
  5748. {
  5749.   MWContext *context = (MWContext *) closure;
  5750.   fe_FindData *find_data = CONTEXT_DATA(context)->find_data;
  5751.   if (find_data) {
  5752.     /* Before we destroy, load all the search parameters */
  5753.     fe_find_refresh_data(find_data);
  5754.     find_data->shell = 0;
  5755.     XP_FREE(find_data);
  5756.     find_data = 0;
  5757.   }
  5758.   /* find_data will be freed when the context is deleted */
  5759. }
  5760.  
  5761. static void
  5762. fe_find_cb(Widget widget, XtPointer closure, XtPointer call_data)
  5763. {
  5764.   XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *) call_data;
  5765.   MWContext *context = (MWContext *) closure;
  5766.   fe_FindData *find_data = CONTEXT_DATA(context)->find_data;
  5767.   int result;
  5768.  
  5769.   XP_ASSERT(find_data && find_data->shell);
  5770.  
  5771.   switch (cb->reason) {
  5772.   case XmCR_OK:        /* ok */
  5773.     result = fe_find(find_data);
  5774.     if (result == FE_FIND_HEADER_FOUND ||
  5775.     result == FE_FIND_HEADER_NOTFOUND)
  5776.       XtUnmanageChild(find_data->shell);
  5777.     break;
  5778.   case XmCR_APPLY:    /* clear */
  5779.     XtVaSetValues (find_data->text, XmNcursorPosition, 0, 0);
  5780.     fe_SetTextField (find_data->text, "");
  5781.     XmProcessTraversal (find_data->text, XmTRAVERSE_CURRENT);
  5782.     break;
  5783.   case XmCR_CANCEL:    /* cancel */
  5784.   default:
  5785.     XtUnmanageChild(find_data->shell);
  5786.   }
  5787. }
  5788.  
  5789. static void
  5790. fe_find_head_or_body_changed(Widget widget, XtPointer closure,
  5791.                  XtPointer call_data)
  5792. {
  5793.   fe_FindData *find_data = (fe_FindData *) closure;
  5794.   XP_ASSERT(find_data);
  5795.   if (widget == find_data->msg_body) {
  5796.     find_data->find_in_headers = FALSE;
  5797.   } else {
  5798.     XP_ASSERT(widget == find_data->msg_head);
  5799.     find_data->find_in_headers = TRUE;
  5800.   }
  5801.   XmToggleButtonGadgetSetState(find_data->msg_body, !find_data->find_in_headers, FALSE);
  5802.   XmToggleButtonGadgetSetState(find_data->msg_head, find_data->find_in_headers, FALSE);
  5803.   XtVaSetValues(find_data->backward, XmNsensitive, !find_data->find_in_headers, 0);
  5804. }
  5805.   
  5806.  
  5807. void
  5808. fe_FindDialog (MWContext *context, Boolean again)
  5809. {
  5810.   Widget mainw = CONTEXT_WIDGET (context);
  5811.   Widget kids [50];
  5812.   Arg av [20];
  5813.   int ac;
  5814.   Widget shell, form, find_label, find_text;
  5815.   Widget findin = 0;
  5816.   Widget msg_head = 0;
  5817.   Widget msg_body = 0;
  5818.   Widget case_sensitive_toggle, backwards_toggle;
  5819.   Visual *v = 0;
  5820.   Colormap cmap = 0;
  5821.   Cardinal depth = 0;
  5822.   fe_FindData *find_data = CONTEXT_DATA(context)->find_data;
  5823.   char *loc;
  5824.   INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  5825.  
  5826.   /* Force Find if this was the first time */
  5827.   if (!find_data && again)
  5828.       again = False;
  5829.  
  5830.   if (again) {
  5831.     if (find_data->find_in_headers) {
  5832.       XP_ASSERT(find_data->context->type == MWContextMail ||
  5833.         find_data->context->type == MWContextNews);
  5834.       if (find_data->context->type == MWContextMail ||
  5835.       find_data->context->type == MWContextNews) {
  5836. #ifdef NOTDEF            /* ###tw */
  5837.       MSG_Command(CONTEXT_DATA(last_find_junk->context)->messagepane,
  5838.               MSG_FindAgain);
  5839. #endif /* NOTDEF */
  5840.     return;
  5841.       }
  5842.     }
  5843.     fe_find (find_data);
  5844.     return;
  5845.   }
  5846.   else if (find_data && find_data->shell) {
  5847.     /* The find dialog is already there. Use it. */
  5848.     XtManageChild(find_data->shell);
  5849.     XMapRaised(XtDisplay(find_data->shell),
  5850.            XtWindow(find_data->shell));
  5851.     return;
  5852.   }
  5853.  
  5854.   /* Create the find dialog */
  5855.   if (!find_data) {
  5856.     find_data = (fe_FindData *) XP_NEW_ZAP (fe_FindData);
  5857.     CONTEXT_DATA(context)->find_data = find_data;
  5858.     find_data->case_sensitive_p = False;
  5859.     if (context->type == MWContextMail && context->type == MWContextNews)
  5860.       find_data->find_in_headers = True;
  5861.     else
  5862.       find_data->find_in_headers = False;
  5863.   }
  5864.  
  5865.   fe_getVisualOfContext(context, &v, &cmap, &depth);
  5866.  
  5867.   ac = 0;
  5868.   XtSetArg (av[ac], XmNvisual, v); ac++;
  5869.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  5870.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  5871.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  5872.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_MODELESS); ac++;
  5873.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  5874.   XtSetArg (av[ac], XmNdeleteResponse, XmUNMAP); ac++;
  5875.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  5876.   XtSetArg (av[ac], XmNuserData, find_data); ac++;    /* this must go */
  5877.   shell = XmCreatePromptDialog (mainw, "findDialog", av, ac);
  5878.  
  5879.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell,
  5880.                         XmDIALOG_SELECTION_LABEL));
  5881.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_TEXT));
  5882.   XtManageChild (XmSelectionBoxGetChild (shell, XmDIALOG_APPLY_BUTTON));
  5883. #ifdef NO_HELP
  5884.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (shell, XmDIALOG_HELP_BUTTON));
  5885. #endif
  5886.  
  5887.   ac = 0;
  5888.   form = XmCreateForm (shell, "form", av, ac);
  5889.  
  5890. #if 0
  5891.   /* find in headers has been replaced byy ldap search
  5892.    */
  5893.   if (context->type == MWContextMail || context->type == MWContextNews) {
  5894.     ac = 0;
  5895.     findin = XmCreateLabelGadget(form, "findInLabel", av, ac);
  5896.     ac = 0;
  5897.     msg_head = XmCreateToggleButtonGadget(form, "msgHeaders", av, ac);
  5898.     ac = 0;
  5899.     msg_body = XmCreateToggleButtonGadget(form, "msgBody", av, ac);
  5900.     XtAddCallback(msg_body, XmNvalueChangedCallback,
  5901.           fe_find_head_or_body_changed, find_data);
  5902.     XtAddCallback(msg_head, XmNvalueChangedCallback,
  5903.           fe_find_head_or_body_changed, find_data);
  5904.   }
  5905. #endif
  5906.  
  5907.   ac = 0;
  5908.   find_label = XmCreateLabelGadget (form, "findLabel", av, ac);
  5909.   ac = 0;
  5910.   loc = (char *) fe_ConvertToLocaleEncoding (INTL_GetCSIWinCSID(c),
  5911.                     (unsigned char *) find_data->string);
  5912.   XtSetArg (av [ac], XmNvalue, loc ? loc : ""); ac++;
  5913.   find_text = fe_CreateTextField (form, "findText", av, ac);
  5914.   if (loc && (loc != find_data->string)) {
  5915.     free (loc);
  5916.   }
  5917.   ac = 0;
  5918.   XtSetArg (av [ac], XmNset, find_data->case_sensitive_p); ac++;
  5919.   case_sensitive_toggle = XmCreateToggleButtonGadget (form, "caseSensitive",
  5920.                               av, ac);
  5921.   ac = 0;
  5922.   XtSetArg (av [ac], XmNset, find_data->backward_p); ac++;
  5923.   backwards_toggle = XmCreateToggleButtonGadget (form, "backwards", av, ac);
  5924.  
  5925.   XtAddCallback (shell, XmNdestroyCallback, fe_find_destroy_cb, context);
  5926.   XtAddCallback (shell, XmNokCallback, fe_find_cb, context);
  5927.   XtAddCallback (shell, XmNcancelCallback, fe_find_cb, context);
  5928.   XtAddCallback (shell, XmNapplyCallback, fe_find_cb, context);
  5929.  
  5930.   find_data->msg_head = msg_head;
  5931.   find_data->msg_body = msg_body;
  5932.   find_data->context = context;
  5933.   find_data->context_to_find = fe_findcommand_context();
  5934.   if (!find_data->context_to_find)
  5935.     find_data->context_to_find = fe_GetFocusGridOfContext(context);
  5936.   find_data->shell = shell;
  5937.   find_data->text = find_text;
  5938.   find_data->case_sensitive = case_sensitive_toggle;
  5939.   find_data->backward = backwards_toggle;
  5940.  
  5941.   if (findin) {
  5942.     XtVaSetValues(findin,
  5943.           XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5944.           XmNtopWidget, msg_head,
  5945.           XmNleftAttachment, XmATTACH_FORM,
  5946.           XmNrightAttachment, XmATTACH_WIDGET,
  5947.           XmNrightWidget, msg_head,
  5948.           XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5949.           XmNbottomWidget, msg_head,
  5950.           0);
  5951.     XtVaSetValues(msg_head,
  5952.           XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5953.           XmNtopWidget, msg_body,
  5954.           XmNrightAttachment, XmATTACH_WIDGET,
  5955.           XmNrightWidget, msg_body,
  5956.           XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5957.           XmNbottomWidget, msg_body,
  5958.           0);
  5959.     XtVaSetValues(msg_body,
  5960.           XmNtopAttachment, XmATTACH_FORM,
  5961.           XmNrightAttachment, XmATTACH_FORM,
  5962.           XmNbottomAttachment, XmATTACH_NONE,
  5963.           0);
  5964.   }
  5965.  
  5966.   XtVaSetValues (find_label,
  5967.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5968.          XmNtopWidget, find_text,
  5969.          XmNleftAttachment, XmATTACH_FORM,
  5970.          XmNrightAttachment, XmATTACH_WIDGET,
  5971.          XmNrightWidget, find_text,
  5972.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5973.          XmNbottomWidget, find_text,
  5974.          0);
  5975.   XtVaSetValues (find_text,
  5976.          XmNtopAttachment, msg_body ? XmATTACH_WIDGET : XmATTACH_FORM,
  5977.          XmNtopWidget, msg_body,
  5978.          XmNleftAttachment, XmATTACH_POSITION,
  5979.          XmNleftPosition, 10,
  5980.          XmNrightAttachment, XmATTACH_FORM,
  5981.          XmNbottomAttachment, XmATTACH_NONE,
  5982.          0);
  5983.   XtVaSetValues (case_sensitive_toggle,
  5984.          XmNtopAttachment, XmATTACH_WIDGET,
  5985.          XmNtopWidget, find_text,
  5986.          XmNbottomAttachment, XmATTACH_NONE,
  5987.          XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
  5988.          XmNleftWidget, find_text,
  5989.          XmNrightAttachment, XmATTACH_NONE,
  5990.          0);
  5991.   XtVaSetValues (backwards_toggle,
  5992.          XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET,
  5993.          XmNtopWidget, case_sensitive_toggle,
  5994.          XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
  5995.          XmNbottomWidget, case_sensitive_toggle,
  5996.          XmNleftAttachment, XmATTACH_WIDGET,
  5997.          XmNleftWidget, case_sensitive_toggle,
  5998.          XmNrightAttachment, XmATTACH_NONE,
  5999.          0);
  6000.   ac = 0;
  6001.   if (findin) {
  6002.     fe_find_head_or_body_changed(find_data->find_in_headers ? msg_head : msg_body,
  6003.                  (XtPointer)find_data, (XtPointer)0);
  6004.     kids[ac++] = findin;
  6005.     kids[ac++] = msg_head;
  6006.     kids[ac++] = msg_body;
  6007.   }
  6008.   kids[ac++] = find_label;
  6009.   kids[ac++] = find_text;
  6010.   kids[ac++] = case_sensitive_toggle;
  6011.   kids[ac++] = backwards_toggle;
  6012.   XtManageChildren (kids, ac);
  6013.   ac = 0;
  6014.   XtManageChild (form);
  6015.   XtVaSetValues (form, XmNinitialFocus, find_text, 0);
  6016.  
  6017.   fe_NukeBackingStore (shell);
  6018.   XtManageChild (shell);
  6019. }
  6020.  
  6021. /* When a new layout begins, the find data is invalid.
  6022.  */
  6023. void
  6024. fe_FindReset (MWContext *context)
  6025. {
  6026.   fe_FindData *find_data;
  6027.   MWContext *top_context = XP_GetNonGridContext(context);
  6028.  
  6029.   find_data = CONTEXT_DATA(top_context)->find_data;
  6030.   
  6031.   if (!find_data) return;
  6032.  
  6033.   if (find_data->context_to_find == context ||
  6034.       find_data->context == context) {
  6035.     find_data->start_element = 0;
  6036.     find_data->end_element = 0;
  6037.     find_data->start_pos = 0;
  6038.     find_data->end_pos = 0;
  6039.   }
  6040. }
  6041.  
  6042.  
  6043. /* Streaming audio
  6044.  */
  6045.  
  6046. int
  6047. XFE_AskStreamQuestion (MWContext *context)
  6048. {
  6049.   struct fe_confirm_data data;
  6050.   Widget mainw = CONTEXT_WIDGET (context);
  6051.   Widget dialog;
  6052.   Arg av [20];
  6053.   int ac;
  6054.   Visual *v = 0;
  6055.   Colormap cmap = 0;
  6056.   Cardinal depth = 0;
  6057.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  6058.          XtNdepth, &depth, 0);
  6059.   ac = 0;
  6060.   XtSetArg (av[ac], XmNvisual, v); ac++;
  6061.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  6062.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  6063.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  6064.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  6065.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
  6066.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  6067.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  6068.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  6069.   dialog = XmCreatePromptDialog (mainw, "streamingAudioQuery", av, ac);
  6070.  
  6071.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_SEPARATOR));
  6072.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_TEXT));
  6073.   XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL));
  6074.   XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_APPLY_BUTTON));
  6075. #ifdef NO_HELP
  6076.   fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
  6077. #endif
  6078.  
  6079.   fe_NukeBackingStore (dialog);
  6080.   XtManageChild (dialog);
  6081.  
  6082.   XtAddCallback (dialog, XmNokCallback, fe_destroy_ok_cb, &data);
  6083.   XtAddCallback (dialog, XmNapplyCallback, fe_destroy_apply_cb, &data);
  6084.   XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cancel_cb, &data);
  6085.   XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  6086.  
  6087.   data.context = context;
  6088.   data.widget = dialog;
  6089.   data.answer = Answer_Invalid;
  6090.  
  6091.   while (data.answer == Answer_Invalid)
  6092.     fe_EventLoop ();
  6093.  
  6094.   if (data.answer == Answer_Cancel || data.answer == Answer_Destroy)
  6095.     return -1;
  6096.   else if (data.answer == Answer_OK)
  6097.     return 1;
  6098.   else if (data.answer == Answer_Apply)
  6099.     return 0;
  6100.   else
  6101.     abort ();
  6102. }
  6103.  
  6104.  
  6105. /* Care and feeding of lawyers and other parasites */
  6106.  
  6107. static XtErrorHandler old_xt_warning_handler = NULL;
  6108.  
  6109. static void 
  6110. xt_warning_handler(String msg)
  6111. {
  6112.     if (!msg)
  6113.     {
  6114.         return;
  6115.     }
  6116.  
  6117. #ifndef DEBUG
  6118.     /* Ignore warnings that contain "Actions not found" (non debug only) */
  6119.     if (XP_STRSTR(msg,"Actions not found"))
  6120.     {
  6121.         return;
  6122.     }
  6123. #endif
  6124.     
  6125.     (*old_xt_warning_handler)(msg);
  6126. }
  6127.  
  6128. void
  6129. fe_LicenseDialog (MWContext *context)
  6130. {
  6131.   Widget mainw = CONTEXT_WIDGET (context);
  6132.   Widget dialog;
  6133.   Arg av [20];
  6134.   int ac;
  6135.   Visual *v = 0;
  6136.   Colormap cmap = 0;
  6137.   Cardinal depth = 0;
  6138.   Widget form, label1, text, label2;
  6139.   Widget accept, reject;
  6140.  
  6141.   char crockery [1024];
  6142.   PR_snprintf (crockery, sizeof (crockery), "%d ", getuid ());
  6143.   strcat (crockery, fe_version);
  6144.  
  6145.   if (fe_VendorAnim)
  6146.     return;
  6147.  
  6148.   if (fe_globalPrefs.license_accepted &&
  6149.       !strcmp (crockery, fe_globalPrefs.license_accepted))
  6150.     return;
  6151.  
  6152.   XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  6153.          XtNdepth, &depth, 0);
  6154.   ac = 0;
  6155.   XtSetArg (av[ac], XmNvisual, v); ac++;
  6156.   XtSetArg (av[ac], XmNdepth, depth); ac++;
  6157.   XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  6158.   XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  6159.   XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  6160.   XtSetArg (av[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
  6161.   XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  6162.   XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  6163.   XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  6164.   XtSetArg (av[ac], XmNdefaultButton, 0); ac++;
  6165.   dialog = XmCreateTemplateDialog (mainw, "licenseDialog", av, ac);
  6166.  
  6167.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON));
  6168.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON));
  6169. /*  fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_APPLY_BUTTON));*/
  6170.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog,XmDIALOG_DEFAULT_BUTTON));
  6171.   fe_UnmanageChild_safe (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
  6172.  
  6173.   ac = 0;
  6174.   accept = XmCreatePushButtonGadget (dialog, "accept", av, ac);
  6175.   reject = XmCreatePushButtonGadget (dialog, "reject", av, ac);
  6176.   form = XmCreateForm (dialog, "form", av, ac);
  6177.   label1 = XmCreateLabelGadget (form, "label1", av, ac);
  6178.  
  6179.   XtSetArg (av [ac], XmNeditable, False); ac++;
  6180.   XtSetArg (av [ac], XmNcursorPositionVisible, False); ac++;
  6181.   XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
  6182.   text = XmCreateScrolledText (form, "text", av, ac);
  6183.   fe_HackDialogTranslations (text);
  6184.   ac = 0;
  6185.   label2 = XmCreateLabelGadget (form, "label2", av, ac);
  6186.  
  6187.   XtVaSetValues (label1,
  6188.          XmNtopAttachment, XmATTACH_FORM,
  6189.          XmNbottomAttachment, XmATTACH_NONE,
  6190.          XmNleftAttachment, XmATTACH_FORM,
  6191.          XmNrightAttachment, XmATTACH_FORM,
  6192.          0);
  6193.   XtVaSetValues (XtParent (text),
  6194.          XmNtopAttachment, XmATTACH_WIDGET,
  6195.          XmNtopWidget, label1,
  6196.          XmNbottomAttachment, XmATTACH_WIDGET,
  6197.          XmNbottomWidget, label2,
  6198.          XmNleftAttachment, XmATTACH_FORM,
  6199.          XmNrightAttachment, XmATTACH_FORM,
  6200.          0);
  6201.   XtVaSetValues (label2,
  6202.          XmNtopAttachment, XmATTACH_NONE,
  6203.          XmNbottomAttachment, XmATTACH_FORM,
  6204.          XmNleftAttachment, XmATTACH_FORM,
  6205.          XmNrightAttachment, XmATTACH_FORM,
  6206.          0);
  6207.  
  6208.   {
  6209.     char *license = 0;
  6210.     int32 length = 0;
  6211.     char *ctype = 0;
  6212.     void *data = FE_AboutData ("license", &license, &length, &ctype);
  6213.     if (!license || length < 300)
  6214.       {
  6215.         license = "Please fill in";
  6216.         /* abort (); */
  6217.       }
  6218.     XtVaSetValues (text, XmNvalue, license, 0);
  6219.     if (data) free (data);
  6220.   }
  6221.  
  6222.   XtManageChild (label1);
  6223.   XtManageChild (text);
  6224.   XtManageChild (XtParent (text));
  6225.   XtManageChild (label2);
  6226.   XtManageChild (form);
  6227.   XtManageChild (accept);
  6228.   XtManageChild (reject);
  6229.  
  6230.   {
  6231.     struct fe_confirm_data data;
  6232.     XtVaSetValues (dialog, XmNdefaultButton, accept, 0);
  6233.     XtAddCallback (accept, XmNactivateCallback, fe_destroy_ok_cb, &data);
  6234.     XtAddCallback (reject, XmNactivateCallback, fe_destroy_cancel_cb, &data);
  6235.     XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb, &data);
  6236.  
  6237.     data.context = context;
  6238.     data.widget = dialog;
  6239.     data.answer = Answer_Invalid;
  6240.  
  6241.     fe_NukeBackingStore (dialog);
  6242.  
  6243.     /* Install a warning handler that ignores translation warnings */
  6244.     old_xt_warning_handler = XtAppSetWarningHandler(fe_XtAppContext,
  6245.                                                     xt_warning_handler);
  6246.  
  6247.     XtManageChild (dialog);
  6248.  
  6249.     /* Restore the original warning handler after the dialog is managed */
  6250.     XtAppSetWarningHandler(fe_XtAppContext,old_xt_warning_handler);
  6251.  
  6252.     while (data.answer == Answer_Invalid)
  6253.       fe_EventLoop ();
  6254.  
  6255.     if (data.answer == Answer_Cancel || data.answer == Answer_Destroy)
  6256.       {
  6257.     if (fe_pidlock) unlink (fe_pidlock);
  6258.     exit (0);
  6259.       }
  6260.     else if (data.answer == Answer_OK)
  6261.       {
  6262.     /* Store crockery into preferences, and save. */
  6263.     StrAllocCopy (fe_globalPrefs.license_accepted, crockery);
  6264.     if (!XFE_UpgradePrefs ((char *) fe_globalData.user_prefs_file,
  6265.                 &fe_globalPrefs))
  6266.       fe_perror (context, XP_GetString(XFE_CANT_SAVE_PREFS));
  6267.     return;
  6268.       }
  6269.     else
  6270.       {
  6271.     abort ();
  6272.       }
  6273.   }
  6274. }
  6275.  
  6276. void
  6277. fe_UpdateDocInfoDialog (MWContext *context)
  6278. {
  6279.     /* nada for now */
  6280. }
  6281.  
  6282. static void
  6283. fe_security_dialog_toggle (Widget widget, XtPointer closure,
  6284.                XtPointer call_data)
  6285. {
  6286.   XP_Bool *prefs_toggle = (XP_Bool *) closure;
  6287.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  6288.   *prefs_toggle = cb->set;
  6289.   return;
  6290. }
  6291.  
  6292. static void
  6293. fe_movemail_dialog_toggle (Widget widget, XtPointer closure,
  6294.                XtPointer call_data)
  6295. {
  6296.   XP_Bool *prefs_toggle = (XP_Bool *) closure;
  6297.   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)call_data;
  6298.   *prefs_toggle = cb->set;
  6299.   if (!XFE_SavePrefs ((char *) fe_globalData.user_prefs_file, &fe_globalPrefs))
  6300.     fe_perror (fe_all_MWContexts->context,
  6301.                XP_GetString( XFE_ERROR_SAVING_OPTIONS ) );
  6302. }
  6303.  
  6304. #ifdef MOZ_MAIL_NEWS
  6305. /*
  6306.  * fe_MovemailWarning
  6307.  * Stolen from FE_SecurityDialog
  6308.  */
  6309. extern Boolean
  6310. fe_MovemailWarning(MWContext *context)
  6311. {
  6312.   if ( fe_globalPrefs.movemail_warn == True ) {
  6313.     Widget mainw = CONTEXT_WIDGET (context);
  6314.     Widget dialog;
  6315.     Widget form;
  6316.     Widget toggle;
  6317.     Arg av [20];
  6318.     int ac;
  6319.     Visual *v = 0;
  6320.     Colormap cmap = 0;
  6321.     Cardinal depth = 0;
  6322.     XmString ok_label;
  6323.     XmString cancel_label;
  6324.     XmString selection_label;
  6325.     XmString toggle_label;
  6326.     struct fe_confirm_data data;
  6327.     char buf[256];
  6328.     char* from;
  6329.     const char* to;
  6330.  
  6331.     from = fe_mn_getmailbox();
  6332.     to   = FE_GetFolderDirectory(context);
  6333.  
  6334.     /*
  6335.      * This dialog should probably be popped up in fe_mn_getmailbox()
  6336.      * instead.  Otherwise, we have to check everywhere it's used.
  6337.      * (Only two places at this point, though.)
  6338.      */
  6339.     if ( from == NULL ) {
  6340.         FE_Alert(context, XP_GetString(XFE_MAIL_SPOOL_UNKNOWN));
  6341.         return False;
  6342.     }
  6343.  
  6344.     PR_snprintf(buf, sizeof(buf), XP_GetString(XFE_MOVEMAIL_EXPLANATION),
  6345.                 from, to, from);
  6346.  
  6347.     ok_label = XmStringCreateLtoR(XP_GetString(XFE_CONTINUE_MOVEMAIL),
  6348.                                   XmFONTLIST_DEFAULT_TAG);
  6349.     cancel_label = XmStringCreateLtoR(XP_GetString(XFE_CANCEL_MOVEMAIL),
  6350.                                       XmFONTLIST_DEFAULT_TAG);
  6351.     selection_label = XmStringCreateLtoR(buf,
  6352.                                          XmFONTLIST_DEFAULT_TAG);
  6353.     toggle_label = XmStringCreateLtoR(XP_GetString(XFE_SHOW_NEXT_TIME),
  6354.                                       XmFONTLIST_DEFAULT_TAG);
  6355.  
  6356.     XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  6357.                    XtNdepth, &depth, 0);
  6358.     ac = 0;
  6359.     XtSetArg (av[ac], XmNvisual, v); ac++;
  6360.     XtSetArg (av[ac], XmNdepth, depth); ac++;
  6361.     XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  6362.     XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  6363.     XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  6364.     XtSetArg (av[ac], XmNdialogStyle,
  6365.               XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  6366.     XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  6367.     XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  6368.     XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  6369.     XtSetArg (av[ac], XmNchildPlacement, XmPLACE_BELOW_SELECTION); ac++;
  6370.     XtSetArg (av[ac], XmNokLabelString, ok_label); ac++;
  6371.     XtSetArg (av[ac], XmNcancelLabelString, cancel_label); ac++;
  6372.     XtSetArg (av[ac], XmNselectionLabelString, selection_label); ac++;
  6373.     dialog = XmCreatePromptDialog (mainw, "movemailWarnDialog", av, ac);
  6374.  
  6375.     if ( ok_label ) XmStringFree(ok_label);
  6376.     if ( cancel_label ) XmStringFree(cancel_label);
  6377.     if ( selection_label ) XmStringFree(selection_label);
  6378.  
  6379.     XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL));
  6380.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_SEPARATOR));
  6381.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_TEXT));
  6382.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog,
  6383.                                                   XmDIALOG_APPLY_BUTTON));
  6384. #ifdef NO_HELP
  6385.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog,
  6386.                                                   XmDIALOG_HELP_BUTTON));
  6387. #endif
  6388.  
  6389.     ac = 0;
  6390.     form = XmCreateForm (dialog, "form", av, ac);
  6391.     ac = 0;
  6392.     XtSetArg (av[ac], XmNset, fe_globalPrefs.movemail_warn); ac++;
  6393.     XtSetArg (av[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  6394.     XtSetArg (av[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  6395.     XtSetArg (av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  6396.     XtSetArg (av[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  6397.     XtSetArg (av[ac], XmNlabelString, toggle_label); ac++;
  6398.     toggle = XmCreateToggleButtonGadget (form, "toggle", av, ac);
  6399.     if ( toggle_label ) XmStringFree(toggle_label);
  6400.  
  6401.     XtAddCallback (toggle, XmNvalueChangedCallback,
  6402.                fe_movemail_dialog_toggle, &fe_globalPrefs.movemail_warn);
  6403.     XtManageChild (toggle);
  6404.     XtManageChild (form);
  6405.  
  6406.     fe_NukeBackingStore (dialog);
  6407.     XtManageChild (dialog);
  6408.  
  6409.     XtAddCallback (dialog, XmNokCallback, fe_destroy_ok_cb, &data);
  6410.     XtAddCallback (dialog, XmNapplyCallback, fe_destroy_apply_cb, &data);
  6411.     XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cancel_cb, &data);
  6412.     XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb,&data);
  6413.  
  6414.     data.context = context;
  6415.     data.widget = dialog;
  6416.     data.answer = Answer_Invalid;
  6417.  
  6418.     while (data.answer == Answer_Invalid)
  6419.       fe_EventLoop ();
  6420.  
  6421.     if (data.answer == Answer_Cancel || data.answer == Answer_Destroy)
  6422.       return False;
  6423.     else if (data.answer == Answer_OK)
  6424.       return True;
  6425.     else
  6426.       abort ();
  6427.   }
  6428.  
  6429.   return True;
  6430. }
  6431. #endif  /* MOZ_MAIL_NEWS */
  6432.  
  6433.  
  6434. extern Bool
  6435. FE_SecurityDialog (MWContext *context, int state, XP_Bool *prefs_toggle)
  6436. {
  6437.   char *name;
  6438.   Bool cancel_p = True;
  6439.   Bool cancel_default_p = False;
  6440.   switch (state)
  6441.     {
  6442.     case SD_INSECURE_POST_FROM_SECURE_DOC:
  6443.       name = "insecurePostFromSecureDocDialog";
  6444.       cancel_p = True;
  6445.       cancel_default_p = True;
  6446.       break;
  6447.     case SD_INSECURE_POST_FROM_INSECURE_DOC:
  6448.       name = "insecurePostFromInsecureDocDialog";
  6449.       cancel_p = True;
  6450.       break;
  6451.     case SD_ENTERING_SECURE_SPACE:
  6452.       name = "enteringSecureDialog";
  6453.       cancel_p = False;
  6454.       break;
  6455.     case SD_LEAVING_SECURE_SPACE:
  6456.       name = "leavingSecureDialog";
  6457.       cancel_p = True;
  6458.       break;
  6459.     case SD_INSECURE_DOCS_WITHIN_SECURE_DOCS_NOT_SHOWN:
  6460.       name = "mixedSecurityDialog";
  6461.       cancel_p = False;
  6462.       break;
  6463.     case SD_REDIRECTION_TO_INSECURE_DOC:
  6464.       name = "redirectionToInsecureDialog";
  6465.       cancel_p = True;
  6466.       break;
  6467.     case SD_REDIRECTION_TO_SECURE_SITE:
  6468.       name = "redirectionToSecureDialog";
  6469.       cancel_p = True;
  6470.       break;
  6471.     default:
  6472.       abort ();
  6473.     }
  6474.  
  6475.   if (prefs_toggle && !*prefs_toggle)
  6476.     return True;
  6477.  
  6478.   {
  6479.     Widget mainw = CONTEXT_WIDGET (context);
  6480.     Widget dialog;
  6481.     Arg av [20];
  6482.     int ac;
  6483.     Visual *v = 0;
  6484.     Colormap cmap = 0;
  6485.     Cardinal depth = 0;
  6486.     XtVaGetValues (mainw, XtNvisual, &v, XtNcolormap, &cmap,
  6487.            XtNdepth, &depth, 0);
  6488.     ac = 0;
  6489.     XtSetArg (av[ac], XmNvisual, v); ac++;
  6490.     XtSetArg (av[ac], XmNdepth, depth); ac++;
  6491.     XtSetArg (av[ac], XmNcolormap, cmap); ac++;
  6492.     XtSetArg (av[ac], XmNallowShellResize, TRUE); ac++;
  6493.     XtSetArg (av[ac], XmNtransientFor, mainw); ac++;
  6494.     XtSetArg (av[ac], XmNdialogStyle,
  6495.               XmDIALOG_PRIMARY_APPLICATION_MODAL); ac++;
  6496.     if (cancel_p)
  6497.       {
  6498.           XtSetArg (av[ac], XmNdialogType, XmDIALOG_QUESTION); ac++;
  6499.       }
  6500.     else
  6501.       {
  6502.           XtSetArg (av[ac], XmNdialogType, XmDIALOG_INFORMATION); ac++;
  6503.       }
  6504.     XtSetArg (av[ac], XmNdeleteResponse, XmDESTROY); ac++;
  6505.     XtSetArg (av[ac], XmNautoUnmanage, False); ac++;
  6506.     XtSetArg (av[ac], XmNchildPlacement, XmPLACE_BELOW_SELECTION); ac++;
  6507.     dialog = XmCreatePromptDialog (mainw, name, av, ac);
  6508.  
  6509.     XtManageChild (XmSelectionBoxGetChild (dialog, XmDIALOG_SELECTION_LABEL));
  6510.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_SEPARATOR));
  6511.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog, XmDIALOG_TEXT));
  6512.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog,
  6513.                           XmDIALOG_APPLY_BUTTON));
  6514. #ifdef NO_HELP
  6515.     fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog,
  6516.                           XmDIALOG_HELP_BUTTON));
  6517. #endif
  6518.     if (! cancel_p)
  6519.       fe_UnmanageChild_safe (XmSelectionBoxGetChild (dialog,
  6520.                             XmDIALOG_CANCEL_BUTTON));
  6521.  
  6522.     if (prefs_toggle)
  6523.       {
  6524.     Widget form, toggle;
  6525.     ac = 0;
  6526.     form = XmCreateForm (dialog, "form", av, ac);
  6527.     ac = 0;
  6528.     XtSetArg (av[ac], XmNset, *prefs_toggle); ac++;
  6529.     XtSetArg (av[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  6530.     XtSetArg (av[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  6531.     XtSetArg (av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  6532.     XtSetArg (av[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
  6533.     toggle = XmCreateToggleButtonGadget (form, "toggle", av, ac);
  6534.     XtAddCallback (toggle, XmNvalueChangedCallback,
  6535.                fe_security_dialog_toggle, prefs_toggle);
  6536.     XtManageChild (toggle);
  6537.     XtManageChild (form);
  6538.       }
  6539.  
  6540.     if (cancel_default_p)
  6541.       {
  6542.     Widget c = XmSelectionBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON);
  6543.     if (!c) abort ();
  6544.     XtVaSetValues (dialog, XmNdefaultButton, c, XmNinitialFocus, c, 0);
  6545.       }
  6546.  
  6547.     fe_NukeBackingStore (dialog);
  6548.     XtManageChild (dialog);
  6549.  
  6550.       {
  6551.     struct fe_confirm_data data;
  6552.     XtAddCallback (dialog, XmNokCallback, fe_destroy_ok_cb, &data);
  6553.     if (cancel_p)
  6554.       {
  6555.         XtAddCallback (dialog, XmNapplyCallback, fe_destroy_apply_cb, &data);
  6556.         XtAddCallback (dialog, XmNcancelCallback, fe_destroy_cancel_cb, &data);
  6557.         XtAddCallback (dialog, XmNdestroyCallback, fe_destroy_finish_cb,&data);
  6558.       }
  6559.     
  6560.     data.context = context;
  6561.     data.widget = dialog;
  6562.     data.answer = Answer_Invalid;
  6563.  
  6564.     while (data.answer == Answer_Invalid)
  6565.       fe_EventLoop ();
  6566.  
  6567.     if (data.answer == Answer_Cancel || data.answer == Answer_Destroy)
  6568.       return False;
  6569.     else if (data.answer == Answer_OK)
  6570.       return True;
  6571.     else
  6572.       abort ();
  6573.       }
  6574.   }
  6575. }
  6576.