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