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