Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtfile / dtcopy / sharedFuncs.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: sharedFuncs.c /main/9 1998/04/06 13:15:57 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           sharedFuncs.c
28  *
29  *
30  *   DESCRIPTION:    Common functions for both dtfile and dtfile_copy
31  *
32  *   FUNCTIONS: CreateDefaultImage
33  *              ImageInitialize
34  *              auto_rename
35  *              build_path
36  *              generate_NewPath
37  *              split_path
38  *
39  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
40  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
41  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
42  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
43  *
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 #if defined(SVR4)
48 #  include <sys/fs/ufs_fs.h>
49 #  define ROOTINO UFSROOTINO
50 #endif  /* SVR4 */
51
52 #if defined(__linux__) || defined(CSRG_BASED)
53 #  include <sys/param.h>
54 #  define ROOTINO 2
55 #endif
56
57
58 #include <string.h>
59 #include <sys/stat.h>
60 #include <stdio.h>
61 #include <errno.h>
62 #include <sys/types.h>
63 #include <sys/mount.h>
64 #include <pwd.h>
65 #include <fcntl.h>
66 #if !defined(CSRG_BASED) && !defined(__linux__)
67 #include <ustat.h>
68 #endif
69 #if defined(__linux__)
70 #include <sys/vfs.h>
71 #include <linux/magic.h>
72 #endif
73 #include <dirent.h>
74
75
76 #include <Xm/Xm.h>
77
78 #include <Xm/Form.h>
79 #include <Xm/PushB.h>
80
81 #include <Dt/Connect.h>
82 #include <Dt/DtNlUtils.h>
83 #include <Dt/SharedProcs.h>
84
85 #include "sharedFuncs.h"
86 #include "dtcopy.h"
87
88
89
90 /************************************************************************
91  *  Bitmap Data for Default Symbol
92  **********************************<->***********************************/
93
94 static unsigned char errorBits[] = {
95    0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0xf0, 0x3a, 0x00, 0x58, 0x55, 0x00,
96    0x2c, 0xa0, 0x00, 0x56, 0x40, 0x01, 0xaa, 0x80, 0x02, 0x46, 0x81, 0x01,
97    0x8a, 0x82, 0x02, 0x06, 0x85, 0x01, 0x0a, 0x8a, 0x02, 0x06, 0x94, 0x01,
98    0x0a, 0xe8, 0x02, 0x14, 0x50, 0x01, 0x28, 0xb0, 0x00, 0xd0, 0x5f, 0x00,
99    0xa0, 0x2a, 0x00, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
100
101 static unsigned char infoBits[] = {
102    0x00, 0x00, 0x78, 0x00, 0x54, 0x00, 0x2c, 0x00, 0x54, 0x00, 0x28, 0x00,
103    0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x2a, 0x00, 0x5c, 0x00, 0x28, 0x00,
104    0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00, 0x58, 0x00, 0x28, 0x00,
105    0x58, 0x00, 0xae, 0x01, 0x56, 0x01, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00};
106
107 static unsigned char questionBits[] = {
108    0xf0, 0x3f, 0x00, 0x58, 0x55, 0x00, 0xac, 0xaa, 0x00, 0xd6, 0x5f, 0x01,
109    0xea, 0xbf, 0x02, 0xf6, 0x7f, 0x01, 0xea, 0xba, 0x02, 0xf6, 0x7d, 0x05,
110    0xea, 0xba, 0x0a, 0x56, 0x7d, 0x15, 0xaa, 0xbe, 0x1e, 0x56, 0x5f, 0x01,
111    0xac, 0xaf, 0x02, 0x58, 0x57, 0x01, 0xb0, 0xaf, 0x00, 0x60, 0x55, 0x01,
112    0xa0, 0xaa, 0x00, 0x60, 0x17, 0x00, 0xa0, 0x2f, 0x00, 0x60, 0x17, 0x00,
113    0xb0, 0x2a, 0x00, 0x50, 0x55, 0x00};
114
115 static unsigned char warningBits[] = {
116    0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x56, 0x00, 0x2a, 0x00, 0x56, 0x00,
117    0x2a, 0x00, 0x56, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x2c, 0x00, 0x14, 0x00,
118    0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x14, 0x00,
119    0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00};
120
121 static unsigned char workingBits[] = {
122    0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xaa, 0xaa, 0x0a, 0x44, 0x55, 0x06,
123    0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x84, 0x15, 0x06,
124    0x8c, 0x2a, 0x02, 0x04, 0x15, 0x06, 0x0c, 0x0a, 0x02, 0x04, 0x06, 0x06,
125    0x0c, 0x0b, 0x02, 0x84, 0x15, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
126    0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06, 0xcc, 0x2a, 0x02, 0x44, 0x55, 0x06,
127    0xfe, 0xff, 0x0f, 0x56, 0x55, 0x05, 0x00, 0x00, 0x00};
128
129 Widget G_toplevel;
130 int    G_dialog_closed = FALSE;
131
132 /*----------------------------------------------------------
133  *
134  *  split_path
135  *
136  *  Given a path, return a pointer to the directory (folder)
137  *  and file (object). On error, both will be set to empty
138  *  strings.
139  *
140  *  The calling routine is responsible for allocating space
141  *  for object and folder.
142  *
143  *  This function simply searches for the last slash (/) in
144  *  the path and returns the characters preceding the slash
145  *  as folder and the characters after the last slash as
146  *  object. Thus, object could be a directory/folder or a
147  *  file.
148  *
149  *  There is a complimentary function, build_path, to put
150  *  object and folder back together to form a path.
151  *
152  *-----------------------------------------------------------*/
153
154 void
155 split_path(const String path, String folder, String object)
156
157 {
158
159    String lastSlash;
160
161    if ( (lastSlash = strrchr(path,'/')) != NULL)
162    {
163       strcpy(object,lastSlash+1);
164       if(lastSlash == path)  /* Must be root Folder */
165         strcpy(folder,"/");
166       else
167       {
168         *lastSlash = '\0';
169         strcpy(folder,path);
170         *lastSlash = '/';
171       }
172    }
173    else
174    {
175       folder[0] = object[0] = '\0';
176    }
177 }  /* end split_path */
178
179 char *
180 get_path(char *path)
181 {
182     char *rpath, tmppath[MAX_PATH];
183     char * _DtCopyPathFromInput();
184     if (!getcwd(tmppath,MAX_PATH))
185         return NULL;
186     rpath = _DtCopyPathFromInput(path,tmppath);
187     return rpath;
188 }
189
190 /*-----------------------------------------------------------------
191  *
192  *  build_path
193  *
194  *  Given a directory (folder) and file (object), build a string
195  *  with the complete path and return it.
196  *
197  *  The calling routine is responsible for freeing storage used
198  *  for the returned string.
199  *
200  *  There is a complimentary function, split_path, to take
201  *  path apart to form folder and object
202  *
203  *-----------------------------------------------------------------*/
204
205 String
206 build_path(const String folder, const String object)
207
208 {
209    char    s[MAX_PATH];
210    String  path;
211
212    strncpy(s, folder, MAX_PATH);
213    strncat(s, "/",    MAX_PATH-strlen(s));
214    strncat(s, object, MAX_PATH-strlen(s));
215    path = (String) malloc(strlen(s)+1);
216    strcpy(path,s);
217
218    return path;
219
220 }  /* end build_path */
221
222
223
224 /*--------------------------------------------------------------
225  *
226  *  auto_rename
227  *
228  *  Given a path, generate a new file name and rename the file.
229  *
230  *  The rc from the system call is returned and errno is set.
231  *
232  *--------------------------------------------------------------*/
233
234 int
235 auto_rename(const String path)
236
237 {
238    char newPath[MAX_PATH];
239
240    generate_NewPath(newPath,path);
241    errno = 0;
242    return (rename(path,newPath));
243
244 }  /* end auto_rename */
245
246
247 /*-----------------------------------------------------------------------
248  *
249  *  generate_NewPath
250  *
251  *  Given a path (and a complete path is required), append a
252  *  sequence number to generate a new file name. The new file
253  *  will not exist. The sequence number consists of a one-character
254  *  delimiter and an integer. The function will start with
255  *  1, if the file with 1 exists it will continue to 2, etc.
256  *  newPath and oldPath can point to the same area. The sequence number
257  *  is appended to the end of the name unless it contains a
258  *  dot, in which case the sequence number precedes the dot. For example,
259  *  /cde/dtfile/dtcopy/overwrtdialog.c becomes
260  *  /cde/dtfile/dtcopy/overwrtdialog~1.c. However, if the dot
261  *  is the first character in the file name, the sequence number is
262  *  appended, (e.g. .profile --> .profile~1).
263  *
264  *-----------------------------------------------------------------------*/
265
266 void
267 generate_NewPath(String newPath, String oldPath)
268
269 {
270
271    const char   delim = '_';
272
273    struct stat  buf;
274    String       lastDot, lastSlash;
275    char         firstPart[MAX_PATH], lastPart[MAX_PATH];
276    int          i = 0;
277    int          len;
278
279
280    lastDot   = strrchr(oldPath,'.');
281    lastSlash = strrchr(oldPath,'/');
282    if (lastSlash == NULL)
283       lastSlash = oldPath - 1;   /* allows for no path and first char is dot */
284    len = lastDot - oldPath;
285    if ( lastDot != NULL &&            /* no dot */
286         lastDot > lastSlash+1 &&      /* dot is in filename, not directory name */
287         len != strlen(oldPath)-1 )    /* dot is not last character of filename */
288    {
289       /* sequence number will be inserted before filename suffix */
290       memcpy(firstPart,oldPath,len);
291       firstPart[len] = '\0';
292       strcpy(lastPart,lastDot);
293    }
294    else
295    {
296       /* sequence number will be appended to filename */
297       strcpy(firstPart,oldPath);
298       lastPart[0] = '\0';
299    }
300
301
302    do
303    {
304       i++;
305       sprintf(newPath,"%s%c%d%s",firstPart,delim,i,lastPart);
306    } while (lstat(newPath,&buf) == 0);
307
308    return;
309
310
311 }  /* end generate_NewPath */
312
313
314 /****************************************************************
315  * Create a default images for symbol... used in ClassInitialize.
316  ****************/
317
318 XImage *
319 CreateDefaultImage(
320         Display *display,
321         char *bits,
322         unsigned int width,
323         unsigned int height )
324 {
325     XImage *image ;
326
327     image = XCreateImage(display,
328                          DefaultVisual(display, DefaultScreen(display)),
329                          1, XYBitmap, 0, bits, width, height, 8,
330                          (width+7) >> 3);
331     image->byte_order = LSBFirst;
332     image->bitmap_unit = 8;
333     image->bitmap_bit_order = LSBFirst;
334
335     return( image) ;
336 }  /* end CreateDefaultImage */
337
338
339
340 void
341 ImageInitialize( Display *display )
342 {
343     XImage *image;
344
345     /* create and install the default images for the symbol */
346
347     image = CreateDefaultImage (display, (char *)errorBits, 20, 20);
348     XmInstallImage (image, "default_xm_error");
349
350     image = CreateDefaultImage (display, (char *)infoBits, 11, 24);
351     XmInstallImage (image, "default_xm_information");
352
353     image = CreateDefaultImage (display, (char *)questionBits, 22, 22);
354     XmInstallImage (image, "default_xm_question");
355
356     image = CreateDefaultImage (display, (char *)warningBits, 9, 22);
357     XmInstallImage (image, "default_xm_warning");
358
359     image = CreateDefaultImage (display, (char *)workingBits, 21, 23);
360     XmInstallImage (image, "default_xm_working");
361
362     return ;
363 }  /*  end ImageInitialize */
364
365 static int
366 CopyCheckDeletePermissionRecur(
367   char *destinationPath)
368 {
369   struct stat statbuf;
370   DIR *dirp;
371   struct dirent * dp;
372   Boolean first_file;
373   char *fnamep;
374
375   DPRINTF(("CheckDeletePermissionRecur(\"%s\")\n", destinationPath));
376
377   if (lstat(destinationPath, &statbuf) < 0)
378     return -1;  /* probably does not exist */
379
380   if (! S_ISDIR(statbuf.st_mode))
381   {
382     if(access(destinationPath,04) < 0)
383        return -1;
384     return 0;   /* no need to check anything more */
385   }
386
387   dirp = opendir (destinationPath);
388   if (dirp == NULL)
389     return -1;  /* could not read directory */
390
391
392   first_file = True;
393
394   while (dp = readdir (dirp))
395   {
396     if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
397     {
398       if (first_file)
399       {
400         /* check for write permission in this directory */
401         if (access(destinationPath, 04|02|01) < 0)
402         {
403             closedir(dirp);
404             return -1;
405         }
406
407         /* append a '/' to the end of directory name */
408         fnamep = destinationPath + strlen(destinationPath);
409         *fnamep++ = '/';
410
411         first_file = False;
412       }
413
414       /* append file name to end of directory name */
415       strcpy(fnamep, dp->d_name);
416
417       /* recursively check permission on this file */
418       if (CopyCheckDeletePermissionRecur(destinationPath))
419         {
420             closedir(dirp);
421             return -1;
422         }
423     }
424   }
425
426   closedir(dirp);
427   return 0;
428 }
429
430 static int
431 CopyCheckDeletePermission(
432   char *parentdir,
433   char *destinationPath)
434 {
435 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
436   struct statfs statbuf;
437 #elif defined(__NetBSD__)
438   struct statvfs statbuf;
439 #else
440   struct stat statbuf;
441 #endif
442   char fname[PATH_MAX];
443
444 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
445   if (statfs(parentdir,&statbuf) < 0)  /* does not exist */
446 #elif defined(__NetBSD__)
447   if (statvfs(parentdir,&statbuf) < 0)  /* does not exist */
448 #else
449   if (lstat(parentdir,&statbuf) < 0)  /* does not exist */
450 #endif
451     return -1;
452
453   /* check if we are root */
454   if (getuid() == 0)
455   {
456     /* if NFS, need to check if server trusts root */
457 #if defined(CSRG_BASED)
458     if (!strcmp(statbuf.f_fstypename, "nfs"))  /* Root user and nfs */
459 #elif defined(__linux__)
460     if (statbuf.f_type == NFS_SUPER_MAGIC)
461 #else
462     /* nothing - always check if root */
463 #endif
464     {
465        char *tmpfile;
466        int rv;
467        tmpfile = tempnam(parentdir,"dtfile");
468        if (tmpfile)
469        {
470            /* Create a temporary file */
471            if ( (rv = creat(tmpfile,O_RDONLY)) < 0)
472            {
473                free(tmpfile);
474                return -1;
475            }
476            close(rv);
477            /* Delete the created file */
478            if (remove(tmpfile) < 0)
479            {
480                free(tmpfile);
481                return -1;
482            }
483
484            free(tmpfile);
485        }
486        else
487            return -1;
488     }
489
490     /* root user can delete anything */
491     return 0;
492   }
493
494   /* check for read/write and execute permission on parent dir */
495   if (access(parentdir, R_OK | W_OK | X_OK) < 0)
496       return -1;
497
498   /* copy destinationPath to tmp buffer */
499   strcpy(fname, destinationPath);
500
501   return CopyCheckDeletePermissionRecur(fname);
502 }
503
504 void
505 CloseTopLevel(
506      Widget w,
507      void *client_data,
508      void *call_data)
509 {
510   XtDestroyWidget((Widget)G_toplevel);
511   exit(-1);
512 }
513
514 void
515 CheckDeleteAccess(
516      XtAppContext app_context,
517      int delay,
518      Boolean checkPerms,
519      Boolean move,
520      char *source_name)
521 {
522   if(checkPerms && move)
523   {
524      char title[200],*msg,*tmpmsg;
525      char *tmpstring = strdup(source_name),*tmpptr;
526      XEvent event;
527      int perm_status = 0;
528
529      delay = 10000;
530      tmpptr = strrchr(tmpstring,'/');
531      if(!tmpstring || !tmpptr)                               /* Error */
532        perm_status = 1;
533      else
534      {
535        if(tmpptr == tmpstring)
536           tmpptr = "/";
537        else
538        {
539          *tmpptr = '\0';
540          tmpptr = tmpstring;
541        }
542        perm_status = CopyCheckDeletePermission(tmpptr,source_name);
543        free(tmpstring);
544        tmpstring = NULL;
545      }
546      if(!perm_status)  /* Everything is fine just return */
547      {
548          return;
549      }
550
551      free(tmpstring);
552
553      strcpy(title,GETMESSAGE(4,7,"Object Trash - Error"));
554      tmpmsg =  GETMESSAGE(4,8,"You do not have permission to put the object \n\n%s\n\ninto trash.\n\nUse the Change Permissions choice from the object's\npopup menu or from the Selected menu to turn on your\nRead permission on the object.\n\nNote: If this object is a folder, you must also have\nRead permission for each of the objects inside the\nfolder before you can put the folder in the trash.");
555
556      msg = XtMalloc(strlen(tmpmsg)+strlen(source_name)+2);
557      sprintf(msg,tmpmsg,source_name);
558      _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
559          CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
560 /*
561      XtAppAddTimeOut(app_context, delay, TimeoutHandler, NULL);
562 */
563
564     /* wait for user to close the dialog before exiting */
565      XtFree(msg);
566      while (!G_dialog_closed)
567      {
568          XtAppNextEvent(app_context, &event);
569          XtDispatchEvent(&event);
570      }
571   }
572 }
573
574 void
575 TimeoutHandler(XtPointer client_data, XtIntervalId *id)
576 {
577   exit(0);
578 }
579
580 /*
581  * This is a generic function for resolving a cannonical path from user input.
582  */
583
584 char *
585 _DtCopyPathFromInput(char *input_string, char *current_dir)
586 {
587     char *path = NULL;
588     char *tmp_path = NULL;
589     int dir_len;
590     char *_DtCopyChangeTildeToHome();
591
592     /* find relative path */
593
594     tmp_path = path = XtNewString(input_string);
595
596
597     /* Strip any spaces from name -- input is overwritten */
598     path = (char *) _DtStripSpaces(path);
599
600     /* Resolve, if there're any, environement variables */
601     {
602         FILE *pfp;
603         char command[MAX_PATH];
604
605         sprintf(command,"echo %s",path);
606         if((pfp=popen(command,"r")) == NULL)
607         {
608
609         }
610         else
611         {
612             if (fscanf(pfp,"%s",command) >= 1)
613             {
614                 XtFree(path);
615                 path = XtNewString(command);
616             }
617             else
618                 path = NULL;
619
620             pclose(pfp);
621         }
622     }
623
624     if (!path)
625         return NULL;
626
627     /* Resolve '~' -- new memory is allocated, old memory is freed */
628     if (*path == '~')
629         path = _DtCopyChangeTildeToHome(path);
630
631     /* If current dir provided, check for relative path */
632     if (path && current_dir)
633     {
634         if (*path != '/')
635         {
636             /* file is relative path i.e.      xyz/abc */
637             if (strcmp(current_dir, "/") == 0)
638             {
639                 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
640                 sprintf(tmp_path, "%s%s", current_dir, path);
641             }
642             else
643             {
644                 tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
645                 sprintf(tmp_path, "%s/%s", current_dir, path);
646             }
647
648             XtFree(path);
649             path = tmp_path;
650             tmp_path = NULL;
651         }
652     }
653     else if (!path)
654     {
655         XtFree(tmp_path);
656         return NULL;
657     }
658
659     /* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
660     /* Save pointer to path to free if output is NULL.                  */
661     tmp_path = path;
662     path = (char *) XeEliminateDots(path);
663
664     /* Strip off trailing '/' */
665     dir_len = strlen(path);
666     if (dir_len > 1 && *(path + dir_len - 1) == '/')
667         *(path + dir_len - 1) = '\0';
668     return path;
669 }
670 char *
671 #ifdef _NO_PROTO
672 _DtCopyChangeTildeToHome (input_string)
673     char *input_string;
674 #else
675     _DtCopyChangeTildeToHome (
676     char *input_string)
677 #endif
678 {
679     char *path;
680     char *full_path;
681     struct passwd * pwInfo;
682     char * homedir = (char *) XtNewString(getenv("HOME"));
683
684     if ((input_string[1] != '/'))
685     {
686         char *path;
687
688         /* ~user or ~user/path format */
689
690         /* is there a path? */
691         path = (char *) DtStrchr(input_string, '/');
692
693         /* find user */
694         if (path)
695             *path = '/';
696         if ((pwInfo = getpwnam(input_string + 1)) == NULL)
697         {
698             /* user doesn't exist */
699             if (path)
700                 *path = '/';
701             return NULL;
702         }
703
704         if (path)
705         {
706             /* ~user/path format */
707
708             *path = '/';
709
710             if (strcmp(pwInfo->pw_dir, "/") == 0)
711             {
712                 /* We don't want to end up with double '/' in the path */
713                 full_path = (char *) XtMalloc(strlen(path) + 1);
714                 strcpy(full_path, path);
715             }
716             else
717             {
718                 full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
719                                               strlen(path) + 1);
720                 sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
721             }
722         }
723         else
724         {
725             /* ~user format */
726
727             full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
728             strcpy(full_path, pwInfo->pw_dir);
729         }
730     }
731     else if (input_string[1])
732     {
733         /* ~/path format */
734
735         /* NOTE: users_home_dir has trailing '/' */
736         full_path = (char *) XtMalloc(strlen(homedir) + strlen(input_string+2) + 1);
737         sprintf(full_path, "%s%s", homedir, (input_string + 2));
738     }
739     else
740     {
741
742         /* ~ format */
743
744         full_path = XtMalloc(strlen(homedir) + 1);
745         strcpy(full_path, homedir);
746     }
747
748     XtFree(homedir);
749     XtFree(input_string);
750     return(full_path);
751 }
752
753 int
754 Check(char *spth, char *dpth, int mode)
755 {
756     struct stat sbuf, dbuf;
757     char filename [MAX_PATH];
758     char * msg;
759     char * tmpStr;
760     char title[300];
761
762     sbuf.st_ino = 0;
763     if (lstat (spth, &sbuf) < 0)
764     {
765         tmpStr = (GETMESSAGE(4,9, "Cannot open %s"));
766         msg = XtMalloc(strlen(tmpStr)+strlen(filename)+1);
767         sprintf(msg,tmpStr,filename);
768         _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
769                           CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
770         XtFree(msg);
771         return 0;
772     }
773     (void) strcpy (filename, dpth);
774     if(mode)
775         strcpy(title,GETMESSAGE(4,5,"Object Move - Error"));
776     else
777         strcpy(title,GETMESSAGE(4,6,"Object Copy - Error"));
778
779     dbuf.st_ino = 0;
780     while (dbuf.st_ino != ROOTINO)
781     {
782         /* Destination may not be available, in which case we need to
783            create it, so just return as successful and the remaining
784            code takes care of everything */
785
786         if (lstat (filename, &dbuf) < 0)
787             return 0;
788
789         if (dbuf.st_ino == sbuf.st_ino)
790         {
791             if(mode)
792                 tmpStr = GETMESSAGE(3,19,"Cannot move folder into itself. %s");
793             else
794                 tmpStr = GETMESSAGE(3,20,"Cannot copy folder into itself. %s");
795             msg = XtMalloc(strlen(tmpStr)+strlen(dpth)+1);
796             sprintf(msg,tmpStr,dpth);
797             _DtMessageDialog (G_toplevel, title, msg, 0, FALSE, NULL,
798                               CloseTopLevel, NULL, NULL, False, ERROR_DIALOG);
799
800             XtFree(msg);
801             return(1);
802         }
803
804         (void) strcat (filename, "/..");
805     }
806
807     return(0);
808 }