yelp-document: Fix return type of document_indexed
[yelp.git] / libyelp / yelp-uri.c
blob7425f25c9499c25d6d3af983308c119d547e13ac
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Shaun McCance <shaunm@gnome.org>
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <string.h>
26 #include <stdio.h>
28 #include <glib.h>
29 #include <gio/gio.h>
31 #include "yelp-uri.h"
32 #include "yelp-settings.h"
34 static void yelp_uri_dispose (GObject *object);
35 static void yelp_uri_finalize (GObject *object);
37 static void resolve_start (YelpUri *uri);
38 static void resolve_sync (YelpUri *uri);
39 static void resolve_async (YelpUri *uri);
40 static gboolean resolve_final (YelpUri *uri);
42 static void resolve_file_uri (YelpUri *uri);
43 static void resolve_file_path (YelpUri *uri);
44 static void resolve_data_dirs (YelpUri *uri,
45 const gchar *subdir,
46 const gchar *docid,
47 const gchar *pageid,
48 gboolean langfirst);
49 static void resolve_ghelp_uri (YelpUri *uri);
50 static void resolve_help_uri (YelpUri *uri);
51 static void resolve_help_list_uri (YelpUri *uri);
52 static void resolve_man_uri (YelpUri *uri);
53 static void resolve_info_uri (YelpUri *uri);
54 static void resolve_xref_uri (YelpUri *uri);
55 static void resolve_page_and_frag (YelpUri *uri,
56 const gchar *arg);
57 static void resolve_gfile (YelpUri *uri,
58 const gchar *query,
59 const gchar *hash);
61 static gboolean is_man_path (const gchar *uri,
62 const gchar *encoding);
64 G_DEFINE_TYPE (YelpUri, yelp_uri, G_TYPE_OBJECT)
65 #define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_URI, YelpUriPrivate))
67 typedef struct _YelpUriPrivate YelpUriPrivate;
68 struct _YelpUriPrivate {
69 GThread *resolver;
71 YelpUriDocumentType doctype;
72 YelpUriDocumentType tmptype;
74 gchar *docuri;
75 gchar *fulluri;
76 GFile *gfile;
78 gchar **search_path;
79 gchar *page_id;
80 gchar *frag_id;
82 GHashTable *query;
84 /* Unresolved */
85 YelpUri *res_base;
86 gchar *res_arg;
89 enum {
90 RESOLVED,
91 LAST_SIGNAL
93 static guint uri_signals[LAST_SIGNAL] = {0,};
95 /******************************************************************************/
97 static const gchar *mancats[] = {
98 "0p",
99 "1", "1p", "1g", "1t", "1x", "1ssl", "1m",
100 "2",
101 "3", "3o", "3t", "3p", "3blt", "3nas", "3form", "3menu", "3tiff", "3ssl", "3readline",
102 "3ncurses", "3curses", "3f", "3pm", "3perl", "3qt", "3x", "3X11",
103 "4", "4x",
104 "5", "5snmp", "5x", "5ssl",
105 "6", "6x",
106 "7", "7gcc", "7x", "7ssl",
107 "8", "8l", "9", "0p",
108 NULL
111 static const gchar *infosuffix[] = {
112 ".info",
113 ".info.gz", ".info.bz2", ".info.lzma",
114 ".gz", ".bz2", ".lzma",
115 NULL
118 static const gchar default_info_path[] =
119 "/usr/info:/usr/share/info:/usr/local/info:/usr/local/share/info";
121 /******************************************************************************/
123 static void
124 yelp_uri_class_init (YelpUriClass *klass)
126 GObjectClass *object_class = G_OBJECT_CLASS (klass);
128 object_class->dispose = yelp_uri_dispose;
129 object_class->finalize = yelp_uri_finalize;
131 uri_signals[RESOLVED] =
132 g_signal_new ("resolved",
133 G_OBJECT_CLASS_TYPE (klass),
134 G_SIGNAL_RUN_LAST,
135 0, NULL, NULL,
136 g_cclosure_marshal_VOID__VOID,
137 G_TYPE_NONE, 0);
139 g_type_class_add_private (klass, sizeof (YelpUriPrivate));
142 static void
143 yelp_uri_init (YelpUri *uri)
145 YelpUriPrivate *priv = GET_PRIV (uri);
147 priv->query = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
149 return;
152 static void
153 yelp_uri_dispose (GObject *object)
155 YelpUriPrivate *priv = GET_PRIV (object);
157 if (priv->gfile) {
158 g_object_unref (priv->gfile);
159 priv->gfile = NULL;
162 if (priv->res_base) {
163 g_object_unref (priv->res_base);
164 priv->res_base = NULL;
167 if (priv->query) {
168 g_hash_table_destroy (priv->query);
169 priv->query = NULL;
172 G_OBJECT_CLASS (yelp_uri_parent_class)->dispose (object);
175 static void
176 yelp_uri_finalize (GObject *object)
178 YelpUriPrivate *priv = GET_PRIV (object);
180 g_free (priv->docuri);
181 g_free (priv->fulluri);
182 g_strfreev (priv->search_path);
183 g_free (priv->page_id);
184 g_free (priv->frag_id);
185 g_free (priv->res_arg);
187 G_OBJECT_CLASS (yelp_uri_parent_class)->finalize (object);
190 /******************************************************************************/
192 YelpUri *
193 yelp_uri_new (const gchar *arg)
195 return yelp_uri_new_relative (NULL, arg);
198 YelpUri *
199 yelp_uri_new_relative (YelpUri *base, const gchar *arg)
201 YelpUri *uri;
202 YelpUriPrivate *priv;
204 uri = (YelpUri *) g_object_new (YELP_TYPE_URI, NULL);
206 priv = GET_PRIV (uri);
207 priv->doctype = YELP_URI_DOCUMENT_TYPE_UNRESOLVED;
208 if (base)
209 priv->res_base = g_object_ref (base);
210 priv->res_arg = g_strdup (arg);
212 return uri;
215 YelpUri *
216 yelp_uri_new_search (YelpUri *base,
217 const gchar *text)
219 YelpUri *uri;
220 YelpUriPrivate *priv;
221 gchar *tmp;
223 uri = (YelpUri *) g_object_new (YELP_TYPE_URI, NULL);
225 priv = GET_PRIV (uri);
226 priv->doctype = YELP_URI_DOCUMENT_TYPE_UNRESOLVED;
227 if (base)
228 priv->res_base = g_object_ref (base);
229 tmp = g_uri_escape_string (text, NULL, FALSE);
230 priv->res_arg = g_strconcat("xref:search=", tmp, NULL);
231 g_free (tmp);
233 return uri;
236 /******************************************************************************/
238 void
239 yelp_uri_resolve (YelpUri *uri)
241 YelpUriPrivate *priv = GET_PRIV (uri);
243 if (priv->res_base && !yelp_uri_is_resolved (priv->res_base)) {
244 g_signal_connect_swapped (priv->res_base, "resolved",
245 G_CALLBACK (resolve_start),
246 uri);
247 yelp_uri_resolve (priv->res_base);
249 else {
250 resolve_start (uri);
254 void
255 yelp_uri_resolve_sync (YelpUri *uri)
257 YelpUriPrivate *priv = GET_PRIV (uri);
259 if (priv->doctype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
260 return;
262 if (priv->res_base)
263 yelp_uri_resolve_sync (priv->res_base);
265 g_object_ref (uri);
266 resolve_sync (uri);
267 resolve_final (uri);
270 /* We want code to be able to do something like this:
272 * if (yelp_uri_get_document_type (uri) != YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
273 * g_signal_connect (uri, "resolve", callback, data);
274 * yelp_uri_resolve (uri);
277 * Resolving happens in a separate thread, though, so if that thread can change
278 * the document type, we have a race condition. So here's the rules we play by:
280 * 1) None of the getters except the document type getter can return real data
281 * while the URI is unresolved. They all do a resolved check first, and
282 * return NULL if the URI is not resolved.
284 * 2) The threaded resolver functions can modify anything but the document
285 * type. They are the only things that are allowed to modify that data.
287 * 3) The resolver thread is not allowed to modify the document type. When
288 * it's done, it queues an async function to set the document type and
289 * emit "resolved" in the main thread.
291 * 4) Once a URI is resolved, it is immutable.
293 static void
294 resolve_start (YelpUri *uri)
296 YelpUriPrivate *priv = GET_PRIV (uri);
298 if (priv->resolver == NULL) {
299 g_object_ref (uri);
300 priv->resolver = g_thread_new ("uri-resolve",
301 (GThreadFunc) resolve_async,
302 uri);
306 static void
307 resolve_sync (YelpUri *uri)
309 YelpUriPrivate *priv = GET_PRIV (uri);
311 if (g_str_has_prefix (priv->res_arg, "ghelp:")
312 || g_str_has_prefix (priv->res_arg, "gnome-help:")) {
313 resolve_ghelp_uri (uri);
315 else if (g_str_has_prefix (priv->res_arg, "help:")) {
316 resolve_help_uri (uri);
318 else if (g_str_has_prefix (priv->res_arg, "help-list:")) {
319 resolve_help_list_uri (uri);
321 else if (g_str_has_prefix (priv->res_arg, "file:")) {
322 resolve_file_uri (uri);
324 else if (g_str_has_prefix (priv->res_arg, "man:")) {
325 resolve_man_uri (uri);
327 else if (g_str_has_prefix (priv->res_arg, "info:")) {
328 resolve_info_uri (uri);
330 else if (g_str_has_prefix (priv->res_arg, "xref:")) {
331 YelpUriPrivate *base_priv;
332 if (priv->res_base == NULL) {
333 priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
334 return;
336 base_priv = GET_PRIV (priv->res_base);
337 switch (base_priv->doctype) {
338 case YELP_URI_DOCUMENT_TYPE_UNRESOLVED:
339 break;
340 case YELP_URI_DOCUMENT_TYPE_DOCBOOK:
341 case YELP_URI_DOCUMENT_TYPE_MALLARD:
342 case YELP_URI_DOCUMENT_TYPE_INFO:
343 resolve_xref_uri (uri);
344 break;
345 case YELP_URI_DOCUMENT_TYPE_MAN: {
346 gchar *tmp = g_strconcat ("man:", priv->res_arg + 5, NULL);
347 g_free (priv->res_arg);
348 priv->res_arg = tmp;
349 resolve_man_uri (uri);
350 break;
352 case YELP_URI_DOCUMENT_TYPE_TEXT:
353 case YELP_URI_DOCUMENT_TYPE_HTML:
354 case YELP_URI_DOCUMENT_TYPE_XHTML:
355 resolve_file_path (uri);
356 break;
357 case YELP_URI_DOCUMENT_TYPE_HELP_LIST:
358 /* FIXME: what do we do? */
359 break;
360 case YELP_URI_DOCUMENT_TYPE_NOT_FOUND:
361 case YELP_URI_DOCUMENT_TYPE_EXTERNAL:
362 case YELP_URI_DOCUMENT_TYPE_ERROR:
363 break;
364 default:
365 g_assert_not_reached ();
366 break;
369 else if (strchr (priv->res_arg, ':')) {
370 priv->tmptype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
372 else {
373 resolve_file_path (uri);
376 /* We _always_ want to have a non-null fulluri, so check for it
377 * having been set here and, if we can't think of something
378 * better, set it to res_arg. */
379 if (!priv->fulluri) {
380 priv->fulluri = g_strdup (priv->res_arg);
384 static void
385 resolve_async (YelpUri *uri)
387 resolve_sync (uri);
388 g_idle_add ((GSourceFunc) resolve_final, uri);
391 static gboolean
392 resolve_final (YelpUri *uri)
394 YelpUriPrivate *priv = GET_PRIV (uri);
396 priv->resolver = NULL;
398 if (priv->tmptype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
399 priv->doctype = priv->tmptype;
400 else
401 priv->doctype = YELP_URI_DOCUMENT_TYPE_ERROR;
403 if (priv->res_base) {
404 g_object_unref (priv->res_base);
405 priv->res_base = NULL;
408 if (priv->res_arg) {
409 g_free (priv->res_arg);
410 priv->res_arg = NULL;
413 g_signal_emit (uri, uri_signals[RESOLVED], 0);
414 g_object_unref (uri);
415 return FALSE;
418 /******************************************************************************/
420 gboolean
421 yelp_uri_is_resolved (YelpUri *uri)
423 YelpUriPrivate *priv = GET_PRIV (uri);
424 return priv->doctype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED;
427 YelpUriDocumentType
428 yelp_uri_get_document_type (YelpUri *uri)
430 YelpUriPrivate *priv = GET_PRIV (uri);
431 return priv->doctype;
434 gchar *
435 yelp_uri_get_document_uri (YelpUri *uri)
437 YelpUriPrivate *priv = GET_PRIV (uri);
438 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
439 return NULL;
441 /* There's some client code where it makes sense to want a
442 * document uri, whether or not it conforms to a scheme we really
443 * understand. For example, we might want to look up whether the
444 * given page is currently being visited. */
445 if ((!priv->docuri) && priv->fulluri) {
446 return g_strdup (priv->fulluri);
449 return g_strdup (priv->docuri);
452 gchar *
453 yelp_uri_get_canonical_uri (YelpUri *uri)
455 YelpUriPrivate *priv = GET_PRIV (uri);
456 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
457 return NULL;
458 return g_strdup (priv->fulluri);
461 GFile *
462 yelp_uri_get_file (YelpUri *uri)
464 YelpUriPrivate *priv = GET_PRIV (uri);
465 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
466 return NULL;
467 return priv->gfile ? g_object_ref (priv->gfile) : NULL;
470 gchar **
471 yelp_uri_get_search_path (YelpUri *uri)
473 YelpUriPrivate *priv = GET_PRIV (uri);
474 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
475 return NULL;
476 return g_strdupv (priv->search_path);
479 gchar *
480 yelp_uri_get_page_id (YelpUri *uri)
482 YelpUriPrivate *priv = GET_PRIV (uri);
483 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
484 return NULL;
485 return g_strdup (priv->page_id);
488 gchar *
489 yelp_uri_get_frag_id (YelpUri *uri)
491 YelpUriPrivate *priv = GET_PRIV (uri);
492 if (priv->doctype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
493 return NULL;
494 return g_strdup (priv->frag_id);
497 gchar *
498 yelp_uri_get_query (YelpUri *uri,
499 const gchar *key)
501 YelpUriPrivate *priv = GET_PRIV (uri);
502 const gchar *ret = g_hash_table_lookup (priv->query, key);
503 if (ret)
504 return g_strdup (ret);
505 else
506 return NULL;
509 /******************************************************************************/
511 gchar *
512 yelp_uri_locate_file_uri (YelpUri *uri,
513 const gchar *filename)
515 YelpUriPrivate *priv = GET_PRIV (uri);
516 GFile *gfile;
517 gchar *fullpath;
518 gchar *returi = NULL;
519 gint i;
521 if (g_path_is_absolute (filename)) {
522 if (g_file_test (filename, G_FILE_TEST_EXISTS))
523 return g_filename_to_uri (filename, NULL, NULL);
524 return NULL;
527 for (i = 0; priv->search_path[i] != NULL; i++) {
528 fullpath = g_strconcat (priv->search_path[i],
529 G_DIR_SEPARATOR_S,
530 filename,
531 NULL);
532 if (g_file_test (fullpath, G_FILE_TEST_EXISTS)) {
533 gfile = g_file_new_for_path (fullpath);
534 returi = g_file_get_uri (gfile);
535 g_object_unref (gfile);
537 g_free (fullpath);
538 if (returi)
539 break;
541 return returi;
544 /******************************************************************************/
546 static void
547 resolve_file_uri (YelpUri *uri)
549 YelpUriPrivate *priv = GET_PRIV (uri);
550 gchar *uristr;
551 const gchar *hash = strchr (priv->res_arg, '#');
553 if (hash) {
554 uristr = g_strndup (priv->res_arg, hash - priv->res_arg);
555 hash++;
557 else
558 uristr = priv->res_arg;
560 priv->gfile = g_file_new_for_uri (uristr);
562 resolve_gfile (uri, NULL, hash);
565 static void
566 resolve_file_path (YelpUri *uri)
568 YelpUriPrivate *base_priv = NULL;
569 YelpUriPrivate *priv = GET_PRIV (uri);
570 gchar *path;
571 const gchar *hash;
573 /* Treat xref: URIs like relative file paths */
574 if (g_str_has_prefix (priv->res_arg, "xref:")) {
575 gchar *tmp = g_strdup (priv->res_arg + 5);
576 g_free (priv->res_arg);
577 priv->res_arg = tmp;
580 if (priv->res_base)
581 base_priv = GET_PRIV (priv->res_base);
583 hash = strchr (priv->res_arg, '#');
584 if (hash) {
585 path = g_strndup (priv->res_arg, hash - priv->res_arg);
586 hash++;
588 else
589 path = priv->res_arg;
591 if (priv->res_arg[0] == '/') {
592 priv->gfile = g_file_new_for_path (path);
594 else if (base_priv && base_priv->gfile) {
595 GFileInfo *info;
596 info = g_file_query_info (base_priv->gfile,
597 G_FILE_ATTRIBUTE_STANDARD_TYPE,
598 G_FILE_QUERY_INFO_NONE,
599 NULL, NULL);
600 if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR) {
601 GFile *parent = g_file_get_parent (base_priv->gfile);
602 priv->gfile = g_file_resolve_relative_path (parent, path);
603 g_object_unref (parent);
605 else {
606 priv->gfile = g_file_resolve_relative_path (base_priv->gfile, path);
609 else {
610 gchar *cur;
611 GFile *curfile;
612 cur = g_get_current_dir ();
613 curfile = g_file_new_for_path (cur);
614 priv->gfile = g_file_resolve_relative_path (curfile, path);
615 g_object_unref (curfile);
616 g_free (cur);
619 resolve_gfile (uri, NULL, hash);
622 static void
623 resolve_data_dirs (YelpUri *ret,
624 const gchar *subdir,
625 const gchar *docid,
626 const gchar *pageid,
627 gboolean langfirst)
629 const gchar * const *sdatadirs = g_get_system_data_dirs ();
630 const gchar * const *langs = g_get_language_names ();
631 /* The strings are still owned by GLib; we just own the array. */
632 gchar **datadirs;
633 YelpUriPrivate *priv = GET_PRIV (ret);
634 gchar *filename = NULL;
635 gchar **searchpath = NULL;
636 gint searchi, searchmax;
637 gint datadir_i, lang_i;
639 datadirs = g_new0 (gchar *, g_strv_length ((gchar **) sdatadirs) + 2);
640 datadirs[0] = (gchar *) g_get_user_data_dir ();
641 for (datadir_i = 0; sdatadirs[datadir_i]; datadir_i++)
642 datadirs[datadir_i + 1] = (gchar *) sdatadirs[datadir_i];
644 searchi = 0;
645 searchmax = 10;
646 searchpath = g_new0 (gchar *, 10);
648 for (datadir_i = 0; datadirs[datadir_i]; datadir_i++) {
649 for (lang_i = 0; langs[lang_i]; lang_i++) {
650 gchar *helpdir = g_build_filename (datadirs[datadir_i],
651 subdir,
652 langfirst ? langs[lang_i] : docid,
653 langfirst ? docid : langs[lang_i],
654 NULL);
655 if (!g_file_test (helpdir, G_FILE_TEST_IS_DIR)) {
656 g_free (helpdir);
657 continue;
660 if (searchi + 1 >= searchmax) {
661 searchmax += 5;
662 searchpath = g_renew (gchar *, searchpath, searchmax);
664 searchpath[searchi] = helpdir;
665 searchpath[++searchi] = NULL;
667 if (priv->tmptype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED)
668 /* We've already found it. We're just adding to the search path now. */
669 continue;
671 filename = g_strdup_printf ("%s/index.page", helpdir);
672 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
673 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
674 g_free (filename);
675 filename = g_strdup (helpdir);
676 continue;
678 g_free (filename);
680 if (langfirst) {
681 filename = g_strdup_printf ("%s/index.docbook", helpdir);
682 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
683 priv->tmptype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
684 continue;
686 g_free (filename);
688 else {
689 filename = g_strdup_printf ("%s/%s.xml", helpdir, pageid);
690 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
691 priv->tmptype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
692 continue;
694 g_free (filename);
697 filename = g_strdup_printf ("%s/%s.html", helpdir, pageid);
698 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
699 priv->tmptype = YELP_URI_DOCUMENT_TYPE_HTML;
700 continue;
702 g_free (filename);
704 filename = g_strdup_printf ("%s/%s.xhtml", helpdir, pageid);
705 if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
706 priv->tmptype = YELP_URI_DOCUMENT_TYPE_XHTML;
707 continue;
709 g_free (filename);
710 } /* end for langs */
711 } /* end for datadirs */
713 g_free (datadirs);
714 if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
715 g_strfreev (searchpath);
716 priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
718 else {
719 priv->gfile = g_file_new_for_path (filename);
720 priv->search_path = searchpath;
724 static void
725 build_ghelp_fulluri (YelpUri *uri)
727 YelpUriPrivate *priv = GET_PRIV (uri);
729 g_assert (priv->tmptype != YELP_URI_DOCUMENT_TYPE_UNRESOLVED);
730 g_assert (priv->docuri != NULL);
731 priv->fulluri = g_strconcat (priv->docuri,
732 priv->tmptype == YELP_URI_DOCUMENT_TYPE_MALLARD ? "/" : "",
733 priv->page_id ? "?" : "",
734 priv->page_id ? priv->page_id : "",
735 priv->frag_id ? "#" : "",
736 priv->frag_id ? priv->frag_id : "",
737 NULL);
740 static void
741 resolve_ghelp_uri (YelpUri *uri)
743 /* ghelp:/path/to/file
744 * ghelp:document[/file][?page][#frag]
746 YelpUriPrivate *priv = GET_PRIV (uri);
747 gchar *document, *slash, *query, *hash;
748 gchar *colon, *c; /* do not free */
750 colon = strchr (priv->res_arg, ':');
751 if (!colon) {
752 priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
753 return;
756 slash = query = hash = NULL;
757 for (c = colon; *c != '\0'; c++) {
758 if (*c == '#' && hash == NULL)
759 hash = c;
760 else if (*c == '?' && query == NULL && hash == NULL)
761 query = c;
762 else if (*c == '/' && slash == NULL && query == NULL && hash == NULL)
763 slash = c;
766 if (slash || query || hash)
767 document = g_strndup (colon + 1,
768 (slash ? slash : (query ? query : hash)) - colon - 1);
769 else
770 document = g_strdup (colon + 1);
772 if (slash && (query || hash))
773 slash = g_strndup (slash + 1,
774 (query ? query : hash) - slash - 1);
775 else if (slash)
776 slash = g_strdup (slash + 1);
778 if (query && hash)
779 query = g_strndup (query + 1,
780 hash - query - 1);
781 else if (query)
782 query = g_strdup (query + 1);
784 if (hash)
785 hash = g_strdup (hash + 1);
787 if (*(colon + 1) == '/') {
788 gchar *path;
790 path = g_build_filename ("/", slash, NULL);
791 if (g_file_test (path, G_FILE_TEST_EXISTS)) {
792 priv->gfile = g_file_new_for_path (path);
793 resolve_gfile (uri, query, hash);
794 } else {
795 gchar *dirname = g_path_get_dirname (path);
796 gchar *basename = g_path_get_basename (path);
798 priv->gfile = g_file_new_for_path (dirname);
799 g_free (dirname);
800 resolve_gfile (uri, basename, hash);
801 g_free (basename);
803 g_free (path);
804 g_free (slash);
805 g_free (query);
806 g_free (hash);
807 g_free (document);
809 return;
812 resolve_data_dirs (uri, "gnome/help", document, slash ? slash : document, FALSE);
814 if (query && hash) {
815 priv->page_id = query;
816 priv->frag_id = hash;
818 else if (query) {
819 priv->page_id = query;
820 if (priv->tmptype != YELP_URI_DOCUMENT_TYPE_MALLARD)
821 priv->frag_id = g_strdup (query);
823 else if (hash) {
824 priv->page_id = hash;
825 priv->frag_id = g_strdup (hash);
828 if (priv->frag_id && g_str_has_prefix (priv->frag_id, "search=")) {
829 g_free (priv->frag_id);
830 priv->frag_id = NULL;
833 priv->docuri = g_strconcat ("ghelp:", document,
834 slash ? "/" : NULL,
835 slash, NULL);
837 build_ghelp_fulluri (uri);
839 g_free (document);
840 g_free (slash);
841 return;
844 static void
845 resolve_help_uri (YelpUri *uri)
847 /* help:document[/page][?query][#frag]
849 YelpUriPrivate *priv = GET_PRIV (uri);
850 gchar *document, *slash, *query, *hash;
851 gchar *colon, *c; /* do not free */
853 colon = strchr (priv->res_arg, ':');
854 if (!colon) {
855 priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
856 return;
859 slash = query = hash = NULL;
860 for (c = colon; *c != '\0'; c++) {
861 if (*c == '#' && hash == NULL)
862 hash = c;
863 else if (*c == '?' && query == NULL && hash == NULL)
864 query = c;
865 else if (*c == '/' && slash == NULL && query == NULL && hash == NULL)
866 slash = c;
869 if (slash || query || hash)
870 document = g_strndup (colon + 1,
871 (slash ? slash : (query ? query : hash)) - colon - 1);
872 else
873 document = g_strdup (colon + 1);
875 if (slash && (query || hash))
876 slash = g_strndup (slash + 1,
877 (query ? query : hash) - slash - 1);
878 else if (slash)
879 slash = g_strdup (slash + 1);
881 if (query && hash)
882 query = g_strndup (query + 1,
883 hash - query - 1);
884 else if (query)
885 query = g_strdup (query + 1);
887 if (query) {
888 gchar **keyvals = g_strsplit (query, "&", 0);
889 gint i;
891 for (i = 0; keyvals[i]; i++) {
892 gchar *key, *val;
893 val = strchr (keyvals[i], '=');
894 if (val == NULL)
895 continue;
896 key = g_uri_unescape_segment (keyvals[i], val, NULL);
897 val = g_uri_unescape_string (val + 1, NULL);
899 g_hash_table_insert (priv->query, key, val);
902 g_strfreev (keyvals);
905 if (hash)
906 hash = g_strdup (hash + 1);
908 priv->page_id = (slash ? slash : g_strdup ("index"));
909 resolve_data_dirs (uri, "help", document, priv->page_id, TRUE);
911 if (hash)
912 priv->frag_id = hash;
913 if (priv->frag_id && g_str_has_prefix (priv->frag_id, "search=")) {
914 g_free (priv->frag_id);
915 priv->frag_id = NULL;
918 priv->docuri = g_strconcat ("help:", document, NULL);
920 priv->fulluri = g_strconcat (priv->docuri,
921 priv->page_id ? "/" : "",
922 priv->page_id ? priv->page_id : "",
923 query ? "?" : "",
924 query ? query : "",
925 priv->frag_id ? "#" : "",
926 priv->frag_id ? priv->frag_id : "",
927 NULL);
929 g_free (query);
930 g_free (document);
931 return;
934 static void
935 resolve_help_list_uri (YelpUri *uri)
937 YelpUriPrivate *priv = GET_PRIV (uri);
938 priv->docuri = g_strdup ("help-list:");
939 priv->fulluri = g_strdup (priv->res_arg);
940 priv->page_id = g_strdup ("index");
941 priv->tmptype = YELP_URI_DOCUMENT_TYPE_HELP_LIST;
945 Resolve a manual file's path using 'man -w'. section may be NULL,
946 otherwise should be the section of the manual (ie should have dealt
947 with empty strings before calling this!) Returns NULL if the file
948 can't be found.
950 static gchar*
951 find_man_path (gchar* name, gchar* section)
953 const gchar* argv[] = { "man", "-w", NULL, NULL, NULL };
954 gchar **my_argv;
955 gchar *ystdout = NULL;
956 gint status;
957 gchar **lines;
958 GError *error = NULL;
960 /* Syntax for man is "man -w <section> <name>", possibly omitting
961 section */
962 if (section) {
963 argv[2] = section;
964 argv[3] = name;
965 } else {
966 argv[2] = name;
969 /* g_strdupv() should accept a "const gchar **". */
970 my_argv = g_strdupv ((gchar **) argv);
972 if (!g_spawn_sync (NULL, my_argv, NULL,
973 G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
974 NULL, NULL,
975 &ystdout, NULL, &status, &error)) {
976 g_warning ("Couldn't find path for %s(%s). Error: %s",
977 name, section, error->message);
978 g_error_free (error);
981 g_strfreev (my_argv);
983 if (status == 0) {
984 lines = g_strsplit (ystdout, "\n", 2);
985 g_free (ystdout);
986 ystdout = g_strdup (lines[0]);
988 g_strfreev (lines);
989 return ystdout;
990 } else {
991 g_free (ystdout);
992 return NULL;
996 static void
997 build_man_uris (YelpUri *uri, const char *name, const char *section)
999 YelpUriPrivate *priv = GET_PRIV (uri);
1001 g_assert (priv->tmptype == YELP_URI_DOCUMENT_TYPE_MAN);
1002 priv->docuri = g_strdup ("man:");
1003 priv->fulluri = g_strconcat ("man:", name,
1004 section ? "." : "",
1005 section ? section : "",
1006 NULL);
1007 priv->page_id = g_strconcat (name,
1008 section ? "." : "",
1009 section ? section : "",
1010 NULL);
1013 static void
1014 resolve_man_uri (YelpUri *uri)
1016 YelpUriPrivate *priv = GET_PRIV (uri);
1017 /* man:/path/to/file
1018 * man:name(section)
1019 * man:name.section
1020 * man:name
1023 /* Search via regular expressions for name, name(section) and
1024 * name.section (assuming that name doesn't contain forward
1025 * slashes or other nasties)
1027 * If these don't match, assume that we were given a filename
1028 * (absolute iff it starts with a /).
1030 static GRegex* man_not_path = NULL;
1031 GError *error = NULL;
1032 GMatchInfo *match_info = NULL;
1033 gchar *name, *section, *hash;
1034 gchar *path;
1036 if (!man_not_path) {
1037 /* Match group 1 should contain the name; then one of groups 3
1038 * and 4 will contain the section if there was one. Group 6
1039 * will contain any hash fragment. */
1040 man_not_path = g_regex_new ("man:((?:[^ /.()#]|\\.(?=[^0-9]))+)"
1041 "(\\(([0-9A-Za-z]+)\\)|\\.([0-9A-Za-z]+)|)"
1042 "(#([^/ ()]+))?",
1043 0, 0, &error);
1044 if (!man_not_path) {
1045 g_error ("Error with regex in man uri: %s\n",
1046 error->message);
1050 if (!g_regex_match (man_not_path, priv->res_arg,
1051 0, &match_info)) {
1052 /* The regexp didn't match, so treat as a file name. */
1053 guint i;
1054 static const char *man_suffixes[] = { "gz", "bz2", "lzma", NULL };
1056 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1057 priv->gfile = g_file_new_for_path (priv->res_arg + 4);
1058 name = g_file_get_basename (priv->gfile);
1059 for (i = 0; i < G_N_ELEMENTS (man_suffixes); i++) {
1060 if (is_man_path (name, man_suffixes[i])) {
1061 if (man_suffixes[i])
1062 name[strlen (name) - strlen (man_suffixes[i]) - 1] = '\0';
1063 break;
1066 build_man_uris (uri, name, NULL);
1068 else {
1069 /* The regexp matched, so we've got a name/section pair that
1070 * needs resolving. */
1071 name = g_match_info_fetch (match_info, 1);
1072 section = g_match_info_fetch (match_info, 3);
1073 hash = g_match_info_fetch (match_info, 6);
1074 if (!name) {
1075 g_error ("Error matching strings in man uri '%s'",
1076 priv->res_arg);
1078 if ((!section) || (section[0] == '\0')) {
1079 section = g_match_info_fetch (match_info, 4);
1081 if (section && section[0] == '\0') section = NULL;
1083 path = find_man_path (name, section);
1085 if (!path) {
1086 priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
1087 return;
1089 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1090 priv->gfile = g_file_new_for_path (path);
1091 build_man_uris (uri, name, section);
1093 if (hash && hash[0] != '\0')
1094 resolve_page_and_frag (uri, hash + 1);
1096 g_free (path);
1097 g_match_info_free (match_info);
1101 static void
1102 build_info_uris (YelpUri *uri, const char *name, const char *section)
1104 YelpUriPrivate *priv = GET_PRIV (uri);
1106 g_assert (priv->tmptype == YELP_URI_DOCUMENT_TYPE_INFO);
1107 priv->docuri = g_strconcat ("info:", name, NULL);
1108 priv->fulluri = g_strconcat (priv->docuri,
1109 section ? "#" : "",
1110 section ? section : "",
1111 NULL);
1112 priv->page_id = g_strdup (section);
1113 priv->frag_id = g_strdup (section);
1116 static void
1117 resolve_info_uri (YelpUri *uri)
1119 YelpUriPrivate *priv = GET_PRIV (uri);
1120 /* info:/path/to/file
1121 * info:name#node
1122 * info:name
1123 * info:(name)node
1124 * info:(name)
1126 static gchar **infopath = NULL;
1127 gchar *name = NULL;
1128 gchar *sect = NULL;
1129 gchar *fullpath = NULL;
1130 /* do not free */
1131 gchar *colon;
1132 gint infopath_i, suffix_i;
1134 if (g_str_has_prefix (priv->res_arg, "info:/")) {
1135 const gchar *hash;
1137 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1139 hash = strchr (priv->res_arg + 5, '#');
1140 if (hash) {
1141 gchar *path;
1143 path = g_strndup (priv->res_arg + 5, hash - (priv->res_arg + 5));
1144 priv->gfile = g_file_new_for_path (path);
1145 g_free (path);
1146 sect = g_strdup (hash + 1);
1148 else
1149 priv->gfile = g_file_new_for_path (priv->res_arg + 5);
1151 name = g_file_get_basename (priv->gfile);
1152 for (suffix_i = 0; infosuffix[suffix_i]; suffix_i++) {
1153 if (g_str_has_suffix (name, infosuffix[suffix_i])) {
1154 name[strlen (name) - strlen (infosuffix[suffix_i])] = '\0';
1155 break;
1159 build_info_uris (uri, name, sect);
1160 g_free (name);
1161 g_free (sect);
1162 return;
1165 if (!infopath) {
1166 /* Initialize infopath only once */
1168 /* Use the same logic as the info program. If INFOPATH is not
1169 specified, use the default. If it is specified, just use it
1170 unless it ends with a colon, in which case we add the
1171 default as a suffix.
1173 const gchar *env = g_getenv ("INFOPATH");
1174 gchar *paths;
1175 if (!env || env[0] == '\0')
1176 paths = g_strdup (default_info_path);
1177 else if (env[strlen (env)-1] == ':')
1178 paths = g_strconcat (env, default_info_path, NULL);
1179 else
1180 paths = g_strdup (env);
1182 infopath = g_strsplit (paths, ":", 0);
1184 g_free (paths);
1187 colon = strchr (priv->res_arg, ':');
1188 if (colon)
1189 colon++;
1190 else
1191 colon = (gchar *) priv->res_arg;
1193 if (colon[0] == '(') {
1194 const gchar *rbrace = strchr (colon, ')');
1195 if (rbrace) {
1196 name = g_strndup (colon + 1, rbrace - colon - 1);
1197 sect = g_strdup (rbrace + 1);
1200 else {
1201 const gchar *hash = strchr (colon, '#');
1202 if (hash) {
1203 name = g_strndup (colon, hash - colon);
1204 sect = g_strdup (hash + 1);
1206 else {
1207 name = g_strdup (colon);
1208 sect = NULL;
1212 for (infopath_i = 0; infopath[infopath_i]; infopath_i++) {
1213 if (!g_file_test (infopath[infopath_i], G_FILE_TEST_IS_DIR))
1214 continue;
1215 for (suffix_i = 0; infosuffix[suffix_i]; suffix_i++) {
1216 fullpath = g_strconcat (infopath[infopath_i], "/",
1217 name, infosuffix[suffix_i], NULL);
1218 if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
1219 break;
1220 g_free (fullpath);
1221 fullpath = NULL;
1223 if (fullpath != NULL)
1224 break;
1227 if (fullpath) {
1228 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1229 priv->gfile = g_file_new_for_path (fullpath);
1230 build_info_uris (uri, name, sect);
1231 } else {
1232 gchar *res_arg = priv->res_arg;
1233 priv->res_arg = g_strconcat ("man:", name, NULL);
1234 resolve_man_uri (uri);
1235 if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_MAN) {
1236 g_free (priv->res_arg);
1237 priv->res_arg = res_arg;
1239 else {
1240 g_free (res_arg);
1241 priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
1244 g_free (fullpath);
1245 g_free (name);
1246 g_free (sect);
1249 static void
1250 resolve_xref_uri (YelpUri *uri)
1252 YelpUriPrivate *priv = GET_PRIV (uri);
1253 const gchar *arg = priv->res_arg + 5;
1254 YelpUriPrivate *base_priv = GET_PRIV (priv->res_base);
1256 priv->tmptype = base_priv->doctype;
1257 priv->gfile = g_object_ref (base_priv->gfile);
1258 priv->search_path = g_strdupv (base_priv->search_path);
1259 priv->docuri = g_strdup (base_priv->docuri);
1261 if (arg[0] == '#') {
1262 priv->page_id = g_strdup (base_priv->page_id);
1263 priv->frag_id = g_strdup (arg + 1);
1265 else {
1266 gchar *hash = strchr (arg, '#');
1267 if (hash) {
1268 priv->page_id = g_strndup (arg, hash - arg);
1269 priv->frag_id = g_strdup (hash + 1);
1271 else {
1272 priv->page_id = g_strdup (arg);
1273 priv->frag_id = NULL;
1276 if (priv->page_id && priv->page_id[0] == '\0') {
1277 g_free (priv->page_id);
1278 if (g_str_has_prefix (priv->docuri, "help:"))
1279 priv->page_id = g_strdup ("index");
1280 else
1281 priv->page_id = NULL;
1284 if (priv->page_id &&
1285 g_str_has_prefix (priv->docuri, "info:")) {
1287 Special characters get url-encoded when they get clicked on
1288 as links. Info files, at least, don't want that so decode
1289 the url again here.
1291 gchar* tmp = priv->page_id;
1292 priv->page_id = g_uri_unescape_string (tmp, NULL);
1293 g_free (tmp);
1296 if (g_str_has_prefix (priv->docuri, "ghelp:"))
1297 build_ghelp_fulluri (uri);
1298 else if (g_str_has_prefix (priv->docuri, "help:"))
1299 priv->fulluri = g_strconcat (priv->docuri,
1300 priv->page_id ? "/" : "",
1301 priv->page_id ? priv->page_id : "",
1302 priv->frag_id ? "#" : "",
1303 priv->frag_id ? priv->frag_id : "",
1304 NULL);
1305 else if (g_str_has_prefix (priv->docuri, "file:") ||
1306 g_str_has_prefix (priv->docuri, "info:") )
1307 priv->fulluri = g_strconcat (priv->docuri,
1308 (priv->page_id || priv->frag_id) ? "#" : "",
1309 priv->page_id ? priv->page_id : "",
1310 priv->frag_id ? "#" : "",
1311 priv->frag_id,
1312 NULL);
1313 else
1314 /* FIXME: other URI schemes */
1315 priv->fulluri = g_strconcat (priv->docuri,
1316 priv->page_id ? "#" : "",
1317 priv->page_id,
1318 NULL);
1321 static void
1322 resolve_page_and_frag (YelpUri *uri, const gchar *arg)
1324 YelpUriPrivate *priv = GET_PRIV (uri);
1325 gchar *hash;
1327 if (!arg || arg[0] == '\0')
1328 return;
1330 hash = strchr (arg, '#');
1331 if (hash) {
1332 priv->page_id = g_strndup (arg, hash - arg);
1333 priv->frag_id = g_strdup (hash + 1);
1334 } else {
1335 priv->page_id = g_strdup (arg);
1336 priv->frag_id = g_strdup (arg);
1338 return;
1341 static void
1342 resolve_gfile (YelpUri *uri, const gchar *query, const gchar *hash)
1344 YelpUriPrivate *priv = GET_PRIV (uri);
1345 GFileInfo *info;
1346 GError *error = NULL;
1348 info = g_file_query_info (priv->gfile,
1349 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
1350 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
1351 G_FILE_QUERY_INFO_NONE,
1352 NULL, &error);
1353 if (error) {
1354 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
1355 priv->tmptype = YELP_URI_DOCUMENT_TYPE_NOT_FOUND;
1357 else
1358 priv->tmptype = YELP_URI_DOCUMENT_TYPE_ERROR;
1359 g_error_free (error);
1360 return;
1363 if (priv->search_path == NULL) {
1364 if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) ==
1365 G_FILE_TYPE_DIRECTORY) {
1366 priv->search_path = g_new0 (gchar *, 2);
1367 priv->search_path[0] = g_file_get_path (priv->gfile);
1368 } else {
1369 GFile *parent = g_file_get_parent (priv->gfile);
1370 priv->search_path = g_new0 (gchar *, 2);
1371 priv->search_path[0] = g_file_get_path (parent);
1372 g_object_unref (parent);
1376 if (priv->tmptype == YELP_URI_DOCUMENT_TYPE_UNRESOLVED) {
1377 priv->tmptype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
1379 if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) ==
1380 G_FILE_TYPE_DIRECTORY) {
1381 GFile *child = g_file_get_child (priv->gfile, "index.page");
1382 if (g_file_query_exists (child, NULL)) {
1383 char *path;
1385 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
1386 if (priv->page_id == NULL)
1387 priv->page_id = g_strdup (query);
1388 if (priv->frag_id == NULL)
1389 priv->frag_id = g_strdup (hash);
1391 path = g_file_get_path (priv->gfile);
1392 priv->docuri = g_strconcat ("ghelp:", path, NULL);
1393 build_ghelp_fulluri (uri);
1394 g_free (path);
1396 else if (yelp_settings_get_editor_mode (yelp_settings_get_default ())) {
1397 g_object_unref (child);
1398 child = g_file_get_child (priv->gfile, "index.page.stub");
1399 if (g_file_query_exists (child, NULL)) {
1400 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
1401 if (priv->page_id == NULL)
1402 priv->page_id = g_strdup (query);
1403 if (priv->frag_id == NULL)
1404 priv->frag_id = g_strdup (hash);
1407 g_object_unref (child);
1409 else {
1410 gchar *basename;
1411 const gchar *mime_type = g_file_info_get_attribute_string (info,
1412 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
1413 basename = g_file_get_basename (priv->gfile);
1414 if (g_str_has_suffix (basename, ".page")) {
1415 GFile *old;
1416 char *path;
1418 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MALLARD;
1419 old = priv->gfile;
1420 priv->gfile = g_file_get_parent (old);
1421 if (priv->page_id == NULL) {
1422 /* File names aren't really page IDs, so we stick an illegal character
1423 on the beginning so it can't possibly be confused with a real page
1424 ID. Then we let YelpMallardDocument map file names to pages IDs.
1426 gchar *tmp = g_file_get_basename (old);
1427 priv->page_id = g_strconcat (G_DIR_SEPARATOR_S, tmp, NULL);
1428 g_free (tmp);
1431 if (priv->frag_id == NULL)
1432 priv->frag_id = g_strdup (hash);
1433 path = g_file_get_path (priv->gfile);
1434 priv->docuri = g_strconcat ("ghelp:", path, NULL);
1435 build_ghelp_fulluri (uri);
1436 g_free (path);
1437 g_object_unref (old);
1439 else if (g_str_equal (mime_type, "text/xml") ||
1440 g_str_equal (mime_type, "application/docbook+xml") ||
1441 g_str_equal (mime_type, "application/xml") ||
1442 g_str_has_suffix (basename, ".docbook")) {
1443 char *path;
1445 priv->tmptype = YELP_URI_DOCUMENT_TYPE_DOCBOOK;
1447 if (priv->page_id == NULL)
1448 priv->page_id = g_strdup (query);
1449 if (priv->frag_id == NULL)
1450 priv->frag_id = g_strdup (hash);
1452 path = g_file_get_path (priv->gfile);
1453 priv->docuri = g_strconcat ("ghelp:", path, NULL);
1454 build_ghelp_fulluri (uri);
1455 g_free (path);
1457 else if (g_str_equal (mime_type, "text/html") ||
1458 g_str_equal (mime_type, "application/xhtml+xml")) {
1459 GFile *parent = g_file_get_parent (priv->gfile);
1460 priv->docuri = g_file_get_uri (parent);
1461 g_object_unref (parent);
1462 priv->tmptype = mime_type[0] == 't' ? YELP_URI_DOCUMENT_TYPE_HTML : YELP_URI_DOCUMENT_TYPE_XHTML;
1463 if (priv->page_id == NULL)
1464 priv->page_id = g_strdup (basename);
1465 if (priv->frag_id == NULL)
1466 priv->frag_id = g_strdup (hash);
1467 if (priv->fulluri == NULL) {
1468 gchar *fulluri;
1469 fulluri = g_file_get_uri (priv->gfile);
1470 priv->fulluri = g_strconcat (fulluri,
1471 priv->frag_id ? "#" : NULL,
1472 priv->frag_id,
1473 NULL);
1474 g_free (fulluri);
1477 else if (g_str_equal (mime_type, "application/x-gzip") ||
1478 g_str_equal (mime_type, "application/gzip")) {
1479 if (g_str_has_suffix (basename, ".info.gz")) {
1480 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1481 basename[strlen (basename) - strlen (".info.gz")] = '\0';
1482 build_info_uris (uri, basename, hash);
1484 else if (is_man_path (basename, "gz")) {
1485 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1486 basename[strlen (basename) - strlen ("gz") - 1] = '\0';
1487 build_man_uris (uri, basename, NULL);
1490 else if (g_str_equal (mime_type, "application/x-bzip")) {
1491 if (g_str_has_suffix (basename, ".info.bz2")) {
1492 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1493 basename[strlen (basename) - strlen (".info.bz2")] = '\0';
1494 build_info_uris (uri, basename, hash);
1496 else if (is_man_path (basename, "bz2")) {
1497 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1498 basename[strlen (basename) - strlen ("bz2") - 1] = '\0';
1499 build_man_uris (uri, basename, NULL);
1502 else if (g_str_equal (mime_type, "application/x-lzma")) {
1503 if (g_str_has_suffix (basename, ".info.lzma")) {
1504 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1505 basename[strlen (basename) - strlen (".info.lzma")] = '\0';
1506 build_info_uris (uri, basename, hash);
1508 else if (is_man_path (basename, "lzma")) {
1509 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1510 basename[strlen (basename) - strlen ("lzma") - 1] = '\0';
1511 build_man_uris (uri, basename, NULL);
1514 else if (g_str_equal (mime_type, "application/octet-stream")) {
1515 if (g_str_has_suffix (basename, ".info")) {
1516 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1517 basename[strlen (basename) - strlen (".info")] = '\0';
1518 build_info_uris (uri, basename, hash);
1520 else if (is_man_path (basename, NULL)) {
1521 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1522 build_man_uris (uri, basename, NULL);
1525 else if (g_str_equal (mime_type, "text/plain")) {
1526 if (g_str_has_suffix (basename, ".info")) {
1527 priv->tmptype = YELP_URI_DOCUMENT_TYPE_INFO;
1528 basename[strlen (basename) - strlen (".info")] = '\0';
1529 build_info_uris (uri, basename, hash);
1531 else if (is_man_path (basename, NULL)) {
1532 priv->tmptype = YELP_URI_DOCUMENT_TYPE_MAN;
1533 build_man_uris (uri, basename, NULL);
1534 } else
1535 priv->tmptype = YELP_URI_DOCUMENT_TYPE_TEXT;
1536 if (priv->frag_id == NULL)
1537 priv->frag_id = g_strdup (hash);
1539 else if (g_str_equal (mime_type, "text/x-readme")) {
1540 priv->tmptype = YELP_URI_DOCUMENT_TYPE_TEXT;
1542 else {
1543 priv->tmptype = YELP_URI_DOCUMENT_TYPE_EXTERNAL;
1545 g_free (basename);
1549 if (priv->docuri == NULL)
1550 priv->docuri = g_file_get_uri (priv->gfile);
1552 if (priv->fulluri == NULL)
1553 priv->fulluri = g_strconcat (priv->docuri,
1554 (priv->page_id || priv->frag_id) ? "#" : NULL,
1555 priv->page_id ? priv->page_id : "",
1556 priv->frag_id ? "#" : NULL,
1557 priv->frag_id ? priv->frag_id : NULL,
1558 NULL);
1560 g_object_unref (info);
1563 static gboolean
1564 is_man_path (const gchar *path, const gchar *encoding)
1566 gchar **iter = (gchar **) mancats;
1568 if (encoding && *encoding) {
1569 while (iter && *iter) {
1570 gchar *ending = g_strdup_printf ("%s.%s", *iter, encoding);
1571 if (g_str_has_suffix (path, ending)) {
1572 g_free (ending);
1573 return TRUE;
1575 g_free (ending);
1576 iter++;
1578 } else {
1579 while (iter && *iter) {
1580 if (g_str_has_suffix (path, *iter)) {
1581 return TRUE;
1583 iter++;
1586 return FALSE;