~vcs-imports/gnome-vfs/main

209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
/* gnome-vfs-utils.c - Private utility functions for the GNOME Virtual
3
   File System.
4
5
   Copyright (C) 1999 Free Software Foundation
6
7
   The Gnome Library is free software; you can redistribute it and/or
8
   modify it under the terms of the GNU Library General Public License as
9
   published by the Free Software Foundation; either version 2 of the
10
   License, or (at your option) any later version.
11
12
   The Gnome Library is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
   Library General Public License for more details.
16
17
   You should have received a copy of the GNU Library General Public
18
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
19
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
   Boston, MA 02111-1307, USA.
21
22
   Author: Ettore Perazzoli <ettore@comm2000.it>
23
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
24
   `_gnome_vfs_canonicalize_pathname()' derived from code by Brian Fox and Chet
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
25
   Ramey in GNU Bash, the Bourne Again SHell.  Copyright (C) 1987, 1988, 1989,
26
   1990, 1991, 1992 Free Software Foundation, Inc.  */
27
28
#include <config.h>
1414 by darin
* acconfig.h:
29
#include "gnome-vfs-private-utils.h"
30
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
31
#include "gnome-vfs-utils.h"
1414 by darin
* acconfig.h:
32
#include "gnome-vfs-cancellation.h"
1565 by darin
Finished deprecating gnome-vfs-types.h.
33
#include "gnome-vfs-ops.h"
1480 by seth
2001-06-02 Seth Nickell <snickell@stanford.edu>
34
#include "gnome-vfs-uri.h"
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
35
#include <errno.h>
4425 by cosimoc
2008-12-06 Cosimo Cecchi <cosimoc@gnome.org>
36
#include <glib.h>
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
37
#include <gconf/gconf-client.h>
1414 by darin
* acconfig.h:
38
#include <stdlib.h>
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
39
#include <string.h>
40
#include <sys/types.h>
1565 by darin
Finished deprecating gnome-vfs-types.h.
41
#include <time.h>
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
42
#include <unistd.h>
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
43
#include <fcntl.h>
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
44
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
45
#ifndef G_OS_WIN32
46
#include <sys/socket.h>
47
#include <sys/wait.h>
48
#else
49
#include <winsock2.h>
50
#endif
51
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
52
#define GCONF_URL_HANDLER_PATH      	 "/desktop/gnome/url-handlers/"
53
#define GCONF_DEFAULT_TERMINAL_EXEC_PATH "/desktop/gnome/applications/terminal/exec"
54
#define GCONF_DEFAULT_TERMINAL_ARG_PATH  "/desktop/gnome/applications/terminal/exec_arg"
55
2243 by alexl
2003-04-02 Shailesh Mittal <shailesh.mittal@wipro.com>
56
/* Check whether the node is IPv6 enabled.*/
57
gboolean
3096 by teuf
2004-08-12 Ryan Lortie <desrt@desrt.ca>
58
_gnome_vfs_have_ipv6 (void)
2243 by alexl
2003-04-02 Shailesh Mittal <shailesh.mittal@wipro.com>
59
{
60
#ifdef ENABLE_IPV6
61
	int s;
62
63
	s = socket (AF_INET6, SOCK_STREAM, 0);
64
	if (s != -1) {
65
		close (s);
66
		return TRUE;
67
	}
68
69
#endif
70
	return FALSE;
71
}
72
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
73
static int
74
find_next_slash (const char *path, int current_offset)
75
{
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
76
	const char *match;
77
	
78
	g_assert (current_offset <= strlen (path));
79
	
80
	match = strchr (path + current_offset, GNOME_VFS_URI_PATH_CHR);
81
	return match == NULL ? -1 : match - path;
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
82
}
83
84
static int
85
find_slash_before_offset (const char *path, int to)
86
{
87
	int result;
88
	int next_offset;
89
90
	result = -1;
91
	next_offset = 0;
92
	for (;;) {
93
		next_offset = find_next_slash (path, next_offset);
94
		if (next_offset < 0 || next_offset >= to) {
95
			break;
96
		}
97
		result = next_offset;
98
		next_offset++;
99
	}
100
	return result;
101
}
102
103
static void
104
collapse_slash_runs (char *path, int from_offset)
105
{
106
	int i;
107
	/* Collapse multiple `/'s in a row. */
108
	for (i = from_offset;; i++) {
109
		if (path[i] != GNOME_VFS_URI_PATH_CHR) {
110
			break;
111
		}
112
	}
113
114
	if (from_offset < i) {
2512 by teuf
2003-10-20 Christophe Fergeau <teuf@gnome.org>
115
		memmove (path + from_offset, path + i, strlen (path + i) + 1);
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
116
		i = from_offset + 1;
117
	}
118
}
645 by mathieu
2000-07-21 Mathieu Lacage <set EMAIL_ADDRESS environment variable>
119
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
120
/* Canonicalize path, and return a new path.  Do everything in situ.  The new
121
   path differs from path in:
122
123
     Multiple `/'s are collapsed to a single `/'.
124
     Leading `./'s and trailing `/.'s are removed.
125
     Non-leading `../'s and trailing `..'s are handled by removing
126
     portions of the path.  */
127
gchar *
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
128
_gnome_vfs_canonicalize_pathname (gchar *path)
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
129
{
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
130
	int i, marker;
131
132
	if (path == NULL || strlen (path) == 0) {
133
		return "";
134
	}
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
135
136
	/* Walk along path looking for things to compact. */
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
137
	for (i = 0, marker = 0;;) {
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
138
		if (!path[i])
139
			break;
140
141
		/* Check for `../', `./' or trailing `.' by itself. */
142
		if (path[i] == '.') {
143
			/* Handle trailing `.' by itself. */
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
144
			if (path[i + 1] == '\0') {
145
				if (i > 1 && path[i - 1] == GNOME_VFS_URI_PATH_CHR) {
146
					/* strip the trailing /. */
147
					path[i - 1] = '\0';
148
				} else {
149
					/* convert path "/." to "/" */
150
					path[i] = '\0';
151
				}
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
152
				break;
153
			}
154
155
			/* Handle `./'. */
156
			if (path[i + 1] == GNOME_VFS_URI_PATH_CHR) {
2507 by teuf
2003-10-18 Christophe Fergeau <teuf@gnome.org>
157
				memmove (path + i, path + i + 2, 
2512 by teuf
2003-10-20 Christophe Fergeau <teuf@gnome.org>
158
					 strlen (path + i + 2) + 1);
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
159
				if (i == 0) {
160
					/* don't leave leading '/' for paths that started
161
					 * as relative (.//foo)
162
					 */
163
					collapse_slash_runs (path, i);
164
					marker = 0;
165
				}
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
166
				continue;
167
			}
168
169
			/* Handle `../' or trailing `..' by itself. 
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
170
			 * Remove the previous xxx/ part 
171
			 */
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
172
			if (path[i + 1] == '.'
173
			    && (path[i + 2] == GNOME_VFS_URI_PATH_CHR
174
				|| path[i + 2] == '\0')) {
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
175
176
				/* ignore ../ at the beginning of a path */
177
				if (i != 0) {
178
					marker = find_slash_before_offset (path, i - 1);
179
180
					/* Either advance past '/' or point to the first character */
181
					marker ++;
182
					if (path [i + 2] == '\0' && marker > 1) {
183
						/* If we are looking at a /.. at the end of the uri and we
184
						 * need to eat the last '/' too.
185
						 */
186
						 marker--;
187
					}
188
					g_assert(marker < i);
189
					
190
					if (path[i + 2] == GNOME_VFS_URI_PATH_CHR) {
191
						/* strip the entire ../ string */
192
						i++;
193
					}
194
2507 by teuf
2003-10-18 Christophe Fergeau <teuf@gnome.org>
195
					memmove (path + marker, path + i + 2,
2512 by teuf
2003-10-20 Christophe Fergeau <teuf@gnome.org>
196
						 strlen (path + i + 2) + 1);
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
197
					i = marker;
198
				} else {
199
					i = 2;
200
					if (path[i] == GNOME_VFS_URI_PATH_CHR) {
201
						i++;
202
					}
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
203
				}
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
204
				collapse_slash_runs (path, i);
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
205
				continue;
206
			}
207
		}
924 by pce
2000-10-18 Pavel Cisler <pavel@eazel.com>
208
		
209
		/* advance to the next '/' */
210
		i = find_next_slash (path, i);
211
212
		/* If we didn't find any slashes, then there is nothing left to do. */
213
		if (i < 0) {
214
			break;
215
		}
216
217
		marker = i++;
218
		collapse_slash_runs (path, i);
219
	}
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
220
	return path;
221
}
222
223
/**
224
 * gnome_vfs_create_temp:
225
 * @prefix: Prefix for the name of the temporary file
226
 * @name_return: Pointer to a pointer that, on return, will point to
227
 * the dynamically allocated name for the new temporary file created.
228
 * @handle_return: Pointer to a variable that will hold a file handle for
229
 * the new temporary file on return.
230
 * 
231
 * Create a temporary file whose name is prefixed with @prefix, and return an
232
 * open file handle for it in @*handle_return.
233
 * 
234
 * Return value: An integer value representing the result of the operation
235
 **/
236
GnomeVFSResult
237
gnome_vfs_create_temp (const gchar *prefix,
238
		       gchar **name_return,
239
		       GnomeVFSHandle **handle_return)
240
{
241
	GnomeVFSHandle *handle;
242
	GnomeVFSResult result;
243
	gchar *name;
593 by yakk
* Tempfile race fixes
244
	gint fd;
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
245
246
	while (1) {
593 by yakk
* Tempfile race fixes
247
		name = g_strdup_printf("%sXXXXXX", prefix);
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
248
		fd = g_mkstemp (name);
593 by yakk
* Tempfile race fixes
249
250
		if (fd < 0)
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
251
			return GNOME_VFS_ERROR_INTERNAL;
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
252
		
253
#ifdef HAVE_FCHMOD
254
		fchmod (fd, 0600);
255
#endif
256
		close (fd);
593 by yakk
* Tempfile race fixes
257
258
		result = gnome_vfs_open
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
259
			(&handle, name,
593 by yakk
* Tempfile race fixes
260
			 GNOME_VFS_OPEN_WRITE | GNOME_VFS_OPEN_READ);
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
261
262
		if (result == GNOME_VFS_OK) {
263
			*name_return = name;
264
			*handle_return = handle;
265
			return GNOME_VFS_OK;
266
		}
267
517 by gzr
2000-06-21 Gene Z. Ragan <gzr@eazel.com>
268
		if (result != GNOME_VFS_ERROR_FILE_EXISTS) {
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
269
			*name_return = NULL;
270
			*handle_return = NULL;
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
271
			g_free (name);
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
272
			return result;
273
		}
274
	}
275
}
276
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
277
#ifndef G_OS_WIN32
278
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
279
/* The following comes from GNU Wget with minor changes by myself.
280
   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
281
282
/* Converts struct tm to time_t, assuming the data in tm is UTC rather
283
   than local timezone (mktime assumes the latter).
284
285
   Contributed by Roger Beeman <beeman@cisco.com>, with the help of
286
   Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.  */
287
static time_t
288
mktime_from_utc (struct tm *t)
289
{
290
	time_t tl, tb;
291
292
	tl = mktime (t);
293
	if (tl == -1)
294
		return -1;
295
	tb = mktime (gmtime (&tl));
296
	return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
297
}
298
299
/* Check whether the result of strptime() indicates success.
300
   strptime() returns the pointer to how far it got to in the string.
301
   The processing has been successful if the string is at `GMT' or
302
   `+X', or at the end of the string.
303
304
   In extended regexp parlance, the function returns 1 if P matches
305
   "^ *(GMT|[+-][0-9]|$)", 0 otherwise.  P being NULL (a valid result of
306
   strptime()) is considered a failure and 0 is returned.  */
307
static int
308
check_end (const gchar *p)
309
{
310
	if (!p)
311
		return 0;
1636 by darin
* libgnomevfs/Makefile.am:
312
	while (g_ascii_isspace (*p))
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
313
		++p;
314
	if (!*p
315
	    || (p[0] == 'G' && p[1] == 'M' && p[2] == 'T')
1636 by darin
* libgnomevfs/Makefile.am:
316
	    || ((p[0] == '+' || p[1] == '-') && g_ascii_isdigit (p[1])))
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
317
		return 1;
318
	else
319
		return 0;
320
}
321
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
322
#endif /* G_OS_WIN32 */
323
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
324
/* Convert TIME_STRING time to time_t.  TIME_STRING can be in any of
325
   the three formats RFC2068 allows the HTTP servers to emit --
326
   RFC1123-date, RFC850-date or asctime-date.  Timezones are ignored,
327
   and should be GMT.
328
329
   We use strptime() to recognize various dates, which makes it a
330
   little bit slacker than the RFC1123/RFC850/asctime (e.g. it always
331
   allows shortened dates and months, one-digit days, etc.).  It also
332
   allows more than one space anywhere where the specs require one SP.
333
   The routine should probably be even more forgiving (as recommended
334
   by RFC2068), but I do not have the time to write one.
335
336
   Return the computed time_t representation, or -1 if all the
337
   schemes fail.
338
339
   Needless to say, what we *really* need here is something like
340
   Marcus Hennecke's atotm(), which is forgiving, fast, to-the-point,
341
   and does not use strptime().  atotm() is to be found in the sources
342
   of `phttpd', a little-known HTTP server written by Peter Erikson.  */
343
gboolean
344
gnome_vfs_atotm (const gchar *time_string,
345
		 time_t *value_return)
346
{
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
347
#ifndef G_OS_WIN32
209 by sullivan
Made gnome_vfs_file_size_as_string public, and tweaked it.
348
	struct tm t;
349
350
	/* Roger Beeman says: "This function dynamically allocates struct tm
351
	   t, but does no initialization.  The only field that actually
352
	   needs initialization is tm_isdst, since the others will be set by
353
	   strptime.  Since strptime does not set tm_isdst, it will return
354
	   the data structure with whatever data was in tm_isdst to begin
355
	   with.  For those of us in timezones where DST can occur, there
356
	   can be a one hour shift depending on the previous contents of the
357
	   data area where the data structure is allocated."  */
358
	t.tm_isdst = -1;
359
360
	/* Note that under foreign locales Solaris strptime() fails to
361
	   recognize English dates, which renders this function useless.  I
362
	   assume that other non-GNU strptime's are plagued by the same
363
	   disease.  We solve this by setting only LC_MESSAGES in
364
	   i18n_initialize(), instead of LC_ALL.
365
366
	   Another solution could be to temporarily set locale to C, invoke
367
	   strptime(), and restore it back.  This is slow and dirty,
368
	   however, and locale support other than LC_MESSAGES can mess other
369
	   things, so I rather chose to stick with just setting LC_MESSAGES.
370
371
	   Also note that none of this is necessary under GNU strptime(),
372
	   because it recognizes both international and local dates.  */
373
374
	/* NOTE: We don't use `%n' for white space, as OSF's strptime uses
375
	   it to eat all white space up to (and including) a newline, and
376
	   the function fails if there is no newline (!).
377
378
	   Let's hope all strptime() implementations use ` ' to skip *all*
379
	   whitespace instead of just one (it works that way on all the
380
	   systems I've tested it on).  */
381
382
	/* RFC1123: Thu, 29 Jan 1998 22:12:57 */
383
	if (check_end (strptime (time_string, "%a, %d %b %Y %T", &t))) {
384
		*value_return = mktime_from_utc (&t);
385
		return TRUE;
386
	}
387
388
	/* RFC850:  Thu, 29-Jan-98 22:12:57 */
389
	if (check_end (strptime (time_string, "%a, %d-%b-%y %T", &t))) {
390
		*value_return = mktime_from_utc (&t);
391
		return TRUE;
392
	}
393
394
	/* asctime: Thu Jan 29 22:12:57 1998 */
395
	if (check_end (strptime (time_string, "%a %b %d %T %Y", &t))) {
396
		*value_return = mktime_from_utc (&t);
397
		return TRUE;
398
	}
399
400
	/* Failure.  */
401
	return FALSE;
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
402
#else 
403
	g_error ("Not yet implemented: gnome_vfs_atotm()");
404
	return FALSE;
405
#endif /* G_OS_WIN32 */
312 by darin
Changed the async. get_file_info to do multiple files at a time.
406
}
762 by martin
2000-08-31 Martin Baulig <baulig@suse.de>
407
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
408
/* _gnome_vfs_istr_has_prefix
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
409
 * copy-pasted from Nautilus
410
 */
411
gboolean
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
412
_gnome_vfs_istr_has_prefix (const char *haystack, const char *needle)
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
413
{
414
	const char *h, *n;
415
	char hc, nc;
416
417
	/* Eat one character at a time. */
418
	h = haystack == NULL ? "" : haystack;
419
	n = needle == NULL ? "" : needle;
420
	do {
421
		if (*n == '\0') {
422
			return TRUE;
423
		}
424
		if (*h == '\0') {
425
			return FALSE;
426
		}
427
		hc = *h++;
428
		nc = *n++;
1604 by darin
Made builds noticeably faster by not using catch-all includes
429
		hc = g_ascii_tolower (hc);
430
		nc = g_ascii_tolower (nc);
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
431
	} while (hc == nc);
432
	return FALSE;
433
}
434
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
435
/* _gnome_vfs_istr_has_suffix
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
436
 * copy-pasted from Nautilus
437
 */
438
gboolean
2136 by michael
2002-12-19 Michael Meeks <michael@ximian.com>
439
_gnome_vfs_istr_has_suffix (const char *haystack, const char *needle)
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
440
{
441
	const char *h, *n;
442
	char hc, nc;
443
444
	if (needle == NULL) {
445
		return TRUE;
446
	}
447
	if (haystack == NULL) {
448
		return needle[0] == '\0';
449
	}
450
		
451
	/* Eat one character at a time. */
452
	h = haystack + strlen (haystack);
453
	n = needle + strlen (needle);
454
	do {
455
		if (n == needle) {
456
			return TRUE;
457
		}
458
		if (h == haystack) {
459
			return FALSE;
460
		}
461
		hc = *--h;
462
		nc = *--n;
1604 by darin
Made builds noticeably faster by not using catch-all includes
463
		hc = g_ascii_tolower (hc);
464
		nc = g_ascii_tolower (nc);
1374 by darin
Merge all changes from gnome-vfs-1 branch to HEAD.
465
	} while (hc == nc);
466
	return FALSE;
467
}
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
468
469
/**
470
 * _gnome_vfs_use_handler_for_scheme:
471
 * @scheme: the URI scheme
472
 *
473
 * Checks GConf to see if there is a URL handler
474
 * defined for this scheme and if it is enabled.
475
 *
476
 * Return value: TRUE if handler is defined and enabled,
477
 * FALSE otherwise.
478
 *
479
 * Since: 2.4
480
 */
481
gboolean
482
_gnome_vfs_use_handler_for_scheme (const char *scheme)
483
{
484
	GConfClient *client;
485
	gboolean ret;
486
	char *path;
487
	
488
	g_return_val_if_fail (scheme != NULL, FALSE);
489
	
490
	if (!gconf_is_initialized ()) {
491
		if (!gconf_init (0, NULL, NULL)) {
492
			return FALSE;
493
		}
494
	}
495
	
496
	client = gconf_client_get_default ();
497
	path = g_strconcat (GCONF_URL_HANDLER_PATH, scheme, "/enabled", NULL);
498
	ret = gconf_client_get_bool (client, path, NULL);
499
	
500
	g_free (path);
501
	g_object_unref (G_OBJECT (client));
502
	
503
	return ret;
504
}
505
506
/**
507
 * _gnome_vfs_url_show_using_handler_with_env:
508
 * @url: the url to show
509
 * @envp: environment for the handler
510
 * 
511
 * Same as gnome_url_show_using_handler except that the handler
512
 * will be launched with the given environment.
513
 *
514
 * Return value: GNOME_VFS_OK on success.
515
 * GNOME_VFS_ERROR_BAD_PAREMETER if the URL is invalid.
516
 * GNOME_VFS_ERROR_NOT_SUPPORTED if no handler is defined.
517
 * GNOME_VFS_ERROR_PARSE if the handler command can not be parsed.
518
 * GNOME_VFS_ERROR_LAUNCH if the handler command can not be launched.
519
 * GNOME_VFS_ERROR_INTERNAL for internal/GConf errors.
520
 *
521
 * Since: 2.4
522
 */
523
GnomeVFSResult
524
_gnome_vfs_url_show_using_handler_with_env (const char  *url,
525
			                    char       **envp)
526
{
527
	GConfClient *client;
528
	char *path;
529
	char *scheme;
530
	char *template;
531
	char **argv;
532
	int argc;
533
	int i;
534
	gboolean ret;
535
	
536
	g_return_val_if_fail (url != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
537
	
538
	scheme = gnome_vfs_get_uri_scheme (url);
539
	
540
	g_return_val_if_fail (scheme != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
541
	
542
	if (!gconf_is_initialized ()) {
543
		if (!gconf_init (0, NULL, NULL)) {
544
			g_free (scheme);
545
			return GNOME_VFS_ERROR_INTERNAL;
546
		}
547
	}
548
549
	client = gconf_client_get_default ();
550
	path = g_strconcat (GCONF_URL_HANDLER_PATH, scheme, "/command", NULL);
551
	template = gconf_client_get_string (client, path, NULL);
552
	g_free (path);
553
554
	if (template == NULL) {
555
		g_free (template);
556
		g_free (scheme);
2498 by teuf
2003-10-12 Christophe Fergeau <teuf@gnome.org>
557
		g_object_unref (G_OBJECT (client));
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
558
		return GNOME_VFS_ERROR_NO_HANDLER;
559
	}
560
	
561
	if (!g_shell_parse_argv (template,
562
				 &argc,
563
				 &argv,
564
				 NULL)) {
565
		g_free (template);
566
		g_free (scheme);
2498 by teuf
2003-10-12 Christophe Fergeau <teuf@gnome.org>
567
		g_object_unref (G_OBJECT (client));
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
568
		return GNOME_VFS_ERROR_PARSE;
569
	}
570
571
	g_free (template);
572
573
	path = g_strconcat (GCONF_URL_HANDLER_PATH, scheme, "/needs_terminal", NULL);
574
	if (gconf_client_get_bool (client, path, NULL)) {
575
		if (!_gnome_vfs_prepend_terminal_to_vector (&argc, &argv)) {
576
			g_free (path);
577
			g_free (scheme);
578
			g_strfreev (argv);
579
			return GNOME_VFS_ERROR_INTERNAL;
580
		}
581
	}
582
	g_free (path);
583
	g_free (scheme);
584
	
585
	g_object_unref (G_OBJECT (client));
586
587
	for (i = 0; i < argc; i++) {
588
		char *arg;
3530 by cneumair
Properly expand "%s" occuring in arguments in _gnome_vfs_url_show_using_handler_with_env. Fixes bug #302992.
589
		char **strs;
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
590
3530 by cneumair
Properly expand "%s" occuring in arguments in _gnome_vfs_url_show_using_handler_with_env. Fixes bug #302992.
591
		if (!strstr (argv[i], "%s"))
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
592
			continue;
593
3530 by cneumair
Properly expand "%s" occuring in arguments in _gnome_vfs_url_show_using_handler_with_env. Fixes bug #302992.
594
		/* we can't simply printf the uri into argv[i], since the format
595
		 * string might contain other specifiers (%d and friends) or multiple
596
		 * references to the URI, which may result in crashes if expanded using
597
		 * printf. */
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
598
		arg = argv[i];
3530 by cneumair
Properly expand "%s" occuring in arguments in _gnome_vfs_url_show_using_handler_with_env. Fixes bug #302992.
599
600
		strs = g_strsplit (argv[i], "%s", 0);
601
		argv[i] = g_strjoinv (url, strs);
602
		g_strfreev (strs);
603
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
604
		g_free (arg);
605
	}
606
607
	ret = g_spawn_async (NULL /* working directory */,
608
			     argv,
609
			     envp,
610
			     G_SPAWN_SEARCH_PATH /* flags */,
611
			     NULL /* child_setup */,
612
			     NULL /* data */,
613
			     NULL /* child_pid */,
614
			     NULL);
615
	g_strfreev (argv);
616
617
	if (!ret) {
618
		return GNOME_VFS_ERROR_LAUNCH;
619
	}
620
621
	return GNOME_VFS_OK;
622
}
623
624
/* This is a copy from libgnome, internalized here to avoid
625
   strange dependency loops */
626
627
/**
628
 * _gnome_vfs_prepend_terminal_to_vector:
629
 * @argc: a pointer to the vector size
630
 * @argv: a pointer to the vector
631
 *
632
 * Prepends a terminal (either the one configured as default in GnomeVFS
633
 * or one of the common xterm emulators) to the passed in vector, modifying
634
 * it in the process. The vector should be allocated with #g_malloc, as 
635
 * this will #g_free the original vector. Also all elements must
636
 * have been allocated separately. That is the standard glib/GNOME way of
637
 * doing vectors. If the integer that @argc points to is negative, the
638
 * size will first be computed. Also note that passing in pointers to a vector
639
 * that is empty, will just create a new vector for you.
640
 *
641
 * Return value: TRUE if successful, FALSE otherwise.
642
 *
643
 * Since: 2.4
644
 */
645
gboolean
646
_gnome_vfs_prepend_terminal_to_vector (int    *argc,
647
				       char ***argv)
648
{
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
649
#ifndef G_OS_WIN32
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
650
        char **real_argv;
651
        int real_argc;
652
        int i, j;
653
	char **term_argv = NULL;
654
	int term_argc = 0;
655
	GConfClient *client;
656
657
	char *terminal = NULL;
658
	char **the_argv;
659
660
        g_return_val_if_fail (argc != NULL, FALSE);
661
        g_return_val_if_fail (argv != NULL, FALSE);
662
663
	/* sanity */
664
        if(*argv == NULL) {
665
                *argc = 0;
666
	}
667
	
668
	the_argv = *argv;
669
670
	/* compute size if not given */
671
	if (*argc < 0) {
672
		for (i = 0; the_argv[i] != NULL; i++)
673
			;
674
		*argc = i;
675
	}
676
677
	if (!gconf_is_initialized ()) {
678
		if (!gconf_init (0, NULL, NULL)) {
679
			return FALSE;
680
		}
681
	}
682
683
	client = gconf_client_get_default ();
684
	terminal = gconf_client_get_string (client, GCONF_DEFAULT_TERMINAL_EXEC_PATH, NULL);
685
	
686
	if (terminal) {
687
		gchar *exec_flag;
688
		exec_flag = gconf_client_get_string (client, GCONF_DEFAULT_TERMINAL_ARG_PATH, NULL);
689
690
		if (exec_flag == NULL) {
691
			term_argc = 1;
692
			term_argv = g_new0 (char *, 2);
693
			term_argv[0] = terminal;
694
			term_argv[1] = NULL;
695
		} else {
696
			term_argc = 2;
697
			term_argv = g_new0 (char *, 3);
698
			term_argv[0] = terminal;
699
			term_argv[1] = exec_flag;
700
			term_argv[2] = NULL;
701
		}
702
	}
703
704
	g_object_unref (G_OBJECT (client));
705
706
	if (term_argv == NULL) {
707
		char *check;
708
709
		term_argc = 2;
710
		term_argv = g_new0 (char *, 3);
711
712
		check = g_find_program_in_path ("gnome-terminal");
713
		if (check != NULL) {
714
			term_argv[0] = check;
715
			/* Note that gnome-terminal takes -x and
716
			 * as -e in gnome-terminal is broken we use that. */
717
			term_argv[1] = g_strdup ("-x");
718
		} else {
719
			if (check == NULL)
720
				check = g_find_program_in_path ("nxterm");
721
			if (check == NULL)
722
				check = g_find_program_in_path ("color-xterm");
723
			if (check == NULL)
724
				check = g_find_program_in_path ("rxvt");
725
			if (check == NULL)
726
				check = g_find_program_in_path ("xterm");
727
			if (check == NULL)
728
				check = g_find_program_in_path ("dtterm");
729
			if (check == NULL) {
730
				check = g_strdup ("xterm");
731
				g_warning ("couldn't find a terminal, falling back to xterm");
732
			}
733
			term_argv[0] = check;
734
			term_argv[1] = g_strdup ("-e");
735
		}
736
	}
737
738
        real_argc = term_argc + *argc;
739
        real_argv = g_new (char *, real_argc + 1);
740
741
        for (i = 0; i < term_argc; i++)
742
                real_argv[i] = term_argv[i];
743
744
        for (j = 0; j < *argc; j++, i++)
745
                real_argv[i] = (char *)the_argv[j];
746
747
	real_argv[i] = NULL;
748
749
	g_free (*argv);
750
	*argv = real_argv;
751
	*argc = real_argc;
752
753
	/* we use g_free here as we sucked all the inner strings
754
	 * out from it into real_argv */
755
	g_free (term_argv);
756
	return TRUE;
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
757
#else
758
	return FALSE;
759
#endif /* G_OS_WIN32 */
2267 by alexl
2003-04-24 Alexander Larsson <alexl@redhat.com>
760
}		  
761
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
762
#ifndef G_OS_WIN32
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
763
/**
764
 * _gnome_vfs_set_fd_flags:
765
 * @fd: a valid file descriptor
766
 * @flags: file status flags to set
767
 *
768
 * Set the file status flags part of the descriptor’s flags to the
769
 * value specified by @flags.
770
 *
771
 * Return value: TRUE if successful, FALSE otherwise.
772
 *
773
 * Since: 2.7
774
 */
775
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
776
static gboolean
777
_set_fd_flags (int fd, int flags)
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
778
{
779
	int val;
780
781
	val = fcntl (fd, F_GETFL, 0);
782
	if (val < 0) {
783
		g_warning ("fcntl() F_GETFL failed: %s", strerror (errno));
784
		return FALSE;
785
	}
786
787
	val |= flags;
788
	
789
	val = fcntl (fd, F_SETFL, val);
790
	if (val < 0) {
791
		g_warning ("fcntl() F_SETFL failed: %s", strerror (errno));
792
		return FALSE;
793
	}
794
795
	return TRUE;
796
}
797
798
/**
799
 * _gnome_vfs_clear_fd_flags:
800
 * @fd: a valid file descriptor
801
 * @flags: file status flags to clear
802
 *
803
 * Clear the flags sepcified by @flags of the file status flags part of the 
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
804
 * descriptor flags. 
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
805
 *
806
 * Return value: TRUE if successful, FALSE otherwise.
807
 *
808
 * Since: 2.7
809
 */
810
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
811
static gboolean
812
_clear_fd_flags (int fd, int flags)
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
813
{
814
	int val;
815
816
	val = fcntl (fd, F_GETFL, 0);
817
	if (val < 0) {
818
		g_warning ("fcntl() F_GETFL failed: %s", strerror (errno));
819
		return FALSE;
820
	}
821
822
	val &= ~flags;
823
	
824
	val = fcntl (fd, F_SETFL, val);
825
	if (val < 0) {
826
		g_warning ("fcntl() F_SETFL failed: %s", strerror (errno));
827
		return FALSE;
828
	}
829
	
830
	return TRUE;
831
832
}
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
833
#endif /* G_OS_WIN32 */
834
835
gboolean
836
_gnome_vfs_socket_set_blocking (int sock_fd, gboolean blocking)
837
{
838
#ifndef G_OS_WIN32
839
	gboolean result;
840
	if (blocking) {
841
		result = _clear_fd_flags (sock_fd, O_NONBLOCK);
842
	} else {
843
		result = _set_fd_flags (sock_fd, O_NONBLOCK);
844
	}
845
846
	return result;
847
#else 
848
	u_long val;
849
	
850
	val = blocking ? 0 : 1;
851
 
3512 by tml
2005-04-19 Tor Lillqvist <tml@novell.com>
852
	if (ioctlsocket (sock_fd, FIONBIO, &val) == SOCKET_ERROR) {
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
853
		g_warning ("ioctlsocket(FIONBIO) failed: %s",
854
			   _gnome_vfs_winsock_strerror (WSAGetLastError ()));
855
		return FALSE;
856
	}
857
858
	return TRUE;
859
#endif /* G_OS_WIN32 */
860
}
861
862
/**
863
 * _gnome_vfs_pipe:
864
 * @fds: a pointer to an array or two ints
865
 *
866
 * Creates a unidirectional IPC pipe. On Unix, a pipe. On Win32, a
867
 * pair of connected TCP sockets (thus actually bidirectional, but
868
 * ignore that).
869
 *
870
 * Return value: TRUE if successful, FALSE otherwise.
871
 *
872
 * Since: 2.11
873
 */
874
875
int
876
_gnome_vfs_pipe (int *fds)
877
{
878
#ifndef G_OS_WIN32
879
	return pipe (fds);
880
#else
881
	SOCKET temp, socket1 = -1, socket2 = -1;
882
	struct sockaddr_in saddr;
883
	int len;
884
	u_long arg;
885
	fd_set read_set, write_set;
886
	struct timeval tv;
887
888
	temp = socket (AF_INET, SOCK_STREAM, 0);
889
	
890
	if (temp == INVALID_SOCKET) {
891
		_gnome_vfs_map_winsock_error_to_errno ();
892
		goto out0;
893
	}
894
  	
895
	arg = 1;
896
	if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) {
897
		_gnome_vfs_map_winsock_error_to_errno ();
898
		goto out0;
899
	}
900
901
	memset (&saddr, 0, sizeof (saddr));
902
	saddr.sin_family = AF_INET;
903
	saddr.sin_port = 0;
904
	saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
905
906
	if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) {
907
		_gnome_vfs_map_winsock_error_to_errno ();
908
		goto out0;
909
	}
910
911
	if (listen (temp, 1) == SOCKET_ERROR) {
912
		_gnome_vfs_map_winsock_error_to_errno ();
913
		goto out0;
914
	}
915
916
	len = sizeof (saddr);
917
	if (getsockname (temp, (struct sockaddr *)&saddr, &len)) {
918
		_gnome_vfs_map_winsock_error_to_errno ();
919
		goto out0;
920
	}
921
922
	socket1 = socket (AF_INET, SOCK_STREAM, 0);
923
	
924
	if (socket1 == INVALID_SOCKET) {
925
		_gnome_vfs_map_winsock_error_to_errno ();
926
		goto out0;
927
	}
928
929
	arg = 1;
930
	if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { 
931
		_gnome_vfs_map_winsock_error_to_errno ();
932
		goto out1;
933
	}
934
935
	if (connect (socket1, (struct sockaddr  *)&saddr, len) != SOCKET_ERROR ||
936
			WSAGetLastError () != WSAEWOULDBLOCK) {
937
		_gnome_vfs_map_winsock_error_to_errno ();
938
		goto out1;
939
	}
940
941
	FD_ZERO (&read_set);
942
	FD_SET (temp, &read_set);
943
944
	tv.tv_sec = 0;
945
	tv.tv_usec = 0;
946
947
	if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
948
		_gnome_vfs_map_winsock_error_to_errno ();
949
		goto out1;
950
	}
951
952
	if (!FD_ISSET (temp, &read_set)) {
953
		errno = EIO;	/* Oh well, whatever */
954
		goto out1;
955
	}
956
957
	socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
958
	if (socket2 == INVALID_SOCKET) {
959
		_gnome_vfs_map_winsock_error_to_errno ();
960
		goto out1;
961
	}
962
963
	FD_ZERO (&write_set);
964
	FD_SET (socket1, &write_set);
965
966
	tv.tv_sec = 0;
967
	tv.tv_usec = 0;
968
969
	if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
970
		_gnome_vfs_map_winsock_error_to_errno ();
971
		goto out2;
972
	}
973
974
	if (!FD_ISSET (socket1, &write_set)) {
975
		errno = EIO;
976
		goto out2;
977
	}
978
979
	arg = 0;
980
	if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) {
981
		_gnome_vfs_map_winsock_error_to_errno ();
982
		goto out2;
983
	}
984
985
	arg = 0;
986
	if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) {
987
		_gnome_vfs_map_winsock_error_to_errno ();
988
		goto out2;
989
	}
990
3519 by tml
2005-05-03 Tor Lillqvist <tml@novell.com>
991
	fds[0] = socket1;
992
	fds[1] = socket2;
3504 by gicmo
Integration of the Win32 integration patch. Mostly based
993
994
	closesocket (temp);
995
996
	return 0;
997
998
out2:
999
	closesocket (socket2);
1000
out1:
1001
	closesocket (socket1);
1002
out0:
1003
	closesocket (temp);
1004
1005
	return -1;
1006
1007
#endif
1008
}
1009
1010
gboolean
1011
_gnome_vfs_pipe_set_blocking  (int pipe_fd, gboolean blocking)
1012
{
1013
	return _gnome_vfs_socket_set_blocking (pipe_fd, blocking);
1014
}
1015
1016
1017
#ifdef G_OS_WIN32
1018
void
1019
_gnome_vfs_map_winsock_error_to_errno (void)
1020
{
1021
	errno = WSAGetLastError ();
1022
	switch (errno) {
1023
	case WSAEBADF:
1024
		errno = EBADF; break;
1025
	case WSAEWOULDBLOCK:
1026
		errno = EAGAIN; break;
1027
	default:
1028
		errno = EIO; break; /* Oh well */
1029
	}
1030
}
1031
1032
const char *
1033
_gnome_vfs_winsock_strerror (int error)
1034
{
1035
1036
	switch (error) {
1037
	case WSAEOPNOTSUPP:
1038
		return "Operation not supported on transport endpoint";
1039
	case WSAEPFNOSUPPORT:
1040
		return "Protocol family not supported";
1041
	case WSAECONNRESET:
1042
		return "Connection reset by peer";
1043
	case WSAENOBUFS:
1044
		return "No buffer space available";
1045
	case WSAEAFNOSUPPORT:
1046
		return "Address family not supported by protocol family";
1047
	case WSAENOTSOCK:
1048
		return "Socket operation on non-socket";
1049
	case WSAENOPROTOOPT:
1050
		return "Protocol not available";
1051
	case WSAESHUTDOWN:
1052
		return "Can't send after socket shutdown";
1053
	case WSAECONNREFUSED:
1054
		return "Connection refused";
1055
	case WSAEADDRINUSE:
1056
		return "Address already in use";
1057
	case WSAECONNABORTED:
1058
		return "Connection aborted";
1059
	case WSAENETUNREACH:
1060
		return "Network is unreachable";
1061
	case WSAENETDOWN:
1062
		return "Network interface is not configured";
1063
	case WSAETIMEDOUT:
1064
		return "Connection timed out";
1065
	case WSAEHOSTDOWN:
1066
		return "Host is down";
1067
	case WSAEHOSTUNREACH:
1068
		return "Host is unreachable";
1069
	case WSAEINPROGRESS:
1070
		return "Connection already in progress";
1071
	case WSAEALREADY:
1072
		return "Socket already connected";
1073
	case WSAEPROTONOSUPPORT:
1074
		return "Unknown protocol";
1075
	case WSAESOCKTNOSUPPORT:
1076
		return "Socket type not supported";
1077
	case WSAEADDRNOTAVAIL:
1078
		return "Address not available";
1079
	case WSAEISCONN:
1080
		return "Socket is already connected";
1081
	case WSAENOTCONN:
1082
		return "Socket is not connected";
1083
	}
1084
	return "Unknown Windows Sockets error";
1085
}
1086
#endif
2880 by alexl
2004-04-01 Christian Kellner <gicmo@xatom.net>
1087