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