1 /* keyfileutils.c: useful functions for GKeyFile
2  * vim: set ts=2 sw=2 et: */
3 
4 /*
5  * Copyright (C) 2007 Vincent Untz <vuntz@gnome.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
20  * USA.
21  */
22 
23 #include <string.h>
24 
25 #include "keyfileutils.h"
26 
27 gboolean
dfu_key_file_rename_group(GKeyFile * keyfile,const char * oldgroup,const char * newgroup)28 dfu_key_file_rename_group (GKeyFile   *keyfile,
29                            const char *oldgroup,
30                            const char *newgroup)
31 {
32   char         **keys;
33   char          *value;
34   unsigned int   i;
35 
36   g_return_val_if_fail (keyfile != NULL, FALSE);
37 
38   if (!g_key_file_has_group (keyfile, oldgroup))
39     return TRUE;
40 
41   keys = g_key_file_get_keys (keyfile, oldgroup, NULL, NULL);
42   for (i = 0; keys[i] != NULL; i++) {
43     value = g_key_file_get_value (keyfile, oldgroup, keys[i], NULL);
44     g_key_file_set_value (keyfile, newgroup, keys[i], value);
45     g_free (value);
46 
47     value = g_key_file_get_comment (keyfile, oldgroup, keys[i], NULL);
48     if (value) {
49       g_key_file_set_comment (keyfile, newgroup, keys[i], value, NULL);
50       g_free (value);
51     }
52   }
53   g_strfreev (keys);
54 
55   value = g_key_file_get_comment (keyfile, oldgroup, NULL, NULL);
56   if (value) {
57     g_key_file_set_comment (keyfile, newgroup, NULL, value, NULL);
58     g_free (value);
59   }
60 
61   g_key_file_remove_group (keyfile, oldgroup, NULL);
62 
63   return TRUE;
64 }
65 
66 void
dfu_key_file_drop_locale_strings(GKeyFile * keyfile,const char * group,const char * key)67 dfu_key_file_drop_locale_strings (GKeyFile   *keyfile,
68                                   const char *group,
69                                   const char *key)
70 {
71   char  **keys;
72   gsize   len;
73   char   *prefix;
74   gsize   i;
75 
76   keys = g_key_file_get_keys (keyfile, group, &len, NULL);
77   prefix = g_strdup_printf ("%s[", key);
78 
79   for (i = 0; i < len; i++)
80     {
81       if (g_str_has_prefix (keys[i], prefix))
82         g_key_file_remove_key (keyfile, group, keys[i], NULL);
83     }
84 
85   g_free (prefix);
86   g_strfreev (keys);
87 }
88 
89 static gboolean
_dfu_key_file_copy_key_helper(GKeyFile * keyfile,const char * fromgroup,const char * fromkey,const char * togroup,const char * tokey)90 _dfu_key_file_copy_key_helper (GKeyFile   *keyfile,
91                                const char *fromgroup,
92                                const char *fromkey,
93                                const char *togroup,
94                                const char *tokey)
95 {
96   char *value;
97 
98   if (!g_key_file_has_group (keyfile, fromgroup))
99     return FALSE;
100 
101   value = g_key_file_get_value (keyfile, fromgroup, fromkey, NULL);
102   if (!value)
103     return FALSE;
104 
105   g_key_file_set_value (keyfile, togroup, tokey, value);
106 
107   g_free (value);
108 
109   return TRUE;
110 }
111 
112 gboolean
dfu_key_file_copy_key(GKeyFile * keyfile,const char * fromgroup,const char * fromkey,const char * togroup,const char * tokey)113 dfu_key_file_copy_key (GKeyFile   *keyfile,
114                        const char *fromgroup,
115                        const char *fromkey,
116                        const char *togroup,
117                        const char *tokey)
118 {
119   char  **fromkeys;
120   gsize   len;
121   char   *fromprefix;
122   gsize   i;
123 
124   g_return_val_if_fail (keyfile != NULL, FALSE);
125   g_return_val_if_fail (fromgroup != NULL, FALSE);
126   g_return_val_if_fail (fromkey != NULL, FALSE);
127   g_return_val_if_fail (togroup != NULL, FALSE);
128   g_return_val_if_fail (tokey != NULL, FALSE);
129 
130   if (!_dfu_key_file_copy_key_helper (keyfile, fromgroup, fromkey,
131                                       togroup, tokey))
132     return FALSE;
133 
134   /* Also copy translations if we're not dealing with localized keys already
135    * (first drop old ones) */
136   if (strchr (fromkey, '[') != NULL || strchr (tokey, '[') != NULL)
137     return TRUE;
138 
139   dfu_key_file_drop_locale_strings (keyfile, togroup, tokey);
140 
141   fromkeys = g_key_file_get_keys (keyfile, fromgroup, &len, NULL);
142   fromprefix = g_strdup_printf ("%s[", fromkey);
143 
144   for (i = 0; i < len; i++)
145     {
146       if (g_str_has_prefix (fromkeys[i], fromprefix))
147         {
148           const char *locale = fromkeys[i] + strlen (fromkey);
149           char       *tolocalekey = g_strdup_printf ("%s%s", tokey, locale);
150           _dfu_key_file_copy_key_helper (keyfile, fromgroup, fromkeys[i],
151                                          togroup, tolocalekey);
152           g_free (tolocalekey);
153         }
154     }
155 
156   g_free (fromprefix);
157   g_strfreev (fromkeys);
158 
159   return TRUE;
160 }
161 
162 void
dfu_key_file_merge_list(GKeyFile * keyfile,const char * group,const char * key,const char * to_merge)163 dfu_key_file_merge_list (GKeyFile   *keyfile,
164                          const char *group,
165                          const char *key,
166                          const char *to_merge)
167 {
168   char **values;
169   char  *value;
170   char  *str;
171   int    i;
172 
173   g_return_if_fail (keyfile != NULL);
174 
175   values = g_key_file_get_string_list (keyfile, group, key, NULL, NULL);
176 
177   if (values) {
178     for (i = 0; values[i] != NULL; i++) {
179       if (!strcmp (values[i], to_merge)) {
180         g_strfreev (values);
181         return;
182       }
183     }
184 
185     g_strfreev (values);
186   }
187 
188   value = g_key_file_get_value (keyfile, group, key, NULL);
189 
190   if (value) {
191     size_t len = strlen (value);
192     if (len > 0 && value[len - 1] != ';') {
193       str = g_strconcat (value, ";", to_merge, ";", NULL);
194     } else {
195       str = g_strconcat (value, to_merge, ";", NULL);
196     }
197   } else
198     str = g_strconcat (to_merge, ";", NULL);
199 
200   g_key_file_set_value (keyfile, group, key, str);
201 
202   g_free (value);
203   g_free (str);
204 }
205 
206 void
dfu_key_file_remove_list(GKeyFile * keyfile,const char * group,const char * key,const char * to_remove)207 dfu_key_file_remove_list (GKeyFile   *keyfile,
208                           const char *group,
209                           const char *key,
210                           const char *to_remove)
211 {
212   char     **values;
213   GString   *value;
214   gboolean   found;
215   int        i;
216 
217   g_return_if_fail (keyfile != NULL);
218 
219   found = FALSE;
220 
221   value  = g_string_new ("");
222   values = g_key_file_get_string_list (keyfile, group, key, NULL, NULL);
223 
224   if (values) {
225     for (i = 0; values[i] != NULL; i++) {
226       if (!strcmp (values[i], to_remove))
227         found = TRUE;
228       else
229         g_string_append_printf (value, "%s;", values[i]);
230     }
231 
232     g_strfreev (values);
233   }
234 
235   if (!found) {
236     g_string_free (value, TRUE);
237     return;
238   }
239 
240   if (!value->str || value->str[0] == '\0')
241     g_key_file_remove_key (keyfile, group, key, NULL);
242   else
243     g_key_file_set_value (keyfile, group, key, value->str);
244 
245   g_string_free (value, TRUE);
246 }
247 
248 //FIXME: kill this when bug #309224 is fixed
249 gboolean
dfu_key_file_to_path(GKeyFile * keyfile,const char * path,GError ** error)250 dfu_key_file_to_path (GKeyFile     *keyfile,
251                       const char   *path,
252                       GError      **error)
253 {
254   char    *filename;
255   GError  *write_error;
256   char    *data;
257   gsize    length;
258   gboolean res;
259 
260   g_return_val_if_fail (keyfile != NULL, FALSE);
261   g_return_val_if_fail (path != NULL, FALSE);
262 
263   write_error = NULL;
264   data = g_key_file_to_data (keyfile, &length, &write_error);
265   if (write_error) {
266     g_propagate_error (error, write_error);
267     return FALSE;
268   }
269 
270   filename = g_filename_from_utf8 (path, -1, NULL, NULL, &write_error);
271 
272   if (write_error) {
273     g_propagate_error (error, write_error);
274     g_free (data);
275     return FALSE;
276   }
277 
278   res = g_file_set_contents (filename, data, length, &write_error);
279   g_free (filename);
280 
281   if (write_error) {
282     g_propagate_error (error, write_error);
283     g_free (data);
284     return FALSE;
285   }
286 
287   g_free (data);
288   return res;
289 }
290