No issues found
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3 * Copyright (C) 2011 Red Hat, Inc.
4 *
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.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * 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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
19 *
20 * Authors: David Zeuthen <davidz@redhat.com>
21 * Cosimo Cecchi <cosimoc@redhat.com>
22 *
23 */
24
25 #include "shell-mime-sniffer.h"
26 #include "hotplug-mimetypes.h"
27
28 /* Set the environment variable HOTPLUG_SNIFFER_DEBUG to show debug */
29 static void print_debug (const gchar *str, ...);
30
31 #define BUS_NAME "org.gnome.Shell.HotplugSniffer"
32 #define AUTOQUIT_TIMEOUT 5
33
34 static const gchar introspection_xml[] =
35 "<node>"
36 " <interface name='org.gnome.Shell.HotplugSniffer'>"
37 " <method name='SniffURI'>"
38 " <arg type='s' name='uri' direction='in'/>"
39 " <arg type='as' name='content_types' direction='out'/>"
40 " </method>"
41 " </interface>"
42 "</node>";
43
44 static GDBusNodeInfo *introspection_data = NULL;
45 static GMainLoop *loop = NULL;
46 static guint autoquit_id = 0;
47
48 static gboolean
49 autoquit_timeout_cb (gpointer _unused)
50 {
51 print_debug ("Timeout reached, quitting...");
52
53 autoquit_id = 0;
54 g_main_loop_quit (loop);
55
56 return FALSE;
57 }
58
59 static void
60 ensure_autoquit_off (void)
61 {
62 if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
63 return;
64
65 if (autoquit_id != 0)
66 {
67 g_source_remove (autoquit_id);
68 autoquit_id = 0;
69 }
70 }
71
72 static void
73 ensure_autoquit_on (void)
74 {
75 if (g_getenv ("HOTPLUG_SNIFFER_PERSIST") != NULL)
76 return;
77
78 autoquit_id =
79 g_timeout_add_seconds (AUTOQUIT_TIMEOUT,
80 autoquit_timeout_cb, NULL);
81 }
82
83 typedef struct {
84 GVariant *parameters;
85 GDBusMethodInvocation *invocation;
86 } InvocationData;
87
88 static InvocationData *
89 invocation_data_new (GVariant *params,
90 GDBusMethodInvocation *invocation)
91 {
92 InvocationData *ret;
93
94 ret = g_slice_new0 (InvocationData);
95 ret->parameters = g_variant_ref (params);
96 ret->invocation = g_object_ref (invocation);
97
98 return ret;
99 }
100
101 static void
102 invocation_data_free (InvocationData *data)
103 {
104 g_variant_unref (data->parameters);
105 g_clear_object (&data->invocation);
106
107 g_slice_free (InvocationData, data);
108 }
109
110 static void
111 sniff_async_ready_cb (GObject *source,
112 GAsyncResult *res,
113 gpointer user_data)
114 {
115 InvocationData *data = user_data;
116 gchar **types;
117 GError *error = NULL;
118
119 types = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
120 res, &error);
121
122 if (error != NULL)
123 {
124 g_dbus_method_invocation_return_gerror (data->invocation, error);
125 g_error_free (error);
126 goto out;
127 }
128
129 g_dbus_method_invocation_return_value (data->invocation,
130 g_variant_new ("(^as)", types));
131 g_strfreev (types);
132
133 out:
134 invocation_data_free (data);
135 ensure_autoquit_on ();
136 }
137
138 static void
139 handle_sniff_uri (InvocationData *data)
140 {
141 ShellMimeSniffer *sniffer;
142 const gchar *uri;
143 GFile *file;
144
145 ensure_autoquit_off ();
146
147 g_variant_get (data->parameters,
148 "(&s)", &uri,
149 NULL);
150 file = g_file_new_for_uri (uri);
151
152 print_debug ("Initiating sniff for uri %s", uri);
153
154 sniffer = shell_mime_sniffer_new (file);
155 shell_mime_sniffer_sniff_async (sniffer,
156 sniff_async_ready_cb,
157 data);
158
159 g_object_unref (sniffer);
160 g_object_unref (file);
161 }
162
163 static void
164 handle_method_call (GDBusConnection *connection,
165 const gchar *sender,
166 const gchar *object_path,
167 const gchar *interface_name,
168 const gchar *method_name,
169 GVariant *parameters,
170 GDBusMethodInvocation *invocation,
171 gpointer user_data)
172 {
173 InvocationData *data;
174
175 data = invocation_data_new (parameters, invocation);
176
177 if (g_strcmp0 (method_name, "SniffURI") == 0)
178 handle_sniff_uri (data);
179 else
180 g_assert_not_reached ();
181 }
182
183 static const GDBusInterfaceVTable interface_vtable =
184 {
185 handle_method_call,
186 NULL, /* get_property */
187 NULL, /* set_property */
188 };
189
190 static void
191 on_bus_acquired (GDBusConnection *connection,
192 const gchar *name,
193 gpointer user_data)
194 {
195 GError *error = NULL;
196
197 print_debug ("Connected to the session bus: %s", name);
198
199 g_dbus_connection_register_object (connection,
200 "/org/gnome/Shell/HotplugSniffer",
201 introspection_data->interfaces[0],
202 &interface_vtable,
203 NULL,
204 NULL,
205 &error);
206
207 if (error != NULL)
208 {
209 g_printerr ("Error exporting object on the session bus: %s",
210 error->message);
211 g_error_free (error);
212
213 _exit(1);
214 }
215
216 print_debug ("Object exported on the session bus");
217 }
218
219 static void
220 on_name_lost (GDBusConnection *connection,
221 const gchar *name,
222 gpointer user_data)
223 {
224 print_debug ("Lost bus name: %s, exiting", name);
225
226 g_main_loop_quit (loop);
227 }
228
229 static void
230 on_name_acquired (GDBusConnection *connection,
231 const gchar *name,
232 gpointer user_data)
233 {
234 print_debug ("Acquired bus name: %s", name);
235 }
236
237 int
238 main (int argc,
239 char **argv)
240 {
241 guint name_owner_id;
242
243 g_type_init ();
244
245 introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
246 g_assert (introspection_data != NULL);
247
248 ensure_autoquit_on ();
249 loop = g_main_loop_new (NULL, FALSE);
250
251 name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
252 BUS_NAME, 0,
253 on_bus_acquired,
254 on_name_acquired,
255 on_name_lost,
256 NULL,
257 NULL);
258
259 g_main_loop_run (loop);
260
261 if (name_owner_id != 0)
262 g_bus_unown_name (name_owner_id);
263
264 if (loop != NULL)
265 g_main_loop_unref (loop);
266
267 return 0;
268 }
269
270 /* ---------------------------------------------------------------------------------------------------- */
271
272 static void
273 print_debug (const gchar *format, ...)
274 {
275 gchar *s;
276 va_list ap;
277 gchar timebuf[64];
278 GTimeVal now;
279 time_t now_t;
280 struct tm broken_down;
281 static volatile gsize once_init_value = 0;
282 static gboolean show_debug = FALSE;
283 static guint pid = 0;
284
285 if (g_once_init_enter (&once_init_value))
286 {
287 show_debug = (g_getenv ("HOTPLUG_SNIFFER_DEBUG") != NULL);
288 pid = getpid ();
289 g_once_init_leave (&once_init_value, 1);
290 }
291
292 if (!show_debug)
293 goto out;
294
295 g_get_current_time (&now);
296 now_t = now.tv_sec;
297 localtime_r (&now_t, &broken_down);
298 strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
299
300 va_start (ap, format);
301 s = g_strdup_vprintf (format, ap);
302 va_end (ap);
303
304 g_print ("gnome-shell-hotplug-sniffer[%d]: %s.%03d: %s\n", pid, timebuf, (gint) (now.tv_usec / 1000), s);
305 g_free (s);
306 out:
307 ;
308 }