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