Merge branch 'master' of ssh://git.code.sf.net/p/cdesktopenv/code
[oweals/cde.git] / cde / programs / dtfile / SharedProcs.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 /* $XConsortium: SharedProcs.c /main/7 1996/10/03 14:01:42 drk $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           SharedProcs.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   Description:    Contains the set of functions which are of general
32  *                   use to all DT clients.
33  *
34  *   FUNCTIONS: BuildBufferFileName
35  *              RenameCollisions
36  *              RenameEntry
37  *              RetrieveAndUseNameTemplateInfo
38  *              SetBufferFileNames
39  *              _DtAddOneSubdialog
40  *              _DtBuildActionArgsWithDroppedBuffers
41  *              _DtBuildActionArgsWithDroppedFiles
42  *              _DtBuildActionArgsWithSelectedFiles
43  *              _DtBuildActionArgsWithDTSelectedFiles
44  *              _DtBuildFMTitle
45  *              _DtBuildPath
46  *              _DtChangeTildeToHome
47  *              _DtCheckAndFreePixmapData
48  *              _DtCheckForDataTypeProperty
49  *              _DtCompileActionVector
50  *              _DtCopyDroppedFileInfo
51  *              _DtDestroySubdialog
52  *              _DtDestroySubdialogArray
53  *              _DtDuplicateDialogNameList
54  *              _DtFollowLink
55  *              _DtFreeActionArgs
56  *              _DtFreeDroppedBufferInfo
57  *              _DtFreeDroppedFileInfo
58  *              _DtGenericDestroy
59  *              _DtGenericMapWindow
60  *              _DtGenericUpdateWindowPosition
61  *              _DtGetSelectedFilePath
62  *              _DtHideOneSubdialog
63  *              _DtIsBufferExecutable
64  *              _DtLoadSubdialogArray
65  *              _DtMappedCB
66  *              _DtPName
67  *              _DtPathFromInput
68  *              _DtResolveAppManPath
69  *              _DtRetrieveDefaultAction
70  *              _DtRetrievePixmapData
71  *              _DtSaveSubdialogArray
72  *              _DtSetDroppedBufferInfo
73  *              _DtSetDroppedFileInfo
74  *              _DtSpacesInFileNames
75  *              _DtStringsAreEquivalent
76  *
77  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
78  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
79  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
80  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
81  *
82  ****************************************************************************
83  ************************************<+>*************************************/
84
85 #include <sys/types.h>
86 #include <sys/stat.h>
87 #include <errno.h>
88 #include <fcntl.h>
89 #include <limits.h>
90 #include <stdio.h>
91 #include <time.h>
92 #include <pwd.h>
93 #include <ctype.h>
94
95 #include <Xm/Xm.h>
96 #include <Xm/XmP.h>
97 #include <Xm/VendorSEP.h>
98 #include <Xm/MessageB.h>
99 #include <Xm/RowColumn.h>
100 #include <Xm/MwmUtil.h>
101 #include <Xm/Protocols.h>
102 #include <X11/ShellP.h>
103 #include <X11/Shell.h>
104 #include <X11/Xatom.h>
105 /* Copied from Xm/BaseClassI.h */
106 extern XmWidgetExtData _XmGetWidgetExtData( 
107                         Widget widget,
108 #if NeedWidePrototypes
109                         unsigned int extType) ;
110 #else
111                         unsigned char extType) ;
112 #endif /* NeedWidePrototypes */
113
114 #include <Dt/DtP.h>
115 #include <Dt/Connect.h>
116 #include <Dt/DtNlUtils.h>
117 #include <Dt/Dts.h>
118 #include <Dt/Icon.h>
119 #include <Dt/IconP.h>
120 #include <Dt/IconFile.h>
121 #include <Dt/Action.h>
122 #include <Dt/Dnd.h>
123 #include <Dt/Utility.h>
124 #include <Dt/SharedProcs.h>
125
126 #include <Tt/tttk.h>
127
128 #include "Encaps.h"
129 #include "FileMgr.h"
130 #include "Desktop.h"
131 #include "Common.h"
132 #include "Main.h"
133 #include "SharedProcs.h"
134
135 extern char *pathcollapse();
136
137
138 /* Defines */
139 #define RW_ALL S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
140
141
142 /* Global controlling whether auto-positioning is enabled */
143 Boolean disableDialogAutoPlacement = False;
144
145
146 /********    Static Function Declarations    ********/
147
148 static void SetBufferFileNames (
149                         char **file_set,
150                         DtDndBuffer *buffers,
151                         int num_of_buffers) ;
152 static char * BuildBufferFileName (
153                         char *file_name,
154                         int postfix_index,
155                         void *buffer,
156                         int buffer_size) ;
157 static char * RetrieveAndUseNameTemplateInfo(
158                         void *buffer,
159                         int buffer_size,
160                         char *template_input) ;
161 static void RenameEntry(
162                         char **name,
163                         unsigned int addIndex) ;
164 static void RenameCollisions(
165                         char **list,
166                         int count) ;
167
168 /********    End Static Function Declarations    ********/
169
170
171 /************************************************************************
172  *
173  *  _DtPName
174  *      Returns the parent directory of its argument.
175  *      Does this by looking for the last "/" in the name, and
176  *      NULL'ing it out.
177  *
178  ************************************************************************/
179
180 char *
181 _DtPName(
182         register char *name )
183
184 {
185    register char * q;
186    static char pnam[MAXPATHLEN];
187    static char dot[] = ".";
188
189    strcpy(pnam, name);
190    q = strrchr(pnam, '/');
191
192    if (q == NULL)
193       q = pnam;
194    else if ((q == pnam) &&
195 #ifdef NLS16
196             (mblen(q, MB_CUR_MAX) == 1) &&
197 #endif
198             (*q == '/'))
199    {
200       q++;
201    }
202
203    *q = '\0';
204
205    return(pnam[0] ? pnam : dot);
206 }
207
208
209 /*
210  * Given a filename, follow it to the end of its link.  Returns NULL if
211  * a recursive symbolic link is found.
212  *
213  * Note, the path returned is a static buffer, and should not be freed by
214  * the calling function.
215  */
216
217 char *
218 _DtFollowLink (
219    char * path)
220 {
221    char link_path[MAXPATHLEN];
222    static char file[MAXPATHLEN];
223    int link_len;
224    char * end;
225    int history_count;
226    int history_size;
227    char ** history;
228    int i;
229
230    /* Used to check for symbolic link loops */
231    history_count = 0;
232    history_size = 100;
233    history = (char **)XtMalloc(sizeof(char *) * history_size);
234
235    strcpy(file, path);
236
237    while ((link_len = readlink(file, link_path, MAXPATHLEN)) > 0)
238    {
239       link_path[link_len] = '\0';
240
241       /* Force the link to be an absolute path, if necessary */
242       if (link_path[0] != '/')
243       {
244          /* Relative paths are relative to the current directory */
245          end = strrchr(file, '/') + 1;
246          *end = '\0';
247          strcat(file, link_path);
248       }
249       else
250          strcpy(file, link_path);
251
252       /* Check for a recursive loop; abort if found */
253       for (i = 0; i < history_count; i++)
254       {
255          if (strcmp(file, history[i]) == 0)
256          {
257             for (i = 0; i < history_count; i++)
258                XtFree(history[i]);
259             XtFree((char *)history);
260             history = NULL;
261             return(NULL);
262          }
263       }
264
265       /* Add to the history list */
266       if (history_count >= history_size)
267       {
268          history_size += 100;
269          history = (char **)XtRealloc((char *)history,
270                                       sizeof(char *) * history_size);
271       }
272       history[history_count++] = XtNewString(file);
273    }
274
275    /* Free up the history list */
276    for (i = 0; i < history_count; i++)
277       XtFree(history[i]);
278    XtFree((char *)history);
279    history = NULL;
280
281    return(file);
282 }
283
284
285 /************************************************************************
286  *
287  *  _DtStringsAreEquivalent
288  *      Compare two strings and return true if equal.
289  *      The comparison is on lower cased strings.  It is the callers
290  *      responsibility to ensure that test_str is already lower cased.
291  *
292  ************************************************************************/
293
294 Boolean
295 _DtStringsAreEquivalent(
296         register char *in_str,
297         register char *test_str )
298 {
299 #ifdef NLS16
300    wchar_t c1;
301    wchar_t c2;
302    int c1size, c2size;
303 #endif
304    register int i;
305    register int j;
306
307 #ifdef NLS16
308    if (is_multibyte)
309    {
310       for (;;)
311       {
312          /* Convert each character from multibyte to wide format */
313          c1size = mbtowc(&c1, in_str, MB_CUR_MAX);
314          c2size = mbtowc(&c2, test_str, MB_CUR_MAX);
315
316          /* No match, if the two characters have different byte counts */
317          if (c1size != c2size)
318             return(False);
319
320          /* Do case conversion only for single byte characters */
321          if (c1size == 1)
322          {
323             if (isupper((int) c1))
324                c1 = tolower((int) c1);
325          }
326
327          /* See if the two wide characters match */
328          if (c1 != c2)
329             return(False);
330
331          /* Are we at the end of the string? */
332          if (c1 == '\0')
333             return(True);
334
335          /* Keep comparing */
336          in_str += c1size;
337          test_str += c2size;
338       }
339    }
340    else
341 #endif
342    {
343       for (;;)
344       {
345          i = *in_str;
346          j = *test_str;
347
348          if (isupper (i)) i = tolower (i);
349          if (i != j) return (False);
350          if (i == 0) return (True);
351
352          in_str++;
353          test_str++;
354       }
355    }
356 }
357
358
359
360 void
361 _DtDuplicateDialogNameList (
362         char ** nameList,
363         char ** newNameList,
364         int newNameListSize,
365         int * nameCount )
366
367 {
368    int i;
369
370    /*  Get a copy of the name list to be used to build new name lists.  */
371    *nameCount = 0;
372    while (nameList[*nameCount] != NULL)
373    {
374       newNameList[*nameCount] = nameList[*nameCount];
375       (*nameCount)++;
376    }
377
378    /* NULL out any remaining array entries */
379    for (i = (*nameCount); i < newNameListSize; i++)
380       newNameList[i] = NULL;
381 }
382
383
384 void
385 _DtLoadSubdialogArray (
386         char ** nameList,
387         int    nameCount,
388         DialogData *** dialogArray,
389         int    dialogCount,
390         int    dialogId,
391         XrmDatabase dataBase,
392         int    firstId )
393
394 {
395    int i;
396    char number[10];
397
398    /* Load sub-dialogs */
399    nameList[nameCount] = number;
400    nameList[nameCount + 1] = NULL;
401
402    /* Get text annotation dialogs */
403    *dialogArray = (DialogData **) XtMalloc(sizeof(DialogData *) * dialogCount);
404
405    for (i = 0; i < dialogCount; i++)
406    {
407       sprintf(number, "%d", firstId);
408       (*dialogArray)[i] = _DtGetResourceDialogData(dialogId, dataBase, nameList);
409       firstId++;
410    }
411 }
412
413
414
415 void
416 _DtSaveSubdialogArray (
417         char ** nameList,
418         int    nameCount,
419         DialogData ** dialogArray,
420         int    dialogCount,
421         int    fd,
422         int    firstId )
423
424 {
425    int i;
426    char number[10];
427
428    nameList[nameCount] = number;
429    nameList[nameCount + 1] = NULL;
430
431    for (i = 0; i < dialogCount; i++)
432    {
433       sprintf(number, "%d", firstId);
434       _DtWriteDialogData(dialogArray[i], fd, nameList);
435       firstId++;
436    }
437 }
438
439
440 void
441 _DtDestroySubdialogArray (
442         DialogData ** dialogArray,
443         int    dialogCount )
444
445 {
446    int i;
447
448    for (i = 0; i < dialogCount; i++)
449    {
450       if (_DtIsDialogShowing(dialogArray[i]))
451          _DtHideDialog(dialogArray[i], False);
452
453       _DtFreeDialogData(dialogArray[i]);
454    }
455    XtFree((char *)dialogArray);
456 }
457
458
459 void
460 _DtDestroySubdialog (
461         DialogData * dialogData )
462
463 {
464    if (dialogData)
465    {
466       if (_DtIsDialogShowing(dialogData))
467          _DtHideDialog(dialogData, False);
468       _DtFreeDialogData(dialogData);
469    }
470 }
471
472
473 void
474 _DtHideOneSubdialog (
475         DialogData * dialogData,
476         DialogData *** dialogArray,
477         int         * dialogCountPtr )
478
479 {
480    int i, j;
481
482    for (i = 0; i < *dialogCountPtr; i++)
483    {
484       if (dialogData == (*dialogArray)[i])
485       {
486          for (j = i; j < (*dialogCountPtr) - 1; j++)
487             (*dialogArray)[j] = (*dialogArray)[j + 1];
488          break;
489       }
490    }
491
492    /*  Free or decrease the size of the dialog data list  */
493    (*dialogCountPtr)--;
494    if (*dialogCountPtr == 0)
495    {
496       XtFree((char *)*dialogArray);
497       *dialogArray = NULL;
498    }
499    else
500    {
501       *dialogArray = (DialogData **)
502          XtRealloc((char *)*dialogArray,
503                    sizeof(DialogData *) * (*dialogCountPtr));
504    }
505 }
506
507
508 void
509 _DtAddOneSubdialog (
510         DialogData * dialogData,
511         DialogData *** dialogArray,
512         int         * dialogCountPtr )
513
514 {
515    int count;
516
517    count = *dialogCountPtr;
518    (*dialogCountPtr)++;
519    (*dialogArray) = (DialogData **) XtRealloc((char *)(*dialogArray),
520                                   sizeof(DialogData *) * (*dialogCountPtr));
521    (*dialogArray)[count] = dialogData;
522 }
523
524
525 /*
526  * This function acts as a frontend to the encapsulator's map callback
527  * function.  If we are in the middle of a restore session, then we don't
528  * want the map callback to alter the placement of the dialog, so we will
529  * not call the encapsulator's function.
530  */
531
532 void
533 _DtMappedCB(
534          Widget w,
535          XtPointer client_data,
536          XtPointer call_data )
537 {
538    if (!disableDialogAutoPlacement)
539       _DtmapCB(w,client_data,call_data);
540
541    XtRemoveCallback(w, XmNpopupCallback, (XtCallbackProc)_DtMappedCB, client_data);
542 }
543
544
545 /*
546  * This is the generic function for registering the map callback.
547  */
548
549 void
550 _DtGenericMapWindow (
551      Widget parent,
552      XtPointer recordPtr)
553 {
554    GenericRecord * genericRecord = (GenericRecord *) recordPtr;
555
556    XtAddCallback (genericRecord->shell, XmNpopupCallback,
557                   (XtCallbackProc)_DtMappedCB, (XtPointer) parent);
558 }
559
560
561 /*
562  * This is the generic function for destroying a dialog widget hierarchy.
563  */
564
565 void
566 _DtGenericDestroy(
567         XtPointer recordPtr )
568
569 {
570    GenericRecord * genericRecord = (GenericRecord *) recordPtr;
571
572    XtDestroyWidget(genericRecord->shell);
573    XtFree((char *) genericRecord);
574 }
575
576
577 /*
578  * This is the generic function for updating the shell's x and y, to
579  * take the window manager border into consideration.
580  */
581
582 void
583 _DtGenericUpdateWindowPosition(
584         DialogData * dataPtr )
585
586 {
587    DialogInstanceData * genericData = (DialogInstanceData *) dataPtr->data;
588    GenericRecord * genericRecord;
589
590    /* Do nothing, if the dialog is not displayed */
591    if (genericData->displayed == True)
592    {
593       XmVendorShellExtObject vendorExt;
594       XmWidgetExtData        extData;
595       Window                 junkWindow;
596       int                    t_x, t_y;
597       Arg                    args[5];
598
599       genericRecord = (GenericRecord *)_DtGetDialogInstance(dataPtr);
600
601       XtSetArg(args[0], XmNwidth, &genericData->width);
602       XtSetArg(args[1], XmNheight, &genericData->height);
603       XtGetValues(genericRecord->shell, args, 2);
604
605       XTranslateCoordinates(XtDisplay(genericRecord->shell),
606                        XtWindow(genericRecord->shell),
607                        RootWindowOfScreen(XtScreen(genericRecord->shell)),
608                        0, 0, &t_x, &t_y,
609                        &junkWindow);
610       genericData->x = (Position) t_x;
611       genericData->y = (Position) t_y;
612
613       /* Modify x & y to take into account window mgr frames */
614       extData=_XmGetWidgetExtData(genericRecord->shell, XmSHELL_EXTENSION);
615       vendorExt = (XmVendorShellExtObject)extData->widget;
616       genericData->x -= vendorExt->vendor.xOffset;
617       genericData->y -= vendorExt->vendor.yOffset;
618    }
619 }
620
621
622 /*
623  * This is a function for building a path from directory and filename
624  * parameters.
625  */
626
627 void
628 _DtBuildPath(
629         char         *path,
630         char         *directory,
631         char         *fileName)
632
633 {
634   if (directory)
635   {
636     if (fileName)
637       sprintf(path, "%s/%s", directory, fileName);
638     else
639       sprintf(path, "%s", directory);
640   }
641   else
642   {
643     if (fileName)
644       sprintf(path, "%s", fileName);
645     else
646       sprintf(path, "%s", "");
647   }
648 }
649
650
651 /*
652  * This is a function for retrieving the pixmap data for a data type.
653  */
654
655 PixmapData *
656 _DtRetrievePixmapData(
657         char         *dataType,
658         char         *fileName,
659         char         *directory,
660         Widget        shell,
661         int           size)
662
663 {
664   PixmapData *pixmapData;
665   char path[MAXPATHLEN];
666   char *iconName;
667
668   pixmapData = (PixmapData *) XtMalloc(sizeof(PixmapData));
669   if (!pixmapData)
670     return NULL;
671
672   path[0] = 0x0;
673   _DtBuildPath(path, directory, fileName);
674
675   pixmapData->size = size;
676
677   /* retrieve host name */
678   pixmapData->hostPrefix = DtDtsDataTypeToAttributeValue(dataType,
679                                                          DtDTS_DA_DATA_HOST,
680                                                          NULL);
681
682   /*
683      retrieve instance icon name if one exists; otherwise, retrieve class
684      icon name
685   */
686   if (path[0] != 0x0)
687   {
688     pixmapData->instanceIconName = DtDtsDataTypeToAttributeValue(dataType,
689                                             DtDTS_DA_INSTANCE_ICON,
690                                             path);
691   }
692   else
693     pixmapData->instanceIconName = NULL;
694
695   if (pixmapData->instanceIconName == NULL)
696   {
697     pixmapData->iconName = DtDtsDataTypeToAttributeValue( dataType, 
698                                                           DtDTS_DA_ICON, NULL);
699     if( pixmapData->iconName == NULL )
700     {
701       if( strcmp( dataType, LT_DIRECTORY ) == 0 )
702         pixmapData->iconName = XtNewString( "DtdirB" );
703       else
704         pixmapData->iconName = XtNewString( "Dtdeflt" );
705     }
706   }
707   else
708   {
709     pixmapData->iconName = NULL;
710   }
711
712   /* retrieve icon file name */
713   if (pixmapData->size == LARGE)
714      pixmapData->iconFileName = _DtGetIconFileName(XtScreen(shell),
715                                                pixmapData->instanceIconName,
716                                                pixmapData->iconName,
717                                                pixmapData->hostPrefix,
718                                                DtMEDIUM);
719   else
720      pixmapData->iconFileName = _DtGetIconFileName(XtScreen(shell),
721                                                pixmapData->instanceIconName,
722                                                pixmapData->iconName,
723                                                pixmapData->hostPrefix,
724                                                DtTINY);
725
726   /* return pixmap data */
727   return(pixmapData);
728 }
729
730
731 /*
732  * This is a function for checking the size, etc of an icon pixmap and
733  * freeing the pixmap data for an icon.
734  */
735
736 void
737 _DtCheckAndFreePixmapData(
738         char         *dataType,
739         Widget        shell,
740         DtIconGadget  iconGadget,
741         PixmapData   *pixmapData)
742
743 {
744   Arg   args[1];
745
746   if (!pixmapData)
747     return;
748
749   /*
750      if there was an instance icon name; verify that the pixmap parameters
751      do not exceed system limits; if system limits are exceeded, retrieve
752      class icon name and set icon gadget image resource to this value
753   */
754   if (pixmapData->instanceIconName)
755   {
756
757     if(! pixmapData->iconFileName && iconGadget->icon.pixmap == 0)
758     { /* Try to get pixmap name
759       */
760       char * tmp, * ptr;
761
762       tmp = XtNewString( pixmapData->instanceIconName );
763       if( ptr = strrchr( tmp,'/' ) )
764         *(ptr) = 0;
765       XmeFlushIconFileCache( tmp );
766
767       if (pixmapData->iconFileName != NULL)
768          XtFree(pixmapData->iconFileName);
769       if (pixmapData->size == LARGE)
770         pixmapData->iconFileName = _DtGetIconFileName( XtScreen(shell),
771                                               pixmapData->instanceIconName,
772                                               NULL,
773                                               pixmapData->hostPrefix,
774                                               DtMEDIUM );
775       else
776         pixmapData->iconFileName = _DtGetIconFileName(XtScreen(shell),
777                                               pixmapData->instanceIconName,
778                                               NULL,
779                                               pixmapData->hostPrefix,
780                                               DtTINY);
781
782
783
784       XtSetArg(args[0], XmNimageName, pixmapData->iconFileName);
785       XtSetValues((Widget) iconGadget, args, 1);
786
787       XtFree( tmp );
788     }
789
790         
791
792     DtDtsFreeAttributeValue(pixmapData->instanceIconName);
793
794     if (iconGadget->icon.pixmap == 0                     ||
795         iconGadget->icon.pixmap_width == 0               ||
796         iconGadget->icon.pixmap_height == 0              ||
797         (Dimension)iconGadget->icon.pixmap_width > (Dimension)instanceWidth    ||
798         (Dimension)iconGadget->icon.pixmap_height > (Dimension)instanceHeight)
799     {
800
801       pixmapData->iconName = DtDtsDataTypeToAttributeValue(
802                                              dataType, 
803                                              DtDTS_DA_ICON, NULL);
804
805       /* retrieve icon file name */
806       if (pixmapData->iconFileName != NULL)
807       {
808          XtFree(pixmapData->iconFileName);
809          pixmapData->iconFileName = NULL;
810       }
811
812       if (pixmapData->size == LARGE)
813             pixmapData->iconFileName = _DtGetIconFileName(XtScreen(shell),
814                                              pixmapData->instanceIconName,
815                                              pixmapData->iconName,
816                                              pixmapData->hostPrefix,
817                                              DtMEDIUM);
818       else
819             pixmapData->iconFileName = _DtGetIconFileName(XtScreen(shell),
820                                              pixmapData->instanceIconName,
821                                              pixmapData->iconName,
822                                              pixmapData->hostPrefix,
823                                              DtTINY);
824
825
826
827        XtSetArg(args[0], XmNimageName, pixmapData->iconFileName);
828        XtSetValues((Widget) iconGadget, args, 1);
829
830        DtDtsFreeAttributeValue(pixmapData->iconName);
831     }
832   }
833   else
834   {
835      DtDtsFreeAttributeValue(pixmapData->iconName);
836   }
837
838   DtDtsFreeAttributeValue(pixmapData->hostPrefix);
839   if (pixmapData->iconFileName)
840      XtFree(pixmapData->iconFileName);
841
842   XtFree((char *) pixmapData);
843 }
844
845
846 /*
847  * This is a function for checking for a datatype property.
848  */
849
850 Boolean
851 _DtCheckForDataTypeProperty(
852         char *dataType,
853         char *property)
854
855 {
856    char *properties;
857    char *prop;
858    char *props;
859    Boolean found = False;
860
861
862    properties = DtDtsDataTypeToAttributeValue(dataType,
863                                               DtDTS_DA_PROPERTIES,
864                                               NULL);
865
866    if (properties)
867    {
868      props = properties;
869      prop = props;
870      while (props = DtStrchr(props, ','))
871      {
872        *props = '\0';
873        if (strcmp(prop, property) == 0)
874        {
875          found = True;
876          break;
877        }
878        *props = ','; 
879        props++;
880        prop = props;
881      }
882
883      if (!props)
884      {
885        if (strcmp(prop, property) == 0)
886          found = True;
887      }
888
889      DtDtsFreeAttributeValue(properties);
890    }
891
892    return found;
893 }
894
895
896 /*
897  * This is a function for compiling a vectorized action list for a data type.
898  */
899
900 char **
901 _DtCompileActionVector(
902         char *dataType)
903
904 {
905    char *actions;
906    char **vector = NULL;
907
908    actions = DtDtsDataTypeToAttributeValue(dataType,
909                                            DtDTS_DA_ACTION_LIST,
910                                            NULL);
911    if (actions)
912      vector = (char **) _DtVectorizeInPlace(actions, ',');
913
914    return(vector);
915 }
916
917
918 /*
919  * This is a generic function for retrieving the default action for a data
920  * type.
921  */
922
923 char *
924 _DtRetrieveDefaultAction(
925         char *dataType)
926
927 {
928    char *actions;
929    char *acts;
930    char *default_action = NULL;
931
932    actions = DtDtsDataTypeToAttributeValue(dataType,
933                                            DtDTS_DA_ACTION_LIST,
934                                            NULL);
935    if (actions)
936    {
937      if (acts = DtStrchr(actions, ','))
938        *acts = '\0';
939      default_action = XtNewString(actions);
940
941      DtDtsFreeAttributeValue(actions);
942    }
943
944    return(default_action);
945 }
946
947
948 /*
949  * This is a function for building a title for a File Manager view.
950  */
951
952 char *
953 _DtBuildFMTitle(
954         FileMgrData *file_mgr_data )
955
956 {
957    char *title, *ptr, *fileLabel, *fileName;
958
959    if (fileLabel = DtDtsFileToAttributeValue(file_mgr_data->current_directory,
960                                              DtDTS_DA_LABEL))
961       ptr = fileLabel;
962    else if (fileName = strrchr(file_mgr_data->current_directory, '/'))
963       ptr = fileName + 1;
964    else
965       ptr = "";
966
967    if (file_mgr_data->title)
968    {
969       if (file_mgr_data->toolbox &&
970           strcmp(file_mgr_data->current_directory,
971                  file_mgr_data->restricted_directory) != 0)
972       {
973          title = (char *)XtMalloc(strlen(file_mgr_data->title) +
974                                   strlen(ptr) +
975                                   4); /* Need for blank dash blank NULL */
976          sprintf(title, "%s - %s", file_mgr_data->title, ptr);
977       }
978       else
979       {
980          title = XtNewString(file_mgr_data->title);
981       }
982    }
983    else
984    {
985       if (strcmp(file_mgr_data->current_directory, "/") == 0 && !fileLabel)
986       {
987          title = (char *)XtMalloc(strlen((GETMESSAGE(12, 7, "File Manager"))) +
988                                   strlen(file_mgr_data->host) +
989                                   strlen(root_title) +
990                                   5); /* Need for blank dash blank colon NULL */
991          sprintf( title, "%s - %s:%s", (GETMESSAGE(12, 7, "File Manager")),
992                                        file_mgr_data->host,
993                                        root_title );
994       }
995       else
996       {
997          title = (char *)XtMalloc(strlen((GETMESSAGE(12, 7, "File Manager"))) +
998                                   strlen(ptr) +
999                                   4); /* Need for blank dash blank NULL */
1000          sprintf( title, "%s - %s", (GETMESSAGE(12, 7, "File Manager")), ptr);
1001       }
1002    }
1003
1004    DtDtsFreeAttributeValue(fileLabel);
1005    return(title);
1006 }
1007
1008
1009 /*
1010  * This is a function for building a path from the directory name
1011  * and file name pieces of a FileViewData structure.
1012  */
1013
1014 char *
1015 _DtGetSelectedFilePath(
1016         FileViewData *selected_file )
1017
1018 {
1019    char *directory;
1020    char *file;
1021    char *path;
1022
1023    directory = ((DirectorySet *)selected_file->directory_set)->name;
1024    file = selected_file->file_data->file_name;
1025
1026    if (strcmp(directory, "/") == 0)
1027    {
1028       path = XtMalloc(strlen(directory) + strlen(file) + 1);
1029       sprintf(path, "%s%s", directory, file);
1030    }
1031    else
1032    {
1033       path = XtMalloc(strlen(directory) + strlen(file) + 2);
1034       sprintf(path, "%s/%s", directory, file);
1035    }
1036
1037    return(path);
1038 }
1039
1040
1041 /*
1042  * This is a generic function for building action parameters from an array of
1043  * file view data structures.
1044  */
1045
1046 void
1047 _DtBuildActionArgsWithSelectedFiles(
1048         FileViewData **selection_list,
1049         int selected_count,
1050         DtActionArg **action_args,
1051         int *arg_count )
1052
1053 {
1054    *arg_count = 0;
1055
1056    *action_args = (DtActionArg *)
1057                      XtCalloc(1, sizeof(DtActionArg) * selected_count);
1058
1059    if (*action_args)
1060    {
1061       int i;
1062
1063       for(i = 0; i < selected_count; i++)
1064       {
1065          ((*action_args)[(*arg_count)]).argClass = DtACTION_FILE;
1066          ((*action_args)[(*arg_count)++]).u.file.name =
1067                          _DtGetSelectedFilePath(selection_list[i]);
1068       }
1069    }
1070 }
1071
1072
1073 void
1074 _DtBuildActionArgsWithDTSelectedFiles(
1075         DesktopRec **selection_list,
1076         int selected_count,
1077         DtActionArg **action_args,
1078         int *arg_count )
1079
1080 {
1081    *arg_count = 0;
1082
1083    *action_args = (DtActionArg *)
1084                      XtCalloc(1, sizeof(DtActionArg) * selected_count);
1085
1086    if (*action_args)
1087    {
1088       int i;
1089
1090       for(i = 0; i < selected_count; i++)
1091       {
1092          ((*action_args)[(*arg_count)]).argClass = DtACTION_FILE;
1093          ((*action_args)[(*arg_count)++]).u.file.name =
1094                   _DtGetSelectedFilePath(selection_list[i]->file_view_data);
1095       }
1096    }
1097 }
1098
1099
1100 /*
1101  * This is a generic function for building action parameters from drag and drop
1102  * file information.
1103  */
1104
1105 void
1106 _DtBuildActionArgsWithDroppedFiles(
1107         FileViewData *dropped_on_obj,
1108         DtDndDropCallbackStruct *drop_parameters,
1109         DtActionArg **action_args,
1110         int *arg_count )
1111
1112 {
1113    *arg_count = 0;
1114
1115    if (dropped_on_obj)
1116       *action_args = (DtActionArg *) XtCalloc
1117         (1, sizeof(DtActionArg) * (drop_parameters->dropData->numItems + 1));
1118    else
1119       *action_args = (DtActionArg *) XtCalloc
1120         (1, sizeof(DtActionArg) * drop_parameters->dropData->numItems);
1121
1122    if (*action_args)
1123    {
1124       int i;
1125
1126       if (dropped_on_obj)
1127       {
1128          ((*action_args)[(*arg_count)]).argClass = DtACTION_FILE;
1129          ((*action_args)[(*arg_count)++]).u.file.name =
1130                          _DtGetSelectedFilePath(dropped_on_obj);
1131       }
1132
1133       for(i = 0; i < drop_parameters->dropData->numItems; i++)
1134       {
1135          ((*action_args)[(*arg_count)]).argClass = DtACTION_FILE;
1136          ((*action_args)[(*arg_count)++]).u.file.name =
1137                          XtNewString(drop_parameters->dropData->data.files[i]);
1138       }
1139    }
1140 }
1141
1142
1143 /*
1144  * This is a generic function for building action parameters from drag and drop
1145  * buffer information.
1146  */
1147
1148
1149 void
1150 _DtBuildActionArgsWithDroppedBuffers(
1151         FileViewData *dropped_on_obj,
1152         DtDndDropCallbackStruct *drop_parameters,
1153         DtActionArg **action_args,
1154         int *arg_count )
1155
1156 {
1157    *arg_count = 0;
1158
1159    if (dropped_on_obj)
1160       *action_args = (DtActionArg *) XtCalloc
1161         (1, sizeof(DtActionArg) * (drop_parameters->dropData->numItems + 1));
1162    else
1163       *action_args = (DtActionArg *) XtCalloc
1164         (1, sizeof(DtActionArg) * drop_parameters->dropData->numItems);
1165
1166    if (*action_args)
1167    {
1168       int i;
1169       DtActionBuffer buffer_arg = {NULL, 0, NULL, NULL, False};
1170
1171       if (dropped_on_obj)
1172       {
1173          ((*action_args)[(*arg_count)]).argClass = DtACTION_FILE;
1174          ((*action_args)[(*arg_count)++]).u.file.name =
1175                          _DtGetSelectedFilePath(dropped_on_obj);
1176       }
1177
1178       for(i = 0; i < drop_parameters->dropData->numItems; i++)
1179       {
1180          buffer_arg.bp = drop_parameters->dropData->data.buffers[i].bp;
1181          buffer_arg.size = drop_parameters->dropData->data.buffers[i].size;
1182          buffer_arg.name = drop_parameters->dropData->data.buffers[i].name;
1183
1184          ((*action_args)[(*arg_count)]).argClass = DtACTION_BUFFER;
1185          ((*action_args)[(*arg_count)++]).u.buffer = buffer_arg;
1186       }
1187    }
1188 }
1189
1190
1191 /*
1192  * This is a generic function for freeing action parameters.
1193  */
1194
1195 void
1196 _DtFreeActionArgs(
1197         DtActionArg *action_args,
1198         int arg_count )
1199
1200 {
1201    int i;
1202
1203    for (i = 0; i < arg_count; i++)
1204    {
1205       if (action_args[i].argClass == DtACTION_FILE)
1206       {
1207          XtFree(action_args[i].u.file.name);
1208          action_args[i].u.file.name = NULL;
1209       }
1210    }
1211    
1212    XtFree((char *) action_args);
1213 }
1214
1215
1216 /************************************************************************
1217  * The following functions deal with Buffer Manipulation and Naming
1218  ************************************************************************/
1219
1220 /*
1221  * This is a generic function for extracting buffer information from
1222  * drop input.
1223  */
1224
1225 void
1226 _DtSetDroppedBufferInfo(char **file_set,
1227               BufferInfo *buffer_set,
1228               char **host_set,
1229               DtDndDropCallbackStruct *drop_parameters)
1230
1231 {
1232
1233  int num_of_buffers = drop_parameters->dropData->numItems;
1234  int i;
1235  DtDndBuffer *buffers = drop_parameters->dropData->data.buffers;
1236
1237
1238  DPRINTF (("Executing..._DtSetDroppedBufferInfo\n"));
1239
1240  /* Initialize file_set and ensure of unique file names for unamed buffers*/
1241  SetBufferFileNames(file_set, buffers, num_of_buffers);
1242
1243  for (i= 0; i < num_of_buffers; i++)
1244   {
1245
1246      (buffer_set[i]).buf_ptr = buffers[i].bp;
1247      (buffer_set[i]).size    = buffers[i].size;
1248
1249      host_set[i] = XtNewString(home_host_name);
1250
1251      DPRINTF(("_DtSetDroppedBufferInfo:\n host_set[%d]=%s,\
1252               buffer_set[%d].buf_ptr=%p, buffer_set[%d].size=%d\n",
1253               i, host_set[i], i, buffer_set[i].buf_ptr, i, buffer_set[i].size));
1254   }
1255 }
1256
1257
1258 /*
1259  * This is a function for creating file names for a set of buffers.
1260  */
1261
1262 static void
1263 SetBufferFileNames (char **file_set,
1264                     DtDndBuffer *buffers,
1265                     int num_of_buffers)
1266 {
1267  int null_filenames_count = 0;
1268  int i;
1269  int first_nullfile_index = 0;
1270  Boolean NULL_FILENAMES=FALSE;
1271
1272  DPRINTF (("Executing...SetBufferFileNames\n"));
1273
1274  for (i = 0; i < num_of_buffers; i++)
1275  {
1276      if (buffers[i].name == NULL)
1277      {
1278        /* generate buffer name using Untitled as a base name */
1279        file_set[i]=BuildBufferFileName(DEFAULT_BUFFER_FILENAME,
1280                                        -1,
1281                                        buffers[i].bp,
1282                                        buffers[i].size);
1283      }
1284      else
1285      {
1286         /* file name is supplied by the drag initiator */
1287        file_set[i] = XtNewString(buffers[i].name);
1288      }
1289
1290      DPRINTF(("file_set[%d]=%s\n", i, file_set[i]));
1291
1292  } /* end for loop */
1293
1294
1295  /* Rename any collisions to unique names  */
1296  RenameCollisions(file_set, num_of_buffers);
1297
1298  return;
1299 }
1300
1301
1302 /*
1303  * This is a generic function for generating a name for an untitled buffer.
1304  * A default name (Untitled) is used in conjunction with the name template
1305  * information from the types database.
1306  */
1307
1308 static char *
1309 BuildBufferFileName (char   *file_name,
1310                      int     postfix_index,
1311                      void   *buffer,
1312                      int     buffer_size)
1313 {
1314   const char delim = '_';
1315   char *new_file_name;
1316
1317
1318   DPRINTF (("Executing....BuildBufferFileName\n"));
1319
1320   /* Malloc memory and contruct the new file name */
1321   new_file_name = (char *) XtMalloc (strlen(file_name) + 1 +
1322                                      MAX_POSTFIX_LENGTH  + 1);
1323
1324   DPRINTF (("BuildBufferFileName: Old file name is %s\n", file_name));
1325
1326   /* determine whether to append post fix name */
1327   if (postfix_index == -1)
1328      strcpy(new_file_name, file_name);
1329   else
1330      sprintf(new_file_name,"%s%c%d", file_name, delim, postfix_index);
1331
1332   /* Retrieve the name template if it exists and use it in the filename */
1333   new_file_name = RetrieveAndUseNameTemplateInfo(buffer,
1334                                                  buffer_size,
1335                                                  new_file_name);
1336
1337   DPRINTF(("BuildBufferFileName: Returning new_file_name=%s\n", new_file_name));
1338
1339   /* return new file name */
1340   return (new_file_name);
1341 }
1342
1343
1344
1345 /*
1346  * This is a function for building a buffer name using predfined input
1347  * and name template information from the types database.
1348  * WARNING: template_input will be freed. It must point to a char *.
1349  */
1350
1351 static char *
1352 RetrieveAndUseNameTemplateInfo(
1353         void *buffer,
1354         int buffer_size,
1355         char *template_input)
1356
1357 {
1358    char *name_template;
1359    char *buffer_name = NULL;
1360
1361    name_template = DtDtsBufferToAttributeValue(buffer,
1362                                                buffer_size,
1363                                                DtDTS_DA_NAME_TEMPLATE,
1364                                                NULL);
1365    if (name_template)
1366       buffer_name = (char *) XtMalloc(strlen(name_template) +
1367                                       strlen(template_input) +
1368                                        1);
1369    if (buffer_name)
1370    {
1371       sprintf(buffer_name, name_template, template_input);
1372       DtDtsFreeAttributeValue(name_template);
1373       XtFree(template_input);
1374       return(buffer_name);
1375    }
1376    else
1377    {
1378       return(template_input);
1379    }
1380 }
1381
1382
1383 /*
1384  * This is a function for resolving collisions in a list of buffer names.
1385  */
1386
1387 static void
1388 RenameCollisions( char ** list, int count )
1389 {
1390   register int i, j, k, l;
1391   char flg = 0, flg2 = 0;
1392
1393   for( i = 0; i < count; ++i )
1394   {
1395     unsigned int addIndex = 1;
1396
1397     if( *(list[i]) == 0x0 )
1398     {
1399       k = i;
1400       flg = 1;
1401     }
1402
1403     for( j = i+1; j < count; ++j )
1404     {
1405       if( strcmp( list[i], list[j] ) == 0 )
1406       {
1407         RenameEntry( &(list[j]), ++addIndex );
1408         l = i;
1409         flg2 = 1;
1410       }
1411     }
1412     if( flg2 )
1413     {
1414       flg2 = 0;
1415       RenameEntry( &(list[l]), 1 );
1416     }
1417   }
1418   if( flg )
1419   {
1420     free( list[k] );
1421     list[k] = (char *)malloc( strlen( DEFAULT_BUFFER_FILENAME ) + 1 );
1422     sprintf( list[k], "%s", DEFAULT_BUFFER_FILENAME );
1423   }
1424 }
1425
1426
1427 /*
1428  * This is a function for adding an index to a buffer name which has
1429  * collided.
1430  */
1431
1432 static void
1433 RenameEntry( char ** name, unsigned int addIndex )
1434 {
1435
1436 #define MAX_INT_SIZE 15
1437
1438 char * tmpPtr, * newName;
1439
1440   if( *name == 0x0 )
1441     return;
1442   else if( **name == 0x0 )
1443   {
1444     newName = (char *)XtCalloc(1,strlen(DEFAULT_BUFFER_FILENAME)+ MAX_INT_SIZE);
1445     sprintf( newName, "%s_%d", DEFAULT_BUFFER_FILENAME, addIndex );
1446   }
1447   else
1448   {
1449     tmpPtr = strrchr( *name, '.' );
1450
1451     newName = (char *)XtCalloc( 1, strlen( *name ) + MAX_INT_SIZE );
1452
1453     if( tmpPtr == NULL )
1454       sprintf( newName, "%s_%d", *name, addIndex );
1455     else if( tmpPtr == *name )
1456       sprintf( newName, "%d%s", addIndex, *name );
1457     else
1458     {
1459       *tmpPtr = 0x0;
1460       sprintf( newName, "%s_%d.%s", *name, addIndex, ++tmpPtr);
1461     }
1462   }
1463   free( *name );
1464   *name = newName;
1465 }
1466
1467
1468 /*
1469  * This is a generic function for freeing buffer information extracted from
1470  * drop input.
1471  */
1472
1473 void
1474 _DtFreeDroppedBufferInfo(char **file_set,
1475               BufferInfo *buffer_set,
1476               char **host_set,
1477               int num_of_buffers)
1478 {
1479   int i;
1480
1481   DPRINTF (("Executing..._DtFreeDroppedBufferInfo\n"));
1482
1483   /* Check for Null pointers */
1484   if (file_set && buffer_set && host_set )
1485   {
1486      for (i=0; i< num_of_buffers; i++ )
1487      {
1488        XtFree(file_set[i]);
1489        XtFree(host_set[i]);
1490      }
1491
1492      XtFree((char *)file_set);
1493      XtFree((char *)host_set);
1494      XtFree((char *)buffer_set);
1495   }
1496 }
1497
1498
1499 /*
1500  * This is a generic function for determining if a buffer is executable.
1501  */
1502
1503 Boolean
1504 _DtIsBufferExecutable(
1505         void *buffer,
1506         int buffer_size)
1507
1508 {
1509    char *exe_attribute;
1510    Boolean is_exe = False;
1511
1512    exe_attribute = DtDtsBufferToAttributeValue(buffer,
1513                                                buffer_size,
1514                                                "IS_EXECUTABLE",
1515                                                NULL);
1516    if (exe_attribute)
1517    {
1518       if (DtDtsIsTrue(exe_attribute))
1519          is_exe = True;
1520
1521       DtDtsFreeAttributeValue(exe_attribute);
1522    }
1523
1524    return(is_exe);
1525 }
1526
1527
1528 /*
1529  * This is a generic function for extracting file information from drop input.
1530  */
1531
1532 void
1533 _DtSetDroppedFileInfo(
1534         DtDndDropCallbackStruct *drop_parameters,
1535         char ***file_set,
1536         char ***host_set)
1537 {
1538    int numFiles, i;
1539
1540    numFiles = drop_parameters->dropData->numItems;
1541
1542    *file_set = (char **)XtMalloc(sizeof(char *) * numFiles);
1543    *host_set = (char **)XtMalloc(sizeof(char *) * numFiles);
1544    for(i = 0; i < numFiles; i++)
1545    {
1546       (*file_set)[i] = XtNewString(drop_parameters->dropData->data.files[i]);
1547       (*host_set)[i] = home_host_name;
1548
1549       DPRINTF(("ProcessMoveCopyLink:\n host_set[%d]=%s, file_set[%d]=%s\n",
1550                i, (*host_set)[i], i, (*file_set)[i]));
1551    }
1552 }
1553
1554
1555 /*
1556  * This is a generic function for copying file info extracted from drop input.
1557  */
1558
1559 void
1560 _DtCopyDroppedFileInfo(
1561         int num_files,
1562         char **orig_file_set,
1563         char **orig_host_set,
1564         char ***new_file_set,
1565         char ***new_host_set)
1566 {
1567    int i;
1568
1569    *new_file_set = (char **)XtMalloc(sizeof(char *) * num_files);
1570    *new_host_set = (char **)XtMalloc(sizeof(char *) * num_files);
1571    for(i = 0; i < num_files; i++)
1572    {
1573       (*new_file_set)[i] = XtNewString(orig_file_set[i]);
1574       (*new_host_set)[i] = XtNewString(orig_host_set[i]);
1575    }
1576 }
1577
1578
1579 /*
1580  * This is a generic function for freeing file info extracted from drop input.
1581  */
1582
1583 void
1584 _DtFreeDroppedFileInfo(
1585         int num_files,
1586         char **file_set,
1587         char **host_set)
1588 {
1589    int i;
1590
1591    for(i = 0; i < num_files; i++)
1592       XtFree(file_set[i]);
1593
1594    XtFree((char *)file_set);
1595    XtFree((char *)host_set);
1596 }
1597
1598
1599 /*
1600  * This is a generic function for resolving a cannonical path from user input.
1601  */
1602
1603 void
1604 _DtPathFromInput(
1605         char *input_string,
1606         char *current_dir,
1607         char **host,
1608         char **rel_path)
1609
1610 {
1611    char *path;
1612    char *tmp_path = NULL;
1613    char *true_path = NULL;
1614    Tt_status tt_status;
1615    int dir_len;
1616
1617    /* find host */
1618    *host = XtNewString(home_host_name);
1619
1620    /* find relative path */
1621    tmp_path = path = XtNewString(input_string);
1622
1623    /* Strip any spaces from name -- input is overwritten */
1624    path = (char *) _DtStripSpaces(path);
1625
1626    /* Resolve, if there're any, environment variables */
1627    {
1628       FILE *pfp;
1629       char command[MAXPATHLEN];
1630
1631       sprintf(command,"echo %s",path);
1632
1633       if((pfp=popen(command,"r")) != NULL)
1634       {
1635           int read_ok = 1;
1636
1637           if (NULL == (fgets(command,MAXPATHLEN,pfp))) 
1638           {
1639               /*
1640                * Try a few more reads and if the read still fails, 
1641                * just use the path as is.
1642                */
1643               int i;
1644               for (i=0; i < 5; i++) 
1645               {
1646                   sleep (1);
1647                   if (NULL != (fgets(command,MAXPATHLEN,pfp))) 
1648                       break;
1649              }
1650              if (i >= 5)
1651                  read_ok = 0;
1652          }
1653
1654          if (read_ok) 
1655          {
1656              command[strlen(command)-1] = '\0';
1657              XtFree(path);
1658              path = XtNewString(command);
1659              pclose(pfp);
1660          }
1661       }
1662    }
1663
1664    /* Resolve '~' -- new memory is allocated, old memory is freed */
1665    if (*path == '~')
1666       path = _DtChangeTildeToHome(path);
1667
1668    /* If current dir provided, check for relative path */
1669    if (path && current_dir)
1670    {
1671       if (*path != '/')
1672       {
1673          /* file is relative path i.e.      xyz/abc */
1674          if (strcmp(current_dir, "/") == 0)
1675          {
1676             tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 1);
1677             sprintf(tmp_path, "%s%s", current_dir, path);
1678          }
1679          else
1680          {
1681             tmp_path = (char *)XtMalloc(strlen(current_dir) + strlen(path) + 2);
1682             sprintf(tmp_path, "%s/%s", current_dir, path);
1683          }
1684
1685          XtFree(path);
1686          path = tmp_path;
1687          tmp_path = NULL;
1688       }
1689    }
1690    else if (!path)
1691    {
1692      *rel_path = NULL;
1693      XtFree(tmp_path);
1694      return;
1695    }
1696
1697    /* Resolve '.' or '..' -- input is overwritten, output may be NULL! */
1698    /* Save pointer to path to free if output is NULL.                  */
1699    tmp_path = path;
1700    path = (char *) DtEliminateDots(path);
1701
1702    if (path)
1703    {
1704       /* Resolve to local pathname */
1705       true_path = ResolveLocalPathName(*host,
1706                                        path,
1707                                        NULL,
1708                                        home_host_name,
1709                                        &tt_status);
1710       XtFree(path);
1711
1712       /* Strip off trailing '/' */
1713       dir_len = strlen(true_path);
1714       if (dir_len > 1 && *(true_path + dir_len - 1) == '/')
1715          *(true_path + dir_len - 1) = '\0';
1716    }
1717    else
1718    {
1719       true_path = NULL;
1720       XtFree(tmp_path);
1721    }
1722
1723    *rel_path = true_path;
1724 }
1725
1726
1727 /*
1728  * This function takes a path name, and resolves any leading '~' to refer
1729  * to one of the following:
1730  *
1731  *   1) if ~ or ~/path, then it resolves to the user's home directory on
1732  *      their home host.
1733  *
1734  *   2) if ~user or ~user/path, then it resolves to the specified user's
1735  *      home directory on the home host.
1736  *
1737  * This function never resolves to any host but the home host, since we
1738  * have no way of determining a user's home directory on any system other
1739  * than the home system.
1740  */
1741
1742 char *
1743 _DtChangeTildeToHome (
1744         char *input_string)
1745 {
1746    char *path;
1747    char *full_path;
1748    struct passwd * pwInfo;
1749
1750    if ((input_string[1] != '\0') && (input_string[1] != '/'))
1751    {
1752       char *path;
1753
1754       /* ~user or ~user/path format */
1755
1756       /* is there a path? */
1757       path = DtStrchr(input_string, '/');
1758
1759       /* find user */
1760       if (path)
1761          *path = '\0';
1762       if ((pwInfo = getpwnam(input_string + 1)) == NULL)
1763       {
1764          /* user doesn't exist */
1765          if (path)
1766             *path = '/';
1767          return NULL;
1768       }
1769
1770       if (path)
1771       {
1772          /* ~user/path format */
1773
1774          *path = '/';
1775
1776          if (strcmp(pwInfo->pw_dir, "/") == 0)
1777          {
1778             /* We don't want to end up with double '/' in the path */
1779             full_path = (char *) XtMalloc(strlen(path) + 1);
1780             strcpy(full_path, path);
1781          }
1782          else
1783          {
1784             full_path = (char *) XtMalloc(strlen(pwInfo->pw_dir) +
1785                                           strlen(path) + 1);
1786             sprintf(full_path, "%s%s", pwInfo->pw_dir, path);
1787          }
1788       }
1789       else
1790       {
1791          /* ~user format */
1792
1793          full_path = XtMalloc(strlen(pwInfo->pw_dir) + 1);
1794          strcpy(full_path, pwInfo->pw_dir);
1795       }
1796    }
1797    else if (input_string[1])
1798    {
1799       /* ~/path format */
1800
1801       /* NOTE: users_home_dir has trailing '/' */
1802       full_path = XtMalloc(strlen(users_home_dir) + strlen(input_string+2) + 1);
1803       sprintf(full_path, "%s%s", users_home_dir, (input_string + 2));
1804    }
1805    else
1806    {
1807       /* ~ format */
1808
1809       full_path = XtMalloc(strlen(users_home_dir) + 1);
1810       strcpy(full_path, users_home_dir);
1811    }
1812
1813    XtFree(input_string);
1814    return(full_path);
1815 }
1816
1817
1818 /*
1819  * This function checks for spaces in filenames.
1820  */
1821 #ifdef _CHECK_FOR_SPACES
1822
1823 Boolean
1824 _DtSpacesInFileNames(
1825          char **fileNames, 
1826          int  fileCount )
1827 {
1828   int i;
1829
1830   for (i = 0; i < fileCount; i++)
1831   {
1832      fileNames[i] = (char *) _DtStripSpaces(fileNames[i]);
1833
1834      if (DtStrchr (fileNames[i], ' ') != NULL ||
1835          DtStrchr (fileNames[i], '\t') != NULL)
1836         return(TRUE);
1837   }
1838
1839   return(FALSE);
1840 }
1841
1842 #endif
1843
1844 /*
1845  * This resolves the path for an appmanager object to its true path.
1846  */
1847
1848 char *
1849 _DtResolveAppManPath(
1850          char *path,
1851          char *restricted_dir )
1852 {
1853    if (strlen(path) > strlen(restricted_dir))
1854    {
1855       char *linkDir, *ptr, *tmpPath;
1856
1857       linkDir = path + strlen(restricted_dir) + 1;
1858       ptr = DtStrchr(linkDir, '/');
1859       if (ptr)
1860       {
1861          *ptr = '\0';
1862          linkDir = _DtFollowLink(path);
1863          *ptr = '/';
1864          tmpPath = XtMalloc(strlen(linkDir) + strlen(ptr) + 1);
1865          sprintf(tmpPath, "%s%s", linkDir, ptr);
1866          XtFree(path);
1867          path = tmpPath;
1868       }
1869       else
1870       {
1871          linkDir = _DtFollowLink(path);
1872          XtFree(path);
1873          path = XtNewString(linkDir);
1874       }
1875    }
1876
1877    return(path);
1878 }