No issues found
1 /*
2 * Copyright (C) 2009 Jonathan Matthew <jonathan@d14n.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include <string.h>
21 #include <glib.h>
22 #include <glib/gprintf.h>
23 #include <glib-object.h>
24
25 #include "mediaplayerid.h"
26 #include "mpid-private.h"
27
28 static gboolean debug_enabled = FALSE;
29
30 #define ENUM_ENTRY(name, nick) { name, "" #name "", nick }
31
32 /**
33 * MPIDError:
34 * @MPID_ERROR_NONE: Indicates no error has occurred
35 * @MPID_ERROR_NO_DEVICE_PATH: Unable to find the device path
36 * @MPID_ERROR_MECHANISM_FAILED: The device detection mechanism (e.g. udev or HAL) failed
37 * @MPID_ERROR_NOT_MEDIA_PLAYER: The device is not a media player
38 * @MPID_ERROR_DEVICE_INFO_MISSING: The device detection mechanism identified the device
39 * but was unable to locate its device information
40 */
41
42 GType
43 mpid_error_get_type (void)
44 {
45 static GType etype = 0;
46
47 if (etype == 0) {
48 static const GEnumValue values[] = {
49 ENUM_ENTRY(MPID_ERROR_NONE, "OK"),
50 ENUM_ENTRY(MPID_ERROR_NO_DEVICE_PATH, "no-such-device"),
51 ENUM_ENTRY(MPID_ERROR_MECHANISM_FAILED, "device-db-failed"),
52 ENUM_ENTRY(MPID_ERROR_NOT_MEDIA_PLAYER, "not-media-player"),
53 ENUM_ENTRY(MPID_ERROR_DEVICE_INFO_MISSING, "device-info-missing"),
54 { 0, 0, 0 }
55 };
56
57 etype = g_enum_register_static ("MPIDError", values);
58 }
59
60 return etype;
61 }
62
63 /**
64 * MPIDSource:
65 * @MPID_SOURCE_NONE: No device information is available
66 * @MPID_SOURCE_SYSTEM: Device information provided by the operating system (e.g. udev or HAL)
67 * @MPID_SOURCE_OVERRIDE: Device information provided by an override file on the device itself.
68 */
69
70 GType
71 mpid_source_get_type (void)
72 {
73 static GType etype = 0;
74
75 if (etype == 0) {
76 static const GEnumValue values[] = {
77 ENUM_ENTRY(MPID_SOURCE_NONE, "no-device-info"),
78 ENUM_ENTRY(MPID_SOURCE_SYSTEM, "system-device-info"),
79 ENUM_ENTRY(MPID_SOURCE_OVERRIDE, "override-device-info"),
80 { 0, 0, 0 }
81 };
82
83 etype = g_enum_register_static ("MPIDSourceType", values);
84 }
85
86 return etype;
87 }
88
89 /**
90 * mpid_enable_debug:
91 * @debug: whether to enable debug output
92 *
93 * Enables or disables debug output from the MPID library
94 */
95 void
96 mpid_enable_debug (gboolean debug)
97 {
98 debug_enabled = debug;
99 }
100
101 void
102 mpid_debug (const char *format, ...)
103 {
104 va_list args;
105 va_start (args, format);
106 if (debug_enabled)
107 g_vprintf (format, args);
108 va_end (args);
109 }
110
111 void
112 mpid_debug_strv (const char *what, char **strv)
113 {
114 int i;
115 if (strv != NULL) {
116 mpid_debug ("%s:\n", what);
117 for (i = 0; strv[i] != NULL; i++) {
118 mpid_debug ("\t%s\n", strv[i]);
119 }
120 } else {
121 mpid_debug ("%s: (none)\n", what);
122 }
123 }
124
125 void
126 mpid_debug_str (const char *what, const char *str)
127 {
128 if (str != NULL) {
129 mpid_debug ("%s: %s\n", what, str);
130 } else {
131 mpid_debug ("%s: (none)\n", what);
132 }
133 }
134
135 static GKeyFile *
136 read_fake_keyfile (const char *path)
137 {
138 const char *fake_group = "[mpid-data]\n";
139 char *data;
140 char *munged;
141 gsize data_size;
142 gsize munged_data_size;
143 GKeyFile *keyfile;
144 GError *error = NULL;
145
146 if (g_file_get_contents (path, &data, &data_size, &error) == FALSE) {
147 mpid_debug ("unable to read contents of file %s: %s\n", path, error->message);
148 g_clear_error (&error);
149 return NULL;
150 }
151
152 /* prepend a group name to the file contents */
153 munged_data_size = data_size + strlen (fake_group);
154 munged = g_malloc0 (munged_data_size + 1);
155 strcpy (munged, fake_group);
156 memcpy (munged + strlen (fake_group), data, data_size);
157
158 keyfile = g_key_file_new ();
159 if (g_key_file_load_from_data (keyfile, munged, munged_data_size, G_KEY_FILE_NONE, &error) == FALSE) {
160 mpid_debug ("unable to parse contents of file %s: %s\n", path, error->message);
161 g_key_file_free (keyfile);
162 keyfile = NULL;
163
164 /* probably do something with this error too */
165 g_clear_error (&error);
166 }
167
168 g_free (munged);
169 return keyfile;
170 }
171
172 void
173 mpid_override_string_from_keyfile (char **str, GKeyFile *keyfile, const char *group, const char *key)
174 {
175 char *v;
176 v = g_key_file_get_string (keyfile, group, key, NULL);
177 if (v != NULL) {
178 g_free (*str);
179 *str = v;
180 }
181 }
182
183 void
184 mpid_override_strv_from_keyfile (char ***strv, GKeyFile *keyfile, const char *group, const char *key)
185 {
186 char **v;
187 v = g_key_file_get_string_list (keyfile, group, key, NULL, NULL);
188 if (v != NULL) {
189 g_strfreev (*strv);
190 *strv = v;
191 }
192 }
193
194 void
195 mpid_device_read_override_file (MPIDDevice *device)
196 {
197 GKeyFile *keyfile;
198 GError *error = NULL;
199 char *mountpoint;
200 char *override_path;
201 char *start_group;
202 char *str;
203 int val;
204
205 mountpoint = mpid_device_get_mount_point (device);
206 if (mountpoint == NULL) {
207 /* maybe set an error if not already set? */
208 return;
209 }
210
211 override_path = g_build_filename (mountpoint, ".audio_player.mpi", NULL);
212 if (g_file_test (override_path, G_FILE_TEST_EXISTS)) {
213 mpid_debug ("found override file %s on mount %s\n", override_path, mountpoint);
214
215 device->error = MPID_ERROR_NONE;
216 mpid_read_device_file (device, override_path);
217 device->source = MPID_SOURCE_OVERRIDE;
218 g_free (override_path);
219 g_free (mountpoint);
220 return;
221 }
222
223 override_path = g_build_filename (mountpoint, ".is_audio_player", NULL);
224 if (g_file_test (override_path, G_FILE_TEST_EXISTS) == FALSE) {
225 mpid_debug ("override file %s not found on mount %s\n", override_path, mountpoint);
226 g_free (override_path);
227 g_free (mountpoint);
228 return;
229 }
230
231 keyfile = read_fake_keyfile (override_path);
232 g_free (override_path);
233 g_free (mountpoint);
234
235 if (keyfile == NULL) {
236 /* maybe set an error? */
237 return;
238 }
239
240 /* forget any previous error */
241 device->error = MPID_ERROR_NONE;
242 device->source = MPID_SOURCE_OVERRIDE;
243
244 /* ensure we at least have 'storage' protocol and mp3 output.
245 * for mp3-only devices with no playlists, an empty override file should suffice.
246 */
247 if (device->access_protocols == NULL) {
248 char *p[] = { MPID_PROTOCOL_GENERIC, NULL };
249 device->access_protocols = g_strdupv (p);
250 }
251
252 if (device->output_formats == NULL) {
253 char *f[] = { "audio/mpeg", NULL };
254 device->output_formats = g_strdupv (f);
255 }
256
257 /* now apply information from the override file */
258 start_group = g_key_file_get_start_group (keyfile);
259 g_key_file_set_list_separator (keyfile, ',');
260
261 mpid_override_strv_from_keyfile (&device->output_formats, keyfile, start_group, "output_formats");
262 mpid_override_strv_from_keyfile (&device->input_formats, keyfile, start_group, "input_formats");
263 mpid_override_strv_from_keyfile (&device->playlist_formats, keyfile, start_group, "playlist_formats");
264 mpid_override_strv_from_keyfile (&device->audio_folders, keyfile, start_group, "audio_folders");
265
266 str = g_key_file_get_string (keyfile, start_group, "playlist_path", NULL);
267 if (str != NULL) {
268 g_free (device->playlist_path);
269 device->playlist_path = str;
270 }
271
272 val = g_key_file_get_integer (keyfile, start_group, "folder_depth", &error);
273 if (error == NULL) {
274 device->folder_depth = val;
275 } else {
276 g_clear_error (&error);
277 }
278
279 g_key_file_free (keyfile);
280 }