2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: DndFile.c /main/5 1998/04/09 17:48:19 mgreess $ */
24 /*********************************************************************
28 * Description: Implementation of the File Transfer routines
29 * for the DND Convenience API.
31 *********************************************************************
34 * RESTRICTED CONFIDENTIAL INFORMATION:
36 * The information in this document is subject to special
37 * restrictions in a confidential disclosure agreement between
38 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
39 * document outside HP, IBM, Sun, USL, SCO, or Univel without
40 * Sun's specific written approval. This documment and all copies
41 * and derivative works thereof must be returned or destroyed at
44 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
46 * (c) Copyright 1993, 1994 Hewlett-Packard Company
47 * (c) Copyright 1993, 1994 International Business Machines Corp.
48 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
49 * (c) Copyright 1993, 1994 Novell, Inc.
55 #include <sys/param.h>
56 #include <sys/types.h>
58 #include <X11/Intrinsic.h>
59 #include <Xm/AtomMgr.h>
61 #include <Xm/DropSMgr.h>
62 #include <Xm/DropTrans.h>
66 #include "DtSvcLock.h"
69 * File Transfer Protocol Function Prototypes
72 static void dndFileGetTargets(Boolean, Boolean, Atom**, Cardinal*);
73 static void dndFileGetAvailTargets(DtDragInfo*, Atom**, Cardinal*);
74 static void dndFileGetExportTargets(DtDragInfo*, Atom**, Cardinal*);
75 static void dndFileGetImportTargets(DtDropInfo*, Atom**, Cardinal*);
76 static void dndFileConvertInit(DtDragInfo*);
77 static Boolean dndFileConvert(Widget, DtDragInfo*, Atom*, Atom*,
78 Atom*, XtPointer*, unsigned long*, int*,
79 XSelectionRequestEvent*);
80 static void dndFileConvertFinish(DtDragInfo*);
81 static void dndFileTransferTargets(DtDropInfo*,
82 Atom*, Cardinal, Atom**, Cardinal*);
83 static void dndFileTransfer(Widget, DtDropInfo*, Atom*, Atom*, Atom*,
84 XtPointer, unsigned long*, int*);
85 static void dndFileTransferFinish(DtDropInfo*);
88 * File Transfer Support Functions
91 static Boolean dndFileContentsToSelectionValue(String,
92 Atom*, XtPointer*, unsigned long*, int*);
93 static Boolean dndFileListToSelectionValue(String*, Cardinal, Boolean,
94 Atom*, XtPointer*, unsigned long*, int*);
95 static Boolean dndSelectionValueToFileList(Atom, XtPointer, unsigned long, int,
96 Boolean, String**, Cardinal*);
97 static String dndFileEncode(String, Boolean);
98 static String dndFileDecode(String, Boolean);
101 * File Transfer Selection Targets
104 static Atom XA_FILE_NAME;
105 static Atom XA_DT_NETFILE;
108 * File Transfer Protocol Methods
111 static DtDndMethods dndFileTransferProtocol = {
112 "DtDndFileNameTransfer", /* name */
113 (DtDndProtocol)DtDND_FILENAME_TRANSFER, /* protocol */
114 DtDND_DRAG_SOURCE_DATA, /* sourceType */
115 dndFileGetAvailTargets, /* getAvailTargets */
116 dndFileGetExportTargets, /* getExportTargets */
117 dndFileGetImportTargets, /* getImportTargets */
118 dndFileConvertInit, /* convertInit */
119 dndFileConvert, /* convert */
120 dndFileConvertFinish, /* convertFinish */
121 dndFileTransferTargets, /* transferTargets */
122 dndFileTransfer, /* transfer */
123 dndFileTransferFinish, /* transferFinish */
126 typedef struct _ConvertState {
131 * File transfer protocol initialization
134 _DtDndFileTransferProtocolInitialize(
138 if (XA_FILE_NAME == 0) {
139 XA_FILE_NAME = DtGetAtom(dpy,"FILE_NAME");
140 XA_DT_NETFILE = DtGetAtom(dpy,"_DT_NETFILE");
143 _DtSvcProcessUnlock();
144 return &dndFileTransferProtocol;
148 * Returns generic export/import targets for filename transfers
155 Cardinal * numTargets)
159 *numTargets = 2 + (doHost ? 1 : 0) + (owCompat ? 4 : 0);
161 *targets = (Atom *)XtMalloc(*numTargets * sizeof(Atom));
163 (*targets)[ii++] = XA_DT_NETFILE;
164 (*targets)[ii++] = XA_FILE_NAME;
167 (*targets)[ii++] = XA_HOST_NAME;
171 (*targets)[ii++] = XA_TEXT;
172 (*targets)[ii++] = XA_STRING;
173 (*targets)[ii++] = XA_SUN_DATA_LABEL;
174 (*targets)[ii++] = XA_SUN_ATM_METHODS;
179 * Returns available targets for filename transfers
182 dndFileGetAvailTargets(
183 DtDragInfo * dtDragInfo,
184 Atom ** availTargets,
185 Cardinal * numAvailTargets)
187 dndFileGetTargets(True, True, availTargets, numAvailTargets);
191 * Returns export targets for filename transfers
194 dndFileGetExportTargets(
195 DtDragInfo * dtDragInfo,
196 Atom ** exportTargets,
197 Cardinal * numExportTargets)
199 dndFileGetTargets(True, False, exportTargets, numExportTargets);
203 * Returns import targets for filename transfers
206 dndFileGetImportTargets(
207 DtDropInfo * dtDropInfo,
208 Atom ** importTargets,
209 Cardinal * numImportTargets)
211 dndFileGetTargets(False, False, importTargets, numImportTargets);
215 * Initialize protocol specific part of drag data
219 DtDragInfo * dtDragInfo)
221 DtDndContext * dragData = dtDragInfo->dragData;
222 ConvertState * cvtState;
224 dragData->data.files = (String *)
225 XtMalloc(dragData->numItems * sizeof(String));
227 cvtState = (ConvertState *)XtCalloc(1,sizeof(ConvertState));
228 dtDragInfo->clientData = (XtPointer)cvtState;
232 * Convert the file names into selection data
237 DtDragInfo * dtDragInfo,
241 XtPointer * returnValue,
242 unsigned long * returnLength,
244 XSelectionRequestEvent * selectionRequestEvent)
246 DtDndContext * dragData = dtDragInfo->dragData;
247 ConvertState * cvtState = (ConvertState *)dtDragInfo->clientData;
249 *returnType = XA_NULL;
250 *returnValue = (XtPointer)NULL;
255 * Determine file encoding style.
256 * Handle Sun ATM file name.
257 * Reject unknown targets.
260 if (*target == XA_FILE_NAME || *target == XA_DT_NETFILE) {
262 if (!dndFileListToSelectionValue(
263 dragData->data.files, dragData->numItems,
264 (*target == XA_DT_NETFILE),
265 returnType, returnValue,
266 returnLength, returnFormat)) {
270 } else if (*target == XA_TEXT || *target == XA_STRING) {
272 if (dragData->numItems > 1 || !cvtState->owCompat)
275 if (!dndFileContentsToSelectionValue(dragData->data.files[0],
276 returnType, returnValue,
277 returnLength, returnFormat)) {
281 } else if (*target == XA_SUN_SELN_READONLY) {
283 cvtState->owCompat = True;
285 } else if (*target == XA_SUN_DATA_LABEL) {
288 if (dragData->numItems > 1)
291 if ((name = strrchr(dragData->data.files[0],'/')) != NULL)
294 name = dragData->data.files[0];
296 *returnType = XA_STRING;
297 *returnValue = (XtPointer)XtNewString(name);
298 *returnLength = strlen(*returnValue);
301 cvtState->owCompat = True;
303 } else if (*target == XA_SUN_ATM_METHODS) {
305 Atom *atmAtom = XtNew(Atom);
307 atmAtom[0] = XA_SUN_ATM_FILE_NAME;
309 *returnType = XA_ATOM;
310 *returnValue = (XtPointer)atmAtom;
314 cvtState->owCompat = True;
324 * Clean up from the convert init proc
327 dndFileConvertFinish(
328 DtDragInfo * dtDragInfo)
330 DtDndContext * dragData = dtDragInfo->dragData;
332 if (dragData->data.files) {
333 XtFree((char *)dragData->data.files);
334 dragData->data.files = NULL;
336 if (dtDragInfo->clientData)
337 XtFree((char *)dtDragInfo->clientData);
341 * Returns the transfer targets selected from the export targets
342 * Prefer _DT_NETFILE over FILE_NAME; prefer local host file names
345 dndFileTransferTargets(
346 DtDropInfo * dtDropInfo,
347 Atom * exportTargets,
348 Cardinal numExportTargets,
349 Atom ** transferTargets,
350 Cardinal * numTransferTargets)
352 Boolean foundNetFile, foundFileName, foundHostName;
356 foundNetFile = foundFileName = foundHostName = False;
358 for (ii = 0; ii < numExportTargets; ii++) {
359 if (exportTargets[ii] == XA_DT_NETFILE) {
361 } else if (exportTargets[ii] == XA_FILE_NAME) {
362 foundFileName = True;
363 } else if (exportTargets[ii] == XA_HOST_NAME) {
364 foundHostName = True;
368 if (foundNetFile && foundFileName && foundHostName) {
369 target = XA_HOST_NAME;
370 } else if (foundNetFile) {
371 target = XA_DT_NETFILE;
372 } else if (foundFileName) {
373 target = XA_FILE_NAME;
375 *numTransferTargets = 0;
376 *transferTargets = NULL;
380 *numTransferTargets = 1;
382 *transferTargets = (Atom *)XtMalloc(*numTransferTargets * sizeof(Atom));
384 (*transferTargets)[0] = target;
388 * Transfer the selection data into file names
393 DtDropInfo * dtDropInfo,
398 unsigned long * length,
401 DtDndContext * dropData = dtDropInfo->dropData;
404 * Ignore if we've already transferred
407 if (dropData->data.files) {
413 * If hosts are the same then request FILE_NAME else request NETFILE
415 if (*target == XA_HOST_NAME) {
418 if (strcmp(_DtDndGetHostName(),(char *)value) == 0)
419 target = XA_FILE_NAME;
421 target = XA_DT_NETFILE;
423 _DtDndTransferAdd(dropTransfer, dtDropInfo, &target, 1);
426 * Convert NETFILE or FILE_NAME selection to file list
428 } else if (*target == XA_DT_NETFILE || *target == XA_FILE_NAME) {
430 if (!dndSelectionValueToFileList(*type, value,
431 *length, *format, (*target == XA_DT_NETFILE),
432 &(dropData->data.files), &(dropData->numItems))) {
434 dtDropInfo->status = DtDND_FAILURE;
443 * Clean up from the transfer proc
446 dndFileTransferFinish(
447 DtDropInfo * dtDropInfo)
449 DtDndContext * dropData = dtDropInfo->dropData;
452 for (ii = 0; ii < dropData->numItems; ii++) {
453 XtFree((char *)dropData->data.files[ii]);
455 XtFree((char *)dropData->data.files);
459 * Convert the file contents into a STRING selection
462 dndFileContentsToSelectionValue(
465 XtPointer * returnValue,
466 unsigned long * returnLength,
472 unsigned long bufLen, bytesRead;
475 fullPath = dndFileEncode(fileName, False);
477 if (stat(fullPath,&stBuf) == -1)
480 if ((fd = open(fullPath, O_RDONLY)) == -1)
483 bufLen = stBuf.st_size;
484 buf = (void *)XtMalloc(bufLen + 1);
486 bytesRead = read(fd, buf, bufLen);
488 if (bytesRead == -1 || bytesRead != bufLen) {
495 *returnType = XA_STRING;
496 *returnValue = (XtPointer)buf;
497 *returnLength = bufLen;
506 * Convert the filename list into a STRING selection
509 dndFileListToSelectionValue(
514 XtPointer * returnValue,
515 unsigned long * returnLength,
518 XTextProperty textProp;
524 * Encode the file list
527 tmpList = (String *)XtMalloc(numFiles * sizeof(String));
529 for (ii = 0; ii < numFiles; ii++) {
530 tmpList[ii] = dndFileEncode(fileList[ii], doNetFile);
534 * Convert the encoded file list into a string property
537 status = XStringListToTextProperty(tmpList, numFiles, &textProp);
539 for (ii = 0; ii < numFiles; ii++) {
543 XtFree((char *)tmpList);
548 *returnType = textProp.encoding;
549 *returnValue = (XtPointer)textProp.value;
550 *returnLength = textProp.nitems;
551 *returnFormat = textProp.format;
557 * Convert the STRING selection into a filename list
560 dndSelectionValueToFileList(
563 unsigned long length,
566 String ** returnFileList,
567 Cardinal * returnNumFiles)
569 XTextProperty textProp;
576 * Convert text prop to file list
579 textProp.encoding = type;
580 textProp.value = (unsigned char *)value;
581 textProp.nitems = length;
582 textProp.format = format;
584 status = XTextPropertyToStringList(&textProp, &tmpList, &numFiles);
590 * Decode the file list
593 fileList = (String *)XtMalloc(numFiles * sizeof(String));
595 for (ii = 0; ii < numFiles; ii++) {
596 fileList[ii] = dndFileDecode(tmpList[ii], doNetFile);
599 XFreeStringList(tmpList);
601 *returnFileList = fileList;
602 *returnNumFiles = numFiles;
608 * Encodes a file name
609 * Either into ToolTalk NetFile or into a full path if needed
620 netFile = tt_file_netfile(fileName);
621 if (tt_ptr_error(netFile) == TT_OK) {
622 retFile = XtNewString(netFile);
624 retFile = XtNewString(fileName);
627 } else if (fileName[0] != '/') {
628 char cwd[MAXPATHLEN];
631 if (getcwd(cwd,MAXPATHLEN) == NULL) {
634 realPath = XtMalloc(strlen(cwd) + strlen(fileName) + 2);
635 sprintf(realPath,"%s/%s",cwd,fileName);
638 retFile = XtNewString(fileName);
644 * Decodes a file name; possibly from a ToolTalk NetFile
655 file = tt_netfile_file(fileName);
656 if (tt_ptr_error(file) == TT_OK) {
657 retFile = XtNewString(file);
659 retFile = XtNewString(fileName);
663 retFile = XtNewString(fileName);