1  /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * go-file.c :
4  *
5  * Copyright (C) 2009 Hubert Figuiere <hub@figuiere.net>.
6  *     Whose contributions are under GPLv2+
7  * Copyright (C) 2004 Morten Welinder (terra@gnome.org)
8  * Copyright (C) 2003, Red Hat, Inc.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  * 02110-1301 USA.
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 
30 #if 0
31 #include <goffice/goffice-config.h>
32 #include <glib/gi18n-lib.h>
33 #endif
34 #include "ut_go_file.h"
35 #include <gsf/gsf-impl-utils.h>
36 #include <gsf/gsf-input.h>
37 #include <gsf/gsf-input-impl.h>
38 #include <gsf/gsf-output-impl.h>
39 #include <gsf/gsf-input-memory.h>
40 #include <gsf/gsf-output-memory.h>
41 #include <gsf/gsf-input-stdio.h>
42 #include <gsf/gsf-output-stdio.h>
43 #include <glib/gstdio.h>
44 #include <libxml/encoding.h>
45 
46 #if TOOLKIT_COCOA
47 #include <CoreFoundation/CoreFoundation.h>
48 #include <ApplicationServices/ApplicationServices.h>
49 #endif
50 
51 #ifdef WITH_GSF_INPUT_HTTP
52 #include <gsf/gsf-input-http.h>
53 #endif
54 #include <stdio.h>
55 
56 #if HAVE_GSF_GIO
57 #  include <gsf/gsf-input-gio.h>
58 #  include <gsf/gsf-output-gio.h>
59 #elif defined(WITH_GNOMEVFS)
60 #  define GOFFICE_WITH_GNOME
61 #  include <libgnomevfs/gnome-vfs-mime-utils.h>
62 #  include <libgnomevfs/gnome-vfs-mime-handlers.h>
63 #  include <gsf-gnome/gsf-input-gnomevfs.h>
64 #  include <gsf-gnome/gsf-output-gnomevfs.h>
65 #endif
66 
67 #ifdef TOOLKIT_GTK_ALL
68 #include <gdk/gdk.h>
69 #include <gtk/gtk.h>
70 #if defined(WITH_GNOMEVFS)
71 // needed for gnome_vfs_url_show()
72 #include <libgnomevfs/gnome-vfs-utils.h>
73 #endif
74 #endif
75 
76 #if defined G_OS_WIN32
77 #include <windows.h>
78 #include <shellapi.h>
79 #include <io.h>
80 #include <fcntl.h>
81 #endif
82 
83 #include <string>
84 #include <string.h>
85 #include <stdlib.h>
86 #include <time.h>
87 
88 #ifdef WIN32
89   #ifndef S_ISDIR
90   #define S_ISDIR(m) (((m) & _S_IFMT ) == _S_IFDIR)
91   #endif
92 #else
93 #include <unistd.h>
94 #endif
95 
96 #include "ut_types.h"
97 
98 #ifndef _
99 #define _(X) X
100 #endif
101 
102 /* ------------------------------------------------------------------------- */
103 
104 /* TODO: push this up into libgsf proper */
105 
106 GsfInput *
gsf_input_memory_new_from_file(FILE * input)107 gsf_input_memory_new_from_file (FILE * input)
108 {
109 	GsfOutput *memory_output;
110 	GsfInput  *memory_input = NULL;
111 
112 	g_return_val_if_fail (input != NULL, NULL);
113 
114 	memory_output = gsf_output_memory_new ();
115 	while (TRUE) {
116 		guint8 buf[1024];
117 		size_t nread;
118 		gboolean res;
119 
120 		nread = fread (buf, 1, sizeof(buf), input);
121 		res = gsf_output_write (memory_output, nread, buf);
122 
123 		if (ferror (input) || !res) {
124 			/* trouble reading from @input or trouble writing to @memory_output */
125 			g_object_unref (G_OBJECT (memory_output));
126 			return NULL;
127 		}
128 		else if ((nread < sizeof(buf)) && feof (input)) /* hit eof */
129 			break;
130 	}
131 
132 	if (gsf_output_close (memory_output))
133 		memory_input = gsf_input_memory_new_clone (gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (memory_output)),
134 							   gsf_output_size (memory_output));
135 
136 	g_object_unref (G_OBJECT (memory_output));
137 
138 	return memory_input;
139 }
140 
141 /* ------------------------------------------------------------------------- */
142 
143 /* TODO: push this up into libgsf proper */
144 
145 #define GSF_OUTPUT_PROXY_TYPE	(gsf_output_proxy_get_type ())
146 #define GSF_OUTPUT_PROXY(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GSF_OUTPUT_PROXY_TYPE, GsfOutputProxy))
147 #define GSF_IS_OUTPUT_PROXY(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GSF_OUTPUT_PROXY_TYPE))
148 
149 typedef struct _GsfOutputProxy GsfOutputProxy;
150 
151 GType gsf_output_proxy_get_type      (void) G_GNUC_CONST;
152 void  gsf_output_proxy_register_type (GTypeModule *module);
153 
154 GsfOutput *gsf_output_proxy_new      (GsfOutput * sink);
155 
156 enum {
157 	PROP_0,
158 	PROP_SINK
159 };
160 
161 static GsfOutputClass *parent_class;
162 
163 struct _GsfOutputProxy {
164 	GsfOutput output;
165 	GsfOutput *memory_output;
166 	GsfOutput *sink;
167 };
168 
169 typedef struct {
170 	GsfOutputClass output_class;
171 } GsfOutputProxyClass;
172 
173 /**
174  * gsf_output_proxy_new :
175  *
176  * Returns a new file or NULL.
177  **/
178 GsfOutput *
gsf_output_proxy_new(GsfOutput * sink)179 gsf_output_proxy_new (GsfOutput * sink)
180 {
181 	g_return_val_if_fail (sink != NULL, NULL);
182 	g_return_val_if_fail (GSF_IS_OUTPUT (sink), NULL);
183 
184 	return (GsfOutput *)g_object_new (GSF_OUTPUT_PROXY_TYPE, "sink", sink, (void *)NULL);
185 }
186 
187 static gboolean
gsf_output_proxy_close(GsfOutput * object)188 gsf_output_proxy_close (GsfOutput *object)
189 {
190 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
191 
192 	if(gsf_output_close (proxy->memory_output))
193 		{
194 			const guint8 *bytes;
195 			size_t num_bytes;
196 
197 			bytes = gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (proxy->memory_output));
198 			num_bytes = gsf_output_size (proxy->memory_output);
199 
200 			if (gsf_output_write (proxy->sink, num_bytes, bytes))
201 				return gsf_output_close (proxy->sink);
202 		}
203 
204 	return FALSE;
205 }
206 
207 static void
gsf_output_proxy_finalize(GObject * object)208 gsf_output_proxy_finalize (GObject *object)
209 {
210 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
211 
212 	g_object_unref (proxy->memory_output);
213 	g_object_unref (proxy->sink);
214 
215 	G_OBJECT_CLASS (parent_class)->finalize (object);
216 }
217 
218 static gboolean
gsf_output_proxy_seek(GsfOutput * object,gsf_off_t offset,GSeekType whence)219 gsf_output_proxy_seek (GsfOutput *object,
220 		       gsf_off_t offset,
221 		       GSeekType whence)
222 {
223 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
224 
225 	return gsf_output_seek (proxy->memory_output, offset, whence);
226 }
227 
228 
229 static gboolean
gsf_output_proxy_write(GsfOutput * object,size_t num_bytes,guint8 const * buffer)230 gsf_output_proxy_write (GsfOutput *object,
231 			size_t num_bytes,
232 			guint8 const *buffer)
233 {
234 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
235 
236 	return gsf_output_write (proxy->memory_output, num_bytes, buffer);
237 }
238 
239 static gsf_off_t gsf_output_proxy_vprintf (GsfOutput *object,
240 					  char const *format, va_list args) G_GNUC_PRINTF (2, 0);
241 
242 static gsf_off_t
gsf_output_proxy_vprintf(GsfOutput * object,char const * format,va_list args)243 gsf_output_proxy_vprintf (GsfOutput *object, char const *format, va_list args)
244 {
245 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
246 
247 	return gsf_output_vprintf (proxy->memory_output, format, args);
248 }
249 
250 static void
gsf_output_proxy_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)251 gsf_output_proxy_get_property (GObject     *object,
252 			       guint        property_id,
253 			       GValue      *value,
254 			       GParamSpec  *pspec)
255 {
256 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
257 
258 	switch (property_id) {
259 	case PROP_SINK:
260 		g_value_set_object (value, proxy->sink);
261 		break;
262 	default:
263 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
264 		break;
265 	}
266 }
267 
268 static void
gsf_output_proxy_set_sink(GsfOutputProxy * proxy,GsfOutput * sink)269 gsf_output_proxy_set_sink (GsfOutputProxy *proxy, GsfOutput *sink)
270 {
271 	g_return_if_fail (GSF_IS_OUTPUT (sink));
272 	g_object_ref (sink);
273 	if (proxy->sink)
274 		g_object_unref (proxy->sink);
275 	proxy->sink = sink;
276 }
277 
278 static void
gsf_output_proxy_set_property(GObject * object,guint property_id,GValue const * value,GParamSpec * pspec)279 gsf_output_proxy_set_property (GObject      *object,
280 			       guint         property_id,
281 			       GValue const *value,
282 			       GParamSpec   *pspec)
283 {
284 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
285 
286 	switch (property_id) {
287 	case PROP_SINK:
288 		gsf_output_proxy_set_sink (proxy, (GsfOutput *)g_value_get_object (value));
289 		break;
290 	default:
291 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
292 		break;
293 	}
294 }
295 
296 static void
gsf_output_proxy_init(GObject * object)297 gsf_output_proxy_init (GObject *object)
298 {
299 	GsfOutputProxy *proxy = (GsfOutputProxy *)object;
300 
301 	proxy->memory_output = gsf_output_memory_new ();
302 	proxy->sink = NULL;
303 }
304 
305 static void
gsf_output_proxy_class_init(GObjectClass * gobject_class)306 gsf_output_proxy_class_init (GObjectClass *gobject_class)
307 {
308 	GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
309 
310 	gobject_class->finalize = gsf_output_proxy_finalize;
311 	gobject_class->set_property = gsf_output_proxy_set_property;
312 	gobject_class->get_property = gsf_output_proxy_get_property;
313 	output_class->Close     = gsf_output_proxy_close;
314 	output_class->Seek      = gsf_output_proxy_seek;
315 	output_class->Write     = gsf_output_proxy_write;
316 	output_class->Vprintf   = gsf_output_proxy_vprintf;
317 
318 	g_object_class_install_property
319 		(gobject_class,
320 		 PROP_SINK,
321 		 g_param_spec_object ("sink", "Sink",
322 				      "Where the converted data is written.",
323 				      GSF_OUTPUT_TYPE,
324 				      (GParamFlags)(GSF_PARAM_STATIC |
325 						    G_PARAM_READWRITE |
326 						    G_PARAM_CONSTRUCT_ONLY)));
327 
328 	parent_class = GSF_OUTPUT_CLASS (g_type_class_peek_parent (gobject_class));
329 }
330 
331 /* GSF_DYNAMIC_CLASS once we move this back into libgsf */
332 GSF_CLASS (GsfOutputProxy, gsf_output_proxy,
333 	   gsf_output_proxy_class_init, gsf_output_proxy_init,
334 	   GSF_OUTPUT_TYPE)
335 
336 /* ------------------------------------------------------------------------- */
337 
338 static gboolean
339 is_fd_uri (const char *uri, int *fd);
340 
341 /* ------------------------------------------------------------------------- */
342 
343 /*
344  * Return TRUE if @path represents a URI, false if not
345  */
346 gboolean
UT_go_path_is_uri(const char * path)347 UT_go_path_is_uri (const char * path)
348 {
349 	// hack until i come up with a better test
350 	if (g_str_has_prefix (path, "mailto:"))
351 		return TRUE;
352 	else
353 		return (strstr (path, "://") != NULL);
354 }
355 
UT_go_path_is_path(const char * path)356 gboolean UT_go_path_is_path (const char * path)
357 {
358 	return (strstr (path, G_DIR_SEPARATOR_S) != NULL);
359 }
360 
361 /*
362  * Convert an escaped URI into a filename.
363  */
364 char *
UT_go_filename_from_uri(const char * uri)365 UT_go_filename_from_uri (const char *uri)
366 {
367 #if defined(GOFFICE_WITH_GNOME)
368 	return gnome_vfs_get_local_path_from_uri (uri);
369 #else
370 	return g_filename_from_uri (uri, NULL, NULL);
371 #endif
372 }
373 
374 /*
375  * Convert a filename into an escaped URI.
376  */
377 char *
UT_go_filename_to_uri(const char * filename)378 UT_go_filename_to_uri (const char *filename)
379 {
380 	char *simp, *uri;
381 
382 	g_return_val_if_fail (filename != NULL, NULL);
383 
384 	simp = UT_go_filename_simplify (filename, UT_GO_DOTDOT_TEST, TRUE);
385 
386 #if defined(GOFFICE_WITH_GNOME)
387 	uri = gnome_vfs_get_uri_from_local_path (simp);
388 #else
389 	uri = g_filename_to_uri (simp, NULL, NULL);
390 #endif
391 	g_free (simp);
392 	return uri;
393 }
394 
395 char *
UT_go_filename_simplify(const char * filename,UT_GODotDot dotdot,gboolean make_absolute)396 UT_go_filename_simplify (const char *filename, UT_GODotDot dotdot,
397 		      gboolean make_absolute)
398 {
399 	char *simp, *p, *q;
400 
401 	g_return_val_if_fail (filename != NULL, NULL);
402 
403 	if (make_absolute && !g_path_is_absolute (filename)) {
404 		/*
405 		 * FIXME: this probably does not work for "c:foo" on
406 		 * Win32.
407 		 */
408 		char *current_dir = g_get_current_dir ();
409 		simp = g_build_filename (current_dir, filename, NULL);
410 		g_free (current_dir);
411 	} else
412 		simp = g_strdup (filename);
413 
414 	for (p = q = simp; *p;) {
415 		if (p != simp &&
416 		    G_IS_DIR_SEPARATOR (p[0]) &&
417 		    G_IS_DIR_SEPARATOR (p[1])) {
418 			/* "//" --> "/", except initially.  */
419 			p++;
420 			continue;
421 		}
422 
423 		if (G_IS_DIR_SEPARATOR (p[0]) &&
424 		    p[1] == '.' &&
425 		    G_IS_DIR_SEPARATOR (p[2])) {
426 			/* "/./" -> "/".  */
427 			p += 2;
428 			continue;
429 		}
430 
431 		if (G_IS_DIR_SEPARATOR (p[0]) &&
432 		    p[1] == '.' &&
433 		    p[2] == '.' &&
434 		    G_IS_DIR_SEPARATOR (p[3])) {
435 			if (p == simp) {
436 				/* "/../" --> "/" initially.  */
437 				p += 3;
438 				continue;
439 			} else if (p == simp + 1) {
440 				/* Nothing, leave "//../" initially alone.  */
441 			} else {
442 				/*
443 				 * "prefix/dir/../" --> "prefix/" if
444 				 * "dir" is an existing directory (not
445 				 * a symlink).
446 				 */
447 				gboolean isdir;
448 
449 				switch (dotdot) {
450 				case UT_GO_DOTDOT_SYNTACTIC:
451 					isdir = TRUE;
452 					break;
453 				case UT_GO_DOTDOT_TEST: {
454 #if GLIB_CHECK_VERSION(2,26,0) || defined(G_OS_WIN32)
455 					GStatBuf statbuf;
456 #else
457 					struct stat statbuf;
458 #endif
459 					char savec = *q;
460 					/*
461 					 * Terminate the path so far so we can
462 					 * it.  Restore because "p" loops over
463 					 * the same.
464 					 */
465 					*q = 0;
466 					isdir = (g_lstat (simp, &statbuf) == 0) &&
467 						S_ISDIR (statbuf.st_mode);
468 					*q = savec;
469 					break;
470 				}
471 				default:
472 					isdir = FALSE;
473 					break;
474 				}
475 
476 				if (isdir) {
477 					do {
478 						g_assert (q != simp);
479 						q--;
480 					} while (!G_IS_DIR_SEPARATOR (*q));
481 					p += 3;
482 					continue;
483 				} else {
484 					/*
485 					 * Do nothing.
486 					 *
487 					 * Maybe the prefix does not
488 					 * exist, or maybe it is not
489 					 * a directory (for example
490 					 * because it is a symlink).
491 					 */
492 				}
493 			}
494 		}
495 
496 		*q++ = *p++;
497 	}
498 	*q = 0;
499 
500 	return simp;
501 }
502 
503 /*
504  * Simplify a potentially non-local path using only slashes.
505  */
506 static char *
simplify_path(const char * uri)507 simplify_path (const char *uri)
508 {
509 	char *simp, *p, *q;
510 
511 	simp = g_strdup (uri);
512 
513 	for (p = q = simp; *p;) {
514 		if (p[0] == '/' && p[1] == '/') {
515 			/* "//" --> "/".  */
516 			p++;
517 			continue;
518 		}
519 
520 		if (p[0] == '/' && p[1] == '.' && p[2] == '/') {
521 			/* "/./" -> "/".  */
522 			p += 2;
523 			continue;
524 		}
525 
526 		if (p[0] == '/' && p[1] == '.' && p[2] == '.' && p[3] == '/') {
527 			if (p == simp) {
528 				/* "/../" --> "/" initially.  */
529 				p += 3;
530 				continue;
531 			} else {
532 				/* Leave alone */
533 			}
534 		}
535 
536 		*q++ = *p++;
537 	}
538 	*q = 0;
539 
540 	return simp;
541 }
542 
543 static char *
simplify_host_path(const char * uri,size_t hstart)544 simplify_host_path (const char *uri, size_t hstart)
545 {
546 	const char *slash = strchr (uri + hstart, '/');
547 	char *simp, *psimp;
548 	size_t pstart;
549 
550 	if (!slash)
551 		return g_strdup (uri);
552 
553 	pstart = slash + 1 - uri;
554 	psimp = simplify_path (slash + 1);
555 	simp = g_new (char, pstart + strlen (psimp) + 1);
556 	memcpy (simp, uri, pstart);
557 	strcpy (simp + pstart, psimp);
558 	g_free (psimp);
559 	return simp;
560 }
561 
562 char *
UT_go_url_simplify(const char * uri)563 UT_go_url_simplify (const char *uri)
564 {
565 	char *simp, *p;
566 
567 	g_return_val_if_fail (uri != NULL, NULL);
568 
569 	if (g_ascii_strncasecmp (uri, "file:///", 8) == 0) {
570 		char *filename = UT_go_filename_from_uri (uri);
571 		simp = filename ? UT_go_filename_to_uri (filename) : NULL;
572 		g_free (filename);
573 		return simp;
574 	}
575 
576 	if (g_ascii_strncasecmp (uri, "http://", 7) == 0)
577 		simp = simplify_host_path (uri, 7);
578 	else if (g_ascii_strncasecmp (uri, "https://", 8) == 0)
579 		simp = simplify_host_path (uri, 8);
580 	else if (g_ascii_strncasecmp (uri, "ftp://", 6) == 0)
581 		simp = simplify_host_path (uri, 6);
582 	else
583 		simp = g_strdup (uri);
584 
585 	/* Lower-case protocol name.  */
586 	for (p = simp; g_ascii_isalpha (*p); p++)
587 		*p = g_ascii_tolower (*p);
588 
589 	return simp;
590 }
591 
592 
593 #ifndef GOFFICE_WITH_GNOME
594 
595 /* code borrowed from gnome-vfs' gnome-vfs-uri.c */
596 
597 static gboolean
is_uri_relative(const char * uri)598 is_uri_relative (const char *uri)
599 {
600         const char *current;
601 
602         /* RFC 2396 section 3.1 */
603         for (current = uri ;
604                 *current
605 		     &&      ((*current >= 'a' && *current <= 'z')
606 			      || (*current >= 'A' && *current <= 'Z')
607 			      || (*current >= '0' && *current <= '9')
608 			      || ('-' == *current)
609 			      || ('+' == *current)
610 			      || ('.' == *current)) ;
611              current++) {
612 	}
613 
614         return  !(':' == *current);
615 }
616 
617 static void
remove_internal_relative_components(char * uri_current)618 remove_internal_relative_components (char *uri_current)
619 {
620 	char *segment_prev, *segment_cur;
621 	gsize len_prev, len_cur;
622 
623 	len_prev = len_cur = 0;
624 	segment_prev = NULL;
625 
626 	segment_cur = uri_current;
627 
628 	while (*segment_cur) {
629 		len_cur = strcspn (segment_cur, "/");
630 
631 		if (len_cur == 1 && segment_cur[0] == '.') {
632 			/* Remove "." 's */
633 			if (segment_cur[1] == '\0') {
634 				segment_cur[0] = '\0';
635 				break;
636 			} else {
637 				memmove (segment_cur, segment_cur + 2, strlen (segment_cur + 2) + 1);
638 				continue;
639 			}
640 		} else if (len_cur == 2 && segment_cur[0] == '.' && segment_cur[1] == '.' ) {
641 			/* Remove ".."'s (and the component to the left of it) that aren't at the
642 			 * beginning or to the right of other ..'s
643 			 */
644 			if (segment_prev) {
645 				if (! (len_prev == 2
646 				       && segment_prev[0] == '.'
647 				       && segment_prev[1] == '.')) {
648 				       	if (segment_cur[2] == '\0') {
649 						segment_prev[0] = '\0';
650 						break;
651 				       	} else {
652 						memmove (segment_prev, segment_cur + 3, strlen (segment_cur + 3) + 1);
653 
654 						segment_cur = segment_prev;
655 						len_cur = len_prev;
656 
657 						/* now we find the previous segment_prev */
658 						if (segment_prev == uri_current) {
659 							segment_prev = NULL;
660 						} else if (segment_prev - uri_current >= 2) {
661 							segment_prev -= 2;
662 							for ( ; segment_prev > uri_current && segment_prev[0] != '/'
663 							      ; segment_prev-- ) {
664 							}
665 							if (segment_prev[0] == '/') {
666 								segment_prev++;
667 							}
668 						}
669 						continue;
670 					}
671 				}
672 			}
673 		}
674 
675 		/*Forward to next segment */
676 
677 		if (segment_cur [len_cur] == '\0') {
678 			break;
679 		}
680 
681 		segment_prev = segment_cur;
682 		len_prev = len_cur;
683 		segment_cur += len_cur + 1;
684 	}
685 
686 }
687 
688 static char *
make_full_uri_from_relative(const char * base_uri,const char * uri)689 make_full_uri_from_relative (const char *base_uri, const char *uri)
690 {
691 	char *result = NULL;
692 
693 	char *mutable_base_uri;
694 	char *mutable_uri;
695 
696 	char *uri_current;
697 	gsize base_uri_length;
698 	char *separator;
699 
700 	/* We may need one extra character
701 	 * to append a "/" to uri's that have no "/"
702 	 * (such as help:)
703 	 */
704 
705 	mutable_base_uri = (char *)g_malloc(strlen(base_uri)+2);
706 	strcpy (mutable_base_uri, base_uri);
707 
708 	uri_current = mutable_uri = g_strdup (uri);
709 
710 	/* Chew off Fragment and Query from the base_url */
711 
712 	separator = strrchr (mutable_base_uri, '#');
713 
714 	if (separator) {
715 		*separator = '\0';
716 	}
717 
718 	separator = strrchr (mutable_base_uri, '?');
719 
720 	if (separator) {
721 		*separator = '\0';
722 	}
723 
724 	if ('/' == uri_current[0] && '/' == uri_current [1]) {
725 		/* Relative URI's beginning with the authority
726 		 * component inherit only the scheme from their parents
727 		 */
728 
729 		separator = strchr (mutable_base_uri, ':');
730 
731 		if (separator) {
732 			separator[1] = '\0';
733 		}
734 	} else if ('/' == uri_current[0]) {
735 		/* Relative URI's beginning with '/' absolute-path based
736 		 * at the root of the base uri
737 		 */
738 
739 		separator = strchr (mutable_base_uri, ':');
740 
741 		/* g_assert (separator), really */
742 		if (separator) {
743 			/* If we start with //, skip past the authority section */
744 			if ('/' == separator[1] && '/' == separator[2]) {
745 				separator = strchr (separator + 3, '/');
746 				if (separator) {
747 					separator[0] = '\0';
748 				}
749 			} else {
750 				/* If there's no //, just assume the scheme is the root */
751 				separator[1] = '\0';
752 			}
753 		}
754 	} else if ('#' != uri_current[0]) {
755 		/* Handle the ".." convention for relative uri's */
756 
757 		/* If there's a trailing '/' on base_url, treat base_url
758 		 * as a directory path.
759 		 * Otherwise, treat it as a file path, and chop off the filename
760 		 */
761 
762 		base_uri_length = strlen (mutable_base_uri);
763 		if ('/' == mutable_base_uri[base_uri_length-1]) {
764 			/* Trim off '/' for the operation below */
765 			mutable_base_uri[base_uri_length-1] = 0;
766 		} else {
767 			separator = strrchr (mutable_base_uri, '/');
768 			if (separator) {
769 				/* Make sure we don't eat a domain part */
770 				char *tmp = separator - 1;
771 				if ((separator != mutable_base_uri) && (*tmp != '/')) {
772 					*separator = '\0';
773 				} else {
774 					/* Maybe there is no domain part and this is a toplevel URI's child */
775 					char *tmp2 = strstr (mutable_base_uri, ":///");
776 					if (tmp2 != NULL && tmp2 + 3 == separator) {
777 						*(separator + 1) = '\0';
778 					}
779 				}
780 			}
781 		}
782 
783 		remove_internal_relative_components (uri_current);
784 
785 		/* handle the "../"'s at the beginning of the relative URI */
786 		while (0 == strncmp ("../", uri_current, 3)) {
787 			uri_current += 3;
788 			separator = strrchr (mutable_base_uri, '/');
789 			if (separator) {
790 				*separator = '\0';
791 			} else {
792 				/* <shrug> */
793 				break;
794 			}
795 		}
796 
797 		/* handle a ".." at the end */
798 		if (uri_current[0] == '.' && uri_current[1] == '.'
799 		    && uri_current[2] == '\0') {
800 
801 			uri_current += 2;
802 			separator = strrchr (mutable_base_uri, '/');
803 			if (separator) {
804 				*separator = '\0';
805 			}
806 		}
807 
808 		/* Re-append the '/' */
809 		mutable_base_uri [strlen(mutable_base_uri)+1] = '\0';
810 		mutable_base_uri [strlen(mutable_base_uri)] = '/';
811 	}
812 
813 	result = g_strconcat (mutable_base_uri, uri_current, NULL);
814 	g_free (mutable_base_uri);
815 	g_free (mutable_uri);
816 
817 	return result;
818 }
819 
820 #endif
821 
822 /*
823  * More or less the same as gnome_vfs_uri_make_full_from_relative.
824  */
825 char *
UT_go_url_resolve_relative(const char * ref_uri,const char * rel_uri)826 UT_go_url_resolve_relative (const char *ref_uri, const char *rel_uri)
827 {
828 	char *simp, *uri;
829 
830 #if defined(GOFFICE_WITH_GNOME)
831 	uri = gnome_vfs_uri_make_full_from_relative (ref_uri, rel_uri);
832 #else
833 	g_return_val_if_fail (rel_uri != NULL, NULL);
834 
835 	if (is_uri_relative (rel_uri)) {
836 		g_return_val_if_fail (ref_uri != NULL, NULL);
837 		uri = make_full_uri_from_relative (ref_uri,
838 						   rel_uri);
839 	} else {
840 		uri = g_strdup (rel_uri);
841 	}
842 #endif
843 
844 	simp = UT_go_url_simplify (uri);
845 	g_free (uri);
846 	return simp;
847 }
848 
849 static char *
make_rel(const char * uri,const char * ref_uri,const char * uri_host,const char * slash)850 make_rel (const char *uri, const char *ref_uri,
851 	  const char *uri_host, const char *slash)
852 {
853 	const char *p, *q;
854 	int n;
855 	GString *res;
856 
857 	if (!slash)
858 		return NULL;
859 
860 	if (uri_host != NULL &&
861 	    strncmp (uri_host, ref_uri + (uri_host - uri), slash - uri_host))
862 		return NULL;
863 
864 	for (p = slash; *p; p++) {
865 		if (*p != ref_uri[p - uri])
866 			break;
867 		else if (*p == '/')
868 			slash = p;
869 	}
870 	/* URI components agree until slash.  */
871 
872 	/* Find out the number of '/' in uri after slash.  */
873 	n = 0;
874 	q = slash;
875 	while (1) {
876 		q = strchr (q + 1, '/');
877 		if (q)
878 			n++;
879 		else
880 			break;
881 	}
882 
883 	res = g_string_new (NULL);
884 	while (n-- > 0)
885 		g_string_append (res, "../");
886 	g_string_append (res, slash + 1);
887 	return g_string_free (res, FALSE);
888 }
889 
890 char *
UT_go_url_make_relative(const char * uri,const char * ref_uri)891 UT_go_url_make_relative (const char *uri, const char *ref_uri)
892 {
893 	int i;
894 
895 	/* Check that protocols are the same.  */
896 	for (i = 0; 1; i++) {
897 		char c = uri[i];
898 		char rc = ref_uri[i];
899 
900 		if (c == 0)
901 			return NULL;
902 
903 		if (c == ':') {
904 			if (rc == ':')
905 				break;
906 			return NULL;
907 		}
908 
909 		if (g_ascii_tolower (c) != g_ascii_tolower (rc))
910 			return NULL;
911 	}
912 
913 	if (g_ascii_strncasecmp (uri, "file:///", 8) == 0)
914 		return make_rel (uri, ref_uri, NULL, uri + 7);  /* Yes, 7.  */
915 
916 	if (g_ascii_strncasecmp (uri, "http://", 7) == 0)
917 		return make_rel (uri, ref_uri, uri + 7, strchr (uri + 7, '/'));
918 
919 	if (g_ascii_strncasecmp (uri, "https://", 8) == 0)
920 		return make_rel (uri, ref_uri, uri + 8, strchr (uri + 8, '/'));
921 
922 	if (g_ascii_strncasecmp (uri, "ftp://", 6) == 0)
923 		return make_rel (uri, ref_uri, uri + 6, strchr (uri + 6, '/'));
924 
925 	return NULL;
926 }
927 
928 /*
929  * Convert a shell argv entry (assumed already translated into filename
930  * encoding) to an escaped URI.
931  */
932 char *
UT_go_shell_arg_to_uri(const char * arg)933 UT_go_shell_arg_to_uri (const char *arg)
934 {
935 	gchar *tmp;
936 
937 	if (is_fd_uri (arg, NULL))
938 		return g_strdup (arg);
939 
940 	if (g_path_is_absolute (arg) || strchr (arg, ':') == NULL)
941 		return UT_go_filename_to_uri (arg);
942 
943 	tmp = UT_go_filename_from_uri (arg);
944 	if (tmp) {
945 		/*
946 		 * Do the reverse translation to get a minimum of
947 		 * canonicalization.
948 		 */
949 		char *res = UT_go_filename_to_uri (tmp);
950 		g_free (tmp);
951 		return res;
952 	}
953 
954 #if HAVE_GSF_GIO
955 	{
956 		GFile *f = g_file_new_for_commandline_arg (arg);
957 		char *uri = g_file_get_uri (f);
958 		g_object_unref (G_OBJECT (f));
959 		if (uri) {
960 			char *uri2 = UT_go_url_simplify(uri);
961 			g_free (uri);
962 			return uri2;
963 		}
964 	}
965 #elif defined(GOFFICE_WITH_GNOME)
966 	{
967 		/*
968 		 * oink://     --> NULL
969 		 * http://     --> "http" URI
970 		 */
971 		GnomeVFSURI *uri = gnome_vfs_uri_new (arg);
972 		if (uri) {
973 			gnome_vfs_uri_unref (uri);
974 			return UT_go_url_simplify (arg);
975 		}
976 	}
977 #elif defined(WITH_GSF_INPUT_HTTP)
978 	{
979 		if (g_ascii_strncasecmp (arg, "http://", strlen ("http://")) == 0) {
980 			return UT_go_url_simplify (arg);
981 		}
982 	}
983 #endif
984 
985 	/* Just assume it's a filename.  */
986 	return UT_go_filename_to_uri (arg);
987 }
988 
989 /**
990  * UT_go_basename_from_uri:
991  * @uri :
992  *
993  * Decode the final path component.  Returns as UTF-8 encoded suitable
994  * for display.
995  **/
996 char *
UT_go_basename_from_uri(const char * uri)997 UT_go_basename_from_uri (const char *uri)
998 {
999 	char *res;
1000 
1001 #if HAVE_GSF_GIO
1002 	GFile *f = g_file_new_for_uri (uri);
1003 	char *basename = g_file_get_basename (f);
1004 	g_object_unref (G_OBJECT (f));
1005 #elif defined(GOFFICE_WITH_GNOME)
1006 	char *raw_uri = gnome_vfs_unescape_string (uri, G_DIR_SEPARATOR_S);
1007 	char *basename = raw_uri ? g_path_get_basename (raw_uri) : NULL;
1008 	g_free (raw_uri);
1009 #else
1010 	char *uri_basename = g_path_get_basename (uri);
1011 	char *fake_uri = g_strconcat ("file:///", uri_basename, NULL);
1012 	char *filename = UT_go_filename_from_uri (fake_uri);
1013 	char *basename = filename ? g_path_get_basename (filename) : NULL;
1014 	g_free (uri_basename);
1015 	g_free (fake_uri);
1016 	g_free (filename);
1017 
1018 #endif
1019 
1020 	res = basename ? g_filename_display_name (basename) : NULL;
1021 	g_free (basename);
1022 	return res;
1023 }
1024 
1025 /**
1026  * UT_go_dirname_from_uri:
1027  * @uri :
1028  * @brief: if TRUE, hide "file://" if present.
1029  *
1030  * Decode the all but the final path component.  Returns as UTF-8 encoded
1031  * suitable for display.
1032  **/
1033 char *
UT_go_dirname_from_uri(const char * uri,gboolean brief)1034 UT_go_dirname_from_uri (const char *uri, gboolean brief)
1035 {
1036 	char *dirname_utf8, *dirname;
1037 
1038 #if defined(GOFFICE_WITH_GNOME)
1039 	char *raw_uri = gnome_vfs_unescape_string (uri, G_DIR_SEPARATOR_S);
1040 	dirname = raw_uri ? g_path_get_dirname (raw_uri) : NULL;
1041 	g_free (raw_uri);
1042 #else
1043 	char *uri_dirname = g_path_get_dirname (uri);
1044 	dirname = uri_dirname ? UT_go_filename_from_uri (uri_dirname) : NULL;
1045 	if(uri_dirname) {
1046 		g_free (uri_dirname);
1047 	}
1048 	uri_dirname = dirname ? g_strconcat ("file://", dirname, NULL) : NULL;
1049 	if(dirname) {
1050 		g_free (dirname);
1051 	}
1052 	dirname = uri_dirname;
1053 #endif
1054 
1055 	if (brief && dirname &&
1056 	    g_ascii_strncasecmp (dirname, "file:///", 8) == 0) {
1057 		char *temp = g_strdup (dirname + 7);
1058 		g_free (dirname);
1059 		dirname = temp;
1060 	}
1061 
1062 	dirname_utf8 = dirname ? g_filename_display_name (dirname) : NULL;
1063 	g_free (dirname);
1064 	return dirname_utf8;
1065 }
1066 
1067 
1068 gboolean
UT_go_directory_create(char const * uri,int mode,GError ** error)1069 UT_go_directory_create (char const *uri, int mode, GError **error)
1070 {
1071 #if HAVE_GSF_GIO
1072 	GFile *f = g_file_new_for_uri (uri);
1073 	gboolean res = g_file_make_directory (f, NULL, error);
1074 	g_object_unref (G_OBJECT (f));
1075 	UT_UNUSED(mode);
1076 	return res;
1077 #elif defined(GOFFICE_WITH_GNOME)
1078 	GnomeVFSResult vfs_result;
1079 
1080 	vfs_result = gnome_vfs_make_directory (uri, mode);
1081 	if(vfs_result != GNOME_VFS_OK) {
1082 		g_set_error (error, gsf_output_error_id (), (gint) vfs_result,
1083 			     gnome_vfs_result_to_string (vfs_result));
1084 
1085 		return FALSE;
1086 	}
1087 
1088 	return TRUE;
1089 #else
1090 	char *filename;
1091 	if(error) {
1092 		*error = NULL;
1093 	}
1094 
1095 	filename = UT_go_filename_from_uri (uri);
1096 	if (filename) {
1097 		int result;
1098 
1099 		result = g_mkdir(filename, mode);
1100 		g_free (filename);
1101 		return (result == 0);
1102 	}
1103 
1104 	return FALSE;
1105 #endif
1106 }
1107 
1108 /* ------------------------------------------------------------------------- */
1109 
1110 static gboolean
is_fd_uri(const char * uri,int * fd)1111 is_fd_uri (const char *uri, int *fd)
1112 {
1113 	unsigned long ul;
1114 	char *end;
1115 
1116 	if (g_ascii_strncasecmp (uri, "fd://", 5))
1117 		return FALSE;
1118 	uri += 5;
1119 	if (!g_ascii_isdigit (*uri))
1120 		return FALSE;  /* Space, for example.  */
1121 
1122 	ul = strtoul (uri, &end, 10);
1123 	if (*end != 0 || ul > INT_MAX)
1124 		return FALSE;
1125 
1126 	if (fd != NULL)
1127 		*fd = (int)ul;
1128 	return TRUE;
1129 }
1130 
1131 /* ------------------------------------------------------------------------- */
1132 
1133 static GsfInput *
open_plain_file(const char * path,GError ** err)1134 open_plain_file (const char *path, GError **err)
1135 {
1136 	GsfInput *input = gsf_input_mmap_new (path, NULL);
1137 	if (input != NULL)
1138 		return input;
1139 	/* Only report error if stdio fails too */
1140 	return gsf_input_stdio_new (path, err);
1141 }
1142 
1143 static GsfInput *
UT_go_file_open_impl(char const * uri,GError ** err)1144 UT_go_file_open_impl (char const *uri, GError **err)
1145 {
1146 	char *filename;
1147 	int fd;
1148 
1149 	if (err != NULL)
1150 		*err = NULL;
1151 	g_return_val_if_fail (uri != NULL, NULL);
1152 
1153 	if (uri[0] == G_DIR_SEPARATOR) {
1154 		g_warning ("Got plain filename %s in UT_go_file_open.", uri);
1155 		return open_plain_file (uri, err);
1156 	}
1157 
1158 	filename = UT_go_filename_from_uri (uri);
1159 	if (filename) {
1160 		GsfInput *result = open_plain_file (filename, err);
1161 		g_free (filename);
1162 		return result;
1163 	}
1164 
1165 	if (is_fd_uri (uri, &fd)) {
1166 #if defined G_OS_WIN32
1167 		setmode (fd, O_BINARY);
1168 #endif
1169 		int fd2 = dup (fd);
1170 		FILE *fil = fd2 != -1 ? fdopen (fd2, "rb") : NULL;
1171 		GsfInput *result;
1172 
1173 		if (!fil) {
1174 			g_set_error (err, gsf_output_error_id (), 0,
1175 				     "Unable to read from %s", uri);
1176 			return NULL;
1177 		}
1178 
1179 		/* guarantee that file descriptors will be seekable */
1180 		result = gsf_input_memory_new_from_file (fil);
1181 		fclose (fil);
1182 
1183 		return result;
1184 	}
1185 
1186 	if (!strncmp (uri, "http://", 7) || !strncmp (uri, "https://", 8))
1187 		return gsf_input_http_new (uri, err);
1188 #if HAVE_GSF_GIO
1189 	return gsf_input_gio_new_for_uri (uri, err);
1190 #elif defined(GOFFICE_WITH_GNOME)
1191 	return gsf_input_gnomevfs_new (uri, err);
1192 #endif
1193 	g_set_error (err, gsf_input_error (), 0,
1194 		     "Invalid or non-supported URI");
1195 	return NULL;
1196 }
1197 
1198 /**
1199  * UT_go_file_open :
1200  * @uri :
1201  * @err : #GError
1202  *
1203  * Try all available methods to open a file or return an error
1204  **/
1205 GsfInput *
UT_go_file_open(char const * uri,GError ** err)1206 UT_go_file_open (char const *uri, GError **err)
1207 {
1208 	GsfInput * input;
1209 
1210 	input = UT_go_file_open_impl (uri, err);
1211 	if (input != NULL)
1212 	{
1213 		GsfInput * uncompress = gsf_input_uncompress (input);
1214 		gsf_input_set_name (uncompress, uri);
1215 		return uncompress;
1216 	}
1217 	return NULL;
1218 }
1219 
1220 static GsfOutput *
gsf_output_proxy_create(GsfOutput * wrapped,char const * uri,GError ** err)1221 gsf_output_proxy_create (GsfOutput *wrapped, char const *uri, GError **err)
1222 {
1223 	if (!wrapped) {
1224 		g_set_error (err, gsf_output_error_id (), 0,
1225 			     "Unable to write to %s", uri);
1226 		return NULL;
1227 	}
1228 
1229 	/* guarantee that file descriptors will be seekable */
1230 	return gsf_output_proxy_new (wrapped);
1231 }
1232 
1233 static GsfOutput *
UT_go_file_create_impl(char const * uri,GError ** err)1234 UT_go_file_create_impl (char const *uri, GError **err)
1235 {
1236 	char *filename;
1237 	int fd;
1238 	g_return_val_if_fail (uri != NULL, NULL);
1239 
1240 	std::string path = uri;
1241         bool is_uri = UT_go_path_is_uri(path.c_str());
1242         bool is_filename = is_uri ? false : path.find_last_of(G_DIR_SEPARATOR) == std::string::npos;
1243 	bool is_path = !is_uri && !is_filename;
1244 
1245 	filename = UT_go_filename_from_uri (uri);
1246 	if (is_path || filename) {
1247 		GsfOutput *result = gsf_output_stdio_new (filename?filename:uri, err);
1248 		if(filename)
1249 			g_free (filename);
1250 		return result;
1251 	}
1252 
1253 	if (is_fd_uri (uri, &fd)) {
1254 #if defined G_OS_WIN32
1255 		setmode (fd, O_BINARY);
1256 #endif
1257 		int fd2 = dup (fd);
1258 		FILE *fil = fd2 != -1 ? fdopen (fd2, "wb") : NULL;
1259 		GsfOutput *result = fil ? gsf_output_stdio_new_FILE (uri, fil, FALSE) : NULL;
1260 
1261 		/* guarantee that file descriptors will be seekable */
1262 		return gsf_output_proxy_create(result, uri, err);
1263 	}
1264 
1265 #if HAVE_GSF_GIO
1266 	return gsf_output_proxy_create(gsf_output_gio_new_for_uri (uri, err), uri, err);
1267 #elif defined(GOFFICE_WITH_GNOME)
1268 	return gsf_output_gnomevfs_new (uri, err);
1269 #else
1270 	g_set_error (err, gsf_output_error_id (), 0,
1271 		     "Invalid or non-supported URI");
1272 	return NULL;
1273 #endif
1274 }
1275 
1276 GsfOutput *
UT_go_file_create(char const * uri,GError ** err)1277 UT_go_file_create (char const *uri, GError **err)
1278 {
1279 	GsfOutput * output;
1280 
1281 	output = UT_go_file_create_impl (uri, err);
1282 	if (output != NULL)
1283 	{
1284 		gsf_output_set_name (output, uri);
1285 		return output;
1286 	}
1287 	return NULL;
1288 }
1289 
1290 gboolean
UT_go_file_remove(char const * uri,GError ** err)1291 UT_go_file_remove (char const *uri, GError ** err)
1292 {
1293 	char *filename;
1294 
1295 	g_return_val_if_fail (uri != NULL, FALSE);
1296 
1297 	filename = UT_go_filename_from_uri (uri);
1298 	if (filename) {
1299 		int result = remove (filename);
1300 		g_free (filename);
1301 		return (result == 0);
1302 	}
1303 
1304 
1305 #if HAVE_GSF_GIO
1306 
1307 	{
1308 		GFile *f = g_file_new_for_uri (uri);
1309 		gboolean res = g_file_delete (f, NULL, err);
1310 		g_object_unref (G_OBJECT (f));
1311 
1312 		return res;
1313 	}
1314 
1315 #elif defined(GOFFICE_WITH_GNOME)
1316 	UT_UNUSED(err);
1317 	return (gnome_vfs_unlink (uri) == GNOME_VFS_OK);
1318 #else
1319 	g_set_error (err, gsf_output_error_id (), 0,
1320 		     "Invalid or non-supported URI");
1321 	return FALSE;
1322 #endif
1323 }
1324 
1325 /* ------------------------------------------------------------------------- */
1326 /* Adapted from gtkfilechooserdefault.c.  Unfortunately it is static there.  */
1327 
1328 GSList *
UT_go_file_split_urls(const char * data)1329 UT_go_file_split_urls (const char *data)
1330 {
1331   GSList *uris;
1332   const char *p, *q;
1333 
1334   uris = NULL;
1335 
1336   p = data;
1337 
1338   /* We don't actually try to validate the URI according to RFC
1339    * 2396, or even check for allowed characters - we just ignore
1340    * comments and trim whitespace off the ends.  We also
1341    * allow LF delimination as well as the specified CRLF.
1342    *
1343    * We do allow comments like specified in RFC 2483.
1344    */
1345   while (p)
1346     {
1347       if (*p != '#')
1348 	{
1349 	  while (g_ascii_isspace (*p))
1350 	    p++;
1351 
1352 	  q = p;
1353 	  while (*q && (*q != '\n') && (*q != '\r'))
1354 	    q++;
1355 
1356 	  if (q > p)
1357 	    {
1358 	      q--;
1359 	      while (q > p && g_ascii_isspace (*q))
1360 		q--;
1361 
1362 	      if (q > p)
1363 		uris = g_slist_prepend (uris, g_strndup (p, q - p + 1));
1364 	    }
1365 	}
1366       p = strchr (p, '\n');
1367       if (p)
1368 	p++;
1369     }
1370 
1371   uris = g_slist_reverse (uris);
1372   return uris;
1373 }
1374 
1375 gboolean
UT_go_file_exists(char const * uri)1376 UT_go_file_exists (char const *uri)
1377 {
1378 #if HAVE_GSF_GIO
1379 	GFile *f = g_file_new_for_uri (uri);
1380 	gboolean res = g_file_query_exists (f, NULL);
1381 	g_object_unref (G_OBJECT (f));
1382 	return res;
1383 #elif defined (GOFFICE_WITH_GNOME)
1384 	GnomeVFSURI *vfs_uri = gnome_vfs_uri_new (uri);
1385 	if (vfs_uri) {
1386 		gboolean exists = gnome_vfs_uri_exists (vfs_uri);
1387 		gnome_vfs_uri_unref (vfs_uri);
1388 		return exists;
1389 	}
1390 
1391 	return FALSE;
1392 #else
1393 
1394 #if GLIB_CHECK_VERSION(2,26,0) || defined(G_OS_WIN32)
1395 	GStatBuf file_stat;
1396 #else
1397 	struct stat file_stat;
1398 #endif
1399 	char *filename = UT_go_filename_from_uri (uri);
1400 	int result = filename ? g_stat (filename, &file_stat) : -1;
1401 
1402 	g_free (filename);
1403 
1404 	return result == 0;
1405 #endif
1406 }
1407 
1408 UT_GOFilePermissions *
UT_go_get_file_permissions(char const * uri)1409 UT_go_get_file_permissions (char const *uri)
1410 {
1411 	UT_GOFilePermissions * file_permissions = NULL;
1412 
1413 #if defined (GOFFICE_WITH_GNOME)
1414 	GnomeVFSFileInfo *file_info;
1415 	GnomeVFSResult result;
1416 
1417         file_info = gnome_vfs_file_info_new ();
1418         result = gnome_vfs_get_file_info (uri, file_info,
1419 					  (GnomeVFSFileInfoOptions)(GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS |
1420 								    GNOME_VFS_FILE_INFO_FOLLOW_LINKS));
1421 
1422         if (result == GNOME_VFS_OK) {
1423 		file_permissions = g_new0 (UT_GOFilePermissions, 1);
1424 
1425 		/* Owner  Permissions */
1426 		file_permissions->owner_read    = ((file_info->permissions & GNOME_VFS_PERM_USER_READ) != 0);
1427 		file_permissions->owner_write   = ((file_info->permissions & GNOME_VFS_PERM_USER_WRITE) != 0);
1428 		file_permissions->owner_execute = ((file_info->permissions & GNOME_VFS_PERM_USER_EXEC) != 0);
1429 
1430 		/* Group  Permissions */
1431 		file_permissions->group_read    = ((file_info->permissions & GNOME_VFS_PERM_GROUP_READ) != 0);
1432 		file_permissions->group_write   = ((file_info->permissions & GNOME_VFS_PERM_GROUP_WRITE) != 0);
1433 		file_permissions->group_execute = ((file_info->permissions & GNOME_VFS_PERM_GROUP_EXEC) != 0);
1434 
1435 		/* Others Permissions */
1436 		file_permissions->others_read    = ((file_info->permissions & GNOME_VFS_PERM_OTHER_READ) != 0);
1437 		file_permissions->others_write   = ((file_info->permissions & GNOME_VFS_PERM_OTHER_WRITE) != 0);
1438 		file_permissions->others_execute = ((file_info->permissions & GNOME_VFS_PERM_OTHER_EXEC) != 0);
1439 	}
1440 
1441 	gnome_vfs_file_info_unref (file_info);
1442 #else
1443 
1444 #if GLIB_CHECK_VERSION(2,26,0) || defined(G_OS_WIN32)
1445 	GStatBuf file_stat;
1446 #else
1447 	struct stat file_stat;
1448 #endif
1449 	char *filename = UT_go_filename_from_uri (uri);
1450 	int result = filename ? g_stat (filename, &file_stat) : -1;
1451 
1452 	g_free (filename);
1453 	if (result == 0) {
1454 		file_permissions = g_new0 (UT_GOFilePermissions, 1);
1455 #if ! defined (G_OS_WIN32)
1456 		/* Owner  Permissions */
1457 		file_permissions->owner_read    = ((file_stat.st_mode & S_IRUSR) != 0);
1458 		file_permissions->owner_write   = ((file_stat.st_mode & S_IWUSR) != 0);
1459 		file_permissions->owner_execute = ((file_stat.st_mode & S_IXUSR) != 0);
1460 
1461 		/* Group  Permissions */
1462 		file_permissions->group_read    = ((file_stat.st_mode & S_IRGRP) != 0);
1463 		file_permissions->group_write   = ((file_stat.st_mode & S_IWGRP) != 0);
1464 		file_permissions->group_execute = ((file_stat.st_mode & S_IXGRP) != 0);
1465 
1466 		/* Others Permissions */
1467 		file_permissions->others_read    = ((file_stat.st_mode & S_IROTH) != 0);
1468 		file_permissions->others_write   = ((file_stat.st_mode & S_IWOTH) != 0);
1469 		file_permissions->others_execute = ((file_stat.st_mode & S_IXOTH) != 0);
1470 #else
1471 		/* Windows */
1472 		/* Owner  Permissions */
1473 		file_permissions->owner_read    = ((file_stat.st_mode & S_IREAD) != 0);
1474 		file_permissions->owner_write   = ((file_stat.st_mode & S_IWRITE) != 0);
1475 		file_permissions->owner_execute = ((file_stat.st_mode & S_IEXEC) != 0);
1476 #endif
1477 	}
1478 #endif
1479 	return file_permissions;
1480 }
1481 
1482 void
UT_go_set_file_permissions(char const * uri,UT_GOFilePermissions * file_permissions)1483 UT_go_set_file_permissions (char const *uri, UT_GOFilePermissions * file_permissions)
1484 {
1485 #if defined (GOFFICE_WITH_GNOME)
1486 	GnomeVFSFileInfo *file_info;
1487 	GnomeVFSResult result;
1488 
1489         file_info = gnome_vfs_file_info_new ();
1490 	file_info->permissions = (GnomeVFSFilePermissions)0;
1491 
1492 	/* Set owner permissions */
1493 	if (file_permissions->owner_read == TRUE)
1494 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_USER_READ);
1495 
1496 	if (file_permissions->owner_write == TRUE)
1497 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_USER_WRITE);
1498 
1499 	if (file_permissions->owner_execute == TRUE)
1500 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_USER_EXEC);
1501 
1502 	/* Set group permissions */
1503 	if (file_permissions->group_read == TRUE)
1504 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_GROUP_READ);
1505 
1506 	if (file_permissions->group_write == TRUE)
1507 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_GROUP_WRITE);
1508 
1509 	if (file_permissions->group_execute == TRUE)
1510 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_GROUP_EXEC);
1511 
1512 	/* Set others permissions */
1513 	if (file_permissions->others_read == TRUE)
1514 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_OTHER_READ);
1515 
1516 	if (file_permissions->others_write == TRUE)
1517 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_OTHER_WRITE);
1518 
1519 	if (file_permissions->others_execute == TRUE)
1520 		file_info->permissions = (GnomeVFSFilePermissions)(file_info->permissions | GNOME_VFS_PERM_OTHER_EXEC);
1521 
1522 	result = gnome_vfs_set_file_info (uri, file_info,
1523 					  (GnomeVFSSetFileInfoMask) (GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS |
1524 								    GNOME_VFS_FILE_INFO_FOLLOW_LINKS |
1525 								    GNOME_VFS_SET_FILE_INFO_PERMISSIONS));
1526 
1527 	if (result != GNOME_VFS_OK)
1528 		g_warning ("Error setting permissions for '%s'.", uri);
1529 
1530 	gnome_vfs_file_info_unref (file_info);
1531 #elif ! defined (G_OS_WIN32)
1532 	mode_t permissions = 0;
1533 	int result;
1534 	char *filename;
1535 
1536 	/* Set owner permissions */
1537 	if (file_permissions->owner_read == TRUE)
1538 		permissions |= S_IRUSR;
1539 
1540 	if (file_permissions->owner_write == TRUE)
1541 		permissions |= S_IWUSR;
1542 
1543 	if (file_permissions->owner_execute == TRUE)
1544 		permissions |= S_IXUSR;
1545 
1546 	/* Set group permissions */
1547 	if (file_permissions->group_read == TRUE)
1548 		permissions |= S_IRGRP;
1549 
1550 	if (file_permissions->group_write == TRUE)
1551 		permissions |= S_IWGRP;
1552 
1553 	if (file_permissions->group_execute == TRUE)
1554 		permissions |= S_IXGRP;
1555 
1556 	/* Set others permissions */
1557 	if (file_permissions->others_read == TRUE)
1558 		permissions |= S_IROTH;
1559 
1560 	if (file_permissions->others_write == TRUE)
1561 		permissions |= S_IWOTH;
1562 
1563 	if (file_permissions->others_execute == TRUE)
1564 		permissions |= S_IXOTH;
1565 
1566 	filename = UT_go_filename_from_uri (uri);
1567 
1568 #ifdef HAVE_G_CHMOD
1569 	result = g_chmod (filename, permissions);
1570 #else
1571 	result = chmod (filename, permissions);
1572 #endif
1573 
1574 	g_free (filename);
1575 
1576 	if (result != 0)
1577 		g_warning ("Error setting permissions for %s.", uri);
1578 #endif
1579 }
1580 
1581 typedef enum {
1582 	UT_GO_FILE_DATE_TYPE_ACCESSED = 0,
1583 	UT_GO_FILE_DATE_TYPE_MODIFIED,
1584 	UT_GO_FILE_DATE_TYPE_CHANGED
1585 } UT_GOFileDateType;
1586 
1587 static time_t
UT_go_file_get_date(char const * uri,UT_GOFileDateType type)1588 UT_go_file_get_date (char const *uri, UT_GOFileDateType type)
1589 {
1590 	time_t tm = -1;
1591 
1592 #if defined(GOFFICE_WITH_GNOME)
1593 	GnomeVFSFileInfo *file_info;
1594 
1595 	GnomeVFSResult result;
1596 
1597         file_info = gnome_vfs_file_info_new ();
1598         result = gnome_vfs_get_file_info (uri, file_info,
1599                                           GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
1600 
1601         if (result == GNOME_VFS_OK) {
1602 		switch (type) {
1603 			case UT_GO_FILE_DATE_TYPE_ACCESSED:
1604 				tm = file_info->atime;
1605 				break;
1606 			case UT_GO_FILE_DATE_TYPE_MODIFIED:
1607 				tm = file_info->mtime;
1608 				break;
1609 			case UT_GO_FILE_DATE_TYPE_CHANGED:
1610 				tm = file_info->ctime;
1611 				break;
1612 		}
1613 	}
1614 
1615 	gnome_vfs_file_info_unref (file_info);
1616 #else
1617 #if GLIB_CHECK_VERSION(2,26,0) || defined(G_OS_WIN32)
1618 	GStatBuf file_stat;
1619 #else
1620 	struct stat file_stat;
1621 #endif
1622 	char *filename = UT_go_filename_from_uri (uri);
1623 	int result = filename ? g_stat (filename, &file_stat) : -1;
1624 
1625 	g_free (filename);
1626 	if (result == 0) {
1627 		switch (type) {
1628 			case UT_GO_FILE_DATE_TYPE_ACCESSED:
1629 				tm = file_stat.st_atime;
1630 				break;
1631 			case UT_GO_FILE_DATE_TYPE_MODIFIED:
1632 				tm = file_stat.st_mtime;
1633 				break;
1634 			case UT_GO_FILE_DATE_TYPE_CHANGED:
1635 				tm = file_stat.st_ctime;
1636 				break;
1637 		}
1638 	}
1639 #endif
1640 
1641 	return tm;
1642 }
1643 
1644 time_t
UT_go_file_get_date_accessed(char const * uri)1645 UT_go_file_get_date_accessed (char const *uri)
1646 {
1647 	return UT_go_file_get_date (uri, UT_GO_FILE_DATE_TYPE_ACCESSED);
1648 }
1649 
1650 time_t
UT_go_file_get_date_modified(char const * uri)1651 UT_go_file_get_date_modified (char const *uri)
1652 {
1653 	return UT_go_file_get_date (uri, UT_GO_FILE_DATE_TYPE_MODIFIED);
1654 }
1655 
1656 time_t
UT_go_file_get_date_changed(char const * uri)1657 UT_go_file_get_date_changed (char const *uri)
1658 {
1659 	return UT_go_file_get_date (uri, UT_GO_FILE_DATE_TYPE_CHANGED);
1660 }
1661 
1662 /* ------------------------------------------------------------------------- */
1663 #ifdef TOOLKIT_GTK_ALL
1664 // We need this for systems where gtk_show_uri() is broken
1665 // Don't get me started.
1666 // Note that if gtk_show_uri() fails but returns true, then
1667 // there is nothing that can be done.
1668 static char *
check_program(char const * prog)1669 check_program (char const *prog)
1670 {
1671 	if (NULL == prog)
1672 		return NULL;
1673 	if (g_path_is_absolute (prog)) {
1674 		if (!g_file_test (prog, G_FILE_TEST_IS_EXECUTABLE))
1675 			return NULL;
1676 	} else if (!g_find_program_in_path (prog))
1677 		return NULL;
1678 	return g_strdup (prog);
1679 }
1680 
1681 static void
fallback_open_uri(const gchar * url,GError ** err)1682 fallback_open_uri(const gchar* url, GError** err)
1683 {
1684 	gchar *browser = NULL;
1685 	gchar *clean_url = NULL;
1686 
1687 	/* 1) Check BROWSER env var */
1688 	browser = check_program (getenv ("BROWSER"));
1689 
1690 	if (browser == NULL) {
1691 		static char const * const browsers[] = {
1692 			"xdg-open",             /* XDG. you shouldn't need anything else */
1693 			"sensible-browser",	/* debian */
1694 			"epiphany",		/* primary gnome */
1695 			"galeon",		/* secondary gnome */
1696 			"encompass",
1697 			"firefox",
1698 			"mozilla-firebird",
1699 			"mozilla",
1700 			"netscape",
1701 			"konqueror",
1702 			"xterm -e w3m",
1703 			"xterm -e lynx",
1704 			"xterm -e links"
1705 		};
1706 		unsigned i;
1707 		for (i = 0 ; i < G_N_ELEMENTS (browsers) ; i++)
1708 			if (NULL != (browser = check_program (browsers[i])))
1709 				break;
1710   	}
1711 
1712 	if (browser != NULL) {
1713 		gint    argc;
1714 		gchar **argv = NULL;
1715 		char   *cmd_line = g_strconcat (browser, " %1", NULL);
1716 
1717 		if (g_shell_parse_argv (cmd_line, &argc, &argv, err)) {
1718 			/* check for '%1' in an argument and substitute the url
1719 			 * otherwise append it */
1720 			gint i;
1721 			char *tmp;
1722 
1723 			for (i = 1 ; i < argc ; i++)
1724 				if (NULL != (tmp = strstr (argv[i], "%1"))) {
1725 					*tmp = '\0';
1726 					tmp = g_strconcat (argv[i],
1727 						(clean_url != NULL) ? (char const *)clean_url : url,
1728 						tmp+2, NULL);
1729 					g_free (argv[i]);
1730 					argv[i] = tmp;
1731 					break;
1732 				}
1733 
1734 			/* there was actually a %1, drop the one we added */
1735 			if (i != argc-1) {
1736 				g_free (argv[argc-1]);
1737 				argv[argc-1] = NULL;
1738 			}
1739 			g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
1740 				NULL, NULL, NULL, err);
1741 			g_strfreev (argv);
1742 		}
1743 		g_free (cmd_line);
1744 	}
1745 	g_free (browser);
1746 	g_free (clean_url);
1747 }
1748 #endif
1749 
1750 #ifdef G_OS_WIN32
1751 #undef _
1752 #include "ut_Win32LocaleString.h"
1753 #endif
1754 
1755 GError *
UT_go_url_show(gchar const * url)1756 UT_go_url_show (gchar const *url)
1757 {
1758 #ifdef G_OS_WIN32
1759 	UT_Win32LocaleString str;
1760 	str.fromUTF8 (url);
1761 	ShellExecuteW (NULL, L"open", str.c_str(), NULL, NULL, SW_SHOWNORMAL);
1762 	return NULL;
1763 #elif TOOLKIT_COCOA
1764 	CFStringRef urlStr = CFStringCreateWithCString(kCFAllocatorDefault, url, kCFStringEncodingUTF8);
1765 	CFURLRef cfUrl = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
1766 	OSStatus err = LSOpenCFURLRef(cfUrl, NULL);
1767 	CFRelease(cfUrl);
1768 	CFRelease(urlStr);
1769 	if (err != noErr) {
1770 		;
1771 	}
1772 	return NULL;
1773 #else
1774 	GError *err = NULL;
1775 #if GTK_CHECK_VERSION(2,14,0)
1776 	if(!gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &err)) {
1777 		fallback_open_uri(url, &err);
1778 	}
1779 	return err;
1780 #elif defined(WITH_GNOMEVFS)
1781 	gnome_vfs_url_show (url);
1782 	return err;
1783 #else
1784 	fallback_open_uri(url, &err);
1785 	return err;
1786 #endif
1787 #endif
1788 }
1789 
1790 /**
1791  * UT_go_url_check_extension
1792  * @uri     : Uri
1793  * @std_ext : Standard extension for the content type
1794  * @new_uri : New uri
1795  *
1796  * Modifies given @uri by adding the extension @std_ext if needed.
1797  * If no @std_ext is given or @uri already has some extension,
1798  * it just copies @uri.
1799  *
1800  * Value in new_uri:  newly allocated string which you should g_free after
1801  *                    use, containing (optionally) modified uri.
1802  *
1803  * Return Value:  FALSE if the uri has an extension not matching @std_ext
1804  */
1805 gboolean
UT_go_url_check_extension(gchar const * uri,gchar const * std_ext,gchar ** new_uri)1806 UT_go_url_check_extension (gchar const *uri,
1807 			gchar const *std_ext,
1808 			gchar **new_uri)
1809 {
1810 	gchar *base;
1811 	gchar *user_ext;
1812 	gboolean res;
1813 
1814 	g_return_val_if_fail (uri != NULL, FALSE);
1815 	g_return_val_if_fail (new_uri != NULL, FALSE);
1816 
1817 	res      = TRUE;
1818 	base     = g_path_get_basename (uri);
1819 	user_ext = strrchr (base, '.');
1820 	if (std_ext != NULL && strlen (std_ext) > 0 && user_ext == NULL)
1821 		*new_uri = g_strconcat (uri, ".", std_ext, NULL);
1822 	else {
1823 		if (user_ext != NULL && std_ext != NULL)
1824 			res = !UT_go_utf8_collate_casefold (user_ext + 1, std_ext);
1825 		*new_uri = g_strdup (uri);
1826 	}
1827 	g_free (base);
1828 
1829 	return res;
1830 }
1831 
1832 gchar *
UT_go_get_mime_type(gchar const * uri)1833 UT_go_get_mime_type (gchar const *uri)
1834 {
1835 #if HAVE_GSF_GIO
1836 	gboolean content_type_uncertain = FALSE;
1837 	char *content_type = g_content_type_guess (uri, NULL, 0, &content_type_uncertain);
1838 	if (content_type) {
1839 		char *mime_type = g_content_type_get_mime_type (content_type);
1840 		g_free (content_type);
1841 
1842 		if (mime_type)
1843 			return mime_type;
1844 	}
1845 
1846 	return g_strdup ("application/octet-stream");
1847 
1848 #elif defined(GOFFICE_WITH_GNOME)
1849 	return gnome_vfs_get_mime_type (uri);
1850 #elif 0 /* defined(G_OS_WIN32) */
1851 	LPWSTR wuri, mime_type;
1852 
1853 	wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
1854 	if (wuri &&
1855 	    FindMimeFromData (NULL, wuri, NULL, 0, NULL, 0, &mime_type, 0) == NOERROR)
1856 	{
1857 		g_free (wuri);
1858 		return g_utf16_to_utf8 (mime_type, -1, NULL, NULL, NULL);
1859 	}
1860 
1861 	g_free (wuri);
1862 
1863 	/* We try to determine mime using FindMimeFromData().
1864 	 * However, we are not sure whether the functions will know about
1865 	 * the necessary mime types. In the worst wase we fall back to
1866 	 * "text/plain"
1867 	 */
1868 	return g_strdup ("text/plain");
1869 #else
1870 	UT_UNUSED(uri);
1871 	return g_strdup ("application/octet-stream");
1872 #endif
1873 }
1874 
1875 gchar
UT_go_get_mime_type_for_data(gconstpointer data,int data_size)1876 *UT_go_get_mime_type_for_data	(gconstpointer data, int data_size)
1877 {
1878 #if defined(GOFFICE_WITH_GNOME)
1879 	return g_strdup (gnome_vfs_get_mime_type_for_data (data, data_size));
1880 #elif 0 /* defined G_OS_WIN32 */
1881 	LPWSTR mime_type;
1882 
1883 	if (FindMimeFromData (NULL, NULL, (LPVOID)data, (DWORD)data_size, NULL, 0, &mime_type, 0) == NOERROR)
1884 	{
1885 		return g_utf16_to_utf8 (mime_type, -1, NULL, NULL, NULL);
1886 	}
1887 
1888 	/* We try to determine mime using FindMimeFromData().
1889 	 * However, we are not sure whether the functions will know about
1890 	 * the necessary mime types. In the worst wase we fall back to
1891 	 * "text/plain"
1892 	 */
1893 	return g_strdup ("text/plain");
1894 #else
1895 	UT_UNUSED(data);
1896 	UT_UNUSED(data_size);
1897 	return g_strdup ("application/octet-stream");
1898 #endif
1899 }
1900 
1901 gchar const
UT_go_mime_type_get_description(gchar const * mime_type)1902 *UT_go_mime_type_get_description	(gchar const *mime_type)
1903 {
1904 #if defined(GOFFICE_WITH_GNOME)
1905 	return gnome_vfs_mime_get_description (mime_type);
1906 #else
1907 	return mime_type;
1908 #endif
1909 }
1910 
1911 /* ------------------------------------------------------------------------- */
1912 
1913 #ifdef G_OS_WIN32
1914 static gchar **saved_args;
1915 static int saved_argc;
1916 #endif
1917 
1918 gchar const **
UT_go_shell_argv_to_glib_encoding(gint argc,gchar const ** argv)1919 UT_go_shell_argv_to_glib_encoding (gint argc, gchar const **argv)
1920 {
1921 #ifdef G_OS_WIN32
1922 	gchar **args;
1923 	gint i;
1924 
1925 	args = g_new (gchar *, argc);
1926 	if (G_WIN32_IS_NT_BASED ())
1927 	{
1928 		LPWSTR *wargs;
1929 		gint narg;
1930 		GIConv conv;
1931 
1932 		wargs = CommandLineToArgvW (GetCommandLineW (), &narg);
1933 		conv = g_iconv_open ("utf-8", "utf-16le");
1934 		for (i = 0; i < narg; ++i)
1935 			args[i] = g_convert_with_iconv ((const gchar *) wargs[i], wcslen (wargs[i]) << 1, conv, NULL, NULL, NULL);
1936 		g_iconv_close (conv);
1937 	}
1938 	else
1939 	{
1940 		for (i = 0; i < argc; ++i)
1941 			args[i] = g_locale_to_utf8 (argv[i], -1, NULL, NULL, NULL);
1942 	}
1943 
1944 	saved_args = args;
1945 	saved_argc = argc;
1946 
1947 	return (gchar const **) args;
1948 #else
1949 	UT_UNUSED(argc);
1950 	return argv;
1951 #endif
1952 }
1953 
1954 void
UT_go_shell_argv_to_glib_encoding_free(void)1955 UT_go_shell_argv_to_glib_encoding_free (void)
1956 {
1957 #ifdef G_OS_WIN32
1958 	if (saved_args) {
1959 		gint i;
1960 
1961 		for (i = 0; i < saved_argc; ++i)
1962 			g_free (saved_args[i]);
1963 		g_free (saved_args);
1964 	}
1965 #endif
1966 }
1967 
1968 /*
1969  * go-glib-extras.c:  Various utility routines that should have been in glib.
1970  *
1971  * Authors:
1972  *    Miguel de Icaza (miguel@gnu.org)
1973  *    Jukka-Pekka Iivonen (iivonen@iki.fi)
1974  *    Zbigniew Chyla (cyba@gnome.pl)
1975  *    Morten Welinder (terra@gnome.org)
1976  */
1977 
1978 const char *
UT_go_guess_encoding(const char * raw,size_t len,const char * user_guess,char ** utf8_str)1979 UT_go_guess_encoding (const char *raw, size_t len, const char *user_guess,
1980 		      char **utf8_str)
1981 {
1982 	int try_nb;
1983 	gboolean debug = FALSE;
1984 
1985 	g_return_val_if_fail (raw != NULL, NULL);
1986 
1987 	for (try_nb = 1; 1; try_nb++) {
1988 		const char *guess;
1989 		GError *error = NULL;
1990 		char *utf8_data;
1991 
1992 		switch (try_nb) {
1993 		case 1: guess = user_guess; break;
1994 		case 2: g_get_charset (&guess); break;
1995 		case 3: {
1996 			xmlCharEncoding enc =
1997 				xmlDetectCharEncoding ((const unsigned char*)raw, len);
1998 			switch (enc) {
1999 			case XML_CHAR_ENCODING_ERROR:
2000 			case XML_CHAR_ENCODING_NONE:
2001 				break;
2002 			case XML_CHAR_ENCODING_UTF16LE:
2003 				/* Default would give "UTF-16".  */
2004 				guess = "UTF-16LE";
2005 				break;
2006 			case XML_CHAR_ENCODING_UTF16BE:
2007 				/* Default would give "UTF-16".  */
2008 				guess = "UTF-16BE";
2009 				break;
2010 			default:
2011 				guess = xmlGetCharEncodingName (enc);
2012 			}
2013 			break;
2014 		}
2015 		case 4: guess = "ASCII"; break;
2016 		case 5: guess = "ISO-8859-1"; break;
2017 		case 6: guess = "UTF-8"; break;
2018 		default: return NULL;
2019 		}
2020 
2021 		if (!guess)
2022 			continue;
2023 
2024 		if (debug)
2025 			g_print ("Trying %s as encoding.\n", guess);
2026 
2027 		utf8_data = g_convert (raw, len, "UTF-8", guess,
2028 				       NULL, NULL, &error);
2029 		if (!error) {
2030 			if (debug)
2031 				g_print ("Guessed %s as encoding.\n", guess);
2032 			if (utf8_str)
2033 				*utf8_str = utf8_data;
2034 			else
2035 				g_free (utf8_data);
2036 			return guess;
2037 		}
2038 
2039 		g_error_free (error);
2040 	}
2041 }
2042 
2043 /**
2044  * UT_go_get_real_name :
2045  *
2046  * Return a utf8 encoded string with the current user name.
2047  * Caller should _NOT_ g_free the result.
2048  **/
2049 char const *
UT_go_get_real_name(void)2050 UT_go_get_real_name (void)
2051 {
2052 	/* We will leak this.  */
2053 	static char *UT_go_real_name = NULL;
2054 
2055 	if (UT_go_real_name == NULL) {
2056 		char const *name = getenv ("NAME");
2057 		if (name == NULL)
2058 			name = g_get_real_name ();
2059 		if (name == NULL)
2060 			name = g_get_user_name ();
2061 		if (name != NULL)
2062 			(void) UT_go_guess_encoding (name, strlen (name),
2063 				NULL, &UT_go_real_name);
2064 		else
2065 			UT_go_real_name = (char *)"unknown";
2066 	}
2067 	return UT_go_real_name;
2068 }
2069 
2070 gint
UT_go_utf8_collate_casefold(const char * a,const char * b)2071 UT_go_utf8_collate_casefold (const char *a, const char *b)
2072 {
2073 	char *a2 = g_utf8_casefold (a, -1);
2074 	char *b2 = g_utf8_casefold (b, -1);
2075 	int res = g_utf8_collate (a2, b2);
2076 	g_free (a2);
2077 	g_free (b2);
2078 	return res;
2079 }
2080 
2081