Fix:binding_dbus:Beginning of moving methods into a table
[navit-package] / navit / binding / dbus / binding_dbus.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
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
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <string.h>
21 #define DBUS_API_SUBJECT_TO_CHANGE
22 #include <dbus/dbus.h>
23 #include <dbus/dbus-glib.h>
24 #include <dbus/dbus-glib-lowlevel.h>
25 #include "config.h"
26 #include "main.h"
27 #include "navit.h"
28 #include "coord.h"
29 #include "point.h"
30 #include "plugin.h"
31 #include "debug.h"
32 #include "item.h"
33 #include "attr.h"
34 #include "layout.h"
35
36
37 static DBusConnection *connection;
38
39 static char *service_name="org.navit-project.navit";
40 static char *object_path="/org/navit_project/navit";
41
42 GHashTable *object_hash;
43 GHashTable *object_count;
44
45 static char *
46 object_new(char *type, void *object)
47 {
48         int id;
49         char *ret;
50         dbg(0,"enter %s\n", type);
51         id=(int)g_hash_table_lookup(object_count, type);
52         g_hash_table_insert(object_count, type, (void *)(id+1));
53         ret=g_strdup_printf("%s/%s/%d", object_path, type, id);
54         g_hash_table_insert(object_hash, ret, object);
55         dbg(0,"return %s\n", ret);
56         return (ret);
57 }
58
59 static void *
60 object_get(const char *path)
61 {
62         return g_hash_table_lookup(object_hash, path);
63 }
64
65 static void *
66 object_get_from_message_arg(DBusMessage *message, char *type)
67 {
68         char *opath;
69         char *prefix;
70         DBusError error;
71         void *ret=NULL;
72
73         dbus_error_init(&error);
74         if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID)) {
75                 dbus_error_free(&error);
76                 dbg(0,"wrong arg type\n");
77                 return NULL;
78         }
79         prefix=g_strdup_printf("%s/%s/", object_path, type);
80         if (!strncmp(prefix, opath, strlen(prefix)))
81                 ret=object_get(opath);
82         else
83                 dbg(0,"wrong object type\n");
84         g_free(prefix);
85         return ret;
86 }
87
88 static void *
89 object_get_from_message(DBusMessage *message, char *type)
90 {
91         const char *opath=dbus_message_get_path(message);
92         char *prefix;
93         void *ret=NULL;
94
95         prefix=g_strdup_printf("%s/%s/", object_path, type);
96         if (!strncmp(prefix, opath, strlen(prefix)))
97                 ret=object_get(opath);
98         else
99                 dbg(0,"wrong object type\n");
100         g_free(prefix);
101         return ret;
102 }
103
104 static DBusHandlerResult
105 empty_reply(DBusConnection *connection, DBusMessage *message)
106 {
107         DBusMessage *reply;
108
109         reply = dbus_message_new_method_return(message);
110         dbus_connection_send (connection, reply, NULL);
111         dbus_message_unref (reply);
112
113         return DBUS_HANDLER_RESULT_HANDLED;
114 }
115
116 static DBusHandlerResult
117 request_main_get_navit(DBusConnection *connection, DBusMessage *message)
118 {
119         DBusMessage *reply;
120         DBusError error;
121         struct iter *iter;
122         struct navit *navit;
123         char *opath;
124
125         dbus_error_init(&error);
126
127         if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID)) {
128                 dbg(0,"Error parsing\n");
129                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
130         }
131         dbg(0,"opath=%s\n", opath);
132         iter=object_get(opath);
133         navit=main_get_navit(iter);
134         if (navit) {
135                 reply = dbus_message_new_method_return(message);
136                 opath=object_new("navit",navit);
137                 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID);
138                 dbus_connection_send (connection, reply, NULL);
139                 dbus_message_unref (reply);
140                 return DBUS_HANDLER_RESULT_HANDLED;
141         }
142         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
143 }
144
145 static DBusHandlerResult
146 request_main_iter(DBusConnection *connection, DBusMessage *message)
147 {
148         DBusMessage *reply;
149         struct iter *iter=main_iter_new();
150         dbg(0,"iter=%p\n", iter);
151         char *opath=object_new("main_iter",iter);
152         reply = dbus_message_new_method_return(message);
153         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID);
154         dbus_connection_send (connection, reply, NULL);
155         dbus_message_unref (reply);
156
157         return DBUS_HANDLER_RESULT_HANDLED;
158 }
159
160 static DBusHandlerResult
161 request_main_iter_destroy(DBusConnection *connection, DBusMessage *message)
162 {
163         struct iter *iter;
164         
165         iter=object_get_from_message_arg(message, "main_iter");
166         if (! iter)
167                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
168         main_iter_destroy(iter);
169
170         return empty_reply(connection, message);
171 }
172
173 /**
174  * Extracts a struct pcoord from a DBus message
175  *
176  * @param message The DBus message
177  * @param iter Sort of pointer that points on that (iii)-object in the message
178  * @param pc Pointer where the data should get stored
179  */
180 static int
181 pcoord_get_from_message(DBusMessage *message, DBusMessageIter *iter, struct pcoord *pc)
182 {
183         DBusMessageIter iter2;
184
185         dbg(0,"%s\n", dbus_message_iter_get_signature(iter));
186         
187         dbus_message_iter_recurse(iter, &iter2);
188
189         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
190                 return 0;
191         dbus_message_iter_get_basic(&iter2, &pc->pro);
192         
193         dbus_message_iter_next(&iter2);
194         
195         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
196                 return 0;
197         dbus_message_iter_get_basic(&iter2, &pc->x);
198         
199         dbus_message_iter_next(&iter2);
200
201         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
202                 return 0;
203         dbus_message_iter_get_basic(&iter2, &pc->y);
204
205         dbg(0, " pro -> %i x -> %i y -> %i\n", &pc->pro, &pc->x, &pc->y);
206         
207         dbus_message_iter_next(&iter2);
208         
209         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INVALID)
210                 return 0;
211
212         return 1;
213 }
214
215 /**
216  * Extracts a struct point from a DBus message
217  *
218  * @param message The DBus message
219  * @param iter Sort of pointer that points on that (ii)-object in the message
220  * @param p Pointer where the data should get stored
221  */
222 static int
223 point_get_from_message(DBusMessage *message, DBusMessageIter *iter, struct point *p)
224 {
225         DBusMessageIter iter2;
226
227         dbg(0,"%s\n", dbus_message_iter_get_signature(iter));
228         
229         dbus_message_iter_recurse(iter, &iter2);
230
231         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
232                 return 0;
233         dbus_message_iter_get_basic(&iter2, &p->x);
234         
235         dbus_message_iter_next(&iter2);
236         
237         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
238                 return 0;
239         dbus_message_iter_get_basic(&iter2, &p->y);
240
241         dbg(0, " x -> %i  y -> %i\n", p->x, p->y);
242         
243         dbus_message_iter_next(&iter2);
244
245         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INVALID)
246                 return 0;
247         
248         return 1;
249 }
250
251 static DBusHandlerResult
252 request_navit_set_center(DBusConnection *connection, DBusMessage *message)
253 {
254         struct pcoord pc;
255         struct navit *navit;
256         DBusMessageIter iter;
257
258         navit=object_get_from_message(message, "navit");
259         if (! navit)
260                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
261
262         dbus_message_iter_init(message, &iter);
263
264         if (!pcoord_get_from_message(message, &iter, &pc))
265                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
266         navit_set_center(navit, &pc);
267         return empty_reply(connection, message);
268 }
269
270 static DBusHandlerResult
271 request_navit_set_center_screen(DBusConnection *connection, DBusMessage *message)
272 {
273         struct point p;
274         struct navit *navit;
275         DBusMessageIter iter;
276
277         navit=object_get_from_message(message, "navit");
278         if (! navit)
279                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
280
281         dbus_message_iter_init(message, &iter);
282
283         if (!point_get_from_message(message, &iter, &p))
284                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
285         navit_set_center_screen(navit, &p);
286         return empty_reply(connection, message);
287 }
288
289 static DBusHandlerResult
290 request_navit_set_layout(DBusConnection *connection, DBusMessage *message)
291 {
292         char *new_layout_name;
293         struct navit *navit;
294         struct attr attr;
295         struct attr_iter *iter;
296
297         navit=object_get_from_message(message, "navit");
298         if (! navit)
299                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
300         
301     if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &new_layout_name, DBUS_TYPE_INVALID))
302                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
303         
304     iter=navit_attr_iter_new();
305         while(navit_get_attr(navit, attr_layout, &attr, iter)) {
306                 if (strcmp(attr.u.layout->name, new_layout_name) == 0) {
307                         navit_set_attr(navit, &attr);
308                 }
309         }
310         return empty_reply(connection, message);
311 }
312
313 static DBusHandlerResult
314 request_navit_zoom(DBusConnection *connection, DBusMessage *message)
315 {
316         int factor;
317         struct point *p = malloc(sizeof(struct point));
318         struct navit *navit;
319         DBusMessageIter iter;
320
321         navit = object_get_from_message(message, "navit");
322         if (! navit)
323                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
324
325         dbus_message_iter_init(message, &iter);
326         dbg(0,"%s\n", dbus_message_iter_get_signature(&iter));
327         
328         dbus_message_iter_get_basic(&iter, &factor);
329         
330         if (dbus_message_iter_has_next(&iter))
331         {
332                 dbus_message_iter_next(&iter);
333                 if (!point_get_from_message(message, &iter, p))
334                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
335         }
336
337         if (factor > 1)
338                 navit_zoom_in(navit, factor, p);
339         else if (factor < -1)
340                 navit_zoom_out(navit, 0-factor, p);
341
342         return empty_reply(connection, message);
343
344 }
345
346 static DBusHandlerResult
347 request_navit_resize(DBusConnection *connection, DBusMessage *message)
348 {
349         struct navit *navit;
350         int w, h;
351         DBusMessageIter iter;
352
353         navit = object_get_from_message(message, "navit");
354         if (! navit)
355                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
356
357         dbus_message_iter_init(message, &iter);
358         dbg(0,"%s\n", dbus_message_iter_get_signature(&iter));
359         
360         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
361                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
362         dbus_message_iter_get_basic(&iter, &w);
363         
364         dbus_message_iter_next(&iter);
365         
366         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
367                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
368         dbus_message_iter_get_basic(&iter, &h);
369
370         dbg(0, " w -> %i  h -> %i\n", w, h);
371         
372         navit_resize(navit, w, h);
373
374         return empty_reply(connection, message);
375
376 }
377
378 static DBusHandlerResult
379 request_navit_set_position(DBusConnection *connection, DBusMessage *message)
380 {
381         struct navit *navit;
382         struct pcoord c;
383
384         DBusMessageIter iter;
385
386         navit = object_get_from_message(message, "navit");
387         if (! navit)
388                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
389
390         dbus_message_iter_init(message, &iter);
391         pcoord_get_from_message(message, &iter, &c);
392         
393         navit_set_position(navit, &c);
394         return empty_reply(connection, message);
395 }
396
397 static DBusHandlerResult
398 request_navit_set_destination(DBusConnection *connection, DBusMessage *message)
399 {
400         struct navit *navit;
401         struct pcoord c;
402         char *description;
403
404         DBusMessageIter iter;
405
406         navit = object_get_from_message(message, "navit");
407         if (! navit)
408                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
409
410         dbus_message_iter_init(message, &iter);
411         pcoord_get_from_message(message, &iter, &c);
412         
413         dbus_message_iter_next(&iter);
414         dbus_message_iter_get_basic(&iter, &description);
415         dbg(0, " destination -> %s\n", description);
416         
417         navit_set_destination(navit, &c, description);
418         return empty_reply(connection, message);
419 }
420
421 struct dbus_method {
422         char *path;
423         char *method;
424         char *signature;
425         DBusHandlerResult(*func)(DBusConnection *connection, DBusMessage *message);
426 } dbus_methods[] = {
427         {"",            "iter",         "",             request_main_iter},
428         {".navit",      "set_center",   "(iii)",        request_navit_set_center},
429 };
430
431 static DBusHandlerResult
432 navit_handler_func(DBusConnection *connection, DBusMessage *message, void *user_data)
433 {
434         int i;
435         char *path;
436         dbg(0,"type=%s interface=%s path=%s member=%s signature=%s\n", dbus_message_type_to_string(dbus_message_get_type(message)), dbus_message_get_interface(message), dbus_message_get_path(message), dbus_message_get_member(message), dbus_message_get_signature(message));
437 #if 0
438         if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
439                 DBusMessage *reply;
440                 gchar *idata;
441                 dbg(0,"Introspect\n");
442                 if (! strcmp(dbus_message_get_path(message), "/org/navit_project/navit")) {
443                         g_file_get_contents("binding/dbus/navit.introspect", &idata, NULL, NULL);
444                         reply = dbus_message_new_method_return(message);
445                         dbus_message_append_args(reply, DBUS_TYPE_STRING, &idata, DBUS_TYPE_INVALID);
446                         dbus_connection_send (connection, reply, NULL);
447                         dbus_message_unref (reply);
448                         g_free(idata);
449                         return DBUS_HANDLER_RESULT_HANDLED;
450                 }
451         }
452 #endif
453         for (i = 0 ; i < sizeof(dbus_methods)/sizeof(struct dbus_method) ; i++) {
454                 path=g_strdup_printf("org.navit_project.navit%s", dbus_methods[i].path);
455                 if (dbus_message_is_method_call(message, path, dbus_methods[i].method) &&
456                     dbus_message_has_signature(message, dbus_methods[i].signature)) {
457                         g_free(path);
458                         return dbus_methods[i].func(connection, message);
459                 }
460                 g_free(path);
461         }
462         if (dbus_message_is_method_call (message, "org.navit_project.navit", "iter_destroy") &&
463                 dbus_message_has_signature(message, "o"))
464                 return request_main_iter_destroy(connection, message);
465         if (dbus_message_is_method_call (message, "org.navit_project.navit", "get_navit") &&
466                 dbus_message_has_signature(message,"o")) 
467                 return request_main_get_navit(connection, message);
468         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "set_center_screen") &&
469                 dbus_message_has_signature(message,"(ii)")) 
470                 return request_navit_set_center_screen(connection, message);
471         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "set_layout") &&
472                 dbus_message_has_signature(message,"s")) 
473                 return request_navit_set_layout(connection, message);
474         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "zoom") &&
475                 dbus_message_has_signature(message, "i(ii)")) 
476                 return request_navit_zoom(connection, message);
477         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "zoom") &&
478                 dbus_message_has_signature(message, "i")) 
479                 return request_navit_zoom(connection, message);
480         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "resize") &&
481                 dbus_message_has_signature(message, "ii")) 
482                 return request_navit_resize(connection, message);
483         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "set_position") &&
484                 dbus_message_has_signature(message, "(iii)")) 
485                 return request_navit_set_position(connection, message);
486         if (dbus_message_is_method_call (message, "org.navit_project.navit.navit", "set_destination") &&
487                 dbus_message_has_signature(message, "(iii)s")) 
488                 return request_navit_set_destination(connection, message);
489         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
490 }
491
492 static DBusObjectPathVTable dbus_navit_vtable = {
493         NULL,
494         navit_handler_func,
495         NULL
496 };
497
498 #if 0
499 DBusHandlerResult
500 filter(DBusConnection *connection, DBusMessage *message, void *user_data)
501 {
502         dbg(0,"type=%s interface=%s path=%s member=%s signature=%s\n", dbus_message_type_to_string(dbus_message_get_type(message)), dbus_message_get_interface(message), dbus_message_get_path(message), dbus_message_get_member(message), dbus_message_get_signature(message));
503         if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
504         }
505         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
506 }
507 #endif
508
509 void plugin_init(void)
510 {
511         DBusError error;
512
513         object_hash=g_hash_table_new(g_str_hash, g_str_equal);
514         object_count=g_hash_table_new(g_str_hash, g_str_equal);
515         dbg(0,"enter 1\n");
516         dbus_error_init(&error);
517         connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
518         if (!connection) {
519                 dbg(0,"Failed to open connection to session message bus: %s\n", error.message);
520                 dbus_error_free(&error);
521                 return;
522         }
523         dbus_connection_setup_with_g_main(connection, NULL);
524 #if 0
525         dbus_connection_add_filter(connection, filter, NULL, NULL);
526         dbus_bus_add_match(connection, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
527 #endif
528         dbus_connection_register_fallback(connection, object_path, &dbus_navit_vtable, NULL);
529         dbus_bus_request_name(connection, service_name, 0, &error);
530         if (dbus_error_is_set(&error)) {
531                 dbg(0,"Failed to request name: %s", error.message);
532                 dbus_error_free (&error);
533         }
534 }