1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * The GIMP Help plug-in
5  * Copyright (C) 1999-2008 Sven Neumann <sven@gimp.org>
6  *                         Michael Natterer <mitch@gimp.org>
7  *                         Henrik Brix Andersen <brix@gimp.org>
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21  */
22 
23 /*  This code is written so that it can also be compiled standalone.
24  *  It shouldn't depend on libgimp.
25  */
26 
27 #include "config.h"
28 
29 #include <string.h>
30 
31 #include <glib-object.h>
32 #include <gio/gio.h>
33 
34 #include "libgimpbase/gimpbase.h"
35 
36 #include "gimphelp.h"
37 
38 #ifdef DISABLE_NLS
39 #define _(String)  (String)
40 #else
41 #include "libgimp/stdplugins-intl.h"
42 #endif
43 
44 
45 /*  local function prototypes  */
46 
47 static gboolean   domain_locale_parse (GimpHelpDomain    *domain,
48                                        GimpHelpLocale    *locale,
49                                        GimpHelpProgress  *progress,
50                                        GError           **error);
51 
52 
53 /*  public functions  */
54 
55 GimpHelpDomain *
gimp_help_domain_new(const gchar * domain_name,const gchar * domain_uri)56 gimp_help_domain_new (const gchar *domain_name,
57                       const gchar *domain_uri)
58 {
59   GimpHelpDomain *domain = g_slice_new0 (GimpHelpDomain);
60 
61   domain->help_domain = g_strdup (domain_name);
62   domain->help_uri    = g_strdup (domain_uri);
63 
64   if (domain_uri)
65     {
66       /*  strip trailing slash  */
67       if (g_str_has_suffix (domain->help_uri, "/"))
68         domain->help_uri[strlen (domain->help_uri) - 1] = '\0';
69     }
70 
71   return domain;
72 }
73 
74 void
gimp_help_domain_free(GimpHelpDomain * domain)75 gimp_help_domain_free (GimpHelpDomain *domain)
76 {
77   g_return_if_fail (domain != NULL);
78 
79   if (domain->help_locales)
80     g_hash_table_destroy (domain->help_locales);
81 
82   g_free (domain->help_domain);
83   g_free (domain->help_uri);
84 
85   g_slice_free (GimpHelpDomain, domain);
86 }
87 
88 GimpHelpLocale *
gimp_help_domain_lookup_locale(GimpHelpDomain * domain,const gchar * locale_id,GimpHelpProgress * progress)89 gimp_help_domain_lookup_locale (GimpHelpDomain    *domain,
90                                 const gchar       *locale_id,
91                                 GimpHelpProgress  *progress)
92 {
93   GimpHelpLocale *locale = NULL;
94 
95   if (domain->help_locales)
96     locale = g_hash_table_lookup (domain->help_locales, locale_id);
97   else
98     domain->help_locales =
99       g_hash_table_new_full (g_str_hash, g_str_equal,
100                              g_free,
101                              (GDestroyNotify) gimp_help_locale_free);
102 
103   if (locale)
104     return locale;
105 
106   locale = gimp_help_locale_new (locale_id);
107   g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
108 
109   domain_locale_parse (domain, locale, progress, NULL);
110 
111   return locale;
112 }
113 
114 gchar *
gimp_help_domain_map(GimpHelpDomain * domain,GList * help_locales,const gchar * help_id,GimpHelpProgress * progress,GimpHelpLocale ** ret_locale,gboolean * fatal_error)115 gimp_help_domain_map (GimpHelpDomain    *domain,
116                       GList             *help_locales,
117                       const gchar       *help_id,
118                       GimpHelpProgress  *progress,
119                       GimpHelpLocale   **ret_locale,
120                       gboolean          *fatal_error)
121 {
122   GimpHelpLocale *locale = NULL;
123   const gchar    *ref    = NULL;
124   GList          *list;
125 
126   g_return_val_if_fail (domain != NULL, NULL);
127   g_return_val_if_fail (help_locales != NULL, NULL);
128   g_return_val_if_fail (help_id != NULL, NULL);
129 
130   if (fatal_error)
131     *fatal_error = FALSE;
132 
133   /*  first pass: look for a reference matching the help_id  */
134   for (list = help_locales; list && !ref; list = list->next)
135     {
136       locale = gimp_help_domain_lookup_locale (domain,
137                                                (const gchar *) list->data,
138                                                progress);
139       ref = gimp_help_locale_map (locale, help_id);
140     }
141 
142   /*  second pass: look for a fallback                 */
143   for (list = help_locales; list && !ref; list = list->next)
144     {
145       locale = gimp_help_domain_lookup_locale (domain,
146                                                (const gchar *) list->data,
147                                                progress);
148       ref = locale->help_missing;
149     }
150 
151   if (ret_locale)
152     *ret_locale = locale;
153 
154   if (ref)
155     {
156       return g_strconcat (domain->help_uri,  "/",
157                           locale->locale_id, "/",
158                           ref,
159                           NULL);
160     }
161   else  /*  try to assemble a useful error message  */
162     {
163       GError *error = NULL;
164 
165 #ifdef GIMP_HELP_DEBUG
166       g_printerr ("help: help_id lookup and all fallbacks failed for '%s'\n",
167                   help_id);
168 #endif
169 
170       locale = gimp_help_domain_lookup_locale (domain,
171                                                GIMP_HELP_DEFAULT_LOCALE, NULL);
172 
173       if (! domain_locale_parse (domain, locale, NULL, &error))
174         {
175           switch (error->code)
176             {
177             case G_IO_ERROR_NOT_FOUND:
178               if (domain->help_domain)
179                 {
180                   g_message (_("The help pages for '%s' are not available."),
181                              domain->help_domain);
182                 }
183               else
184                 {
185                   g_message ("%s\n\n%s",
186                              _("The GIMP user manual is not available."),
187                              /* TRANSLATORS: do not end the URL with a dot,
188                               * it would be in the link. Because of
189                               * technical limitations, make sure the URL
190                               * ends with a space, a newline or is end of text.
191                               * Cf. bug 762282.
192                               */
193                              _("Please install the additional help package "
194                                "or use the online user manual at: "
195                                "https://docs.gimp.org/"));
196                 }
197               break;
198 
199             case G_IO_ERROR_NOT_SUPPORTED:
200               g_message ("%s\n\n%s",
201                          error->message,
202                          _("Perhaps you are missing GIO backends and need "
203                            "to install GVFS?"));
204               break;
205 
206             case G_IO_ERROR_CANCELLED:
207               break;
208 
209             default:
210               g_message ("%s", error->message);
211               break;
212             }
213 
214           g_error_free (error);
215 
216           if (fatal_error)
217             *fatal_error = TRUE;
218         }
219       else
220         {
221           g_message (_("Help ID '%s' unknown"), help_id);
222         }
223 
224       return NULL;
225     }
226 }
227 
228 
229 /*  private functions  */
230 
231 static gboolean
domain_locale_parse(GimpHelpDomain * domain,GimpHelpLocale * locale,GimpHelpProgress * progress,GError ** error)232 domain_locale_parse (GimpHelpDomain    *domain,
233                      GimpHelpLocale    *locale,
234                      GimpHelpProgress  *progress,
235                      GError           **error)
236 {
237   gchar    *uri;
238   gboolean  success;
239 
240   g_return_val_if_fail (domain != NULL, FALSE);
241   g_return_val_if_fail (locale != NULL, FALSE);
242   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
243 
244   uri = g_strdup_printf ("%s/%s/gimp-help.xml",
245                          domain->help_uri, locale->locale_id);
246 
247   success = gimp_help_locale_parse (locale, uri, domain->help_domain,
248                                     progress, error);
249 
250   g_free (uri);
251 
252   return success;
253 }
254