Merge branch 'master' into cde-next
[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 libraries 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    int i, menu_offset;
126    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 = NULL;
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          if (file_view_data)
1028              PositionFileView(file_view_data, file_mgr_data);
1029       }
1030    } /* endif for Tree View */
1031
1032   } /* endif drop buffers on window */
1033   else
1034   {
1035     /* Buffers were dropped on a Folder icon */
1036     /* Call MakeFileFromBuffer */
1037
1038
1039     DPRINTF(("ProcessBufferDropOnFolder...Buffers dropped on Folder icon %s\n",
1040              file_view_data ->file_data -> file_name));
1041
1042     if (file_mgr_data->show_type != SINGLE_DIRECTORY &&
1043         file_mgr_data->tree_root == file_view_data)
1044     {
1045         /* dropped on the top level folder in the tree view */
1046         sprintf (directory,"%s",file_mgr_data->current_directory);
1047     }
1048     else
1049         sprintf (directory,"%s/%s",file_mgr_data->current_directory,
1050                  file_view_data->file_data->file_name);
1051     DtEliminateDots(directory);
1052
1053     DPRINTF (("Copying buffer to %s\n", directory));
1054     MakeFilesFromBuffers(file_mgr_data, directory,
1055                          file_mgr_data->host, file_set,
1056                          host_set, buffer_set, num_of_buffers,
1057                          NULL, NULL);
1058
1059   }
1060
1061
1062   /***********************************/
1063   /* free file_set + buffer_set      */
1064   /***********************************/
1065   _DtFreeDroppedBufferInfo (file_set, buffer_set, host_set, num_of_buffers);
1066
1067
1068 }
1069
1070
1071 /************************************************************************
1072  *
1073  *  InvalidTrashDragDrop
1074  *
1075  ************************************************************************/
1076
1077 Boolean
1078 InvalidTrashDragDrop (
1079      int drag_op,
1080      int trash_context,
1081      Widget w)
1082 {
1083    Boolean rc = False;
1084
1085    if ( (drag_op == XmDROP_COPY) ||
1086         (drag_op == XmDROP_LINK) )
1087    {
1088       char *tmpStr, *title, *msg;
1089
1090       tmpStr = GETMESSAGE(18, 22, "Drag Error");
1091       title = XtNewString(tmpStr);
1092
1093       switch(trash_context)
1094       {
1095          case TO_TRASH:
1096          case WITHIN_TRASH:
1097             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."));
1098             break;
1099          case FROM_TRASH:
1100             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."));
1101             break;
1102          default:
1103             tmpStr = NULL;
1104             break;
1105       }
1106
1107       if (tmpStr)
1108       {
1109          msg = XtNewString(tmpStr);
1110          _DtMessage (w, title, msg, NULL, HelpRequestCB);
1111          XtFree(msg);
1112       }
1113
1114       XtFree(title);
1115
1116       rc = True;
1117    }
1118
1119    return(rc);
1120 }
1121
1122
1123 /************************************************************************
1124  *
1125  *  ProcessAction
1126  *
1127  ************************************************************************/
1128
1129 void
1130 ProcessAction (
1131      char *action,
1132      FileViewData *file_view_data,
1133      DtDndDropCallbackStruct *drop_parameters,
1134      char *cur_host,
1135      char *cur_dir,
1136      char *restricted_dir,
1137      Widget w)
1138
1139 {
1140    FileViewData *first_arg = NULL;
1141    DtActionArg * action_args = NULL;
1142    int arg_count = 0;
1143    char * pwd_host = NULL;
1144    char * pwd_dir = NULL;
1145    DirectorySet *directory_set;
1146    FileMgrData *file_mgr_data;
1147
1148    /* We don't want to execute the default action if in trash ...  */
1149    directory_set = (DirectorySet *) file_view_data->directory_set;
1150    file_mgr_data = (FileMgrData *) directory_set->file_mgr_data;
1151    if( trashFileMgrData != NULL
1152        && file_mgr_data == trashFileMgrData)
1153    {
1154       char *tmpStr, *title, *msg;
1155
1156       /* we don't want to execute the default action if in trash ...  */
1157       tmpStr = GETMESSAGE(27, 3, "Trash Can Error");
1158       title = XtNewString(tmpStr);
1159       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.");
1160       msg = XtNewString(tmpStr);
1161
1162       _DtMessage(((FileMgrRec *)file_mgr_data->file_mgr_rec)->file_window,
1163                  title, msg, NULL, HelpRequestCB);
1164       XtFree(title);
1165       XtFree(msg);
1166       return;
1167    }
1168
1169    /* Build action arguments:
1170     *   First, test for redundant action information --
1171     *   file_view_data contains information for the object that the user
1172     *       a) dropped files on
1173     *       b) activated a popup menu over (note that the Actions piece
1174     *          of both the Selected and popup menus is only active when
1175     *          a single file is selected; therefore, this function doesn't
1176     *          deal with cases where multiple files are selected and a
1177     *          popup menu is activated
1178     *       c) doubled-clicked
1179     *
1180     *   If file_view_data contains information for the action that we
1181     *   are processing, then this information is not included as an
1182     *   argument to DtActionInvoke; otherwise, the information is
1183     *   included as the first argument to DtActionInvoke.
1184     */
1185    if ( !DtDtsDataTypeIsAction(file_view_data->file_data->logical_type) ||
1186         (strcmp(action, file_view_data->file_data->logical_type) != 0) ||
1187         (strcmp(action, file_view_data->file_data->file_name)    != 0) )
1188       first_arg = file_view_data;
1189
1190    if (drop_parameters)
1191    {
1192       if (drop_parameters->dropData->protocol == DtDND_FILENAME_TRANSFER)
1193          _DtBuildActionArgsWithDroppedFiles(first_arg, drop_parameters,
1194                                             &action_args, &arg_count);
1195       else
1196          _DtBuildActionArgsWithDroppedBuffers(first_arg, drop_parameters,
1197                                               &action_args, &arg_count);
1198    }
1199    else
1200    {
1201       if (first_arg)
1202          _DtBuildActionArgsWithSelectedFiles(&first_arg, 1,
1203                                              &action_args, &arg_count);
1204    }
1205
1206
1207    /* Retrieve context dir for action -- in the case of toolboxes, the
1208       root toolbox */
1209    SetPWD(cur_host, cur_dir, &pwd_host, &pwd_dir, restricted_dir);
1210
1211
1212    /* Turn on hour glass */
1213    _DtTurnOnHourGlass(w);
1214
1215
1216    /* Invoke action */
1217    DtActionInvoke(w, action, action_args, arg_count,
1218                   NULL, NULL, pwd_dir, True, NULL, NULL);
1219
1220
1221    /* Add timer event to turn off hour glass */
1222    XtAppAddTimeOut(XtWidgetToApplicationContext(w), 1500,
1223                    (XtTimerCallbackProc) TimerEvent, (XtPointer) w);
1224
1225
1226    XtFree(pwd_host);
1227    XtFree(pwd_dir);
1228    _DtFreeActionArgs(action_args, arg_count);
1229 }
1230
1231
1232 /************************************************************************
1233  *
1234  *  TimerEvent
1235  *      This function is called when dtfile does an _DtActionInvoke. All
1236  *      it does is turn off the Hourglass cursor.
1237  *
1238  ************************************************************************/
1239
1240 static void
1241 TimerEvent(
1242         Widget widget,
1243         XtIntervalId *id )
1244 {
1245    _DtTurnOffHourGlass (widget);
1246 }
1247
1248 /************************************************************************
1249  *
1250  * This Handle's the FILESYSTEM_MOVE, FILESYSTEM_COPY, or FILESYSTEM_LINK
1251  * ToolTalk messages.  The operation type is passed in via opType. It is
1252  * either MOVE_FILE, COPY_FILE, or LINK_FILE.  Arg 0 of the ToolTalk message
1253  * contains the folder the operation is taking place TO and arg 1 contains
1254  * the files that the operation  is happening to.
1255  *
1256  ************************************************************************/
1257
1258 void
1259 MoveCopyLinkHandler(
1260                     Tt_message ttMsg,
1261                     int opType)
1262 {
1263    struct stat fileInfo;
1264    char title[256];
1265    int numArgs, i;
1266    char *ptr, *toName, *fileNames = NULL, *type = NULL, *fileList;
1267    char *files = NULL;
1268    char ** file_set = NULL;
1269    char ** host_set = NULL;
1270    unsigned int modifiers = 0;
1271    int file_count = 0;
1272    int file_set_size = 0;
1273    int errorCount = 0;
1274
1275    toName = tt_message_file( ttMsg );
1276    fileNames = fileList = tt_message_arg_val( ttMsg, 1 );
1277
1278    if( tt_is_err( tt_ptr_error( toName ) ) )
1279    { /* No file name */
1280       tt_message_reply( ttMsg );
1281       tttk_message_destroy( ttMsg );
1282       return;
1283    }
1284
1285    /* let's loop through the fileName passed to get the files which the
1286     * operation is to happen on.  The file's are separated by spaces.  What
1287     * happens if a file has a space in it: We parse on the spaces and if the
1288     * next char after a space is a '/' then we assume that is the end of the
1289     * file name.  What this implies is that this won't work for files with
1290     * spaces at the end of the name
1291     */
1292    while(1)
1293    {
1294       /* build the arrary of char pointer's */
1295       if (file_count == file_set_size)
1296       {
1297          file_set_size += 10;
1298          file_set =
1299            (char **) XtRealloc ((char *)file_set,
1300                                 sizeof (char **) * file_set_size);
1301       }
1302
1303       /* find the next space */
1304       ptr = DtStrchr(fileList, ' ');
1305
1306       /* if ptr is NULL, we have our last file name (no spaces found) */
1307       if(ptr == NULL)
1308       {
1309          file_set[file_count] = XtNewString(fileList);
1310          file_count++;
1311          break;
1312       }
1313       else
1314       {
1315          /* Let's check if the next char is a '/'. If it is then we know it's
1316           * the next file name, else the space found is part of a filename.
1317           */
1318          if(ptr[1] == '/')
1319          {
1320             *ptr = '\0';
1321             file_set[file_count] = XtNewString(fileList);
1322             file_count++;
1323          }
1324          fileList = ptr+1;
1325       }
1326    }
1327
1328
1329   /* go clean up all the '.' and '..' */
1330    for(i = 0; i < file_count; i++)
1331       DtEliminateDots( file_set[i] );
1332    DtEliminateDots( toName );
1333
1334   /* Set up the modifier key's */
1335    if( opType == MOVE_FILE)
1336       modifiers = 0;
1337    else if ( opType == COPY_FILE)
1338       modifiers = ControlMask;
1339    else
1340       modifiers = ShiftMask;
1341
1342
1343    /*
1344     * Let's check make sure the Folder the operation is happening to exists.
1345     */
1346    if( stat( toName, &fileInfo ) != 0
1347        && lstat( toName, &fileInfo ) != 0 )
1348    { /* to directory does not exist */
1349       char *dialogTitle;
1350
1351       if(opType == MOVE_FILE)
1352       {
1353          dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1354          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);
1355       }
1356       else if(opType == COPY_FILE)
1357       {
1358          dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1359          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);
1360       }
1361       else
1362       {
1363          dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1364          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);
1365       }
1366       _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1367
1368       tt_free( toName );
1369       tt_message_reply( ttMsg );
1370       tttk_message_destroy( ttMsg );
1371       return;
1372    }
1373
1374
1375    /*
1376     * Let's check make sure the object the operation is happening to is a
1377     * Folder.
1378     */
1379    if ((fileInfo.st_mode & S_IFMT) != S_IFDIR)     /* target not directory */
1380    { /* File that the user is doing the operation to is not a directory */
1381       char *dialogTitle;
1382
1383       if(opType == MOVE_FILE)
1384       {
1385          dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1386          sprintf(title, GETMESSAGE(33, 9, "The location you are trying to Move to:\n\n   %s\n\nis not a folder."), toName);
1387       }
1388       else if(opType == COPY_FILE)
1389       {
1390          dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1391          sprintf(title, GETMESSAGE(33, 10, "The location you are trying to Copy to:\n\n   %s\n\nis not a folder."), toName);
1392       }
1393       else
1394       {
1395          dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1396          sprintf(title, GETMESSAGE(33, 11,"The location you are trying to Link to:\n\n   %s\n\nis not a folder."), toName);
1397       }
1398       _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1399
1400       tt_free( toName );
1401       tt_message_reply( ttMsg );
1402       tttk_message_destroy( ttMsg );
1403       return;
1404    }
1405
1406    /*
1407     *
1408     *
1409     */
1410    for(i = 0; i < file_count; i++)
1411    {
1412       if( stat( file_set[i], &fileInfo ) != 0
1413           && lstat( file_set[i], &fileInfo ) != 0 )
1414       { /* File does not exist */
1415          char *dialogTitle;
1416
1417          if(opType == MOVE_FILE)
1418          {
1419             dialogTitle = XtNewString(GETMESSAGE(33, 3, "Move Object Error"));
1420             if(file_count == 1)
1421                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]);
1422             else
1423                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]);
1424          }
1425          else if(opType == COPY_FILE)
1426          {
1427             dialogTitle = XtNewString(GETMESSAGE(33, 4, "Copy Object Error"));
1428             if(file_count == 1)
1429                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]);
1430             else
1431                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]);
1432          }
1433          else
1434          {
1435             dialogTitle = XtNewString(GETMESSAGE(33, 5, "Link Object Error"));
1436             if(file_count == 1)
1437                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]);
1438             else
1439                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]);
1440          }
1441          _DtMessage( toplevel, dialogTitle, title, NULL, HelpRequestCB );
1442
1443          tt_free( toName );
1444          tt_message_reply( ttMsg );
1445          tttk_message_destroy( ttMsg );
1446          return;
1447       }
1448    }
1449
1450
1451    /* set all the hosts to the home host name since ToolTalk messages pass
1452     * the filenames in host relative paths (Is this correct?)
1453     */
1454    host_set = (char **)XtMalloc(sizeof(char *) * file_count);
1455    for(i = 0; i < file_count; i++)
1456       host_set[i] = home_host_name;
1457
1458    /* Go do the Move/Copy/Link... this function will do proper error checking */
1459    FileMoveCopy(NULL, NULL, toName, home_host_name,
1460                 host_set, file_set, file_count,
1461                 modifiers, NULL, NULL);
1462
1463    tt_free( toName );
1464    tt_message_reply( ttMsg );
1465    tttk_message_destroy( ttMsg );
1466    return;
1467 }
1468