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