dthelp: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / dtfile / FileOp.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 /* $TOG: FileOp.c /main/14 1999/12/09 13:06:21 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           FileOp.c
28  *
29  *   COMPONENT_NAME: Desktop
30  *
31  *   DESCRIPTION:    File processing functions.
32  *
33  *   FUNCTIONS: ChangeIconName
34  *              ChangeIconNameDT
35  *              ChangeIconNameProcess
36  *              ChangeIconPipeCB
37  *              CreateFileFromBuffer
38  *              DisplayDuplicateOpError
39  *              DisplayErrorMessage
40  *              FileMoveCopy
41  *              FileMoveCopyDesktop
42  *              FileMoveCopyProcess
43  *              FileMoveCopyProcessDesktop
44  *              FileOpError
45  *              FileOpPipeCB
46  *              GetTarget
47  *              MakeFile
48  *              MakeFilePipeCB
49  *              MakeFileProcess
50  *              MakeFilesFromBuffers
51  *              MakeFilesFromBuffersDT
52  *              PipeRead
53  *              PipeReadString
54  *              PipeWriteErrmsg
55  *              PipeWriteString
56  *              RemoveIconFromWorkspace
57  *              ChangeWorkspaceIconLink
58  *              SendModifyMsg
59  *              _ChangeIconName
60  *              _FileMoveCopy
61  *              appendErrorMessage
62  *              moveCopyLinkCancel
63  *              moveCopyLinkOK
64  *
65  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
66  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
67  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
68  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
69  *
70  ****************************************************************************
71  ************************************<+>*************************************/
72
73 #include <string.h>
74 #include <stdint.h>
75 #include <errno.h>
76 #include <sys/time.h>
77 #include <sys/types.h>
78 #include <sys/stat.h>
79 #include <sys/signal.h>
80 #include <time.h>
81 #include <utime.h>
82
83 #ifdef _AIX
84 #include <sys/select.h>
85 #endif
86
87 #if defined(_AIX)|| defined(hpux)
88 #include <sys/dir.h>
89 #else
90 #ifndef MAXNAMLEN
91 #define MAXNAMLEN 255
92 #endif
93 #endif
94
95 #include <Xm/XmP.h>
96 #include <Xm/Xm.h>
97 #include <Xm/MwmUtil.h>
98 #include <Xm/TextF.h>
99 #include <Xm/ScrollBar.h>
100 #include <X11/ShellP.h>
101 #include <X11/Shell.h>
102 #include <X11/Xutil.h>
103 #include <X11/Xatom.h>
104
105 #ifdef SHAPE
106 #include <X11/extensions/shape.h>
107 #endif
108
109 #include <Dt/Icon.h>
110 #include <Dt/IconP.h>
111 #include <Dt/IconFile.h>
112 #include <Dt/Action.h>
113 #include <Dt/Connect.h>
114 #include <Dt/Wsm.h>
115 #include <Dt/DtNlUtils.h>
116 #include <Dt/HourGlass.h>
117 #include <Dt/SharedProcs.h>
118
119 #include <Tt/tttk.h>
120
121 #include "Encaps.h"
122 #include "SharedProcs.h"
123 #include "FileMgr.h"
124 #include "Desktop.h"
125 #include "Main.h"
126 #include "Prefs.h"
127 #include "Common.h"
128 #include "Filter.h"
129 #include "Help.h"
130 #include "SharedMsgs.h"
131 #include "sharedFuncs.h"
132
133
134 /* Static Function declarations */
135
136 static Boolean CreateFileFromBuffer(
137                                     int    pipe_s2m,
138                                     char   *directory,
139                                     char   *fully_qualified_name,
140                                     void   *buffer,
141                                     int    size);
142 static String  appendErrorMessage(
143                                     String message,
144                                     String new,
145                                     String arg);
146 static void    DisplayErrorMessage(
147                  int pipe_s2m,
148                  char *errMsg,
149                  char *from,
150                  char *dir);
151 static Boolean    IsInParentDir(char *from,char *to);
152
153 /* the amount of time we wait for a file move/copy to complete */
154 /* @@@ should make this a resource */
155 #define FILE_MOVE_COPY_WAIT_TIME 2
156
157
158 /* types of messages sent through the pipe */
159 #define PIPEMSG_FILEOP_ERROR     1
160 #define PIPEMSG_EXIST_ERROR      2
161 #define PIPEMSG_OTHER_ERROR      3
162 #define PIPEMSG_CONFIRM          4
163 #define PIPEMSG_TARGET_TIME      5
164 #define PIPEMSG_FILE_MODIFIED    6
165 #define PIPEMSG_DONE             7
166 #define PIPEMSG_REPLACE_RENAME   8
167 #define PIPEMSG_REPLACE_RENAME_SAME 9
168 #define PIPEMSG_REPLACE_MERGE       10
169 #define PIPEMSG_MULTICOLLIDE        11
170 #define PIPEMSG_MULTICOLLIDE_SAME   12
171 #define PIPEMSG_MOVE_TO_SAME_DIR    13
172
173 /* the following messages are also defined & used in OverWrite.c */
174 #define PIPEMSG_CANCEL           101
175 #define PIPEMSG_PROCEED          102
176 #define PIPEMSG_MERGE            103
177 #define PIPEMSG_REPLACE_BUFFER   104
178 #define PIPEMSG_RENAME_BUFFER    105
179 #define PIPEMSG_MULTI_PROCEED    106
180
181 extern int G_dropx,G_dropy;
182
183 /* callback data for file move/copy/link */
184 typedef struct {
185    char *host;
186    char *directory;
187    char *app_man_dir;
188    BufferInfo bufferInfo;
189    int first_index;
190    Boolean time_sent;
191    Boolean operationStatus;
192    char *file;
193 } DirUpdate;
194
195 typedef struct
196 {
197    Boolean desktop;
198    FileMgrData *file_mgr_data;
199    FileMgrRec *file_mgr_rec;
200    FileViewData *file_view_data;
201    DesktopRec *desktopWindow;
202    int pipe_m2s;  /* pipe main to slave */
203    int pipe_s2m;  /* pipe slave to main */
204    int mode;
205    char *host;
206    char *directory;
207    int file_count;
208    DirUpdate *updates;
209    void (*finish_callback)();
210    XtPointer callback_data;
211    int child;
212 } FileOpCBData;
213
214
215 /* callback data for file rename */
216 typedef struct
217 {
218    Boolean desktop;
219    Widget w;
220    FileViewData *file_view_data;
221    DesktopRec *desktopWindow;
222    char *host_name;
223    char *directory_name;
224    char *old_name;
225    char *new_name;
226    int child;
227 } ChangeIconCBData;
228
229
230 /* callback data for create file/directory */
231 typedef struct
232 {
233    char *to_host;
234    char *to_dir;
235    char *to_file;
236    void (*finish_callback)();
237    XtPointer callback_data;
238    int child;
239 } MakeFileCBData;
240
241
242 static void
243 DisplayDuplicateOpError(FileOpCBData *cb_data,int index);
244
245
246
247 /*====================================================================
248  *
249  * Routine for sending data through a pipe
250  *
251  *==================================================================*/
252
253 /*--------------------------------------------------------------------
254  * PipeRead:
255  *    Read data from the pipe
256  *------------------------------------------------------------------*/
257
258 int
259 PipeRead(
260         int fd,
261         void *buf,
262         int len)
263 {
264    static int whined_fd = -1;
265    int n = 0;
266    int rc;
267
268    while (n < len)
269    {
270       rc = read(fd, (char *)buf + n, len - n);
271       if (rc > 0)
272         n += rc;
273       else if (rc < 0 && errno == EINTR)
274          ;  /* try again */
275       else
276       {
277          if (rc == 0)
278          {
279             if (whined_fd != fd)
280             {
281                 whined_fd = fd;
282                 fprintf(stderr,
283                   "PipeRead: broken pipe, ppid=%d pid=%d fd=%d\n",
284                   getppid(), getpid(), fd);
285             }
286          }
287          else
288          {
289             perror("dtfile: read failed in PipeRead");
290          }
291          n = -1;
292          break;
293       }
294    }
295
296    return n;
297 }
298
299
300 /*--------------------------------------------------------------------
301  * PipeWriteString:
302  *   write a string to the pipe
303  *------------------------------------------------------------------*/
304
305 int
306 PipeWriteString(
307         int fd,
308         char *s)
309 {
310    short len, sent = 0;
311    void (*oldPipe)();
312
313    oldPipe = (void (*)())signal(SIGPIPE, SIG_IGN);
314
315    if (s == NULL)
316       len = 0;
317    else
318       len = strlen(s);
319
320    if (write(fd, &len, sizeof(short)) < 0) {
321       return -1;
322    }
323
324    if (len > 0)
325       sent = write(fd, s, len);
326
327    signal(SIGPIPE, oldPipe);
328
329    return sent;
330 }
331
332
333 /*--------------------------------------------------------------------
334  * PipeReadString:
335  *   read a string from the pipe
336  *------------------------------------------------------------------*/
337
338 char *
339 PipeReadString(
340         int fd)
341 {
342    short len;
343    char *s;
344    int n;
345
346    /* get the length */
347    if (PipeRead(fd, &len, sizeof(short)) != sizeof(short))
348       return NULL;
349
350    if (len == 0)
351       return NULL;
352
353    /* get the string */
354    s = (char *)XtMalloc(len + 1);
355    if (PipeRead(fd, s, len) != len)
356    {
357       XtFree(s);
358       return NULL;
359    }
360
361    s[len] = '\0';
362    return s;
363 }
364
365
366 /*--------------------------------------------------------------------
367  * PipeWriteErrmsg:
368  *   write an error message to the pipe
369  *------------------------------------------------------------------*/
370
371 static int
372 PipeWriteErrmsg(
373         int fd,
374         int rc,
375         char *msg,
376         char *arg)
377 {
378    short pipe_msg = PIPEMSG_FILEOP_ERROR;
379
380    DPRINTF(("PipeWriteErrmsg: sending error %d \"%s\"\n", rc, msg));
381
382    write(fd, &pipe_msg, sizeof(short));
383    write(fd, &rc, sizeof(int));
384    PipeWriteString(fd, msg);
385    PipeWriteString(fd, arg);
386
387    return 0;
388 }
389
390
391 /*====================================================================
392  *
393  * FileMoveCopy
394  *     Run a background process to move/copy/link files dropped
395  *     on a dtfile window or icon.
396  *
397  *==================================================================*/
398
399 /*--------------------------------------------------------------------
400  * moveCopyLinkCancel:
401  *   Cancel-button callback for overwrite confirmation dialog
402  *------------------------------------------------------------------*/
403
404 int filop_confirm_fd = -1;  /* @@@ can't we pass this in client_data? */
405
406 static void
407 moveCopyLinkCancel(
408         Widget w,
409         XtPointer client_data,
410         XtPointer call_data )
411 {
412     const int rc = PIPEMSG_CANCEL;
413
414     /* close the dialog */
415     XtUnmanageChild((Widget)client_data);
416     XmUpdateDisplay((Widget)client_data);
417     XtDestroyWidget((Widget)client_data);
418
419     /* send return code through the pipe to the background proc */
420     write(filop_confirm_fd, &rc, sizeof(int));
421     filop_confirm_fd = -1;
422 }
423
424
425 /*--------------------------------------------------------------------
426  * moveCopyLinkOK:
427  *   Ok-button callback for overwrite confirmation dialog
428  *------------------------------------------------------------------*/
429
430 static void
431 moveCopyLinkOK(
432         Widget w,
433         XtPointer client_data,
434         XtPointer call_data )
435 {
436     const int rc = PIPEMSG_PROCEED;
437
438     /* close the dialog */
439     XtUnmanageChild((Widget)client_data);
440     XmUpdateDisplay((Widget)client_data);
441     XtDestroyWidget((Widget)client_data);
442
443     /* send affirmative return code through the pipe to the background proc */
444     write(filop_confirm_fd, &rc, sizeof(int));
445     filop_confirm_fd = -1;
446 }
447
448
449 /*--------------------------------------------------------------------
450  * FileOpError
451  *   Error handler for FileManip when called in the background process
452  *------------------------------------------------------------------*/
453
454 void
455 FileOpError(
456         Widget w,
457         char *message1,
458         char *message2 )
459 {
460   int pipe_fd = (int) (intptr_t) w;   /* @@@ Hack! @@@
461                              In the background process we call FileManip with
462                              the file descriptor for the pipe instead of a
463                              widget id.  We rely on the fact that FileManip
464                              never uses the widget as a widget, but only
465                              passes it to the error handler. */
466
467   /* write the error message to the pipe */
468   PipeWriteErrmsg(pipe_fd, -1, message1, message2);
469 }
470
471
472 /*--------------------------------------------------------------------
473  * SendModifyMsg:
474  *   Send a message through the pipe that informs the main process
475  *   that we are about to modify a directory or that a file has been
476  *   modifed.
477  *------------------------------------------------------------------*/
478
479 static void
480 SendModifyMsg(
481         int pipe_fd,
482         int mode,
483         Boolean first,
484         char *to,
485         DirUpdate *updates,
486         int i,
487         char *target_file)
488 {
489    short pipe_msg;
490    char *dir_path;
491    long modify_time;
492    struct stat stat_buf;
493    int j;
494
495    /* if first operation on target dir, send timestamp */
496    if (first)
497    {
498       if (stat(to, &stat_buf) == 0)
499       {
500          modify_time = stat_buf.st_mtime;
501          pipe_msg = PIPEMSG_TARGET_TIME;
502          write(pipe_fd, &pipe_msg, sizeof(short));
503          write(pipe_fd, &modify_time, sizeof(long));
504       }
505    }
506
507    /* if first operation on source dir, get timestamp of source dir */
508    modify_time = 0;
509    j = updates[i].first_index;
510    if (mode == MOVE_FILE && !updates[j].time_sent)
511    {
512       Tt_status tt_status;
513
514       dir_path = ResolveLocalPathName(updates[i].host,
515                                       updates[i].directory,
516                                       NULL,
517                                       home_host_name,
518                                       &tt_status);
519
520       if (stat(dir_path, &stat_buf) == 0)
521          modify_time = stat_buf.st_mtime;
522       XtFree(dir_path);
523       updates[j].time_sent = True;
524    }
525
526    /* send the modify message */
527    pipe_msg = PIPEMSG_FILE_MODIFIED;
528    write(pipe_fd, &pipe_msg, sizeof(short));
529    write(pipe_fd, &i, sizeof(int));
530    write(pipe_fd, &modify_time, sizeof(long));
531    PipeWriteString(pipe_fd, target_file);
532 }
533
534 /*--------------------------------------------------------------------
535  * FileMoveCopyProcess:
536  *     Main routine of the background process
537  *
538  *     This routine has two basic modes of operation:
539  *        It is given a list of source files and a target directory,
540  *           and performs an operation on the source files. This mode
541  *           is used for drag & drop operations where a user can
542  *           select multiple source files and then drop them on a
543  *           target directory to either move, copy, or copy-as-link
544  *           the source files to the target directory. The source
545  *           and target directories must be different.
546  *        It is given a single source file and a target file. The
547  *           target can be either a directory or a file. This mode
548  *           is used for menu-intiated move, copy, or copy-as-link
549  *           operations. The source and target directories can be
550  *           the same.
551  *     The source file(s) are given in updates; the destination is
552  *           in host, dirctory, to_file. If to_file is NULL, the
553  *           first mode (drag & drop) is assumed, otherwise assume
554  *           menu-initiated mode.
555  *
556  *------------------------------------------------------------------*/
557
558 static int
559 FileMoveCopyProcess(
560         int pipe_s2m,
561         int pipe_m2s,
562         char *to_file,
563         char *directory,
564         char *host,
565         DirUpdate *updates,
566         int file_count,
567         int mode,
568         DesktopRec *desktopWindow)
569 {
570    char * target_dir, * from, * to;
571    int i, j, rc, result;
572    Boolean return_val = False;
573    Boolean isContainer;
574    long current;
575    char *tmpStr, *target_file;
576    struct stat stat_buf, from_stat_buf;
577    short pipe_msg;
578    int sameCount = 0;
579    int errorCount = 0;
580    int *sameIndex = NULL, *sameConfirmType = NULL;
581    Boolean first_op = True;
582    Tt_status tt_status;
583    char * renamed_file;
584    long modify_time;
585    String permissionErrors = NULL;
586    Boolean targetChecked = FALSE;
587    Boolean targetError   = FALSE;
588    Boolean CopyError=FALSE,MoveError1=FALSE,MoveError2=FALSE;
589    char  *CopyString=NULL,*MoveString1=NULL,*MoveString2=NULL;
590    Boolean Same;
591
592    /*  Get the fully qualified destination path.  */
593    target_dir = (char *)ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
594    if( TT_OK != tt_status )
595    {
596      char msg1[2*MAX_PATH];
597 #ifdef sun
598      sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
599               directory, host, host);
600 #else
601      sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
602               directory, host, host);
603 #endif
604      PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
605      pipe_msg = PIPEMSG_FILEOP_ERROR;
606      rc = -1;
607      write(pipe_s2m, &pipe_msg, sizeof(short));
608      write(pipe_s2m, &rc, sizeof(int));
609      return rc;
610    }
611
612    DtEliminateDots(target_dir);
613
614    for (i = 0; i < file_count; i++)
615    {
616        Same = False;
617
618       /* get full name of the source file, if just */
619       /* dealing with regular files                */
620       if (mode != MAKE_BUFFER)
621       {
622         from = ResolveLocalPathName(updates[i].host,
623                                     updates[i].directory,
624                                     updates[i].file,
625                                     home_host_name,
626                                     &tt_status);
627         if (from == NULL)
628         {
629           char msg1[2*MAX_PATH];
630
631 #ifdef sun
632           sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
633                    updates[i].directory, updates[i].host, updates[i].host);
634 #else
635           sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
636                    updates[i].directory, updates[i].host, updates[i].host);
637 #endif
638           PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
639           continue;
640         }
641
642         /* do some extra error checking if a target filename is specified */
643         /*   this is meant for the case of a menu-initiated operation     */
644         if (to_file != NULL)
645         {
646           /* Verify that the target directory already exists */
647           if ( (stat(target_dir, &stat_buf) != 0) ||
648                (! S_ISDIR(stat_buf.st_mode)     ) )
649           {
650             char *msg;
651
652             msg = XtNewString(
653               GETMESSAGE(11,41,"The folder\n%s\ndoes not exist."));
654             PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
655             errorCount++;
656             XtFree(msg);
657             XtFree(from);
658             continue;
659           }
660         }
661
662         /* check for a drop of a directory onto itself */
663         if (updates[i].app_man_dir)
664         {
665           char *temp_dir = XtNewString(target_dir);
666
667           temp_dir = _DtResolveAppManPath(temp_dir, updates[i].app_man_dir);
668           if (mode == MOVE_FILE && strcmp(temp_dir, from) == 0)
669           {
670             char *msg;
671
672             msg = XtNewString(
673               GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
674             PipeWriteErrmsg( pipe_s2m, -1, msg, temp_dir );
675             errorCount++;
676             XtFree(msg);
677             XtFree(from);
678             XtFree(temp_dir);
679             continue;
680           }
681           XtFree(temp_dir);
682         }
683         else if (mode == MOVE_FILE && strcmp(target_dir, from) == 0)
684         {
685           char *msg;
686
687           msg = XtNewString(
688             GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"));
689           PipeWriteErrmsg( pipe_s2m, -1, msg, target_dir );
690           errorCount++;
691           XtFree(msg);
692           XtFree(from);
693           continue;
694         }
695         else if (mode == MOVE_FILE && stat(from, &stat_buf) == 0 &&
696                    S_ISDIR(stat_buf.st_mode) && DirectoryBusy(from))
697         {
698           char *msg;
699
700           msg = XtNewString( GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
701
702           PipeWriteErrmsg( pipe_s2m, -1, msg, from );
703           errorCount++;
704           XtFree(msg);
705           XtFree(from);
706           continue;
707         }
708       } /* end if */
709
710      /* for copy operations, check for read permission on the source file */
711      /* the error message is appended to a list and dealt with later      */
712      /* the current file is not processed                                 */
713      if (mode == COPY_FILE)
714         if (CheckAccess(from,R_OK) == -1)
715         {
716            struct stat sbuf;
717            char *tmpStr;
718
719      /* 'errno' is not giving correct results like 'ENOENT' in order to
720          use it here, may be because of the other system calls in 
721          CheckAccess() */
722            
723            if (stat(from, &sbuf) < 0)
724               tmpStr = (GETMESSAGE(28,13,"Object:\n\n   %s\n\n does not exist in the file system"));
725             else
726               tmpStr = GetSharedMessage(CANT_READ_ERROR);
727
728            permissionErrors = appendErrorMessage(permissionErrors, tmpStr, from);
729            errorCount++;
730            continue;
731         }
732
733       if (to_file == NULL)
734       {
735          if (strcmp(target_dir, "/") == 0)
736          {
737            target_file = (char *)XtMalloc(strlen(target_dir) +
738                                           strlen(updates[i].file) + 1);
739            sprintf(target_file, "%s%s", target_dir, updates[i].file);
740          }
741          else
742          {
743            target_file = (char *)XtMalloc(strlen(target_dir) +
744                                           strlen(updates[i].file) + 2);
745            sprintf(target_file, "%s/%s", target_dir, updates[i].file);
746          }
747       }
748       else
749       {
750          if (strcmp(target_dir, "/") == 0)
751          {
752            target_file = (char *)XtMalloc(strlen(target_dir) +
753                                           strlen(to_file) + 1);
754            sprintf(target_file, "%s%s", target_dir, to_file);
755          }
756          else
757          {
758            target_file = (char *)XtMalloc(strlen(target_dir) +
759                                           strlen(to_file) + 2);
760            sprintf(target_file, "%s/%s", target_dir, to_file);
761          }
762       }
763       if (updates[i].app_man_dir)
764          target_file = _DtResolveAppManPath(target_file,
765                                             updates[i].app_man_dir);
766        /* check if source and target files are the same.
767         * if they are the same, set a flag noting that they are.  If the
768         * the operation is a move, it doesn't make any sense to move it, so
769         * send back a MOVE_TO_SAME_DIR msg.
770         */
771
772       if ((mode != MAKE_BUFFER) && (strcmp(target_file, from) == 0))
773       {
774           if (mode == MOVE_FILE && stat(target_file, &stat_buf) == 0)
775           {
776               if(S_ISDIR(stat_buf.st_mode))
777             {
778                 pipe_msg = PIPEMSG_MOVE_TO_SAME_DIR;
779                 write(pipe_s2m, &pipe_msg, sizeof(short));
780                 write(pipe_s2m, &i, sizeof(int));
781                 errorCount++;
782
783                 continue;
784             }
785           }
786           Same = True;
787       }
788
789       /* for copy operations, check for write permission on the target    */
790       /*    directory                                                     */
791       /* for move operations, check for write permission on the source and */
792       /*    target directories                                             */
793       /* the error message is appended to a list and dealt with later      */
794       /* the current file is not processed                                 */
795       if (mode == COPY_FILE)
796       {
797          if (CheckAccess(target_dir,W_OK) == -1)
798          {
799             CopyError = TRUE;
800             errorCount++;
801             if(CopyString == NULL)
802               CopyString = XtNewString(from);
803             else
804             {
805               CopyString = (char *) XtRealloc(CopyString,strlen(CopyString)+
806                                     strlen(from)+2);
807               strcat(CopyString,"\n");
808               strcat(CopyString,from);
809             }
810             continue;
811          }
812       }
813       else if (mode == MOVE_FILE)
814       {
815          Boolean error = FALSE;
816          if (targetChecked || CheckAccess(target_dir,W_OK) == -1)
817          {
818             MoveError1 = TRUE;
819             if(MoveString1 == NULL)
820                MoveString1 = XtNewString(from);
821             else
822             {
823                MoveString1=(char *)XtRealloc(MoveString1,strlen(MoveString1)+
824                                     strlen(from)+2);
825                strcat(MoveString1,"\n");
826                strcat(MoveString1,from);
827             }
828             error = targetError = TRUE;
829             targetChecked = TRUE;
830          }
831          if (CheckAccess(_DtPName(from),W_OK) == -1)
832          {
833             MoveError2 = TRUE;
834             if(MoveString2 == NULL)
835               MoveString2 = XtNewString(from);
836             else
837             {
838               MoveString2 = (char *)XtRealloc(MoveString2,strlen(MoveString2)+
839                                     strlen(from)+2);
840               strcat(MoveString2,"\n");
841               strcat(MoveString2,from);
842             }
843             error = TRUE;
844          }
845          if (error || targetError)
846          {
847             errorCount++;
848             continue;
849          }
850       }
851
852       /* check if target file already exists */
853       if (stat(target_file, &stat_buf) == 0)
854       {
855          /* target file already exists: remember and deal with it later */
856         if(mode == MOVE_FILE && S_ISDIR(stat_buf.st_mode)
857                && DirectoryBusy(target_file))
858         {
859           char *msg;
860
861           msg = XtNewString( GETMESSAGE(11,30, "Cannot move or rename the folder %s.\nAll File Manager views displayed for a folder or its sub-folders\nmust be closed before a folder can be moved or renamed."));
862
863           PipeWriteErrmsg( pipe_s2m, -1, msg, target_file );
864           errorCount++;
865           XtFree(msg);
866           XtFree(target_file);
867           continue;
868         }
869          if (sameIndex == NULL)
870          {
871             sameIndex       = (int *)XtMalloc(file_count*sizeof(int));
872             sameConfirmType = (int *)XtMalloc(file_count*sizeof(int));
873          }
874          sameIndex[sameCount] = i;
875
876          /* determine how to set the pipe message */
877          if (mode == MAKE_BUFFER)
878          {
879            sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
880          }
881          else
882          {
883            stat(from, &from_stat_buf);
884            if ( S_ISDIR(from_stat_buf.st_mode) &&
885                 S_ISDIR(stat_buf.st_mode)      &&
886                 mode == COPY_FILE )
887            {
888                /* if its a directory and there already is a directory of the
889                 * same name the user may want to merge the directories into
890                 * one directory.  But if the directory to be copied is being
891                 * copied into the same directory it came from, it doesn't make
892                 * sense to merge.  Set up message to REPLACE_RENAME_SAME
893                 * indicating it is being copied from and to the same directory
894                 */
895                if(Same)
896                    sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
897                else
898                    sameConfirmType[sameCount] = PIPEMSG_REPLACE_MERGE;
899            }
900            else
901            {
902                /* If the copy/move/link is to the same directory, set up a
903                 * different case then when the op is happening from different
904                 * directories.
905                 */
906                if(Same)
907                    sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME_SAME;
908                else
909                    sameConfirmType[sameCount] = PIPEMSG_REPLACE_RENAME;
910            }
911          } /* endif mode != MAKE_BUFFER */
912
913          sameCount++;
914
915          if (mode != MAKE_BUFFER)
916            XtFree ((char *) from);
917
918          XtFree ((char *) target_file);
919          continue;
920       } /* endif targetfile already exists */
921
922       if ((isContainer = (to_file == NULL)))
923          to = target_dir;
924       else
925          to = target_file;
926
927       /*
928        * Note: it is important that SendModifyMsg is called before any
929        * changes are made to either the source or target directory.
930        * This is because SendModifyMsg is supposed to obtain and send
931        * the time stamp of the directories BEFORE any operation.  If
932        * the wrong timestamp is sent, the window will be updated and
933        * redrawn twice instead of just once.
934        */
935       SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, i,
936                     updates[i].file);
937       first_op = False;
938
939       if (mode == MAKE_BUFFER)
940       {
941         /* Call CreateFileFromBuffer */
942         return_val = CreateFileFromBuffer(pipe_s2m, to,
943                                           target_file,
944                                           updates[i].bufferInfo.buf_ptr,
945                                           updates[i].bufferInfo.size);
946       }
947       else
948       {
949         if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
950             return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
951                                     isContainer,
952                                     FileOpError, True, DESKTOP);
953         else
954             return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
955                                     isContainer,
956                                     FileOpError, True, NOT_DESKTOP);
957         XtFree( (char *) from );
958       }
959
960       XtFree ((char *) target_file);
961
962    } /* end for loop */
963
964    if(CopyError == TRUE)
965    {
966       String errMsg;
967       errMsg = GETMESSAGE(11,48,
968           "Cannot copy the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\nwrite permission for the target folder");
969       DisplayErrorMessage(pipe_s2m,errMsg,CopyString,target_dir);
970       CopyError = FALSE;
971       permissionErrors = NULL;
972       XtFree(CopyString);
973       CopyString = NULL;
974    }
975    if(MoveError1 == TRUE)
976    {
977       String errMsg;
978       errMsg = GETMESSAGE(11,49,
979           "Cannot move the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\nwrite permission for the target folder");
980       DisplayErrorMessage(pipe_s2m,errMsg,MoveString1,target_dir);
981       MoveError1 = FALSE;
982       permissionErrors = NULL;
983       XtFree(MoveString1);
984       MoveString2 = NULL;
985    }
986    if(MoveError2 == TRUE)
987    {
988       String errMsg;
989       errMsg = GETMESSAGE(11,50,
990           "Cannot move the following objects to folder \"%s\"\n\n%s\n\nThe most likely cause is that you do not have\npermission to move source object");
991       DisplayErrorMessage(pipe_s2m,errMsg,MoveString2,target_dir);
992       MoveError2 = FALSE;
993       permissionErrors = NULL;
994       XtFree(MoveString2);
995       MoveString2 = NULL;
996    }
997
998
999    /* If there were any permissions errors, show the error message */
1000    if (permissionErrors != NULL)
1001    {
1002       PipeWriteErrmsg(pipe_s2m, -1, permissionErrors, NULL);
1003       XtFree(permissionErrors);
1004    }
1005
1006
1007    /*
1008     * Now deal with with the cases where we found that the target file
1009     * already exists.
1010     */
1011    if (sameCount != 0)
1012    {
1013
1014       /*
1015        * @@@ Note: The code below for sending a target-time pipe message
1016        * at this point shouldn't really be necessary.
1017        * The problem is that the target directory time stamp MUST be
1018        * obtained BEFORE any changes are made to the directory;
1019        * otherwise, the window will be updated and redrawn twice instead
1020        * of just once.  Unfortunately, currently, if the user chooses to
1021        * replace or rename the existing file, the rename or delete
1022        * operation is done in the main process (inside the
1023        * replace_rename_ok_callback in Overwrite.c), instead of here in
1024        * the child process where it belongs (the main process shouldn't
1025        * do any file system operations because they could block for a
1026        * long time on a slow server).  If and when overwrite dialog code
1027        * is fixed, the code below can be deleted; the target-time
1028        * message will then be sent by the call to SendModifyMsg further
1029        * below after the call to PipeRead.
1030        */
1031       if (first_op)
1032       {
1033          if (stat(target_dir, &stat_buf) == 0)
1034          {
1035             modify_time = stat_buf.st_mtime;
1036             pipe_msg = PIPEMSG_TARGET_TIME;
1037             write(pipe_s2m, &pipe_msg, sizeof(short));
1038             write(pipe_s2m, &modify_time, sizeof(long));
1039          }
1040          first_op = False;
1041       }
1042
1043       /* send message to main process to display dialog (and possibly remove/rename files) */
1044       if (file_count == 1)
1045       {
1046          if (to_file == NULL)   /* note target_file here is only file name, above it is full path */
1047             target_file = updates[sameIndex[0]].file;
1048          else
1049             target_file = to_file;
1050          pipe_msg =  sameConfirmType[0];
1051          DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1052          write(pipe_s2m, &pipe_msg, sizeof(short));
1053          DPRINTF(("FileMoveCopyProcess: sending: mode %d directory \"%s\" file \"%s\" \n",
1054                    mode, directory, target_file));
1055          write(pipe_s2m, &mode, sizeof(int));
1056          PipeWriteString(pipe_s2m, directory);
1057          PipeWriteString(pipe_s2m, target_file);
1058       }
1059       else
1060       {
1061          int processCount=file_count-errorCount;
1062
1063          /* If the copy/move/link is to the same directory, set up a
1064           * different case then when the op is happening from different
1065           * directories.
1066           */
1067          if(Same)
1068              pipe_msg = PIPEMSG_MULTICOLLIDE_SAME;
1069          else
1070              pipe_msg = PIPEMSG_MULTICOLLIDE;
1071
1072          DPRINTF(("FileMoveCopyProcess: sending msg %d\n", pipe_msg));
1073          write(pipe_s2m, &pipe_msg, sizeof(short));
1074          DPRINTF(("FileMoveCopyProcess: sending: mode %d processCount %d sameCount %d directory \"%s\"\n",
1075                    mode, processCount, sameCount, directory));
1076          write(pipe_s2m, &mode, sizeof(int));
1077          write(pipe_s2m, &processCount, sizeof(int));
1078          write(pipe_s2m, &sameCount, sizeof(int));
1079          PipeWriteString(pipe_s2m, directory);
1080          DPRINTF(("FileMoveCopyProcess: sending %d filename strings\n", sameCount));
1081          for (i = 0;  i < sameCount; i++)
1082             PipeWriteString(pipe_s2m, updates[sameIndex[i]].file);
1083       }
1084
1085       /* wait for reply from main process */
1086       rc = -1;
1087       PipeRead(pipe_m2s, &rc, sizeof(int));
1088       DPRINTF(("FileMoveCopyProcess: woke up after confirm, rc %d\n", rc));
1089       if (rc != PIPEMSG_CANCEL)
1090       {
1091          /* affirmative reply: do the operation */
1092          for(i = 0; i < sameCount; i++)
1093          {
1094             j = sameIndex[i];
1095             if (rc != PIPEMSG_RENAME_BUFFER)
1096             {
1097                SendModifyMsg(pipe_s2m, mode, first_op, target_dir, updates, j,
1098                              updates[j].file);
1099                first_op = FALSE;
1100             }
1101             if (rc == PIPEMSG_MULTI_PROCEED)
1102             {
1103                int opvalue;
1104                PipeRead(pipe_m2s, &opvalue, sizeof(int));
1105                if(opvalue != 0)
1106                    continue;
1107             }
1108
1109             if (mode != MAKE_BUFFER)
1110             {
1111               from = ResolveLocalPathName( updates[j].host,
1112                                            updates[j].directory,
1113                                            updates[j].file,
1114                                            home_host_name,
1115                                            &tt_status);
1116               if( TT_OK != tt_status )
1117               {
1118                  char msg1[2*MAX_PATH];
1119
1120 #ifdef sun
1121                  sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1122                           updates[j].directory, updates[j].host,
1123                           updates[j].host);
1124 #else
1125                  sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1126                           updates[j].directory, updates[j].host,
1127                           updates[j].host);
1128 #endif
1129                   PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1130                    continue;
1131               }
1132             } /* endif */
1133
1134
1135
1136             if ( (isContainer = (to_file == NULL)) )
1137             {
1138                to = target_dir;
1139             }
1140             else
1141             {
1142                to = (char *)XtMalloc(strlen(target_dir) + strlen(to_file) + 2);
1143                sprintf(to, "%s/%s", target_dir, to_file);
1144             }
1145
1146
1147
1148             /* check the return code for type of message and */
1149             /* perform the appropriate action                */
1150             switch (rc)
1151             {
1152                 case PIPEMSG_MERGE:
1153
1154                     if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1155                       return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1156                                              to, isContainer,
1157                                              FileOpError, True, DESKTOP);
1158                     else
1159                       return_val = FileManip((Widget) (intptr_t) pipe_s2m, MERGE_DIR, from,
1160                                              to, isContainer,
1161                                              FileOpError, True, NOT_DESKTOP);
1162                     break;
1163
1164                 case PIPEMSG_REPLACE_BUFFER:
1165                     target_file = (char *)XtMalloc(strlen(to) + strlen(updates[j].file)
1166                                               + 2);
1167                     sprintf(target_file, "%s/%s", to, updates[j].file);
1168                     DPRINTF (("file is %s",updates[j].file));
1169                     return_val = CreateFileFromBuffer(pipe_s2m,
1170                                                       to,
1171                                                       target_file,
1172                                                       updates[j].bufferInfo.buf_ptr,
1173                                                       updates[j].bufferInfo.size);
1174                     XtFree((char *)target_file);
1175                     target_file = NULL;
1176                     break;
1177                 case PIPEMSG_RENAME_BUFFER:
1178
1179                     renamed_file = PipeReadString(pipe_m2s);
1180
1181                     SendModifyMsg(pipe_s2m, mode, first_op, to, updates, j, renamed_file);
1182                     target_file = (char *)XtMalloc(strlen(to) + strlen(renamed_file)
1183                                               + 2);
1184                     sprintf(target_file, "%s/%s", to, renamed_file);
1185                     DPRINTF(("file is %s",renamed_file));
1186                     return_val = CreateFileFromBuffer(pipe_s2m,
1187                                                       to,
1188                                                       target_file,
1189                                                       updates[j].bufferInfo.buf_ptr,
1190                                                       updates[j].bufferInfo.size);
1191                     XtFree((char *) target_file);
1192                      target_file = NULL;
1193
1194                     break;
1195                 default:
1196                     if (strncmp(directory, desktop_dir, strlen(desktop_dir)) == 0)
1197                       return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to,
1198                                              isContainer,FileOpError, True,
1199                                              DESKTOP);
1200                     else
1201                     {
1202                         /* if the operation (move/copy/link) is happening from
1203                          * and to the same folder, we want to create a new name
1204                          * for the object for which the operation is happening
1205                          * on.
1206                          */
1207                         if(Same)
1208                         {
1209                             char path[MAX_PATH], newDir[MAX_PATH],
1210                             newFile[MAX_PATH];
1211                             char *toFile;
1212
1213                             strcpy(path, from);
1214                             generate_NewPath(path,path);
1215                             split_path(path, newDir, newFile);
1216                             toFile = (char *)XtMalloc(strlen(newDir) +
1217                                                       strlen(newFile) + 3);
1218                             strcpy(toFile, newDir);
1219                             strcat(toFile, "/");
1220                             strcat(toFile, newFile);
1221
1222                             return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1223                                                    toFile, False, FileOpError,
1224                                                    True, NOT_DESKTOP);
1225                             XtFree(path);
1226                             XtFree(toFile);
1227                         }
1228                         else
1229                             return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from,
1230                                                    to, isContainer, FileOpError,
1231                                                    True, NOT_DESKTOP);
1232                     }
1233             } /* endswitch */
1234
1235            if (to_file != NULL)
1236            {
1237                XtFree ((char *) to);
1238                to = NULL;
1239            }
1240          }/* end for */
1241       }/*end if rc != PIPEMSG_CANCEL*/
1242
1243       /* free sameData */
1244       XtFree((char *)sameIndex);
1245       sameIndex = NULL;
1246       XtFree((char *)sameConfirmType);
1247       sameConfirmType = NULL;
1248       sameCount = 0;
1249    } /* endif sameCount != 0 */
1250
1251
1252    pipe_msg = PIPEMSG_DONE;
1253    if (rc != PIPEMSG_CANCEL)
1254       rc = return_val? 0: -1;
1255    else
1256       rc = 0;
1257    write(pipe_s2m, &pipe_msg, sizeof(short));
1258    write(pipe_s2m, &rc, sizeof(int));
1259
1260    XtFree ((char *) target_dir);
1261    target_dir = NULL;
1262
1263    return rc;
1264 }
1265
1266
1267 /*--------------------------------------------------------------------
1268  * FileMoveCopyProcessDesktop:
1269  *     Main routine of the background process that handles files
1270  *     dropped in desktop icons.
1271  *------------------------------------------------------------------*/
1272
1273 static int
1274 FileMoveCopyProcessDesktop(
1275         int pipe_s2m,
1276         int pipe_m2s,
1277         char *directory,
1278         char *host,
1279         DirUpdate *updates,
1280         int file_count,
1281         int mode,
1282         DesktopRec *desktopWindow)
1283 {
1284    char * to, *from;
1285    int i, rc;
1286    Boolean first_op = True;
1287    Boolean return_val = False;
1288    short pipe_msg;
1289    Tt_status tt_status;
1290
1291    /*  Get the fully qualified destination path.  */
1292    to = ResolveLocalPathName(host, directory, NULL, home_host_name, &tt_status);
1293    if( TT_OK != tt_status )
1294    {
1295      char msg1[2*MAX_PATH];
1296 #ifdef sun
1297      sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1298               directory, host, host);
1299 #else
1300      sprintf (msg1, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1301               directory, host, host);
1302 #endif
1303      PipeWriteErrmsg(pipe_s2m, -1, msg1, NULL);
1304      pipe_msg = PIPEMSG_FILEOP_ERROR;
1305      rc = -1;
1306      write(pipe_s2m, &pipe_msg, sizeof(short));
1307      write(pipe_s2m, &rc, sizeof(int));
1308      return rc;
1309    }
1310    DtEliminateDots(to);
1311
1312    for (i = 0; i < file_count; i++)
1313    {
1314       /* get full name of the source file, if just */
1315       /* dealing with regular files                */
1316       if (mode != MAKE_BUFFER)
1317       {
1318          from = ResolveLocalPathName(updates[i].host,
1319                                      updates[i].directory,
1320                                      updates[i].file,
1321                                      home_host_name,
1322                                      &tt_status);
1323          if (from == NULL)
1324          {
1325             char msg[2*MAX_PATH];
1326
1327 #ifdef sun
1328             sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_1),
1329                        updates[i].directory, updates[i].host, updates[i].host);
1330 #else
1331             sprintf (msg, GetSharedMessage(CANNOT_CONNECT_ERROR_2),
1332                        updates[i].directory, updates[i].host, updates[i].host);
1333 #endif
1334             PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1335          }
1336          else if (strcmp(to, from) == 0)
1337          {
1338             char msg[2*MAX_PATH];
1339
1340             sprintf(msg,GETMESSAGE(11,16, "A folder cannot be moved into itself.\n%s"),to);
1341             PipeWriteErrmsg(pipe_s2m, -1, msg, NULL);
1342             XtFree ((char *) from);
1343              from = NULL;
1344          }
1345       } /* end if dealing with regular files */
1346
1347
1348       SendModifyMsg(pipe_s2m, mode, first_op, to, updates, i, updates[i].file);
1349
1350       return_val = True;
1351
1352       if (mode == MAKE_BUFFER)
1353       {
1354         char *target_file;
1355
1356         if (strcmp(to, "/") == 0)
1357         {
1358            target_file = (char *) XtMalloc(strlen(to) +
1359                                            strlen(updates[i].file) + 1);
1360            sprintf(target_file, "%s%s", to, updates[i].file);
1361         }
1362         else
1363         {
1364            target_file = (char *) XtMalloc(strlen(to) +
1365                                            strlen(updates[i].file) + 2);
1366            sprintf(target_file, "%s/%s", to, updates[i].file);
1367         }
1368
1369         return_val = CreateFileFromBuffer(pipe_s2m,
1370                                           to,
1371                                           target_file,
1372                                           updates[i].bufferInfo.buf_ptr,
1373                                           updates[i].bufferInfo.size);
1374       }
1375       else
1376       {
1377         return_val = FileManip((Widget) (intptr_t) pipe_s2m, mode, from, to, TRUE,
1378                                FileOpError, True, DESKTOP);
1379         XtFree (from);
1380         from = NULL;
1381       }
1382    }
1383
1384    pipe_msg = PIPEMSG_DONE;
1385    rc = return_val? 0: -1;
1386    write(pipe_s2m, &pipe_msg, sizeof(short));
1387    write(pipe_s2m, &rc, sizeof(int));
1388
1389    XtFree ((char *) to);
1390    return rc;
1391 }
1392
1393
1394 static void
1395 RemoveIconFromWorkspace( char * iconName,
1396                          char * targetDir )
1397 {
1398   DesktopRec *desktopWin;
1399   int i;
1400   char fileName[MAX_PATH];
1401
1402
1403   for(i = 0; i < desktop_data->numIconsUsed; i++)
1404   {
1405     desktopWin = desktop_data->desktopWindows[i];
1406
1407     if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1408       sprintf( fileName, "/%s", desktopWin->file_name );
1409     else
1410       sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1411
1412     if( strcmp( fileName, iconName ) == 0 )
1413     {
1414       Window   rootWindow;
1415       Atom     pCurrent;
1416       Screen   *currentScreen;
1417       int      screen;
1418       char     *workspace_name;
1419
1420       screen = XDefaultScreen(XtDisplay(desktopWin->shell));
1421       currentScreen =
1422         XScreenOfDisplay(XtDisplay(desktopWin->shell), screen);
1423       rootWindow = RootWindowOfScreen(currentScreen);
1424
1425       if(DtWsmGetCurrentWorkspace(XtDisplay(desktopWin->shell),
1426                                   rootWindow, &pCurrent) == Success)
1427         workspace_name =
1428           XGetAtomName (XtDisplay(desktopWin->shell), pCurrent);
1429       else
1430         workspace_name = XtNewString("One");
1431
1432       if( strcmp( workspace_name, desktopWin->workspace_name ) == 0 )
1433       {
1434         RemoveDT( desktopWin->shell, (XtPointer) desktopWin,
1435                   (XtPointer)NULL );
1436       }
1437       else
1438       {
1439         XtFree( desktopWin->dir_linked_to );
1440         desktopWin->dir_linked_to = XtNewString( targetDir );
1441       }
1442
1443       XtFree(workspace_name);
1444     }
1445   }
1446 }
1447
1448 static void
1449 ChangeWorkspaceIconLink( FileMgrData *fmd,
1450                          char * iconName,
1451                          char * targetDir,
1452                          char * iconPdir )
1453 {
1454   DesktopRec *desktopWin;
1455   char *dirp = NULL;
1456   int i;
1457   char fileName[MAX_PATH];
1458
1459
1460   for(i = 0; i < desktop_data->numIconsUsed; i++)
1461   {
1462     desktopWin = desktop_data->desktopWindows[i];
1463
1464     if( strcmp( desktopWin->dir_linked_to, "/" ) == 0 )
1465       sprintf( fileName, "/%s", desktopWin->file_name );
1466     else
1467       sprintf( fileName, "%s/%s", desktopWin->dir_linked_to, desktopWin->file_name );
1468
1469     DtEliminateDots(fileName);
1470     if( strcmp( fileName, iconName ) == 0 )
1471       dirp = XtNewString(targetDir);
1472     else if(IsInParentDir(iconName,desktopWin->dir_linked_to))
1473     {
1474       int index = strlen(iconPdir);
1475       char *tptr = desktopWin->dir_linked_to;
1476
1477       dirp = XtCalloc( 1, strlen(targetDir)+ strlen(&tptr[index])+1);
1478       sprintf(dirp,"%s%s",targetDir,&tptr[index]);
1479
1480     }
1481     if(dirp)
1482     {
1483       FileViewData *file_view_data;
1484       DirectorySet *directory_set;
1485       FileMgrData  *file_mgr_data;
1486       Tt_status tt_status;
1487       char * full_dir_name;
1488
1489       file_view_data = desktopWin->file_view_data;
1490       directory_set = (DirectorySet *)file_view_data->directory_set;
1491       file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
1492
1493       if(file_mgr_data)
1494          fmd = file_mgr_data;
1495       FreeFileData( file_view_data->file_data, True );
1496       file_view_data->file_data = NULL;
1497
1498       XtFree( desktopWin->dir_linked_to );
1499       desktopWin->dir_linked_to = XtNewString( dirp );
1500       DtEliminateDots(desktopWin->dir_linked_to);
1501
1502       if(fmd)
1503       {
1504          if (fmd->restricted_directory == NULL)
1505             desktopWin->restricted_directory = NULL;
1506          else
1507             desktopWin->restricted_directory =
1508                 XtNewString(fmd->restricted_directory);
1509
1510          if (fmd->helpVol == NULL)
1511             desktopWin->helpVol = NULL;
1512          else
1513             desktopWin->helpVol = XtNewString(fmd->helpVol);
1514
1515         desktopWin->helpVol         = XtNewString( fmd->helpVol );
1516         desktopWin->view            = fmd->view;
1517         desktopWin->order           = fmd->order;
1518         desktopWin->direction       = fmd->direction;
1519         desktopWin->positionEnabled = fmd->positionEnabled;
1520         desktopWin->toolbox         = fmd->toolbox;
1521       }
1522
1523       full_dir_name = ResolveLocalPathName(desktopWin->host,
1524                                            dirp,
1525                                            NULL,
1526                                            home_host_name,
1527                                            &tt_status);
1528       if( TT_OK == tt_status )
1529       {
1530         FileData2 file_data2;
1531         int n;
1532         Boolean IsToolBox;
1533
1534         DtEliminateDots (full_dir_name);
1535
1536         if ( fmd )
1537           IsToolBox = fmd->toolbox;
1538         else
1539           IsToolBox = False;
1540
1541         if (strcmp(desktopWin->file_name, ".") == 0)
1542             ReadFileData2(&file_data2, full_dir_name, NULL, IsToolBox);
1543         else
1544             ReadFileData2(&file_data2, full_dir_name, desktopWin->file_name,
1545                           IsToolBox);
1546
1547         file_view_data->file_data = FileData2toFileData(&file_data2, &n);
1548         XtFree(full_dir_name);
1549         full_dir_name = NULL;
1550       }
1551
1552       ((DirectorySet *)file_view_data->directory_set)->name =
1553         XtNewString(dirp);
1554
1555       SaveDesktopInfo(NORMAL_RESTORE);
1556       XtFree(dirp);
1557       dirp = NULL;
1558     }
1559   }
1560 }
1561
1562 /*--------------------------------------------------------------------
1563  * FileOpPipeCB
1564  *   Read and process data sent through the pipe.
1565  *------------------------------------------------------------------*/
1566
1567 static void
1568 FileOpPipeCB(
1569    XtPointer client_data,
1570    int *fd,
1571    XtInputId *id)
1572 {
1573    FileOpCBData *cb_data = (FileOpCBData *)client_data;
1574    short pipe_msg;
1575    int i, n, rc;
1576    char *title, *err_msg, *err_arg;
1577    char *directory, *file, *target_file;
1578    long modify_time;
1579    Boolean done;
1580    int mode;
1581    int nSelected, nCollisions;
1582    String *fileList;
1583    static int status = 0;
1584
1585   static ActionAreaItem replace_rename_actionItems[] = {
1586     {"Ok",     9, 27, NULL,  NULL},    /* changed later based on mode */
1587     {"Cancel", 9, 28, replace_rename_cancel_callback, NULL},
1588     {"Help",   9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_REN},
1589   };
1590
1591   ActionAreaDefn replace_renameActions = {
1592      XtNumber(replace_rename_actionItems),
1593      1,                      /* Cancel is default action */
1594      replace_rename_actionItems
1595   };
1596
1597   static ActionAreaItem replace_merge_actionItems[] = {
1598     {"Ok",     9, 27, replace_merge_ok_callback,     NULL},
1599     {"Cancel", 9, 28, replace_merge_cancel_callback, NULL},  /* changed below depending on mode */
1600     {"Help",   9, 29, HelpRequestCB, HELP_FILE_MANAGER_REP_MRG},
1601   };
1602
1603   ActionAreaDefn replace_mergeActions = {
1604      XtNumber(replace_merge_actionItems),
1605      1,                      /* Cancel is default action */
1606      replace_merge_actionItems
1607   };
1608
1609   static ActionAreaItem multicollide_actionItems[] = {
1610     {"Ok",     9, 27, NULL, NULL}, /* changed later based on Mode */
1611     {"Cancel", 9, 28, multicollide_cancel_callback, NULL},  /* changed below depending on mode */
1612     {"Help",   9, 29, HelpRequestCB, HELP_FILE_MANAGER_MULTI},
1613   };
1614
1615   ActionAreaDefn multicollideActions = {
1616      XtNumber(multicollide_actionItems),
1617      1,                      /* Cancel is default action */
1618      multicollide_actionItems
1619   };
1620
1621
1622    /* Initialize Action Area structures based on mode */
1623    /* Set the appropriate callback routines           */
1624    mode = cb_data->mode;
1625    switch (mode)
1626    {
1627      case MAKE_BUFFER:
1628           replace_rename_actionItems[0].callback =
1629                                    buffer_replace_rename_ok_callback;
1630           multicollide_actionItems[0].callback =
1631                                    buffer_multicollide_ok_callback;
1632           break;
1633      default:
1634           replace_rename_actionItems[0].callback =
1635                                    replace_rename_ok_callback;
1636           multicollide_actionItems[0].callback =
1637                                    multicollide_ok_callback;
1638    } /* endswitch */
1639
1640
1641
1642    /* read the next msg from the pipe */
1643    pipe_msg = -1;
1644    n = PipeRead(*fd, &pipe_msg, sizeof(short));
1645    DPRINTF(("FileOpPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
1646
1647    done = False;
1648    switch (pipe_msg)
1649    {
1650       case PIPEMSG_FILEOP_ERROR:
1651          PipeRead(*fd, &rc, sizeof(int));
1652          err_msg = PipeReadString(*fd);
1653          err_arg = PipeReadString(*fd);
1654          if (cb_data->desktop)
1655             FileOperationError(cb_data->file_view_data->widget,
1656                                err_msg, err_arg);
1657          else
1658          {
1659             /* routine can be called with a NULL file_mgr_rec, use the
1660              * top level widget if this is the case.
1661              */
1662             if(cb_data->file_mgr_rec)
1663                FileOperationError(cb_data->file_mgr_rec->file_window,
1664                                   err_msg, err_arg);
1665             else
1666                FileOperationError(toplevel, err_msg, err_arg);
1667          }
1668          XtFree(err_msg);
1669          XtFree(err_arg);
1670          if(cb_data->callback_data)
1671          {
1672            RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1673            ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1674            ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1675          }
1676          status = PIPEMSG_FILEOP_ERROR;
1677          break;
1678
1679       case PIPEMSG_CONFIRM:
1680          err_msg = PipeReadString(*fd);
1681          title = XtNewString(GETMESSAGE(9,11, "File Manager - Move/Copy/Link Warning"));
1682          filop_confirm_fd = cb_data->pipe_m2s;
1683          _DtMessageDialog(toplevel, title, err_msg, NULL, TRUE,
1684                           moveCopyLinkCancel, moveCopyLinkOK, NULL,
1685                           HelpRequestCB, False, QUESTION_DIALOG);
1686          XtFree(err_msg);
1687          XtFree(title);
1688          break;
1689
1690        case PIPEMSG_REPLACE_RENAME_SAME:
1691            /* filename collision: display replace/rename dialog */
1692            PipeRead(*fd, &mode, sizeof(int));
1693            directory = PipeReadString(*fd);
1694            file      = PipeReadString(*fd);
1695            /* routine can be called with a NULL file_mgr_rec, use the
1696             * top level widget if this is the case.
1697             */
1698
1699            /* the object is copying/linking itself to the same folder.  Want
1700             * to indicate the to the ok dialog and the building of the replace
1701             * name dialog.
1702             */
1703            replace_rename_actionItems[0].data = (XtPointer)True;
1704            if(cb_data->file_mgr_rec)
1705                create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1706                                             mode, directory, file,
1707                                             cb_data->pipe_m2s,
1708                                             replace_renameActions, True);
1709            else
1710                create_replace_rename_dialog(toplevel,
1711                                             mode, directory, file,
1712                                             cb_data->pipe_m2s,
1713                                             replace_renameActions, True);
1714            XtFree(directory);
1715            XtFree(file);
1716            break;
1717
1718       case PIPEMSG_REPLACE_RENAME:
1719          /* filename collision: display replace/rename dialog */
1720          PipeRead(*fd, &mode, sizeof(int));
1721          directory = PipeReadString(*fd);
1722          file      = PipeReadString(*fd);
1723          /* routine can be called with a NULL file_mgr_rec, use the
1724           * top level widget if this is the case.
1725           */
1726          replace_rename_actionItems[0].data = (XtPointer)NULL;
1727          if(cb_data->file_mgr_rec)
1728             create_replace_rename_dialog(cb_data->file_mgr_rec->shell,
1729                                          mode, directory, file,
1730                                          cb_data->pipe_m2s,
1731                                          replace_renameActions, False);
1732          else
1733             create_replace_rename_dialog(toplevel,
1734                                          mode, directory, file,
1735                                          cb_data->pipe_m2s,
1736                                          replace_renameActions, False);
1737          XtFree(directory);
1738          XtFree(file);
1739          break;
1740
1741       case PIPEMSG_REPLACE_MERGE:
1742          /* filename collision: display replace/merge dialog */
1743          PipeRead(*fd, &mode, sizeof(int));
1744          directory = PipeReadString(*fd);
1745          file      = PipeReadString(*fd);
1746          /* routine can be called with a NULL file_mgr_rec, use the
1747           * top level widget if this is the case.
1748           */
1749          if(cb_data->file_mgr_rec)
1750             create_replace_merge_dialog(cb_data->file_mgr_rec->shell,
1751                                         mode, directory, file,
1752                                         cb_data->pipe_m2s,
1753                                         replace_mergeActions);
1754          else
1755             create_replace_merge_dialog(toplevel,
1756                                         mode, directory, file,
1757                                         cb_data->pipe_m2s,
1758                                         replace_mergeActions);
1759          XtFree(directory);
1760          XtFree(file);
1761          break;
1762
1763        case PIPEMSG_MULTICOLLIDE_SAME:
1764            /* filename collision: display multicollide dialog */
1765            PipeRead(*fd, &mode,        sizeof(int));
1766            PipeRead(*fd, &nSelected,   sizeof(int));
1767            PipeRead(*fd, &nCollisions, sizeof(int));
1768            directory = PipeReadString(*fd);
1769            file      = XtMalloc( MAX_PATH );
1770            fileList  = (String *) XtMalloc(nCollisions * sizeof(String));   /* de- allocated in dialog's callback functions */
1771            for (i = 0; i < nCollisions; i++)
1772            {
1773                fileList[i] = PipeReadString(*fd);
1774            }
1775            /* routine can be called with a NULL file_mgr_rec, use the
1776             * top level widget if this is the case.
1777             */
1778
1779            /* the object is copying/linking itself to the same folder.  Want
1780             * to indicate the to the ok dialog and the building of the replace
1781             * name dialog.
1782             */
1783            multicollide_actionItems[0].data = (XtPointer)True;
1784            if(cb_data->file_mgr_rec)
1785                create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1786                                           mode, nSelected, nCollisions,
1787                                           directory, fileList,
1788                                           cb_data->pipe_m2s,
1789                                           multicollideActions, True);
1790            else
1791                create_multicollide_dialog(toplevel,
1792                                           mode, nSelected, nCollisions,
1793                                           directory, fileList,
1794                                           cb_data->pipe_m2s,
1795                                           multicollideActions, True);
1796            XtFree(directory);
1797            break;
1798
1799       case PIPEMSG_MULTICOLLIDE:
1800          /* filename collision: display multicollide dialog */
1801          PipeRead(*fd, &mode,        sizeof(int));
1802          PipeRead(*fd, &nSelected,   sizeof(int));
1803          PipeRead(*fd, &nCollisions, sizeof(int));
1804          directory = PipeReadString(*fd);
1805          file      = XtMalloc( MAX_PATH );
1806          fileList  = (String *) XtMalloc(nCollisions * sizeof(String));   /* de-allocated in dialog's callback functions */
1807          for (i = 0; i < nCollisions; i++)
1808          {
1809             fileList[i] = PipeReadString(*fd);
1810          }
1811          /* routine can be called with a NULL file_mgr_rec, use the
1812           * top level widget if this is the case.
1813           */
1814          multicollide_actionItems[0].data = (XtPointer)NULL;
1815          if(cb_data->file_mgr_rec)
1816             create_multicollide_dialog(cb_data->file_mgr_rec->shell,
1817                                        mode, nSelected, nCollisions,
1818                                        directory, fileList,
1819                                        cb_data->pipe_m2s,
1820                                        multicollideActions, False);
1821          else
1822             create_multicollide_dialog(toplevel,
1823                                        mode, nSelected, nCollisions,
1824                                        directory, fileList,
1825                                        cb_data->pipe_m2s,
1826                                        multicollideActions, False);
1827
1828          XtFree(directory);
1829          break;
1830
1831       case PIPEMSG_TARGET_TIME:
1832          /* get the modify time and update the directory cache */
1833          PipeRead(*fd, &modify_time, sizeof(long));
1834          DirectoryModifyTime(cb_data->host, cb_data->directory, modify_time);
1835          break;
1836
1837       case PIPEMSG_MOVE_TO_SAME_DIR:
1838          /* get the update index */
1839          PipeRead(*fd, &i, sizeof(int));
1840          cb_data->updates[i].operationStatus = True;
1841          DisplayDuplicateOpError((void *) cb_data,i);
1842          status = PIPEMSG_MOVE_TO_SAME_DIR;
1843          if(cb_data->callback_data)
1844          {
1845            RenameDoneData *rdd = (RenameDoneData *)cb_data->callback_data;
1846            ResetFlag( rdd->call_struct->dialog_widget,rdd->w);
1847            ResetFlag( rdd->call_struct->dialog_widget,rdd->call_struct->Cancel);
1848          }
1849          break;
1850
1851       case PIPEMSG_FILE_MODIFIED:
1852          /* get the update index and modify time */
1853          PipeRead(*fd, &i, sizeof(int));
1854          PipeRead(*fd, &modify_time, sizeof(long));
1855          target_file = PipeReadString(*fd);
1856          DPRINTF (("PIPEMSG_FILE_MODIFIED %s\n", target_file));
1857
1858          /* mark the file updated in the cached target directory */
1859          DirectoryFileModified(cb_data->host, cb_data->directory,
1860                                target_file);
1861
1862          if (cb_data->mode == MOVE_FILE)
1863          {
1864             /* mark the file updated in the cached source directory */
1865             if (modify_time != 0)
1866                DirectoryModifyTime(cb_data->updates[i].host,
1867                                    cb_data->updates[i].directory,
1868                                    modify_time);
1869             DirectoryFileModified(cb_data->updates[i].host,
1870                                   cb_data->updates[i].directory,
1871                                   cb_data->updates[i].file);
1872          }
1873          cb_data->updates[i].operationStatus = True;
1874          XtFree(target_file); target_file = NULL;
1875          break;
1876
1877       case PIPEMSG_DONE:
1878          PipeRead(*fd, &rc, sizeof(int));
1879          done = True;
1880          break;
1881
1882       default:
1883         fprintf(stderr, "Internal error in FileOpPipeCB: bad pipe_msg %d\n",
1884                 pipe_msg);
1885         rc = -1;
1886         done = True;
1887    }
1888
1889    if (done)
1890    {
1891       char tmpDir[MAX_PATH];
1892
1893       DPRINTF(("FileOpPipeCB: done, rc %d\n", rc));
1894
1895       /* close the pipe and cancel the callback */
1896       close(cb_data->pipe_m2s);
1897       close(cb_data->pipe_s2m);
1898       if (id != NULL)
1899          XtRemoveInput(*id);
1900       else
1901          *fd = (rc == 0)? 0: -1;
1902
1903       /* arrange for modified directories to be updated */
1904       DirectoryEndModify(cb_data->host, cb_data->directory);
1905
1906       /* Reposition the objects which have been modified */
1907       if(!cb_data->finish_callback && cb_data->file_mgr_data)
1908       {
1909         char **file_set;
1910         int actual_count=0;
1911         /* Do this only if it is the current directory and Random placement
1912            is ON */
1913         if(cb_data->file_mgr_data->positionEnabled != RANDOM_OFF && strcmp(
1914             cb_data->directory,cb_data->file_mgr_data->current_directory)==0)
1915         {
1916           file_set = (char **) XtCalloc(1,cb_data->file_count*sizeof(char *));
1917           for(i=0;i<cb_data->file_count;i++)
1918           {
1919              if(cb_data->updates[i].operationStatus == True)
1920                 file_set[actual_count++] = cb_data->updates[i].file;
1921           }
1922           RepositionIcons(cb_data->file_mgr_data, file_set,actual_count,
1923              G_dropx, G_dropy, True);
1924           XtFree((char *)file_set);
1925           file_set = NULL;
1926         }
1927       }
1928
1929       for(i = 0; i < desktop_data->numWorkspaces; i++)
1930         DeselectAllDTFiles(desktop_data->workspaceData[i]);
1931
1932       for (i = 0; i < cb_data->file_count; i++)
1933       {
1934          char fileName[MAX_PATH];
1935
1936          /* Scroll the window to show the created object, since we
1937             cannot keep scrolling for each object we just do it for
1938             one object and we do it in case of Drag/Drop, but not
1939             for Select.MoveTo/CopyTo ... */
1940
1941          if(!i && cb_data->callback_data == NULL)
1942          {
1943            FileMgrData *fmd;
1944
1945            if(cb_data && cb_data->file_mgr_data)
1946            {
1947              fmd = cb_data->file_mgr_data;
1948              fmd->scrollToThisDirectory = XtNewString(cb_data->directory);
1949              fmd->scrollToThisFile = XtNewString(cb_data->updates[i].file);
1950            }
1951          }
1952          if (cb_data->updates[i].first_index == i)
1953          {
1954             if (cb_data->mode == MOVE_FILE)
1955             {
1956               DirectoryEndModify(cb_data->updates[i].host,
1957                                  cb_data->updates[i].directory);
1958               if( strcmp( cb_data->updates[i].directory, "/" ) == 0 )
1959                 tmpDir[0] = 0x0;
1960               else
1961                 sprintf( tmpDir, "%s", cb_data->updates[i].directory );
1962             }
1963
1964             if( cb_data->updates[i].host )
1965               XtFree( cb_data->updates[i].host );
1966             if( cb_data->updates[i].directory )
1967               XtFree( cb_data->updates[i].directory );
1968             if( cb_data->updates[i].app_man_dir )
1969               XtFree( cb_data->updates[i].app_man_dir );
1970          }
1971
1972          if( cb_data->mode == MOVE_FILE )
1973          {
1974            sprintf( fileName, "%s/%s", tmpDir, cb_data->updates[i].file );
1975            if( cb_data->updates[i].operationStatus == True )
1976            {
1977              if( status == PIPEMSG_MOVE_TO_SAME_DIR )
1978              {
1979                RemoveIconFromWorkspace( fileName, cb_data->directory );
1980              }
1981              else if( status != PIPEMSG_FILEOP_ERROR )
1982              {
1983                ChangeWorkspaceIconLink(cb_data->file_mgr_data, fileName,
1984                              cb_data->directory,tmpDir );
1985
1986                /* If it is workspace drag and drop and the move operation
1987                   is not because of  Select.MoveTo menu option  */
1988
1989                if(initiating_view == NULL && cb_data->callback_data == NULL)
1990                {
1991                  sprintf( fileName, "%s/%s", cb_data->directory,
1992                               cb_data->updates[i].file );
1993                  DtEliminateDots(fileName);
1994                  RemoveIconFromWorkspace( fileName, cb_data->directory );
1995                }
1996              }
1997            }
1998          }
1999
2000          XtFree(cb_data->updates[i].file);
2001       }
2002
2003       status = 0;
2004
2005       /* call the callback routine */
2006       if (cb_data->finish_callback)
2007          (*cb_data->finish_callback)(cb_data->callback_data, rc);
2008
2009       /* free the callback data */
2010       XtFree((char *)cb_data->updates);
2011       XtFree((char *)cb_data->directory);
2012       XtFree((char *)cb_data->host);
2013       XtFree(client_data);
2014    }
2015 }
2016
2017
2018 /*--------------------------------------------------------------------
2019  * _FileMoveCopy
2020  *    Start the background process and set up callback for the pipe.
2021  *------------------------------------------------------------------*/
2022
2023 static Boolean
2024 _FileMoveCopy(
2025         XtPointer data,
2026         char *to_file,
2027         char *directory,
2028         char *host,
2029         char **host_set,
2030         char **file_set,
2031         BufferInfo *buffer_set,
2032         int file_count,
2033         unsigned int modifiers,
2034         DesktopRec *desktopWindow,
2035         void (*finish_callback)(),
2036         XtPointer callback_data)
2037 {
2038    static char *pname = "_FileMoveCopy";
2039    int mode;
2040    FileOpCBData *cb_data;
2041    DirUpdate *updates;
2042    int i, j;
2043    char *ptr = NULL;
2044    char *source_dir = NULL;
2045    char *source_file = NULL;
2046    int pipe_m2s[2];
2047    int pipe_s2m[2];
2048    int pid;
2049    fd_set select_fds;
2050    int fd;
2051    struct timeval now, select_end, select_timeout;
2052    Boolean operation_done;
2053    int rc;
2054
2055
2056    /*  Determine the type of operation: move, copy, or link */
2057    /*  or creating buffers                                  */
2058    if (buffer_set != NULL)
2059    {
2060      mode = MAKE_BUFFER;
2061    }
2062    else
2063    {
2064      modifiers &= ~Button2Mask;
2065      if (modifiers == ShiftMask)
2066        mode = LINK_FILE;
2067      else if (modifiers == ControlMask)
2068        mode = COPY_FILE;
2069      else
2070        mode = MOVE_FILE;
2071    }
2072
2073    /* set up the callback data structure */
2074    cb_data = XtNew(FileOpCBData);
2075    cb_data->desktop = (desktopWindow != NULL);
2076    if (cb_data->desktop)
2077    {
2078       cb_data->file_mgr_data = NULL;
2079       cb_data->file_mgr_rec = NULL;
2080       cb_data->file_view_data = (FileViewData *)data;
2081       cb_data->desktopWindow = desktopWindow;
2082    }
2083    else
2084    {
2085       if(data != NULL)
2086       {
2087          cb_data->file_mgr_data = (FileMgrData *)data;
2088          cb_data->file_mgr_rec =
2089            (FileMgrRec *) ((FileMgrData *)data)->file_mgr_rec;
2090       }
2091       else
2092       {
2093          cb_data->file_mgr_data = NULL;
2094          cb_data->file_mgr_rec = NULL;
2095       }
2096       cb_data->file_view_data = NULL;
2097       cb_data->desktopWindow = NULL;
2098    }
2099    cb_data->mode = mode;
2100    cb_data->host = XtNewString(host);
2101    cb_data->directory = XtNewString(directory);
2102    cb_data->finish_callback = finish_callback;
2103    cb_data->callback_data = callback_data;
2104
2105
2106    /* mark the target directory as being modified in the directory cache */
2107    DirectoryBeginModify(host, directory);
2108
2109    /* make a list of the operations to be done */
2110    /* Allocate memory for the DirUpdateStructure */
2111    cb_data->file_count = file_count;
2112    cb_data->updates =
2113      updates = (DirUpdate *)XtMalloc(file_count * sizeof(DirUpdate));
2114
2115    /* Determine whether we are dealing with files or buffers */
2116    /* This affects how the updates structure is initialized  */
2117    if (mode == MAKE_BUFFER)
2118    {
2119       for (i=0; i< file_count; i++)
2120       {
2121         /* just simply set the the updates structure with */
2122         /* the passed in file names                       */
2123         updates[i].file = XtNewString(file_set[i]);
2124         updates[i].bufferInfo.buf_ptr = buffer_set[i].buf_ptr;
2125         updates[i].bufferInfo.size = buffer_set[i].size;
2126
2127         /* set unused updates fields to NOOP values */
2128         updates[i].time_sent = FALSE;
2129         updates[i].first_index = 0;
2130         updates[i].host = NULL;
2131         updates[i].directory = NULL;
2132         updates[i].app_man_dir = NULL;
2133       }
2134     }
2135     else
2136     {
2137       /* Seperate file names, directories, and hosts */
2138       /* when dealing with real files                */
2139       for (i=0; i< file_count; i++)
2140       {
2141         /* get the name of the source directory */
2142         ptr = strrchr(file_set[i], '/');
2143         if (NULL != ptr)
2144         {
2145             if (ptr == file_set[i])
2146               source_dir = "/";
2147             else
2148             {
2149               *ptr = '\0';
2150               source_dir = file_set[i];
2151             }
2152             source_file = ptr + 1;
2153         }
2154         else
2155         {
2156             source_dir = ".";
2157             source_file = file_set[i];
2158         }
2159
2160         /* see if this directory is already in the list */
2161         for (j = 0; j < i; j++)
2162           if (strcmp(updates[j].host, host_set[i]) == 0 &&
2163               strcmp(updates[j].directory, source_dir) == 0)
2164             break;
2165
2166         if (j < i)
2167         {  /* already in the list */
2168           updates[i].host = updates[j].host;
2169           updates[i].directory = updates[j].directory;
2170           updates[i].app_man_dir = updates[j].app_man_dir;
2171         }
2172         else
2173         {  /* not yet in the list */
2174           updates[i].host = XtNewString(host_set[i]);
2175           updates[i].directory = XtNewString(source_dir);
2176           updates[i].app_man_dir = NULL;
2177           if (!desktopWindow)
2178           {
2179              if(data != NULL)
2180              {
2181                 if (((FileMgrData *)data)->toolbox)
2182                    updates[i].app_man_dir =
2183                      XtNewString(((FileMgrData *)data)->restricted_directory);
2184              }
2185           }
2186
2187           /* mark the directory as being modified in the directory cache */
2188           if (mode == MOVE_FILE)
2189             DirectoryBeginModify(updates[i].host, updates[i].directory);
2190         }
2191         updates[i].first_index = j;
2192         updates[i].time_sent = False;
2193         updates[i].operationStatus = False;
2194         updates[i].file = XtNewString(source_file);
2195
2196         if (NULL != ptr) *ptr = '/';
2197       }/* end for loop */
2198     } /* endif */
2199
2200
2201    /* create a pipe */
2202    pipe(pipe_m2s);
2203    pipe(pipe_s2m);
2204
2205    /* fork the process that does the actual work */
2206    pid = fork();
2207    if (pid == -1)
2208    {
2209        DirectoryAbortModify(host, directory);
2210        for (i=0; i<file_count; i++)
2211          if (mode == MOVE_FILE && updates[i].first_index == i)
2212            DirectoryAbortModify(updates[i].host, updates[i].directory);
2213
2214        fprintf(stderr,
2215                 "%s:  fork failed, ppid %d, pid %d: error %d=%s\n",
2216                 pname, getppid(), getpid(), errno, strerror(errno));
2217        return False;
2218    }
2219
2220    if (pid == 0)
2221    {
2222       DBGFORK(("%s:  child forked, m2s %d s2m %d\n",
2223                 pname, pipe_m2s[0], pipe_s2m[1]));
2224
2225       close(pipe_m2s[1]);  /* won't write to pipe_m2s */
2226       close(pipe_s2m[0]);  /* won't read from pipe_s2m */
2227
2228       if (desktopWindow != NULL)
2229          rc = FileMoveCopyProcessDesktop(pipe_s2m[1], pipe_m2s[0],
2230                                          directory, host, updates, file_count,
2231                                          mode, desktopWindow);
2232       else
2233          rc = FileMoveCopyProcess(pipe_s2m[1], pipe_m2s[0], to_file, directory,
2234                                   host, updates, file_count, mode, NULL);
2235
2236       DBGFORK(("%s:  child exiting\n", pname));
2237       exit(rc);
2238    }
2239
2240    DBGFORK(("%s:  forked child<%d>, m2s %d, s2m %d\n",
2241                 pname, pid, pipe_m2s[1], pipe_s2m[0]));
2242
2243
2244    /* parent: set up callback to get the pipe data */
2245    close(pipe_m2s[0]);  /* won't read from pipe_m2s */
2246    close(pipe_s2m[1]);  /* won't write to pipe_s2m */
2247
2248    cb_data->pipe_m2s = pipe_m2s[1];
2249    cb_data->pipe_s2m = pipe_s2m[0];
2250    cb_data->mode = mode;
2251
2252    /*
2253     * We wait a certain amount of time for the background process to finish.
2254     * If it doesn't finish within that time, we do the rest asynchronously.
2255     */
2256
2257    /* set up fd set for select */
2258    FD_ZERO(&select_fds);
2259    fd = pipe_s2m[0];
2260
2261    /* compute until what time we want to wait */
2262    gettimeofday(&select_end, NULL);
2263    select_end.tv_sec += FILE_MOVE_COPY_WAIT_TIME;
2264
2265    operation_done = False;
2266    for (;;)
2267    {
2268       /* determine how much time is left */
2269       gettimeofday(&now, NULL);
2270       select_timeout.tv_sec = select_end.tv_sec - now.tv_sec;
2271       select_timeout.tv_usec = select_end.tv_usec - now.tv_usec;
2272       if (select_timeout.tv_usec < 0)
2273       {
2274          select_timeout.tv_sec--;
2275          select_timeout.tv_usec += 1000000;
2276       }
2277
2278       if ((int) select_timeout.tv_sec < 0)
2279       {
2280          /* check if our time is up */
2281          DPRINTF(("FileMoveCopy: timed out; adding input callback\n"));
2282          XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2283                        pipe_s2m[0], (XtPointer)XtInputReadMask,
2284                        FileOpPipeCB, (XtPointer)cb_data);
2285          break;
2286       }
2287
2288       /* do the select */
2289       FD_SET(fd, &select_fds);
2290 #if defined(__hpux) && (OSMAJORVERSION <= 10) && (OSMINORVERSION < 2)
2291       rc = select(fd + 1, (int *)&select_fds, NULL, NULL, &select_timeout);
2292 #else
2293       rc = select(fd + 1, &select_fds, NULL, NULL, &select_timeout);
2294 #endif
2295       if (rc < 0 && errno != EINTR)
2296       {
2297          perror("select failed in FileMoveCopy");
2298          break;
2299       }
2300       else if (rc == 1)
2301       {
2302          /* call FileOpPipeCB to read & process the data from the pipe */
2303          FileOpPipeCB((XtPointer)cb_data, &fd, NULL);
2304          DPRINTF(("FileMoveCopy: FileOpPipeCB -> fd = %d\n", fd));
2305
2306          /*
2307           * If the background process is done, FileOpPipeCB sets fd
2308           * to zero (in case of success) or -1 (in case of failure).
2309           */
2310          if (fd <= 0)
2311          {
2312             operation_done = (fd == 0);
2313             break;
2314          }
2315       }
2316    }
2317
2318    return operation_done;
2319 }
2320
2321
2322 /*--------------------------------------------------------------------
2323  * FileMoveCopy, FileMoveCopyDesktop
2324  *   External entry points for invoking _FileMoveCopy
2325  *------------------------------------------------------------------*/
2326
2327 Boolean
2328 FileMoveCopy(
2329         FileMgrData *file_mgr_data,
2330         char *to_file,
2331         char *directory,
2332         char *host,
2333         char **host_set,
2334         char **file_set,
2335         int file_count,
2336         unsigned int modifiers,
2337         void (*finish_callback)(),
2338         XtPointer callback_data)
2339 {
2340    return _FileMoveCopy( (XtPointer)file_mgr_data, to_file, directory, host,
2341                          host_set, file_set, NULL, file_count, modifiers, NULL,
2342                          finish_callback, callback_data);
2343 }
2344
2345
2346 Boolean
2347 FileMoveCopyDesktop(
2348       FileViewData *file_view_data,
2349       char * directory,
2350       char ** host_set,
2351       char ** file_set,
2352       int file_count,
2353       unsigned int modifiers,
2354       DesktopRec *desktopWindow,
2355       void (*finish_callback)(),
2356       XtPointer callback_data)
2357 {
2358   return _FileMoveCopy ((XtPointer)file_view_data,
2359                         NULL,
2360                         directory,
2361                         home_host_name,
2362                         host_set,
2363                         file_set,
2364                         NULL,
2365                         file_count,
2366                         modifiers,
2367                         desktopWindow,
2368                         finish_callback,
2369                         callback_data);
2370 }
2371
2372
2373 /*====================================================================
2374  *
2375  * ChangeIconName
2376  *     Run a background process to rename an object.
2377  *
2378  *==================================================================*/
2379
2380 /*--------------------------------------------------------------------
2381  * ChangeIconNameProcess:
2382  *     Main routine of the background process
2383  *------------------------------------------------------------------*/
2384
2385 static int
2386 ChangeIconNameProcess(
2387         int pipe_fd,
2388         char *host_name,
2389         char *directory_name,
2390         char *old_name,
2391         char *new_name)
2392 {
2393    char * full_name, * old_full_name, *dir_path;
2394    struct stat stat_buf;
2395    long modify_time;
2396    Boolean success;
2397    short pipe_msg;
2398    int rc;
2399    Tt_status tt_status;
2400
2401    /* Check for uniqueness */
2402    full_name = ResolveLocalPathName(host_name, directory_name, new_name, home_host_name, &tt_status);
2403    if ( TT_OK != tt_status )
2404    {
2405       DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2406       pipe_msg = PIPEMSG_FILEOP_ERROR;
2407       write(pipe_fd, &pipe_msg, sizeof(short));
2408       XtFree(new_name);
2409       return 1;
2410    }
2411
2412    if (lstat(full_name, &stat_buf) == 0)
2413    {
2414       /* Name is not unique */
2415       DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2416       pipe_msg = PIPEMSG_EXIST_ERROR;
2417       write(pipe_fd, &pipe_msg, sizeof(short));
2418
2419       XtFree(full_name);
2420       XtFree(new_name);
2421       return 1;
2422    }
2423
2424    /* send a modified message back through the pipe */
2425    modify_time = 0;
2426    dir_path = ResolveLocalPathName(host_name, directory_name, NULL, home_host_name, &tt_status);
2427    if( TT_OK != tt_status )
2428    {
2429       DPRINTF(("ChadengeIconNameProcess: sending exist error\n"));
2430       pipe_msg = PIPEMSG_FILEOP_ERROR;
2431       write(pipe_fd, &pipe_msg, sizeof(short));
2432       XtFree(full_name);
2433       XtFree(new_name);
2434       return 1;
2435    }
2436
2437    if (stat(dir_path, &stat_buf) == 0)
2438       modify_time = stat_buf.st_mtime;
2439    XtFree(dir_path);
2440
2441    /* rename the file */
2442    old_full_name = ResolveLocalPathName(host_name, directory_name, old_name, home_host_name, &tt_status);
2443    if( TT_OK != tt_status )
2444    {
2445      DPRINTF(("ChangeIconNameProcess: sending exist error\n"));
2446      pipe_msg = PIPEMSG_FILEOP_ERROR;
2447      write(pipe_fd, &pipe_msg, sizeof(short));
2448      XtFree(full_name);
2449      XtFree(new_name);
2450      return 1;
2451    }
2452    success = FileManip((Widget) (intptr_t) pipe_fd, MOVE_FILE, old_full_name, full_name, TRUE,
2453                        FileOpError, True, NOT_DESKTOP);
2454    XtFree( old_full_name );
2455    /* send a 'done' msg through the pipe */
2456    rc = success? 0: -1;
2457    if (rc == 0)
2458    {
2459      pipe_msg = PIPEMSG_FILE_MODIFIED;
2460      write(pipe_fd, &pipe_msg, sizeof(short));
2461      write(pipe_fd, &modify_time, sizeof(long));
2462    }
2463    DPRINTF(("ChangeIconNameProcess: sending DONE, rc %d\n", rc));
2464    pipe_msg = PIPEMSG_DONE;
2465    write(pipe_fd, &pipe_msg, sizeof(short));
2466    write(pipe_fd, &rc, sizeof(int));
2467    if (rc == 0)
2468       PipeWriteString(pipe_fd, full_name);
2469    XtFree( full_name );
2470    return rc;
2471 }
2472
2473
2474 /*--------------------------------------------------------------------
2475  * ChangeIconPipeCB:
2476  *   Read and process data sent through the pipe.
2477  *------------------------------------------------------------------*/
2478
2479 static void
2480 ChangeIconPipeCB(
2481    XtPointer client_data,
2482    int *fd,
2483    XtInputId *id)
2484 {
2485    ChangeIconCBData *cb_data = (ChangeIconCBData *)client_data;
2486    FileViewData *file_view_data = cb_data->file_view_data;
2487    DesktopRec *desktopWindow = cb_data->desktopWindow;
2488
2489    Widget msg_widget;
2490    DirectorySet *directory_set;
2491    FileMgrData *file_mgr_data = NULL;
2492    FileMgrRec *file_mgr_rec;
2493    short pipe_msg;
2494    int i, j, n;
2495    int rc;
2496    char *title, *err_msg, *err_arg;
2497    long modify_time;
2498    char *full_name;
2499    char *tmpStr;
2500    XmString label;
2501    Arg args[3];
2502    Boolean desktop_changed;
2503
2504    /* get widget for error messages */
2505    if (cb_data->desktop)
2506    {
2507       msg_widget = XtParent(cb_data->w);
2508    }
2509    else
2510    {
2511       directory_set = (DirectorySet *)file_view_data->directory_set;
2512       file_mgr_data = (FileMgrData *)directory_set->file_mgr_data;
2513       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
2514       msg_widget = file_mgr_rec->file_window;
2515    }
2516
2517    /* read the msg from the pipe */
2518    pipe_msg = -1;
2519    n = PipeRead(*fd, &pipe_msg, sizeof(short));
2520    DPRINTF(("ChangeIconPipeCB: n %d, pipe_msg %d\n", n, pipe_msg));
2521
2522    if (pipe_msg == PIPEMSG_FILE_MODIFIED)
2523    {
2524       /* get modify time */
2525       PipeRead(*fd, &modify_time, sizeof(long));
2526
2527       /* mark the old & new files as modified in the directory cache */
2528       if (modify_time != 0)
2529          DirectoryModifyTime(cb_data->host_name, cb_data->directory_name,
2530                              modify_time);
2531       DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2532                             cb_data->old_name);
2533       DirectoryFileModified(cb_data->host_name, cb_data->directory_name,
2534                             cb_data->new_name);
2535       return;
2536    }
2537
2538    if (pipe_msg == PIPEMSG_EXIST_ERROR)
2539    {
2540       /* Name is not unique */
2541       title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2542       if (cb_data->desktop)
2543       {
2544          tmpStr = GETMESSAGE(28,10, "An object with this name already exists in the original folder\n(The folder this object came from).\nPlease choose a different name.");
2545          err_msg = XtNewString(tmpStr);
2546       }
2547       else
2548          err_msg = XtNewString(GETMESSAGE(9,9, "A file with this name already exists.\nPlease choose a different name."));
2549
2550       _DtMessage (msg_widget, title, err_msg, NULL, HelpRequestCB);
2551       XtFree(title);
2552       XtFree(err_msg);
2553    }
2554
2555    else if (pipe_msg == PIPEMSG_FILEOP_ERROR)
2556    {
2557       /* the rename failed */
2558       PipeRead(*fd, &rc, sizeof(int));
2559       err_msg = PipeReadString(*fd);
2560       err_arg = PipeReadString(*fd);
2561       FileOperationError(msg_widget, err_msg, err_arg);
2562       XtFree(err_msg);
2563       XtFree(err_arg);
2564    }
2565
2566    else if (pipe_msg == PIPEMSG_DONE)
2567    {
2568       /* get the return code */
2569       PipeRead(*fd, &rc, sizeof(int));
2570       if (rc == 0)
2571       {
2572          /* the rename was successful */
2573          full_name = PipeReadString(*fd);
2574
2575          /* All went well, destroy the text field */
2576          XtUnmanageChild(cb_data->w);
2577          XtDestroyWidget(cb_data->w);
2578
2579          /* Force the icon label to be updated immediately */
2580          if (cb_data->desktop)
2581          {
2582             XmProcessTraversal(desktopWindow->iconGadget, XmTRAVERSE_CURRENT);
2583             desktopWindow->text = NULL;
2584             /* we'll catch this icon label in the loop after the else */
2585          }
2586          else
2587          {
2588             file_mgr_data->renaming = NULL;
2589
2590             label = XmStringCreateLocalized(cb_data->new_name);
2591             XtSetArg(args[0], XmNstring, label);
2592             XtSetValues(file_view_data->widget, args, 1);
2593             XmStringFree(label);
2594             XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2595             XmUpdateDisplay (file_mgr_rec->file_window);
2596
2597             /*
2598              * To prevent the positional data from becoming disassociated with
2599              * this file, we need to change the name in the positional data
2600              * structure also.
2601              */
2602             for (i = 0; i < file_mgr_data->num_objects; i++)
2603             {
2604                if (strcmp(cb_data->old_name,
2605                           file_mgr_data->object_positions[i]->name) == 0)
2606                {
2607                   /* Found a match */
2608                   XtFree(file_mgr_data->object_positions[i]->name);
2609                   file_mgr_data->object_positions[i]->name =
2610                                              XtNewString(cb_data->new_name);
2611                   break;
2612                }
2613             }
2614          }
2615
2616          /*
2617           * Check all desktop windows to see if they were linked to
2618           * the file we just renamed.  If so, we need to change the
2619           * link in .dt/Desktop that points to it.
2620           *
2621           * Note: We could do this in a background process, but we assume
2622           * that .dt/Desktop is local or, if it's remote and the remote server
2623           * is down, the user is screwed anyway.  So we assume it's ok to do
2624           * blocking operations on .dt/Desktop in the main process.
2625           * Hence we go for the simpler solution here.
2626           */
2627          desktop_changed = False;
2628          for (i = 0; i < desktop_data->numIconsUsed; i++)
2629          {
2630             desktopWindow = desktop_data->desktopWindows[i];
2631
2632             if (strcmp(cb_data->host_name, desktopWindow->host) == 0 &&
2633                 strcmp(cb_data->directory_name, desktopWindow->dir_linked_to) == 0
2634                 && strcmp(cb_data->old_name, desktopWindow->file_name) == 0)
2635             {
2636                XmString label;
2637
2638                /* Force the icon label to be updated immediately */
2639                label = XmStringCreateLocalized(cb_data->new_name);
2640                XtSetArg(args[0], XmNstring, label);
2641                XtSetValues(desktopWindow->iconGadget, args, 1);
2642                XmStringFree(label);
2643
2644                XtFree(desktopWindow->file_name);
2645                desktopWindow->file_name = XtNewString(cb_data->new_name);
2646
2647                XtFree(desktopWindow->file_view_data->file_data->file_name);
2648                desktopWindow->file_view_data->file_data->file_name =
2649                                            XtNewString(cb_data->new_name);
2650                if( strcmp( desktopWindow->title, cb_data->old_name ) == 0 )
2651                {
2652                  XtFree( desktopWindow->title );
2653                  desktopWindow->title = XtNewString( cb_data->new_name );
2654                }
2655 #ifdef SHAPE
2656                GenerateShape(desktopWindow);
2657 #endif
2658                RegisterIconDropsDT(desktopWindow);
2659                XmUpdateDisplay (desktopWindow->iconGadget);
2660
2661                desktop_changed = True;
2662             }
2663          }
2664
2665          if (desktop_changed)
2666          {
2667             SaveDesktopInfo(NORMAL_RESTORE);
2668             CheckDesktop();
2669          }
2670
2671          XtFree(full_name);
2672       }
2673    }
2674    else
2675       fprintf(stderr, "Internal error in ChangeIconPipeCB: bad pipe_msg %d\n",
2676               pipe_msg);
2677
2678    /* arrange for the modified directory to be updated */
2679    DirectoryEndModify(cb_data->host_name, cb_data->directory_name);
2680
2681    /* close the pipe and cancel the callback */
2682    close(*fd);
2683    XtRemoveInput(*id);
2684
2685    /* free callback data */
2686    XtFree(cb_data->host_name);
2687    XtFree(cb_data->directory_name);
2688    XtFree(cb_data->old_name);
2689    XtFree(cb_data->new_name);
2690    XtFree((char *)cb_data);
2691 }
2692
2693
2694 /*--------------------------------------------------------------------
2695  * _ChangeIconName:
2696  *    Start the background process and set up callback for the pipe.
2697  *------------------------------------------------------------------*/
2698
2699 static void
2700 _ChangeIconName (
2701    Widget w,
2702    Boolean desktop,
2703    FileViewData *file_view_data,
2704    DesktopRec *desktopWindow,
2705    char *host_name,
2706    char *directory_name)
2707 {
2708    static char *pname = "_ChangeIconName";
2709    ChangeIconCBData *cb_data;
2710    Arg args[3];
2711    char *input_name;
2712    char *new_name;
2713    char *old_name;
2714    char *title;
2715    char *msg;
2716    char *tmpStr;
2717    int i, j;
2718    int pipe_fd[2];
2719    int pid;
2720    int rc;
2721    int dirNameLength = strlen (directory_name);
2722    int maxFileNameLength = pathconf (directory_name, _PC_NAME_MAX);
2723    int length;
2724
2725
2726    /* get the new name */
2727    XtSetArg(args[0], XmNvalue, &input_name);
2728    XtSetArg(args[1], XmNuserData, &old_name);
2729    XtGetValues(w, args, 2);
2730
2731    new_name = (char *)_DtStripSpaces(XtNewString(input_name));
2732    length = strlen (new_name);
2733
2734
2735    /* new name must be a simple name, no path */
2736    msg = NULL;
2737    if (DtStrchr (new_name, '/') != NULL)
2738       msg = XtNewString(GetSharedMessage(LOCAL_RENAME_ONLY_ERROR));
2739 #ifdef _CHECK_FOR_SPACES
2740    else if (DtStrchr (new_name, ' ') != NULL ||
2741             DtStrchr (new_name, '\t') != NULL)
2742    {
2743       msg = XtNewString(GetSharedMessage(NO_SPACES_ALLOWED_ERROR));
2744    }
2745 #endif
2746    else if (length == 0 || strcmp(new_name, old_name) == 0)
2747    {
2748       /* Noop; simply remove the text field */
2749       XmProcessTraversal(file_view_data->widget, XmTRAVERSE_CURRENT);
2750       XtFree(new_name);
2751       if (desktop )
2752       {
2753         UnpostDTTextField();
2754       }
2755       else
2756       {
2757          DirectorySet *directory_set =
2758             (DirectorySet *)file_view_data->directory_set;
2759          FileMgrData *file_mgr_data =
2760             (FileMgrData *)directory_set->file_mgr_data;
2761          FileMgrRec *file_mgr_rec =
2762             (FileMgrRec *)file_mgr_data->file_mgr_rec;
2763          file_mgr_rec->menuStates |= RENAME;
2764          UnpostTextField( file_mgr_data );
2765          file_mgr_data->renaming = NULL;
2766       }
2767       return;
2768    }
2769    /* Ensure the new name has length less than or equal to the maximum
2770       length that the system allows.
2771       If maxFileNameLength == -1 the file system is not supporting POSIX, use MAXNAMLEN
2772    */
2773    else if( maxFileNameLength < -1  || (  maxFileNameLength == -1 && ( length > MAXNAMLEN  || length + dirNameLength > MAX_PATH ) ) || ( maxFileNameLength > 0 && length > maxFileNameLength ) )
2774    {
2775      msg = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2776    }
2777
2778
2779    if (msg != NULL)
2780    {
2781       title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2782       _DtMessage (XtParent (w), title, msg, NULL, HelpRequestCB);
2783       XtFree(title);
2784       XtFree(msg);
2785       XtFree (new_name);
2786       return;
2787    }
2788
2789    /* Check to see if the file has a representitive on the Desktop.  */
2790    if (desktopWindow == NULL)
2791    {
2792       for (i = 0; i < desktop_data->numIconsUsed; i++)
2793       {
2794          if (strcmp(host_name,
2795                     desktop_data->desktopWindows[i]->host) == 0 &&
2796              strcmp(directory_name,
2797                     desktop_data->desktopWindows[i]->dir_linked_to) == 0 &&
2798              strcmp(old_name, desktop_data->desktopWindows[i]->
2799                                   file_view_data->file_data->file_name) == 0)
2800          {
2801             desktopWindow = desktop_data->desktopWindows[i];
2802             break;
2803          }
2804       }
2805    }
2806
2807    if (desktopWindow != NULL)
2808    {
2809       /*
2810        * There is a representation of this file on the desktop:
2811        * check if the there are any objects which match the new_name
2812        */
2813       for (j = 0; j < desktop_data->numIconsUsed; j++)
2814       {
2815          if (strcmp(new_name, desktop_data->desktopWindows[j]->
2816                          file_view_data->file_data->file_name) == 0)
2817          {
2818             title = XtNewString(GetSharedMessage(FILE_RENAME_ERROR_TITLE));
2819             if (desktop)
2820               tmpStr = GETMESSAGE(28,9, "An object with this name already exists on the Workspace.\nPlease choose a different name.");
2821             else
2822               tmpStr = GETMESSAGE(9,90, "Name Conflict.\nThis object is out on the Workspace back drop.\nAnother object on the back drop already has the name you\nare trying to enter.\nPlease choose a different name.");
2823             msg = XtNewString(tmpStr);
2824             _DtMessage(XtParent (w), title, msg, NULL, HelpRequestCB);
2825             XtFree(title);
2826             XtFree(msg);
2827             XtFree(new_name);
2828             return;
2829          }
2830       }
2831    }
2832
2833    /*
2834     * Now we are ready to start the background process
2835     * that does the actual rename.
2836     */
2837
2838    /* set up callback data */
2839    cb_data = XtNew(ChangeIconCBData);
2840    cb_data->w = w;
2841    cb_data->desktop = desktop;
2842    cb_data->file_view_data = file_view_data;
2843    cb_data->desktopWindow = desktopWindow;
2844    cb_data->host_name = XtNewString(host_name);
2845    cb_data->directory_name = XtNewString(directory_name);
2846    cb_data->old_name = XtNewString(old_name);
2847    cb_data->new_name = new_name;
2848
2849    /* mark the directory as being modified in the directory cache */
2850    DirectoryBeginModify(host_name, directory_name);
2851
2852    /* create a pipe */
2853    pipe(pipe_fd);
2854
2855    /* fork the process that does the actual work */
2856    pid = fork();
2857    if (pid == -1)
2858    {
2859        DirectoryAbortModify(host_name, directory_name);
2860        fprintf(stderr,
2861                 "%s: fork failed, ppid %d, pid %d: error %d=%s\n",
2862                 pname, getppid(), getpid(), errno, strerror(errno));
2863        return;
2864    }
2865
2866    if (pid == 0)
2867    {
2868       DBGFORK(("%s:  child forked, pipe %d\n", pname, pipe_fd[1]));
2869
2870       close(pipe_fd[0]);  /* child won't read from the pipe */
2871
2872       rc = ChangeIconNameProcess(pipe_fd[1], host_name, directory_name,
2873                                  old_name, new_name);
2874       close(pipe_fd[1]);
2875
2876       DBGFORK(("%s:  child exiting\n", pname));
2877
2878       exit(rc);
2879    }
2880
2881    DBGFORK(("%s:  forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
2882
2883
2884    /* parent: set up callback to get the pipe data */
2885    close(pipe_fd[1]);  /* parent won't write the pipe */
2886
2887    cb_data->child = pid;
2888
2889    XtAppAddInput(XtWidgetToApplicationContext(toplevel),
2890                  pipe_fd[0], (XtPointer)XtInputReadMask,
2891                  ChangeIconPipeCB, (XtPointer)cb_data);
2892 }
2893
2894
2895 void
2896 ChangeIconName (
2897    Widget w,
2898    XtPointer client_data,
2899    XmTextVerifyCallbackStruct * call_data)
2900 {
2901    int value, size, increment, page;
2902    Arg args[3];
2903    FileMgrData *file_mgr_data = (FileMgrData *)client_data;
2904    FileMgrRec  *file_mgr_rec = (FileMgrRec *) file_mgr_data->file_mgr_rec;
2905    DirectorySet *directory_set = (DirectorySet *)(file_mgr_data->renaming->directory_set);
2906
2907    if (call_data->reason == XmCR_MODIFYING_TEXT_VALUE ||
2908        call_data->reason == XmCR_MOVING_INSERT_CURSOR  )
2909    {
2910       int SWwidth;
2911          /* x1     - x value of the text widget with respect to scroll window
2912             x2,y2  - x,y values of the cursor position (new) w.r.t text widget
2913             x3,y3  - x,y values of the cursor position (previous) w.r.t textW
2914          */
2915       Position x1,x2,y2,x3,y3;
2916          /* width of the text widget */
2917       Dimension stringWidth;
2918
2919       XtSetArg(args[0],XmNx,&x1);
2920       XtGetValues(w,args,1);
2921
2922       if(XtIsManaged(file_mgr_rec->vertical_scroll_bar))
2923          SWwidth=(file_mgr_rec->scroll_window->core.width -
2924                         file_mgr_rec->vertical_scroll_bar->core.width);
2925       else
2926          SWwidth=file_mgr_rec->scroll_window->core.width;
2927
2928       XmTextFieldPosToXY(w,call_data->newInsert,&x2,&y2);
2929       XmTextFieldPosToXY(w,call_data->currInsert,&x3,&y3);
2930
2931       XtSetArg(args[0],XmNwidth,&stringWidth);
2932       XtGetValues(w,args,1);
2933 /*
2934       printf("\n  x2=%d x1=%d x3=%d\n",x2,x1,x3);
2935 */
2936          if ( (Dimension)(call_data->newInsert) <  stringWidth )
2937          {
2938                 if( XtIsManaged(file_mgr_rec->horizontal_scroll_bar) )
2939                 {
2940                     XmScrollBarGetValues( file_mgr_rec->horizontal_scroll_bar,
2941                                           &value, &size, &increment, &page);
2942                    /*
2943                      printf("\n value = %d",value);
2944                    */
2945                     /* case where cursor is moved forward */
2946                     if( (x2-x3) > 0)
2947                     {
2948                        int max=0;
2949                        XtSetArg (args[0], XmNmaximum, &max);
2950                        XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2951                        if(   (value < (max-size)) &&
2952                              ((x1+x2) - value > 0 ) &&
2953                              ( (Position)(((x1+x2) - value) +
2954                                  file_mgr_rec->vertical_scroll_bar->core.width) > (Position) SWwidth ) )
2955                        {
2956                                if( (value+(x2-x3)) > (max-size) )
2957                                  value = (max-size);
2958                                else
2959                                  value += (x2-x3);
2960                                XmScrollBarSetValues(
2961                                                      file_mgr_rec->horizontal_scroll_bar,
2962                                                      value, size, increment, page,True
2963                                                    );
2964                         }
2965                     }
2966                     /* case where cursor is moved in reverse direction */
2967                     else if( (x2-x3) < 0 )
2968                     {
2969                         int min=0;
2970                         XtSetArg (args[0], XmNminimum, &min);
2971                         XtGetValues ( file_mgr_rec->horizontal_scroll_bar, args, 1);
2972                         if( (value > min) && ((Position)(x1+x3) < (Position)(value+
2973                                        file_mgr_rec->vertical_scroll_bar->core.width)) )
2974                         {
2975                              if( (x2 <= 0)  || ((value - (x3-x2)) < min) )
2976                                 value = min;
2977                               else
2978                                 value -= (x3-x2);
2979                               XmScrollBarSetValues(file_mgr_rec->horizontal_scroll_bar,
2980                                                    value, size, increment, page,True
2981                                                   );
2982                         }
2983                     }
2984                 }
2985          }
2986       return;
2987       }
2988    _ChangeIconName (w, False, file_mgr_data->renaming, NULL,
2989                     file_mgr_data->host, directory_set->name);
2990 }
2991
2992
2993 void
2994 ChangeIconNameDT (
2995    Widget w,
2996    XtPointer client_data,
2997    XtPointer call_data)
2998 {
2999    DesktopRec * desktopWindow = (DesktopRec *)client_data;
3000
3001    _ChangeIconName (w, True, desktopWindow->file_view_data, desktopWindow,
3002                     desktopWindow->host, desktopWindow->dir_linked_to);
3003 }
3004
3005
3006 /*====================================================================
3007  *
3008  * MakeFile
3009  *      Run a background process to create a file or directory.
3010  *
3011  *==================================================================*/
3012
3013 /*--------------------------------------------------------------------
3014  *  GetTarget
3015  *    Build a host, directory, and file name path to be used as the
3016  *    destination of a create, copy or move operation.
3017  *------------------------------------------------------------------*/
3018
3019 void
3020 GetTarget(
3021         char *from_host,
3022         char *from_dir,
3023         char *new_name,
3024         char *to_host,
3025         char *to_dir,
3026         char *to_file)
3027 {
3028    char *ptr;
3029
3030    strcpy(to_host, from_host);
3031
3032    if (strncmp (new_name, "/", 1) == 0)
3033    {
3034      strcpy(to_dir, new_name);
3035    }
3036    else
3037    {
3038      if (strcmp(to_dir, "/") == 0)
3039        sprintf(to_dir, "%s%s", from_dir, new_name);
3040      else
3041        sprintf(to_dir, "%s/%s", from_dir, new_name);
3042    }
3043
3044    ptr = strrchr(to_dir, '/');
3045    *ptr = '\0';
3046    strcpy(to_file, ptr + 1);
3047 }
3048
3049
3050 /*--------------------------------------------------------------------
3051  * MakeFileProcess
3052  *   Main routine of background process for MakeFile
3053  *------------------------------------------------------------------*/
3054
3055 static int
3056 MakeFileProcess(
3057         int pipe_fd,
3058         char *to_host,
3059         char *to_dir,
3060         char *to_file,
3061         unsigned char type)
3062 {
3063    char *to;
3064    struct stat stat_buf;
3065    char *dir_path;
3066    long modify_time;
3067    short pipe_msg;
3068    int fnew;
3069    int rc;
3070    Tt_status tt_status;
3071
3072    /* assume success */
3073    rc = 0;
3074
3075    /* get the full name of the file/dir to be created */
3076    to = ResolveLocalPathName(to_host, to_dir, to_file, home_host_name, &tt_status);
3077    if (to == NULL)
3078       rc = EINVAL;
3079
3080    /* check if a file/dir with the same name already exists */
3081    else if (lstat (to, &stat_buf) == 0)
3082       rc = EEXIST;
3083
3084    /* now create the file/dir */
3085    else
3086    {
3087       /* send a modified message back through the pipe */
3088       modify_time = 0;
3089       dir_path = ResolveLocalPathName(to_host, to_dir, NULL, home_host_name, &tt_status);
3090       if (stat(dir_path, &stat_buf) == 0)
3091          modify_time = stat_buf.st_mtime;
3092       XtFree(dir_path);
3093
3094       pipe_msg = PIPEMSG_FILE_MODIFIED;
3095       write(pipe_fd, &pipe_msg, sizeof(short));
3096       write(pipe_fd, &modify_time, sizeof(long));
3097
3098       /* do the work */
3099       if (type == DtDIRECTORY)
3100       {
3101          if (mkdir (to, (int) DtFILE_DIR_CREATION_MASK) != 0)
3102             rc = errno;
3103       }
3104       else
3105       {
3106          unsigned int mode;
3107
3108          if (type == DtDATA)
3109             mode = DtFILE_DATA_CREATION_MASK;
3110          else
3111             mode = DtFILE_OTHER_CREATION_MASK;
3112
3113          if ((fnew = creat(to, (int) mode)) < 0)
3114             rc = errno;
3115          else
3116             close(fnew);
3117       }
3118    }
3119
3120    /* send a 'done' msg through the pipe */
3121    pipe_msg = PIPEMSG_DONE;
3122    DPRINTF(("MakeFileProcess: sending DONE, rc %d\n", rc));
3123    write(pipe_fd, &pipe_msg, sizeof(short));
3124    write(pipe_fd, &rc, sizeof(int));
3125    PipeWriteString(pipe_fd, to);
3126
3127    XtFree(to);
3128
3129    return rc;
3130 }
3131
3132
3133 /*--------------------------------------------------------------------
3134  * MakeFilePipeCB:
3135  *   Read and process data sent through the pipe.
3136  *------------------------------------------------------------------*/
3137
3138 static void
3139 MakeFilePipeCB(
3140    XtPointer client_data,
3141    int *fd,
3142    XtInputId *id)
3143 {
3144    MakeFileCBData *cb_data = (MakeFileCBData *)client_data;
3145    short pipe_msg;
3146    int n;
3147    long modify_time;
3148    char *full_name;
3149    int rc;
3150
3151    /* read the msg from the pipe */
3152    pipe_msg = -1;
3153    n = PipeRead(*fd, &pipe_msg, sizeof(short));
3154
3155    if (pipe_msg == PIPEMSG_FILE_MODIFIED)
3156    {
3157       /* get modify time */
3158       PipeRead(*fd, &modify_time, sizeof(long));
3159
3160       /* mark the file updated in the directory cache */
3161       if (modify_time != 0)
3162          DirectoryModifyTime(cb_data->to_host, cb_data->to_dir, modify_time);
3163       DirectoryFileModified(cb_data->to_host, cb_data->to_dir,
3164                             cb_data->to_file);
3165       return;
3166    }
3167
3168    if (pipe_msg == PIPEMSG_DONE)
3169    {
3170       PipeRead(*fd, &rc, sizeof(int));
3171       full_name = PipeReadString(*fd);
3172    }
3173    else
3174    {
3175       fprintf(stderr, "Internal error in MakeFilePipeCB: bad pipe_msg %d\n",
3176               pipe_msg);
3177       rc = -1;
3178       full_name = NULL;
3179    }
3180
3181    DPRINTF(("MakeFilePipeCB: n %d, pipe_msg %d, rc %d\n", n, pipe_msg, rc));
3182
3183    /* arrange for the modified directory to be updated */
3184    DirectoryEndModify(cb_data->to_host, cb_data->to_dir);
3185
3186    /* close the pipe and cancel the callback */
3187    close(*fd);
3188    XtRemoveInput(*id);
3189
3190    /* Store away the newly created file so we later on we can
3191       scroll to it.
3192    */
3193    {
3194      MakeFileDoneData * data = (MakeFileDoneData *)cb_data->callback_data;
3195      DialogCallbackStruct * call_struct = data->call_struct;
3196      FileMgrData * file_mgr_data = call_struct->file_mgr_data;
3197
3198      file_mgr_data->scrollToThisDirectory = cb_data->to_dir;
3199      file_mgr_data->scrollToThisFile = cb_data->to_file;
3200    }
3201
3202    /* call the callback routine */
3203    if (cb_data->finish_callback)
3204       (*cb_data->finish_callback)(cb_data->callback_data, full_name, rc);
3205
3206    /* free callback data */
3207    XtFree(full_name);
3208    XtFree(cb_data->to_host);
3209
3210    /* Don't free to_dir and to_file. We used this to remember
3211       which file so later on we can scroll to it.
3212    XtFree(cb_data->to_dir);
3213    XtFree(cb_data->to_file);
3214    */
3215
3216    XtFree((char *)cb_data);
3217 }
3218
3219
3220 /*--------------------------------------------------------------------
3221  * MakeFile:
3222  *    Start the background process and set up callback for the pipe.
3223  *------------------------------------------------------------------*/
3224
3225 void
3226 MakeFile(
3227         Widget w,
3228         char *host_name,
3229         char *directory_name,
3230         char *new_name,
3231         unsigned char type,
3232         void (*finish_callback)(),
3233         XtPointer callback_data)
3234 {
3235    static char *pname = "MakeFile";
3236    MakeFileCBData *cb_data;
3237    char to_host[MAX_PATH];
3238    char to_dir[MAX_PATH];
3239    char to_file[MAX_PATH];
3240    int pipe_fd[2];
3241    int pid;
3242    int rc;
3243
3244    /* get host & path of the target file */
3245    GetTarget(host_name, directory_name, new_name, to_host, to_dir, to_file);
3246
3247    /* mark the target directory as being modified in the directory cache */
3248    DirectoryBeginModify(to_host, to_dir);
3249
3250    /* parent: set up callback to get the pipe data */
3251    cb_data = XtNew(MakeFileCBData);
3252    cb_data->to_host = XtNewString(to_host);
3253    cb_data->to_dir = XtNewString(to_dir);
3254    cb_data->to_file = XtNewString(to_file);
3255    cb_data->finish_callback = finish_callback;
3256    cb_data->callback_data = callback_data;
3257
3258    /* create a pipe */
3259    pipe(pipe_fd);
3260
3261    /* fork the process that does the actual work */
3262    pid = fork();
3263    if (pid == -1)
3264    {
3265        DirectoryAbortModify(to_host, to_dir);
3266        fprintf(stderr,
3267                 "%s:  fork failed, ppid %d, pid %d: error %d=%s\n",
3268                 pname, getppid(), getpid(), errno, strerror(errno));
3269        return;
3270    }
3271
3272    if (pid == 0)
3273    {
3274       /* child process */
3275       DBGFORK(("%s:  child forked, pipe %d\n", pname, pipe_fd[1]));
3276
3277       close(pipe_fd[0]);  /* child won't read from the pipe */
3278
3279       rc = MakeFileProcess(pipe_fd[1], to_host, to_dir, to_file, type);
3280       close(pipe_fd[1]);
3281
3282       DBGFORK(("%s:  child exiting\n", pname));
3283
3284       exit(rc);
3285    }
3286
3287    DBGFORK(("%s:  forked child<%d>, pipe %d\n", pname, pid, pipe_fd[0]));
3288
3289    /* parent: set up callback to get the pipe data */
3290    close(pipe_fd[1]);  /* parent won't write the pipe */
3291
3292    cb_data->child = pid;
3293
3294    XtAppAddInput(XtWidgetToApplicationContext(toplevel),
3295                  pipe_fd[0], (XtPointer)XtInputReadMask,
3296                  MakeFilePipeCB, (XtPointer)cb_data);
3297 }
3298
3299
3300 /*=============================================================
3301  *
3302  * The following routines handle the creation of files from
3303  * buffers: MakeFilesFromBuffers and MakeFilesFromBuffersDT
3304  * follow
3305  *
3306  *=============================================================*/
3307
3308 Boolean
3309 MakeFilesFromBuffers(
3310                      FileMgrData *file_mgr_data,
3311                      char * directory,
3312                      char *host,
3313                      char **file_set,
3314                      char **host_set,
3315                      BufferInfo *buffer_set,
3316                      int num_of_buffers,
3317                      void (*finish_callback)(),
3318                      XtPointer callback_data)
3319 {
3320   return _FileMoveCopy ((XtPointer)file_mgr_data, NULL, directory, host,
3321                         host_set, file_set, buffer_set, num_of_buffers,
3322                         0, NULL, finish_callback, callback_data);
3323 }
3324
3325
3326 Boolean
3327 MakeFilesFromBuffersDT(
3328                      FileViewData *file_view_data,
3329                      char * directory,
3330                      char **file_set,
3331                      char **host_set,
3332                      BufferInfo *buffer_set,
3333                      int num_of_buffers,
3334                      DesktopRec *desktopWindow,
3335                      void (*finish_callback)(),
3336                      XtPointer callback_data)
3337 {
3338   return _FileMoveCopy ((XtPointer)file_view_data, NULL, directory,
3339                         home_host_name,
3340                         host_set, file_set, buffer_set, num_of_buffers,
3341                         0, desktopWindow, finish_callback, callback_data);
3342 }
3343
3344
3345 /*====================================================================
3346  *
3347  * CreateFileFromBuffer
3348  *     Routine to create a file from a buffer
3349  *
3350  *==================================================================*/
3351
3352
3353 static Boolean
3354 CreateFileFromBuffer(int    pipe_s2m,
3355                      char   *directory,
3356                      char   *fully_qualified_name,
3357                      void   *buffer,
3358                      int    size)
3359 {
3360   int fnew = -1;
3361   int rc=0;
3362   unsigned int mode;
3363   Boolean BufferIsExecutable=FALSE;
3364   char *err_msg, *err_arg, *tmpStr;
3365   char *format_str, *strerror_str;
3366   int format_param_len=20;
3367   int savedError = 0;
3368
3369
3370
3371
3372   /* Set the permissions depending if buffer is a */
3373   /* file or an execuatable                       */
3374   if (_DtIsBufferExecutable(buffer,size))
3375   {
3376    mode = S_IRUSR | S_IWUSR | S_IXUSR |
3377           S_IRGRP | S_IWGRP | S_IXGRP |
3378           S_IROTH | S_IWOTH | S_IXOTH;
3379   }
3380   else
3381   {
3382    mode = S_IRUSR | S_IWUSR |
3383           S_IRGRP | S_IWGRP |
3384           S_IROTH | S_IWOTH;
3385   }
3386
3387   /* Create the target file */
3388   if ((fnew = open(fully_qualified_name, O_CREAT| O_WRONLY, mode)) < 0)
3389   {
3390     DPRINTF(("CreateBufferFromFile: Could not create %s\n",
3391               fully_qualified_name));
3392     savedError = errno;
3393     rc = -1;
3394   }
3395   else
3396   {
3397     /* Write the buffer to the target file */
3398     if ((rc = write(fnew, buffer, size)) < 0 )
3399     {
3400       DPRINTF (("CreateBufferFromFile: Could not write buffer to %s\n",
3401                  fully_qualified_name));
3402       savedError=errno;
3403     }
3404     else
3405     {
3406       close(fnew);
3407       fnew = -1;
3408       DPRINTF (("CreateBuffeFromFile: Target file %s created\n",
3409                  fully_qualified_name));
3410     }
3411   }
3412
3413   if (fnew >= 0)
3414       close(fnew);
3415
3416 /* Handle errors */
3417   if (rc < 0)
3418   {
3419     switch (savedError)
3420     {
3421        case EACCES:
3422           tmpStr = GetSharedMessage(CANT_CREATE_ERROR);
3423           err_msg  = XtNewString(tmpStr);
3424           err_arg  = XtNewString(fully_qualified_name);
3425
3426           DPRINTF (("CreateBufferFromFile: EACCESS errno is %d\n",errno));
3427           break;
3428        default :
3429           err_msg = strerror(savedError);
3430           err_arg = NULL;
3431
3432           DPRINTF (("CreateBufferFromFile: %s\n", err_msg));
3433     } /* endswitch */
3434
3435     /* Write error message on pipe so */
3436     /* that the parent process will */
3437     /* display a dialog             */
3438     PipeWriteErrmsg(pipe_s2m, rc, err_msg, err_arg);
3439     if (err_msg) XtFree(err_msg);
3440     if (err_arg) XtFree(err_arg);
3441     return FALSE;
3442   }
3443   else
3444   {
3445     return TRUE;
3446   }
3447
3448 }
3449
3450 /*
3451  * DisplayDuplicateOpError - Used in FileOpPipeCallback when a duplicate
3452  * operation like move/copy/link a file onto the same file is performed,
3453  * this routine gets called and displays an error message.
3454  */
3455
3456 static void
3457 DisplayDuplicateOpError(
3458     FileOpCBData *cb_data,
3459     int index)
3460
3461 {
3462   char *msgptr = NULL,*err_msg = NULL,*title = NULL,*tchar;
3463   Widget dialogwidget;
3464
3465   if (cb_data->mode == MOVE_FILE)
3466   {
3467     if(cb_data->callback_data == NULL)
3468       if(initiating_view == NULL)
3469         return;
3470       else
3471       {
3472         title = XtCalloc(1,strlen(GETMESSAGE(9,73,"Move"))+
3473                 strlen(GETMESSAGE(9,94,"Error"))+5);
3474         tchar = XtNewString(GETMESSAGE(9,73,"Move"));
3475         sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3476         XtFree(tchar);
3477         err_msg = GETMESSAGE(11,135,"Cannot move object %s onto itself");
3478     }
3479   }
3480   else if (cb_data->mode == COPY_FILE)
3481   {
3482     title = XtCalloc(1,strlen(GETMESSAGE(9,72,"Copy"))+
3483                 strlen(GETMESSAGE(9,94,"Error"))+5);
3484     tchar = XtNewString(GETMESSAGE(9,72,"Copy"));
3485     sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3486     XtFree(tchar);
3487     if(cb_data->callback_data == NULL)
3488     {
3489         if(cb_data->file_mgr_data && cb_data->file_mgr_data->toolbox)
3490         {
3491             XtFree(title);
3492             return;
3493         }
3494         else
3495             err_msg = GETMESSAGE(11,136,"Cannot copy object %s onto itself");
3496     }
3497     else
3498     {
3499       err_msg = GETMESSAGE(11,45,"No Copy Operation performed on object %s.\nYou must change either the Destination Folder\nor the Name for Copy before a copy can be created");
3500     }
3501   }
3502   else
3503   {
3504     title = XtCalloc(1,strlen(GETMESSAGE(9,74,"Link"))+
3505                 strlen(GETMESSAGE(9,94,"Error"))+5);
3506     tchar = XtNewString(GETMESSAGE(9,74,"Link"));
3507     sprintf(title,"%s %s",tchar,GETMESSAGE(9,94,"Error"));
3508     XtFree(tchar);
3509     if(cb_data->callback_data == NULL)
3510     {
3511       err_msg = GETMESSAGE(11,137,"Cannot link object %s onto itself");
3512     }
3513     else
3514     {
3515       err_msg = GETMESSAGE(11,46,"No Link Operation performed on object %s.\nYou must change either the Destination Folder\nor the Name for Copy before a link can be created");
3516     }
3517   }
3518
3519   if (!err_msg)
3520   {
3521       XtFree(title);
3522       return;
3523   }
3524
3525   msgptr = XtCalloc(1,strlen(err_msg)+strlen(cb_data->updates[index].file)+10);
3526   sprintf(msgptr,err_msg,cb_data->updates[index].file);
3527
3528   if(cb_data->callback_data)
3529     dialogwidget  = ((RenameDoneData *)(cb_data->callback_data))->w;
3530   else
3531     dialogwidget  = toplevel;
3532   _DtMessage (dialogwidget,title, msgptr, NULL, HelpRequestCB);
3533   XtFree(msgptr);
3534   XtFree(title);
3535 }
3536
3537
3538
3539 /*==============================================================
3540  *
3541  *  appendErrorMessage
3542  *
3543  *  if "arg" is not null, "new" is assumed to include %s
3544  *  "message" is re-allocated and so will have a different
3545  *      address than when the function was called
3546  *
3547  *  usage:  errorMsg = appendErrorMessage(errorMsg,errStr,file);
3548  *
3549  *==============================================================
3550  */
3551
3552 static String
3553 appendErrorMessage(String message, String new, String arg)
3554 {
3555    String newMessage;
3556
3557    if (arg == NULL)
3558       newMessage = XtNewString(new);
3559    else
3560    {
3561       newMessage = XtMalloc(strlen(new) + strlen(arg) + 1);
3562       sprintf(newMessage,new,arg);
3563    }
3564
3565    if (message == NULL)
3566    {
3567       message = XtRealloc(message, (strlen(newMessage) + 2));
3568       *message = '\0';
3569    }
3570    else
3571       message = XtRealloc(message, (strlen(message) + strlen(newMessage) + 2));
3572
3573    strcat(message,newMessage);
3574    strcat(message,"\n");
3575
3576    XtFree(newMessage);
3577
3578    return message;
3579
3580 }  /* end appendErrorMessage */
3581
3582 static void
3583 DisplayErrorMessage(
3584   int pipe_s2m,
3585   char *errMsg,
3586   char *from,
3587   char *tdir)
3588 {
3589   char *localstr;
3590
3591   localstr = (char *) XtMalloc(strlen(errMsg)+strlen(from)+strlen(tdir) + 10 );
3592   sprintf(localstr,errMsg,tdir,from);
3593   PipeWriteErrmsg(pipe_s2m, -1, localstr, NULL);
3594   XtFree(localstr);
3595 }
3596 static Boolean
3597 IsInParentDir(
3598         char *source_path ,
3599         char *dest_path )
3600 {
3601    char filename [MAX_PATH];
3602    char *cptr;
3603    int slen = strlen(source_path);
3604
3605    if(slen > strlen(dest_path))
3606      return False;
3607    strcpy (filename, dest_path);
3608    cptr = strchr(&filename[slen-1],'/');
3609    if(cptr)
3610      *cptr = '\0';
3611    return ((strcmp(source_path,filename) == 0)?True:False);
3612 }