dtwm: basic multihead(xinerama only) support
[oweals/cde.git] / cde / programs / dtfile / Command.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: Command.c /main/9 1996/10/30 11:09:42 drk $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           Command.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    Command processing functions used by the File Browser.
32  *
33  *   FUNCTIONS: ActionCallback
34  *              InvalidTrashDragDrop
35  *              ProcessAction
36  *              ProcessBufferDropOnFolder
37  *              ProcessMoveCopyLink
38  *              ProcessNewView
39  *              RunCommand
40  *              TimerEvent
41  *              UpdateActionMenuPane
42  *
43  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
44  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
45  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
46  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
47  *
48  ****************************************************************************
49  ************************************<+>*************************************/
50
51
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <Xm/PushBG.h>
55 #include <Xm/RowColumn.h>
56 #include <Xm/ScrollBar.h>
57 #include <Xm/SeparatoG.h>
58 #include <Xm/XmP.h>
59 #include <X11/Shell.h>
60 #include <X11/Intrinsic.h>
61
62 #include <Dt/Action.h>
63 #include <Dt/ActionP.h>
64 #include <Dt/Connect.h>
65 #include <Dt/DtNlUtils.h>
66 #include <Dt/HourGlass.h>
67 #include <Dt/Dnd.h>
68 #include <Dt/Dts.h>
69 #include <Dt/SharedProcs.h>
70 #include <Dt/Utility.h>
71
72 #include "Encaps.h"
73 #include "SharedProcs.h"
74 #include "FileMgr.h"
75 #include "Desktop.h"
76 #include "Main.h"
77 #include "Help.h"
78 #include "SharedMsgs.h"
79 #include "Prefs.h"
80
81 /********    Static Function Declarations    ********/
82
83 static void ActionCallback( Widget w,
84                             XtPointer client_data,
85                             XtPointer call_data) ;
86 static void TimerEvent(
87                         Widget widget,
88                         XtIntervalId *id) ;
89 void ProcessBufferDropOnFolder (
90                                 char *command,
91                                 FileMgrData *file_mgr_data,
92                                 FileViewData *file_view_data,
93                                 DtDndDropCallbackStruct *drop_parameters,
94                                 Widget drop_window);
95
96
97 /********    End Static Function Declarations    ********/
98
99 extern int G_dropx,G_dropy;
100
101 /************************************************************************
102  *
103  *  UpdateActionMenuPane
104  *      Build up a set of menu panes for the provided file manager rec
105  *      that contains as items each of the commands for each file type.
106  *
107  ************************************************************************/
108
109 void
110 UpdateActionMenuPane(
111         XtPointer client_data,
112         FileMgrRec *file_mgr_rec,
113         char *file_type,
114         int type,
115         int number,
116         Widget widget,
117         unsigned char physical_type)
118 {
119    XmManagerWidget action_pane;
120    FileMgrData *file_mgr_data = NULL;
121    DialogData * dialog_data;
122    FileViewData *file_view_data;
123    DesktopRec *desktopWindow;
124    Widget child;
125    register int i, menu_offset;
126    register int action_count;
127    int count, del_count;
128    int num_children;
129    char ** command_list;
130    XmString string;
131    char *action_label;
132
133    Arg args[2];
134
135
136    if(type == DESKTOP)
137       desktopWindow = (DesktopRec *)client_data;
138    else if(type == FM_POPUP)
139       file_view_data = (FileViewData *)client_data;
140
141    if (file_mgr_rec)
142    {
143       dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
144       file_mgr_data = (FileMgrData *) dialog_data->data;
145    }
146
147    /*  Count the number of actions defined for the the file type  */
148
149    action_count = 0;
150    command_list = _DtCompileActionVector(file_type);
151
152    if(command_list != NULL)
153       while (command_list[action_count] != NULL &&
154                                     strlen (command_list[action_count]) != 0)
155          action_count++;
156
157    if (physical_type == DtDIRECTORY && type == DESKTOP)
158        ++action_count;
159
160
161    /*  If the menu pane is already set up for the file type then return.  */
162
163    if(type == NOT_DESKTOP)
164    {
165       XtFree(file_mgr_rec->action_pane_file_type);
166       file_mgr_rec->action_pane_file_type = XtNewString(file_type);
167
168       action_pane = (XmManagerWidget) file_mgr_rec->action_pane;
169       menu_offset = number + SELECTED_MENU_MAX;
170    }
171    else
172    {
173       action_pane = (XmManagerWidget) widget;
174       menu_offset = number;
175    }
176
177    num_children = action_pane->composite.num_children;
178
179    /*
180     * This is so that we can determine which icon was responsible for
181     * posting the menu, or requesting help.
182     */
183    if (type == FM_POPUP)
184       file_mgr_data->popup_menu_icon = file_view_data;
185 /*
186    else if (file_mgr_data)
187       file_mgr_data->popup_menu_icon = NULL;
188 */
189
190    if (action_count + menu_offset > num_children)
191    {
192       if(type == FM_POPUP)
193          for (i = number; i < num_children; i++)
194             XtManageChild (action_pane->composite.children[i]);
195       for (i = num_children; i < action_count + menu_offset; i++)
196       {
197          child = XmCreatePushButtonGadget ((Widget)action_pane,
198                                             "action_button", args, 0);
199          if(type == DESKTOP)
200          {
201             XtAddCallback (child, XmNactivateCallback, DTActionCallback,
202                                                     (XtPointer)desktopWindow);
203             XtAddCallback(child, XmNhelpCallback,
204                           (XtCallbackProc)DTHelpRequestCB, NULL);
205          }
206          else if(type == FM_POPUP)
207          {
208             XtAddCallback (child, XmNactivateCallback, ActionCallback, NULL);
209             XtAddCallback(child, XmNhelpCallback,
210                           (XtCallbackProc)HelpRequestCB, NULL);
211          }
212          else
213          {
214             XtAddCallback (child, XmNactivateCallback, ActionCallback,
215                                                     (XtPointer)file_mgr_rec);
216             XtAddCallback(child, XmNhelpCallback,
217                           (XtCallbackProc)HelpRequestCB, NULL);
218          }
219          XtManageChild (child);
220       }
221    }
222    else
223    {
224      for (i = menu_offset; i < num_children; i++)
225      {
226        if (i < action_count + menu_offset)
227        {
228           XtRemoveAllCallbacks(action_pane->composite.children[i],
229                                                    XmNactivateCallback);
230           if(type == DESKTOP)
231              XtAddCallback (action_pane->composite.children[i],
232                                      XmNactivateCallback, DTActionCallback,
233                                      (XtPointer)desktopWindow);
234           else if(type == FM_POPUP)
235              XtAddCallback (action_pane->composite.children[i],
236                                   XmNactivateCallback, ActionCallback, NULL);
237           else
238              XtAddCallback (action_pane->composite.children[i],
239                                         XmNactivateCallback, ActionCallback,
240                                         (XtPointer)file_mgr_rec);
241           XtManageChild (action_pane->composite.children[i]);
242         }
243         else
244           XtUnmanageChild (action_pane->composite.children[i]);
245      }
246    }
247
248    /*  For each action, set the label of the menu button  */
249    /*  and the user data.                                 */
250
251    num_children =  menu_offset + action_count;
252    del_count = 0;
253    for (i = 0; i < action_count; i++)
254    {
255       char *oldCommand;
256       Arg argsTmp[2];
257
258       if(type != DESKTOP)
259       {
260          char* strp;
261
262          strp = XtNewString(command_list[i]);
263          XtSetArg (args[1], XmNuserData, strp);
264
265          action_label = DtActionLabel(command_list[i]);
266
267          if(action_label != NULL)
268              string = XmStringCreateLocalized(action_label);
269          else
270              string = XmStringCreateLocalized(command_list[i]);
271
272          count = i + menu_offset;
273       }
274       else
275       {
276          if (physical_type == DtDIRECTORY && i == 0)
277          {
278             if((action_label = DtActionLabel(openNewView)) != NULL)
279                 string = XmStringCreateLocalized(action_label);
280             else
281                 string = XmStringCreateLocalized(openNewView);
282             XtSetArg (args[1], XmNuserData, openNewView);
283             count = i + number;
284          }
285          else
286          {
287             if (physical_type == DtDIRECTORY)
288             {
289                if(strcmp(command_list[i - 1], openNewView) == 0  ||
290                   strcmp(command_list[i - 1], openInPlace) == 0)
291                {
292                   del_count++;
293                   XtUnmanageChild (action_pane->composite.children[
294                                               num_children - del_count]);
295                   continue;
296                }
297                action_label = DtActionLabel(command_list[i - 1]);
298
299                if(action_label != NULL)
300                    string = XmStringCreateLocalized(action_label);
301                else
302                    string = XmStringCreateLocalized(command_list[i-1]);
303
304                XtSetArg (args[1], XmNuserData, XtNewString
305                                                  (command_list[i - 1]));
306                count = i + number - del_count;
307             }
308             else
309             {
310                action_label = DtActionLabel(command_list[i]);
311
312                if(action_label != NULL)
313                    string = XmStringCreateLocalized(action_label);
314                else
315                    string = XmStringCreateLocalized(command_list[i]);
316
317                XtSetArg (args[1], XmNuserData, XtNewString(command_list[i]));
318                count = i + number;
319             }
320          }
321       }
322
323       /* first we need to get the userData from the push button and
324          free it up */
325       XtSetArg (argsTmp[0], XmNuserData, &oldCommand);
326       XtGetValues (action_pane->composite.children[count], argsTmp, 1);
327
328       if(oldCommand != NULL && strcmp(oldCommand, openNewView) != 0)
329          XtFree(oldCommand);
330
331
332       XtSetArg (args[0], XmNlabelString, string);
333       XtSetValues (action_pane->composite.children[count], args, 2);
334       if(type != NOT_DESKTOP)
335       {
336          XtRemoveAllCallbacks(action_pane->composite.children[count],
337                                                    XmNactivateCallback);
338
339          if(type == DESKTOP)
340          {
341             XtAddCallback (action_pane->composite.children[count],
342                            XmNactivateCallback, DTActionCallback,
343                            (XtPointer)desktopWindow);
344          }
345          else
346             XtAddCallback (action_pane->composite.children[count],
347                            XmNactivateCallback, ActionCallback,
348                            (XtPointer)NULL);
349       }
350       XmStringFree (string);
351       XtFree(action_label);
352    }
353
354    _DtFreeStringVector(command_list);
355 }
356
357
358
359
360 /************************************************************************
361  *
362  *  ActionCallback
363  *      Callback function invoked upon the an actions menu button
364  *      being selected.
365  *
366  ************************************************************************/
367
368 static void
369 ActionCallback(
370         Widget w,
371         XtPointer client_data,
372         XtPointer call_data )
373 {
374    FileMgrRec   * file_mgr_rec;
375    DialogData   * dialog_data;
376    FileMgrData  * file_mgr_data;
377    FileViewData  * file_view_data;
378    char * command;
379    Arg args[1];
380    Widget mbar;
381    Boolean popup = False;
382    XmAnyCallbackStruct * callback;
383
384
385    XmUpdateDisplay (w);
386    mbar = XtParent(w);
387
388    callback = (XmAnyCallbackStruct *) call_data;
389    if(client_data == NULL)
390    {
391       popup = True;
392       XtSetArg(args[0], XmNuserData, &file_mgr_rec);
393       XtGetValues(mbar, args, 1);
394       dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
395       file_mgr_data = (FileMgrData *) dialog_data->data;
396       file_view_data = file_mgr_data->popup_menu_icon;
397       if(!file_view_data) /* The object would have probably been delete */
398          return;
399       file_mgr_data->popup_menu_icon = NULL;  /* Just to make it unuseful */
400    }
401    else
402    {
403       file_mgr_rec = (FileMgrRec *) client_data;
404       dialog_data = _DtGetInstanceData ((XtPointer)file_mgr_rec);
405       file_mgr_data = (FileMgrData *) dialog_data->data;
406    }
407
408
409
410    /*  Find the file data for the file that is selected  */
411
412    XtSetArg (args[0], XmNuserData, (XtPointer) &command);
413    XtGetValues (w, args, 1);
414
415    if(strcmp(command, openNewView) == 0)
416    {
417       XButtonEvent *event = (XButtonEvent *)callback->event;
418       unsigned int modifiers;
419
420       modifiers = event->state;
421       if(popup)
422          RunCommand (command, file_mgr_data, file_view_data, NULL, NULL, NULL);
423       else
424          RunCommand (command, file_mgr_data, file_mgr_data->selection_list[0],
425                      NULL, NULL, NULL);
426
427       if((modifiers != 0) && ((modifiers & ControlMask) != 0))
428       {
429          DialogData  *dialog_data;
430
431          dialog_data = _DtGetInstanceData(file_mgr_data->file_mgr_rec);
432          CloseView(dialog_data);
433       }
434    }
435    else
436    {
437       if(popup)
438          RunCommand (command, file_mgr_data, file_view_data, NULL, NULL, NULL);
439       else
440          RunCommand (command, file_mgr_data, file_mgr_data->selection_list[0],
441                      NULL, NULL, NULL);
442    }
443 }
444
445
446 /************************************************************************
447  *
448  *  RunCommand
449  *
450  *    WARNING: when desktop links are passed in, this function will NOT
451  *             expect the links to have already been mapped to their
452  *             real files.
453  *
454  ************************************************************************/
455
456 void
457 RunCommand(
458         char *command,
459         FileMgrData *file_mgr_data,
460         FileViewData *file_view_data,
461         WindowPosition *position,
462         DtDndDropCallbackStruct *drop_parameters,
463         Widget drop_window )
464
465 {
466    if ((strcmp (command, openInPlace) == 0) ||
467        (strcmp (command, openNewView) == 0))
468    {
469       /* If the folder is locked, don't allow user to go into it */
470       if( strcmp( file_view_data->file_data->logical_type, LT_FOLDER_LOCK ) == 0 )
471       {
472         char *tmpStr, *title, *msg;
473
474         tmpStr = GETMESSAGE(9, 6, "Action Error");
475         title = XtNewString(tmpStr);
476         msg = (char *)XtMalloc(
477                    strlen( GETMESSAGE(30, 1, "Cannot read from %s") )
478                  + strlen( file_view_data->file_data->file_name )
479                  + 1 );
480         sprintf( msg, GETMESSAGE(30, 1, "Cannot read from %s"),
481                  file_view_data->file_data->file_name );
482         _DtMessage(((FileMgrRec*)file_mgr_data->file_mgr_rec)->file_window,
483                    title, msg, NULL, HelpRequestCB );
484         XtFree(title);
485         XtFree(msg);
486         return;
487       }
488
489       /* this statement applies to the case where a user traverses down the *
490        * part of the directory tree containing the application manager      *
491        * directories or the trash directory                                 */
492       if( ((strcmp(file_view_data->file_data->logical_type, LT_AGROUP) == 0) &&
493            (!(file_mgr_data->toolbox)))
494           ||
495           (strcmp(file_view_data->file_data->logical_type, LT_TRASH) == 0) )
496       {
497          ProcessAction(command,
498                        file_view_data,
499                        drop_parameters,
500                        file_mgr_data->host,
501                        file_mgr_data->current_directory,
502                        file_mgr_data->restricted_directory,
503                        ((FileMgrRec *) file_mgr_data->file_mgr_rec)->shell);
504       }
505       else
506       {
507          ProcessNewView(command, file_mgr_data, file_view_data, position);
508       }
509    }
510
511    else if ((strcmp (command, "FILESYSTEM_MOVE") == 0) ||
512             (strcmp (command, "FILESYSTEM_COPY") == 0) ||
513             (strcmp (command, "FILESYSTEM_LINK") == 0))
514    {
515       /* Check to see what was dropped (files or buffers) */
516       /* Call the appropriate routine to handle the drop  */
517       if (drop_parameters->dropData->protocol == DtDND_FILENAME_TRANSFER)
518          ProcessMoveCopyLink(command,
519                              file_mgr_data,
520                              file_view_data,
521                              drop_parameters,
522                              drop_window);
523       else
524          if (drop_parameters->dropData->protocol == DtDND_BUFFER_TRANSFER)
525            ProcessBufferDropOnFolder(command,
526                                      file_mgr_data,
527                                      file_view_data,
528                                      drop_parameters,
529                                      drop_window);
530
531    }
532
533    else
534    {
535       ProcessAction(command,
536                     file_view_data,
537                     drop_parameters,
538                     file_mgr_data->host,
539                     file_mgr_data->current_directory,
540                     file_mgr_data->restricted_directory,
541                     ((FileMgrRec *) file_mgr_data->file_mgr_rec)->shell);
542    }
543 }
544
545
546 /************************************************************************
547  *
548  *  ProcessNewView
549  *
550  ************************************************************************/
551
552 void
553 ProcessNewView (
554      char *command,
555      FileMgrData *file_mgr_data,
556      FileViewData *file_view_data,
557      WindowPosition *position)
558 {
559    DirectorySet * directory_set;
560    char host_name[MAX_PATH];
561    char directory_name[MAX_PATH];
562    char *tmpStr, *title, *msg;
563
564    /* we don't want to execute the default action if in trash ...  */
565    if( trashFileMgrData != NULL
566        && file_mgr_data == trashFileMgrData)
567    {
568       tmpStr = GETMESSAGE(27, 3, "Trash Can Error");
569       title = XtNewString(tmpStr);
570       tmpStr = GETMESSAGE(27, 87, "Object in the Trash cannot be opened.\n\nTo open an object use 'Put Back' to return it to the\nFile Manager then open it there.");
571       msg = XtNewString(tmpStr);
572
573       _DtMessage( ((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
574                   title, msg, NULL, HelpRequestCB);
575       XtFree(title);
576       XtFree(msg);
577       return;
578    }
579
580    strcpy (host_name, file_mgr_data->host);
581
582    directory_set = (DirectorySet *) (file_view_data->directory_set);
583    strcpy (directory_name, directory_set->name);
584
585    if (strcmp (directory_name, "/") != 0)
586       strcat (directory_name, "/");
587
588    strcat (directory_name, file_view_data->file_data->file_name);
589    DtEliminateDots (directory_name);
590
591    if (strcmp (directory_name, "/..") == 0)
592       strcpy (directory_name, "/");
593
594    if (strcmp (command, openInPlace) == 0)
595    {
596       FileMgrRec *file_mgr_rec;
597       Arg args[1];
598       Widget vb;
599       int value, size, increment, page;
600
601       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
602       ShowNewDirectory (file_mgr_data, host_name, directory_name);
603
604       XtSetArg (args[0], XmNverticalScrollBar, &vb);
605       XtGetValues (file_mgr_rec->scroll_window, args, 1);
606
607          /* get scroll bar values */
608       (void)XmScrollBarGetValues(vb, &value, &size, &increment, &page);
609
610          /* set scroll bar values changing its position */
611       if(value != 0)
612         (void)XmScrollBarSetValues(vb, (int)0, size, increment, page, True);
613
614       if(strcmp(file_mgr_data->current_directory,
615                 file_mgr_data->restricted_directory) == 0)
616       {
617          XtSetSensitive(*upBarBtn, False);
618          currentMenuStates &= ~(MOVE_UP);
619          file_mgr_rec->menuStates &= ~(MOVE_UP);
620       }
621       else
622       {
623          file_mgr_rec->menuStates |= MOVE_UP;
624          XtSetSensitive(*upBarBtn, True);
625          currentMenuStates &= ~(MOVE_UP);
626       }
627    }
628    else
629    {
630       initiating_view = (XtPointer) file_mgr_data;
631       if(file_mgr_data->restricted_directory == NULL)
632       {
633          GetNewView (host_name, directory_name, NULL, position, 0);
634       }
635       else
636       {
637          special_view = True;
638          special_treeType = file_mgr_data->show_type;
639          special_viewType = file_mgr_data->view;
640          special_orderType = file_mgr_data->order;
641          special_directionType = file_mgr_data->direction;
642          special_randomType = file_mgr_data->positionEnabled;
643          special_restricted =
644             XtNewString(file_mgr_data->restricted_directory);
645          if(file_mgr_data->title == NULL)
646             special_title = NULL;
647          else
648             special_title = XtNewString(file_mgr_data->title);
649          special_helpVol = XtNewString(file_mgr_data->helpVol);
650          if(file_mgr_data->toolbox)
651             GetNewView (file_mgr_data->host, directory_name,
652                         file_mgr_data->restricted_directory, position, 0);
653          else
654             GetNewView (file_mgr_data->host, directory_name, NULL, position, 0);
655       }
656
657       initiating_view = (XtPointer) NULL;
658    }
659 }
660
661
662 /************************************************************************
663  *
664  *  ProcessMoveCopyLink
665  *
666  ************************************************************************/
667
668 void
669 ProcessMoveCopyLink (
670      char *command,
671      FileMgrData *file_mgr_data,
672      FileViewData *file_view_data,
673      DtDndDropCallbackStruct *drop_parameters,
674      Widget drop_window)
675
676 {
677    unsigned int modifiers = 0;
678    int numFiles, i;
679    char ** file_set = NULL;
680    char ** host_set = NULL;
681    Boolean trashFile;
682
683
684      /***************************************************/
685      /* if no drop_parameters, there is nothing to move */
686      /***************************************************/
687    if (!drop_parameters)
688      return;
689
690
691      /**************************/
692      /* are these trash files? */
693      /**************************/
694    trashFile = FileFromTrash(drop_parameters->dropData->data.files[0]);
695
696
697      /***********************************************/
698      /* if trying to copy or link from trash return */
699      /***********************************************/
700    if (trashFile)
701    {
702      if (file_mgr_data != trashFileMgrData)
703         if (InvalidTrashDragDrop(drop_parameters->operation,
704               FROM_TRASH,
705               ((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window))
706            return;
707    }
708
709
710      /***************************************************/
711      /* extract file and host sets from drop parameters */
712      /***************************************************/
713    numFiles = drop_parameters->dropData->numItems;
714    _DtSetDroppedFileInfo(drop_parameters, &file_set, &host_set);
715
716
717       /******************************/
718       /* set movement modifier mask */
719       /******************************/
720    if( (initiating_view != NULL) &&
721        (((FileMgrData *)initiating_view)->toolbox) )
722    {
723       /* if initiating_view is a toolbox, the transfer must be */
724       /* a copy                                                */
725       modifiers = ControlMask;
726    }
727    else
728    {
729       if (strcmp(command, "FILESYSTEM_COPY") == 0)
730          modifiers = ControlMask;
731       else if (strcmp(command, "FILESYSTEM_LINK") == 0)
732          modifiers = ShiftMask;
733       else
734          modifiers = 0;
735    }
736
737
738       /*****************************/
739       /* Files dropped on a window */
740       /*****************************/
741    if (drop_window)
742    {
743         /****************************************************************/
744         /* Files dropped in the trash -- move files  to trash directory */
745         /****************************************************************/
746       if(file_mgr_data == trashFileMgrData && !trashFile)
747       {
748          DPRINTF(("DropOnFileWindow:Dragging File(s) to Trash Can from NonTrash Window\n"));
749
750          DropOnTrashCan(numFiles, host_set, file_set, drop_parameters);
751       }
752
753         /****************************************************************/
754         /* Files dragged in the trash -- do nothing                     */
755         /****************************************************************/
756       else if(file_mgr_data == trashFileMgrData && trashFile)
757       {
758          DPRINTF(("DropOnFileWindow: Drag from Within Trash Can\n"));
759       }
760
761         /****************************************************************/
762         /* Files dragged from the trash -- move the files to their new  */
763         /* location                                                     */
764         /****************************************************************/
765       else if(trashFile && file_mgr_data != trashFileMgrData)
766       {
767          DPRINTF(("DropOnFileWindow: Dragging from Trash to Folder Window\n"));
768
769          MoveOutOfTrashCan(file_mgr_data,
770                            (FileMgrRec *)file_mgr_data->file_mgr_rec,
771                            XtWindow(drop_window),  numFiles, host_set,
772                            file_set, drop_parameters->x, drop_parameters->y);
773       }
774
775
776         /****************************************************************/
777         /* Files dropped on a non-trash window -- move files to new     */
778         /* location.                                                    */
779         /*                                                              */
780         /* Droppable windows must be handled like the desktop; i.e.     */
781         /* positioning is supported.                                    */
782         /****************************************************************/
783       else
784       {
785          FileMgrRec *file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
786
787 /*
788          if ((file_mgr_data->show_type == SINGLE_DIRECTORY) &&
789              (file_mgr_data->view != BY_ATTRIBUTES))
790 */
791          {
792             if (file_mgr_data == (FileMgrData *) initiating_view)
793             {
794                DPRINTF(("DropOnFileWindow: Dragging and Dropping File within same window\n"));
795
796                   /* Simple reposition in the same window */
797                XmDropSiteStartUpdate(file_mgr_rec->file_window);
798                RepositionIcons(file_mgr_data,
799                                file_set,
800                                numFiles,
801                                drop_parameters->x, drop_parameters->y,
802                                False);
803                LayoutFileIcons(file_mgr_rec, file_mgr_data, False, True);
804                XmDropSiteEndUpdate(file_mgr_rec->file_window);
805             }
806             else
807             {
808                DPRINTF (("DropOnFileWindow: Dragging file(s) and dropping from other folders\n"));
809
810                CheckMoveType(file_mgr_data, (FileViewData *)NULL,
811                              (DirectorySet *)NULL, (DesktopRec *)NULL,
812                              file_set, host_set, modifiers,
813                              numFiles,
814                              drop_parameters->x, drop_parameters->y,
815                              NOT_DESKTOP);
816             }
817          }
818 /*
819          else
820          {
821             DPRINTF(("DropOnFileWindow: Not Single Directory View\n"));
822
823             if (FileMoveCopy (file_mgr_data,
824                               NULL, file_mgr_data->current_directory, file_mgr_data->host,
825                               host_set, file_set, numFiles,
826                               modifiers, NULL, NULL))
827             {
828                DirectorySet * directory_data;
829                char * directory_name;
830                FileViewData * file_view_data;
831                int j;
832
833                DeselectAllFiles (file_mgr_data);
834
835                directory_data = file_mgr_data->directory_set[0];
836                for (i = 0; i < numFiles; i++)
837                {
838                   directory_name = DName (file_set[i]);
839                   for (j = 0; j < directory_data->file_count; j++)
840                   {
841                      file_view_data = directory_data->file_view_data[j];
842                      if ( (file_view_data->filtered != True) &&
843                           (strcmp(directory_name,
844                                   file_view_data->file_data->file_name) == 0) )
845                      {
846                         SelectFile (file_mgr_data, file_view_data);
847                         break;
848                      }
849                   }
850                }
851
852                PositionFileView(file_view_data, file_mgr_data);
853             }
854          }
855 */
856
857          if (file_mgr_data->selected_file_count == 0)
858             ActivateNoSelect (file_mgr_rec);
859          else if (file_mgr_data->selected_file_count == 1)
860             ActivateSingleSelect
861                (file_mgr_rec,
862                 file_mgr_data->selection_list[0]->file_data->logical_type);
863          else
864             ActivateMultipleSelect (file_mgr_rec);
865       }
866    }
867
868       /*****************************/
869       /* Files dropped on an icon  */
870       /*****************************/
871    else
872    {
873       CheckMoveType(file_mgr_data, file_view_data,
874                     (DirectorySet *) file_view_data->directory_set,
875                     (DesktopRec *)NULL,
876                     file_set, host_set, modifiers,
877                     numFiles, drop_parameters->x, drop_parameters->y,
878                     NOT_DESKTOP_DIR);
879    }
880
881       /***************************/
882       /* free file and host sets */
883       /***************************/
884    _DtFreeDroppedFileInfo(numFiles, file_set, host_set);
885
886 }
887
888 /************************************************************************
889  *
890  * ProcessBufferDropOnFolder
891  *
892  ************************************************************************/
893
894 void
895 ProcessBufferDropOnFolder (
896      char *command,
897      FileMgrData *file_mgr_data,
898      FileViewData *file_view_data,
899      DtDndDropCallbackStruct *drop_parameters,
900      Widget drop_window)
901
902 {
903    unsigned int modifiers = 0;
904    int num_of_buffers, i;
905    char ** file_set = NULL;
906    char ** host_set = NULL;
907    BufferInfo *buffer_set = NULL;
908    char  directory[MAX_PATH];
909
910
911
912
913    /***************************************************/
914    /* if no drop_parameters, or invalid params        */
915    /* then disallow the drop                          */
916    /***************************************************/
917    if (!drop_parameters)
918      return;
919
920    /* if dropped on file window and file_mgr_data is null */
921    if (drop_window && (file_mgr_data == NULL))
922      return;
923
924    /* if dropped on a folder icon and file_view_data */
925    /* is NULL, disallow the drop                     */
926    if (!drop_window && (file_view_data == NULL))
927      return;
928
929
930
931
932
933   /****************************************************/
934   /* extract file and host sets from drop parameters  */
935   /* @@@...need to check with Linda about how host_set*/
936   /* is being handled                                 */
937   /****************************************************/
938
939    num_of_buffers = drop_parameters->dropData->numItems;
940
941    /* Allocate memory for file and buffer structures */
942    file_set = (char **)XtMalloc(sizeof(char **) * num_of_buffers );
943    host_set = (char **)XtMalloc(sizeof(char **) * num_of_buffers);
944    buffer_set = (BufferInfo * )XtMalloc (sizeof (BufferInfo) * num_of_buffers);
945
946
947    _DtSetDroppedBufferInfo(file_set, buffer_set, host_set, drop_parameters);
948
949
950
951
952   /*****************************************************/
953   /* If buffers were dropped on the window, determine  */
954   /* which MODE (AS PLACED, GRID, TREE VIEW) and call  */
955   /* the appropriate routines to handle the creation   */
956   /* of the buffers into files. Assuming dropping      */
957   /* on non-trash windows.                             */
958   /*****************************************************/
959
960   if (drop_window)
961   {
962
963     /* Single directory view */
964     if ((file_mgr_data->show_type == SINGLE_DIRECTORY ) &&
965         (file_mgr_data->view != BY_ATTRIBUTES))
966
967     {
968
969       DPRINTF (("ProcessDropOnBufferFolder: Dropping buffers on single directory view: %s\n", file_mgr_data->current_directory));
970
971       G_dropx = drop_parameters->x;
972       G_dropy = drop_parameters->y;
973
974       /* Reposition Icons if in in "AS PLACED" Mode */
975       if (file_mgr_data -> positionEnabled == RANDOM_ON)
976       {
977 /*
978         RepositionIcons (file_mgr_data,
979                          file_set,
980                          num_of_buffers,
981                          drop_parameters->x, drop_parameters->y,
982                          True);
983 */
984       }
985
986       /* Call MakeFileFromBuffer */
987       MakeFilesFromBuffers(file_mgr_data, file_mgr_data->current_directory,
988                            file_mgr_data->host, file_set,
989                            host_set, buffer_set, num_of_buffers,
990                            NULL, NULL);
991
992     }
993     else
994     {
995       DPRINTF (("ProcessDropOnBufferFolder: Dropping buffers in Tree View\n"));
996
997       MakeFilesFromBuffers(file_mgr_data, file_mgr_data->current_directory,
998                            file_mgr_data->host, file_set,
999                            host_set, buffer_set, num_of_buffers,
1000                            NULL, NULL);
1001
1002       /* Do Tree View Stuff      */
1003       {
1004          DirectorySet * directory_data;
1005          char * directory_name;
1006          FileViewData * file_view_data;
1007          int j;
1008
1009          DeselectAllFiles (file_mgr_data);
1010
1011          directory_data = file_mgr_data->directory_set[0];
1012          for (i = 0; i < num_of_buffers; i++)
1013          {
1014             directory_name = DName (file_set[i]);
1015             for (j = 0; j < directory_data->file_count; j++)
1016             {
1017                file_view_data = directory_data->file_view_data[j];
1018                if ( (file_view_data->filtered != True) &&
1019                      (strcmp(directory_name,
1020                      file_view_data->file_data->file_name) == 0) )
1021                {
1022                   SelectFile (file_mgr_data, file_view_data);
1023                   break;
1024                }
1025             }
1026          }
1027          PositionFileView(file_view_data, file_mgr_data);
1028       }
1029    } /* endif for Tree View */
1030
1031   } /* endif drop buffers on window */
1032   else
1033   {
1034     /* Buffers were dropped on a Folder icon */
1035     /* Call MakeFileFromBuffer */
1036
1037
1038     DPRINTF(("ProcessBufferDropOnFolder...Buffers dropped on Folder icon %s\n",
1039              file_view_data ->file_data -> file_name));
1040
1041     if (file_mgr_data->show_type != SINGLE_DIRECTORY &&
1042         file_mgr_data->tree_root == file_view_data)
1043     {
1044         /* dropped on the top level folder in the tree view */
1045         sprintf (directory,"%s",file_mgr_data->current_directory);
1046     }
1047     else
1048         sprintf (directory,"%s/%s",file_mgr_data->current_directory,
1049                  file_view_data->file_data->file_name);
1050     DtEliminateDots(directory);
1051
1052     DPRINTF (("Copying buffer to %s\n", directory));
1053     MakeFilesFromBuffers(file_mgr_data, directory,
1054                          file_mgr_data->host, file_set,
1055                          host_set, buffer_set, num_of_buffers,
1056                          NULL, NULL);
1057
1058   }
1059
1060
1061   /***********************************/
1062   /* free file_set + buffer_set      */
1063   /***********************************/
1064   _DtFreeDroppedBufferInfo (file_set, buffer_set, host_set, num_of_buffers);
1065
1066
1067 }
1068
1069
1070 /************************************************************************
1071  *
1072  *  InvalidTrashDragDrop
1073  *
1074  ************************************************************************/
1075
1076 Boolean
1077 InvalidTrashDragDrop (
1078      int drag_op,
1079      int trash_context,
1080      Widget w)
1081 {
1082    Boolean rc = False;
1083
1084    if ( (drag_op == XmDROP_COPY) ||
1085         (drag_op == XmDROP_LINK) )
1086    {
1087       char *tmpStr, *title, *msg;
1088
1089       tmpStr = GETMESSAGE(18, 22, "Drag Error");
1090       title = XtNewString(tmpStr);
1091
1092       switch(trash_context)
1093       {
1094          case TO_TRASH:
1095          case WITHIN_TRASH:
1096             tmpStr = (GETMESSAGE(18,36, "You can't copy or link a file or folder out of the Trash Can.\nMove the object out of the Trash and put it into the File Manager.\nYou can then copy or link it from there."));
1097             break;
1098          case FROM_TRASH:
1099             tmpStr = (GETMESSAGE(18,37, "You can't copy or link a file or folder out of the Trash Can.\nMove the object out of the Trash and put it into the File Manager.\nYou can then copy or link it from there."));
1100             break;
1101          default:
1102             tmpStr = NULL;
1103             break;
1104       }
1105
1106       if (tmpStr)
1107       {
1108          msg = XtNewString(tmpStr);
1109          _DtMessage (w, title, msg, NULL, HelpRequestCB);
1110          XtFree(msg);
1111       }
1112
1113       XtFree(title);
1114
1115       rc = True;
1116    }
1117
1118    return(rc);
1119 }
1120
1121
1122 /************************************************************************
1123  *
1124  *  ProcessAction
1125  *
1126  ************************************************************************/
1127
1128 void
1129 ProcessAction (
1130      char *action,
1131      FileViewData *file_view_data,
1132      DtDndDropCallbackStruct *drop_parameters,
1133      char *cur_host,
1134      char *cur_dir,
1135      char *restricted_dir,
1136      Widget w)
1137
1138 {
1139    FileViewData *first_arg = NULL;
1140    DtActionArg * action_args = NULL;
1141    int arg_count = 0;
1142    char * pwd_host = NULL;
1143    char * pwd_dir = NULL;
1144    DirectorySet *directory_set;
1145    FileMgrData *file_mgr_data;
1146
1147    /* We don't want to execute the default action if in trash ...  */
1148    directory_set = (DirectorySet *) file_view_data->directory_set;
1149    file_mgr_data = (FileMgrData *) directory_set->file_mgr_data;
1150    if( trashFileMgrData != NULL
1151        && file_mgr_data == trashFileMgrData)
1152    {
1153       char *tmpStr, *title, *msg;
1154
1155       /* we don't want to execute the default action if in trash ...  */
1156       tmpStr = GETMESSAGE(27, 3, "Trash Can Error");
1157       title = XtNewString(tmpStr);
1158       tmpStr = GETMESSAGE(27, 105, "Default action of a trash object will not be executed.\n\nTo execute the default action of this object\n use 'Put Back' to return it to the File Manager\nthen execute it there.");
1159       msg = XtNewString(tmpStr);
1160
1161       _DtMessage(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
1162                  title, msg, NULL, HelpRequestCB);
1163       XtFree(title);
1164       XtFree(msg);
1165       return;
1166    }
1167
1168    /* Build action arguments:
1169     *   First, test for redundant action information --
1170     *   file_view_data contains information for the object that the user
1171     *       a) dropped files on
1172     *       b) activated a popup menu over (note that the Actions piece
1173     *          of both the Selected and popup menus is only active when
1174     *          a single file is selected; therefore, this function doesn't
1175     *          deal with cases where multiple files are selected and a
1176     *          popup menu is activated
1177     *       c) doubled-clicked
1178     *
1179     *   If file_view_data contains information for the action that we
1180     *   are processing, then this information is not included as an
1181     *   argument to DtActionInvoke; otherwise, the information is
1182     *   included as the first argument to DtActionInvoke.
1183     */
1184    if ( !DtDtsDataTypeIsAction(file_view_data->file_data->logical_type) ||
1185         (strcmp(action, file_view_data->file_data->logical_type) != 0) ||
1186         (strcmp(action, file_view_data->file_data->file_name)    != 0) )
1187       first_arg = file_view_data;
1188
1189    if (drop_parameters)
1190    {
1191       if (drop_parameters->dropData->protocol == DtDND_FILENAME_TRANSFER)
1192          _DtBuildActionArgsWithDroppedFiles(first_arg, drop_parameters,
1193                                             &action_args, &arg_count);
1194       else
1195          _DtBuildActionArgsWithDroppedBuffers(first_arg, drop_parameters,
1196                                               &action_args, &arg_count);
1197    }
1198    else
1199    {
1200       if (first_arg)
1201          _DtBuildActionArgsWithSelectedFiles(&first_arg, 1,
1202                                              &action_args, &arg_count);
1203    }
1204
1205
1206    /* Retrieve context dir for action -- in the case of toolboxes, the
1207       root toolbox */
1208    SetPWD(cur_host, cur_dir, &pwd_host, &pwd_dir, restricted_dir);
1209
1210
1211    /* Turn on hour glass */
1212    _DtTurnOnHourGlass(w);
1213
1214
1215    /* Invoke action */
1216    DtActionInvoke(w, action, action_args, arg_count,
1217                   NULL, NULL, pwd_dir, True, NULL, NULL);
1218
1219
1220    /* Add timer event to turn off hour glass */
1221    XtAppAddTimeOut(XtWidgetToApplicationContext(w), 1500,
1222                    (XtTimerCallbackProc) TimerEvent, (XtPointer) w);
1223
1224
1225    XtFree(pwd_host);
1226    XtFree(pwd_dir);
1227    _DtFreeActionArgs(action_args, arg_count);
1228 }
1229
1230
1231 /************************************************************************
1232  *
1233  *  TimerEvent
1234  *      This function is called when dtfile does an _DtActionInvoke. All
1235  *      it does is turn off the Hourglass cursor.
1236  *
1237  ************************************************************************/
1238
1239 static void
1240 TimerEvent(
1241         Widget widget,
1242         XtIntervalId *id )
1243 {
1244    _DtTurnOffHourGlass (widget);
1245 }
1246
1247 /************************************************************************
1248  *
1249  * This Handle's the FILESYSTEM_MOVE, FILESYSTEM_COPY, or FILESYSTEM_LINK
1250  * ToolTalk messages.  The operation type is passed in via opType. It is
1251  * either MOVE_FILE, COPY_FILE, or LINK_FILE.  Arg 0 of the ToolTalk message
1252  * contains the folder the operation is taking place TO and arg 1 contains
1253  * the files that the operation  is happening to.
1254  *
1255  ************************************************************************/
1256
1257 void
1258 MoveCopyLinkHandler(
1259                     Tt_message ttMsg,
1260                     int opType)
1261 {
1262    struct stat fileInfo;
1263    char title[256];
1264    int numArgs, i;
1265    char *ptr, *toName, *fileNames = NULL, *type = NULL, *fileList;
1266    char *files = NULL;
1267    char ** file_set = NULL;
1268    char ** host_set = NULL;
1269    unsigned int modifiers = 0;
1270    int file_count = 0;
1271    int file_set_size = 0;
1272    int errorCount = 0;
1273
1274    toName = tt_message_file( ttMsg );
1275    fileNames = fileList = tt_message_arg_val( ttMsg, 1 );
1276
1277    if( tt_is_err( tt_ptr_error( toName ) ) )
1278    { /* No file name */
1279       tt_message_reply( ttMsg );
1280       tttk_message_destroy( ttMsg );
1281       return;
1282    }
1283
1284    /* let's loop through the fileName passed to get the files which the
1285     * operation is to happen on.  The file's are separated by spaces.  What
1286     * happens if a file has a space in it: We parse on the spaces and if the
1287     * next char after a space is a '/' then we assume that is the end of the
1288     * file name.  What this implies is that this won't work for files with
1289     * spaces at the end of the name
1290     */
1291    while(1)
1292    {
1293       /* build the arrary of char pointer's */
1294       if (file_count == file_set_size)
1295       {
1296          file_set_size += 10;
1297          file_set =
1298            (char **) XtRealloc ((char *)file_set,
1299                                 sizeof (char **) * file_set_size);
1300       }
1301
1302       /* find the next space */
1303       ptr = DtStrchr(fileList, ' ');
1304
1305       /* if ptr is NULL, we have our last file name (no spaces found) */
1306       if(ptr == NULL)
1307       {
1308          file_set[file_count] = XtNewString(fileList);
1309          file_count++;
1310          break;
1311       }
1312       else
1313       {
1314          /* Let's check if the next char is a '/'. If it is then we know it's
1315           * the next file name, else the space found is part of a filename.
1316           */
1317          if(ptr[1] == '/')
1318          {
1319             *ptr = '\0';
1320             file_set[file_count] = XtNewString(fileList);
1321             file_count++;
1322          }
1323          fileList = ptr+1;
1324       }
1325    }
1326
1327
1328   /* go clean up all the '.' and '..' */
1329    for(i = 0; i < file_count; i++)
1330       DtEliminateDots( file_set[i] );
1331    DtEliminateDots( toName );
1332
1333   /* Set up the modifier key's */
1334    if( opType == MOVE_FILE)
1335       modifiers = 0;
1336    else if ( opType == COPY_FILE)
1337       modifiers = ControlMask;
1338    else
1339       modifiers = ShiftMask;
1340
1341
1342    /*
1343     * Let's check make sure the Folder the operation is happening to exists.
1344     */
1345    if( stat( toName, &fileInfo ) != 0
1346        && lstat( toName, &fileInfo ) != 0 )
1347    { /* to directory does not exist */
1348       char *dialogTitle;
1349
1350       if(opType == MOVE_FILE)
1351       {
1352          dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1353          sprintf(title, GETMESSAGE(33, 6, "The location you are trying to Move to:\n\n   %s\n\ndoes not exist in the file system."), toName);
1354       }
1355       else if(opType == COPY_FILE)
1356       {
1357          dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1358          sprintf(title, GETMESSAGE(33, 7, "The location you are trying to Copy to:\n\n   %s\n\ndoes not exist in the file system."), toName);
1359       }
1360       else
1361       {
1362          dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1363          sprintf(title, GETMESSAGE(33, 8, "The location you are trying to Link to:\n\n   %s\n\ndoes not exist in the file system."), toName);
1364       }
1365       _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1366
1367       tt_free( toName );
1368       tt_message_reply( ttMsg );
1369       tttk_message_destroy( ttMsg );
1370       return;
1371    }
1372
1373
1374    /*
1375     * Let's check make sure the object the operation is happening to is a
1376     * Folder.
1377     */
1378    if ((fileInfo.st_mode & S_IFMT) != S_IFDIR)     /* target not directory */
1379    { /* File that the user is doing the operation to is not a directory */
1380       char *dialogTitle;
1381
1382       if(opType == MOVE_FILE)
1383       {
1384          dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1385          sprintf(title, GETMESSAGE(33, 9, "The location you are trying to Move to:\n\n   %s\n\nis not a folder."), toName);
1386       }
1387       else if(opType == COPY_FILE)
1388       {
1389          dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1390          sprintf(title, GETMESSAGE(33, 10, "The location you are trying to Copy to:\n\n   %s\n\nis not a folder."), toName);
1391       }
1392       else
1393       {
1394          dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1395          sprintf(title, GETMESSAGE(33, 11,"The location you are trying to Link to:\n\n   %s\n\nis not a folder."), toName);
1396       }
1397       _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1398
1399       tt_free( toName );
1400       tt_message_reply( ttMsg );
1401       tttk_message_destroy( ttMsg );
1402       return;
1403    }
1404
1405    /*
1406     *
1407     *
1408     */
1409    for(i = 0; i < file_count; i++)
1410    {
1411       if( stat( file_set[i], &fileInfo ) != 0
1412           && lstat( file_set[i], &fileInfo ) != 0 )
1413       { /* File does not exist */
1414          char *dialogTitle;
1415
1416          if(opType == MOVE_FILE)
1417          {
1418             dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1419             if(file_count == 1)
1420                sprintf(title, GETMESSAGE(33, 12, "The object you are trying to Move:\n\n   %s\n\ndoes not exist in the file system."), file_set[i]);
1421             else
1422                sprintf(title, GETMESSAGE(33, 13, "One of the objects you are trying to Move:\n\n   %s\n\ndoes not exist in the file system.\nNot Moving any of them."), file_set[i]);
1423          }
1424          else if(opType == COPY_FILE)
1425          {
1426             dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1427             if(file_count == 1)
1428                sprintf(title, GETMESSAGE(33, 14, "The object you are trying to Copy:\n\n   %s\n\ndoes not exist in the file system."), file_set[i]);
1429             else
1430                sprintf(title, GETMESSAGE(33, 15, "One of the objects you are trying to Copy:\n\n   %s\n\ndoes not exist in the file system.\nNot Copying any of them."), file_set[i]);
1431          }
1432          else
1433          {
1434             dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1435             if(file_count == 1)
1436                sprintf(title, GETMESSAGE(33, 16, "The object you are trying to Link:\n\n   %s\n\ndoes not exist in the file system."), file_set[i]);
1437             else
1438                sprintf(title, GETMESSAGE(33, 17, "One of the objects you are trying to Link:\n\n   %s\n\ndoes not exist in the file system.\nNot Linking any of them."), file_set[i]);
1439          }
1440          _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1441
1442          tt_free( toName );
1443          tt_message_reply( ttMsg );
1444          tttk_message_destroy( ttMsg );
1445          return;
1446       }
1447    }
1448
1449
1450    /* set all the hosts to the home host name since ToolTalk messages pass
1451     * the filenames in host relative paths (Is this correct?)
1452     */
1453    host_set = (char **)XtMalloc(sizeof(char *) * file_count);
1454    for(i = 0; i < file_count; i++)
1455       host_set[i] = home_host_name;
1456
1457    /* Go do the Move/Copy/Link... this function will do proper error checking */
1458    FileMoveCopy(NULL, NULL, toName, home_host_name,
1459                 host_set, file_set, file_count,
1460                 modifiers, NULL, NULL);
1461
1462    tt_free( toName );
1463    tt_message_reply( ttMsg );
1464    tttk_message_destroy( ttMsg );
1465    return;
1466 }
1467