Add:Core:Improved commands
[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 #include "command.h"
36
37
38 static DBusConnection *connection;
39
40 static char *service_name = "org.navit_project.navit";
41 static char *object_path = "/org/navit_project/navit";
42 char *navitintrospectxml_head1 = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
43                                  "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
44                                  "<node name=\"";
45
46 char *navitintrospectxml_head2 = "\">\n"
47                                  "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
48                                  "    <method name=\"Introspect\">\n"
49                                  "      <arg direction=\"out\" type=\"s\" />\n"
50                                  "    </method>\n"
51                                  "  </interface>\n";
52
53
54
55 GHashTable *object_hash;
56 GHashTable *object_count;
57
58 static char *
59 object_new(char *type, void *object)
60 {
61         int id;
62         char *ret;
63         dbg(0,"enter %s\n", type);
64         id=(int)g_hash_table_lookup(object_count, type);
65         g_hash_table_insert(object_count, type, (void *)(id+1));
66         ret=g_strdup_printf("%s/%s/%d", object_path, type, id);
67         g_hash_table_insert(object_hash, ret, object);
68         dbg(0,"return %s\n", ret);
69         return (ret);
70 }
71
72 static void *
73 object_get(const char *path)
74 {
75         return g_hash_table_lookup(object_hash, path);
76 }
77
78 static void *
79 object_get_from_message_arg(DBusMessage *message, char *type)
80 {
81         char *opath;
82         char *prefix;
83         DBusError error;
84         void *ret=NULL;
85
86         dbus_error_init(&error);
87         if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID)) {
88                 dbus_error_free(&error);
89                 dbg(0,"wrong arg type\n");
90                 return NULL;
91         }
92         prefix=g_strdup_printf("%s/%s/", object_path, type);
93         if (!strncmp(prefix, opath, strlen(prefix)))
94                 ret=object_get(opath);
95         else
96                 dbg(0,"wrong object type\n");
97         g_free(prefix);
98         return ret;
99 }
100
101 static void *
102 object_get_from_message(DBusMessage *message, char *type)
103 {
104         const char *opath=dbus_message_get_path(message);
105         char *prefix;
106         void *ret=NULL;
107
108         prefix=g_strdup_printf("%s/%s/", object_path, type);
109         if (!strncmp(prefix, opath, strlen(prefix)))
110                 ret=object_get(opath);
111         else
112                 dbg(0,"wrong object type\n");
113         g_free(prefix);
114         return ret;
115 }
116
117 static DBusHandlerResult
118 reply_simple_as_variant(DBusConnection *connection, DBusMessage *message, int value, int dbus_type)
119 {
120         DBusMessage *reply;
121     
122         reply = dbus_message_new_method_return(message);
123     dbus_message_append_args(reply,
124                              dbus_type, &value,
125                              DBUS_TYPE_INVALID);
126         dbus_connection_send (connection, reply, NULL);
127         dbus_message_unref (reply);
128
129         return DBUS_HANDLER_RESULT_HANDLED;
130 }
131
132 static DBusHandlerResult
133 empty_reply(DBusConnection *connection, DBusMessage *message)
134 {
135         DBusMessage *reply;
136
137         reply = dbus_message_new_method_return(message);
138         dbus_connection_send (connection, reply, NULL);
139         dbus_message_unref (reply);
140
141         return DBUS_HANDLER_RESULT_HANDLED;
142 }
143
144 static DBusHandlerResult
145 request_main_get_navit(DBusConnection *connection, DBusMessage *message)
146 {
147         DBusMessage *reply;
148         DBusError error;
149         struct iter *iter;
150         struct navit *navit;
151         char *opath;
152
153         dbus_error_init(&error);
154
155         if (!dbus_message_get_args(message, &error, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID)) {
156                 dbg(0,"Error parsing\n");
157                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
158         }
159         dbg(0,"opath=%s\n", opath);
160         iter=object_get(opath);
161         navit=main_get_navit(iter);
162         if (navit) {
163                 reply = dbus_message_new_method_return(message);
164                 opath=object_new("navit",navit);
165                 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID);
166                 dbus_connection_send (connection, reply, NULL);
167                 dbus_message_unref (reply);
168                 return DBUS_HANDLER_RESULT_HANDLED;
169         }
170         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
171 }
172
173 static DBusHandlerResult
174 request_main_iter(DBusConnection *connection, DBusMessage *message)
175 {
176         DBusMessage *reply;
177         struct iter *iter=main_iter_new();
178         dbg(0,"iter=%p\n", iter);
179         char *opath=object_new("main_iter",iter);
180         reply = dbus_message_new_method_return(message);
181         dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &opath, DBUS_TYPE_INVALID);
182         dbus_connection_send (connection, reply, NULL);
183         dbus_message_unref (reply);
184
185         return DBUS_HANDLER_RESULT_HANDLED;
186 }
187
188 static DBusHandlerResult
189 request_main_iter_destroy(DBusConnection *connection, DBusMessage *message)
190 {
191         struct iter *iter;
192         
193         iter=object_get_from_message_arg(message, "main_iter");
194         if (! iter)
195                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
196         main_iter_destroy(iter);
197
198         return empty_reply(connection, message);
199 }
200
201 /**
202  * Extracts a struct pcoord from a DBus message
203  *
204  * @param message The DBus message
205  * @param iter Sort of pointer that points on that (iii)-object in the message
206  * @param pc Pointer where the data should get stored
207  * @returns Returns 1 when everything went right, otherwise 0
208  */
209 static int
210 pcoord_get_from_message(DBusMessage *message, DBusMessageIter *iter, struct pcoord *pc)
211 {
212
213     if(!strcmp(dbus_message_iter_get_signature(iter), "s")) {
214         char *coordstring;
215
216         dbus_message_iter_get_basic(iter, &coordstring);
217         if(!pcoord_parse(coordstring, projection_mg, pc))
218             return 0;
219         
220         return 1;
221     } else {
222         
223         DBusMessageIter iter2;
224         dbus_message_iter_recurse(iter, &iter2);
225         if(!strcmp(dbus_message_iter_get_signature(iter), "(is)")) {
226             char *coordstring;
227             int projection;
228             
229             dbus_message_iter_get_basic(&iter2, &projection);
230
231             dbus_message_iter_next(&iter2);
232             dbus_message_iter_get_basic(&iter2, &coordstring);
233
234             if(!pcoord_parse(coordstring, projection, pc))
235                 return 0;
236
237             return 1;
238         } else if(!strcmp(dbus_message_iter_get_signature(iter), "(iii)")) {
239             
240             dbus_message_iter_get_basic(&iter2, &pc->pro);
241             
242             dbus_message_iter_next(&iter2);
243             dbus_message_iter_get_basic(&iter2, &pc->x);
244             
245             dbus_message_iter_next(&iter2);
246             dbus_message_iter_get_basic(&iter2, &pc->y);
247
248             return 1;
249         }
250     }
251     return 0;
252     
253 }
254
255 static DBusHandlerResult
256 request_navit_draw(DBusConnection *connection, DBusMessage *message)
257 {
258         struct navit *navit;
259
260         navit=object_get_from_message(message, "navit");
261         if (! navit)
262                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
263
264         navit_draw(navit);
265         
266     return empty_reply(connection, message);
267 }
268
269
270 /**
271  * Extracts a struct point from a DBus message
272  *
273  * @param message The DBus message
274  * @param iter Sort of pointer that points on that (ii)-object in the message
275  * @param p Pointer where the data should get stored
276  * @returns Returns 1 when everything went right, otherwise 0
277  */
278 static int
279 point_get_from_message(DBusMessage *message, DBusMessageIter *iter, struct point *p)
280 {
281         DBusMessageIter iter2;
282
283         dbg(0,"%s\n", dbus_message_iter_get_signature(iter));
284         
285         dbus_message_iter_recurse(iter, &iter2);
286
287         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
288                 return 0;
289         dbus_message_iter_get_basic(&iter2, &p->x);
290         
291         dbus_message_iter_next(&iter2);
292         
293         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INT32)
294                 return 0;
295         dbus_message_iter_get_basic(&iter2, &p->y);
296
297         dbg(0, " x -> %x  y -> %x\n", p->x, p->y);
298         
299         dbus_message_iter_next(&iter2);
300
301         if (dbus_message_iter_get_arg_type(&iter2) != DBUS_TYPE_INVALID)
302                 return 0;
303         
304         return 1;
305 }
306
307 /**
308  * @brief Shows up a message
309  * @param connection The DBusConnection object through which \a message arrived
310  * @param message The DBusMessage containing the coordinates
311  * @returns An empty reply if everything went right, otherwise DBUS_HANDLER_RESULT_NOT_YET_HANDLED
312  */
313
314 static DBusHandlerResult
315 request_navit_add_message(DBusConnection *connection, DBusMessage *message)
316 {
317         struct navit *navit;
318         char *usermessage;
319     
320     DBusMessageIter iter;
321
322         navit=object_get_from_message(message, "navit");
323         if (! navit)
324                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
325
326         dbus_message_iter_init(message, &iter);
327         dbus_message_iter_get_basic(&iter, &usermessage);
328         
329     navit_add_message(navit, usermessage);
330         
331     return empty_reply(connection, message);
332 }
333
334
335 /**
336  * @brief Centers the screen on a specified position \a pc on the world
337  * @param connection The DBusConnection object through which \a message arrived
338  * @param message The DBusMessage containing the coordinates
339  * @returns An empty reply if everything went right, otherwise DBUS_HANDLER_RESULT_NOT_YET_HANDLED
340  */
341
342 static DBusHandlerResult
343 request_navit_set_center(DBusConnection *connection, DBusMessage *message)
344 {
345         struct pcoord pc;
346         struct navit *navit;
347         DBusMessageIter iter;
348
349         navit=object_get_from_message(message, "navit");
350         if (! navit)
351                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
352
353         dbus_message_iter_init(message, &iter);
354
355         if (!pcoord_get_from_message(message, &iter, &pc))
356                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
357     
358         navit_set_center(navit, &pc);
359         return empty_reply(connection, message);
360 }
361
362 /**
363  * @brief Centers the screen on a specified position \a p shown on the screen
364  * @param connection The DBusConnection object through which \a message arrived
365  * @param message The DBusMessage containing the x and y value
366  * @returns An empty reply if everything went right, otherwise DBUS_HANDLER_RESULT_NOT_YET_HANDLED
367  */
368 static DBusHandlerResult
369 request_navit_set_center_screen(DBusConnection *connection, DBusMessage *message)
370 {
371         struct point p;
372         struct navit *navit;
373         DBusMessageIter iter;
374
375         navit=object_get_from_message(message, "navit");
376         if (! navit)
377                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
378
379         dbus_message_iter_init(message, &iter);
380
381         if (!point_get_from_message(message, &iter, &p))
382                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
383         navit_set_center_screen(navit, &p);
384         return empty_reply(connection, message);
385 }
386
387 /**
388  * @brief Sets the layout to \a new_layout_name extracted from \a message
389  * @param connection The DBusConnection object through which \a message arrived
390  * @param message The DBusMessage containing the name of the layout
391  * @returns An empty reply if everything went right, otherwise DBUS_HANDLER_RESULT_NOT_YET_HANDLED
392  */
393 static DBusHandlerResult
394 request_navit_set_layout(DBusConnection *connection, DBusMessage *message)
395 {
396         char *new_layout_name;
397         struct navit *navit;
398         struct attr attr;
399         struct attr_iter *iter;
400
401         navit=object_get_from_message(message, "navit");
402         if (! navit)
403                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
404         
405     if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &new_layout_name, DBUS_TYPE_INVALID))
406                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
407         
408     iter=navit_attr_iter_new();
409         while(navit_get_attr(navit, attr_layout, &attr, iter)) {
410                 if (strcmp(attr.u.layout->name, new_layout_name) == 0) {
411                         navit_set_attr(navit, &attr);
412                 }
413         }
414         return empty_reply(connection, message);
415 }
416
417 static DBusHandlerResult
418 request_navit_zoom(DBusConnection *connection, DBusMessage *message)
419 {
420         int factor;
421         struct point *p = NULL;
422         struct navit *navit;
423         DBusMessageIter iter;
424
425         navit = object_get_from_message(message, "navit");
426         if (! navit)
427                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
428
429         dbus_message_iter_init(message, &iter);
430         dbg(0,"%s\n", dbus_message_iter_get_signature(&iter));
431         
432         dbus_message_iter_get_basic(&iter, &factor);
433         
434         if (dbus_message_iter_has_next(&iter))
435         {
436                 dbus_message_iter_next(&iter);
437                 if (!point_get_from_message(message, &iter, p))
438                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
439         }
440
441         if (factor > 1)
442                 navit_zoom_in(navit, factor, p);
443         else if (factor < -1)
444                 navit_zoom_out(navit, 0-factor, p);
445
446         return empty_reply(connection, message);
447
448 }
449
450 static DBusHandlerResult
451 request_navit_resize(DBusConnection *connection, DBusMessage *message)
452 {
453         struct navit *navit;
454         int w, h;
455         DBusMessageIter iter;
456
457         navit = object_get_from_message(message, "navit");
458         if (! navit)
459                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
460
461         dbus_message_iter_init(message, &iter);
462         dbg(0,"%s\n", dbus_message_iter_get_signature(&iter));
463         
464         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
465                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
466         dbus_message_iter_get_basic(&iter, &w);
467         
468         dbus_message_iter_next(&iter);
469         
470         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32)
471                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
472         dbus_message_iter_get_basic(&iter, &h);
473
474         dbg(0, " w -> %i  h -> %i\n", w, h);
475         
476         navit_handle_resize(navit, w, h);
477
478         return empty_reply(connection, message);
479
480 }
481
482 static DBusHandlerResult
483 request_navit_get_attr(DBusConnection *connection, DBusMessage *message)
484 {
485     struct navit *navit;
486     DBusMessageIter iter, response;
487     char * attr_type = NULL;
488     struct attr attr;
489     navit = object_get_from_message(message, "navit");
490     if (! navit)
491         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
492
493     dbus_message_iter_init(message, &iter);
494     dbus_message_iter_get_basic(&iter, &attr_type);
495     attr.type = attr_from_name(attr_type); 
496     dbg(0, "attr value: 0x%x string: %s\n", attr.type, attr_type);
497
498     if (attr.type == attr_none)
499         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
500     
501     if (attr.type > attr_type_item_begin && attr.type < attr_type_item_end)
502         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
503
504     else if (attr.type > attr_type_int_begin && attr.type < attr_type_boolean_begin)
505     {
506         dbg(0, "int detected\n");
507         if(navit_get_attr(navit, attr.type, &attr, NULL)) {
508             dbg(0, "%s = %i\n", attr_type, attr.u.num);
509             return reply_simple_as_variant(connection, message, attr.u.num, DBUS_TYPE_INT32);
510         }
511     }
512
513     else if(attr.type > attr_type_boolean_begin && attr.type < attr_type_int_end)
514     {
515         dbg(0, "bool detected\n");
516         if(navit_get_attr(navit, attr.type, &attr, NULL)) {
517             dbg(0, "%s = %i\n", attr_type, attr.u.num);
518             return reply_simple_as_variant(connection, message, attr.u.num, DBUS_TYPE_BOOLEAN);
519         }
520     }
521
522     else if(attr.type > attr_type_string_begin && attr.type < attr_type_string_end)
523     {
524         dbg(0, "string detected\n");
525         if(navit_get_attr(navit, attr.type, &attr, NULL)) {
526             dbg(0, "%s = %s\n", attr_type, &attr.u.layout);
527             return reply_simple_as_variant(connection, message, &attr.u.layout, DBUS_TYPE_STRING);
528         }
529     }
530
531 #if 0
532     else if(attr.type > attr_type_special_begin && attr.type < attr_type_special_end)
533         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
534
535     else if(attr.type > attr_type_double_begin && attr.type < attr_type_double_end)
536         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
537
538     else if(attr.type > attr_type_coord_geo_begin && attr.type < attr_type_coord_geo_end)
539         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
540
541     else if(attr.type > attr_type_color_begin && attr.type < attr_type_color_end)
542         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
543
544     else if(attr.type > attr_type_object_begin && attr.type < attr_type_object_end)
545         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
546
547     else if(attr.type > attr_type_coord_begin && attr.type < attr_type_coord_end)
548         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
549
550     else if(attr.type > attr_type_pcoord_begin && attr.type < attr_type_pcoord_end)
551         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
552
553     else if(attr.type > attr_type_callback_begin && attr.type < attr_type_callback_end)
554         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
555 #endif
556     else {
557         dbg(0, "zomg really unhandled111\n");
558         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
559     }
560
561     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
562 }
563
564
565 static DBusHandlerResult
566 request_navit_set_attr(DBusConnection *connection, DBusMessage *message)
567 {
568     struct navit *navit;
569         DBusMessageIter iter, iterattr;
570     struct attr attr;
571     char *attr_type;
572
573         navit = object_get_from_message(message, "navit");
574         if (! navit)
575                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
576
577     dbus_message_iter_init(message, &iter);
578     dbus_message_iter_get_basic(&iter, &attr_type);
579     attr.type = attr_from_name(attr_type); 
580     dbg(0, "attr value: 0x%x string: %s\n", attr.type, attr_type);
581     
582     if (attr.type == attr_none)
583         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
584     
585     dbus_message_iter_next(&iter);
586     dbus_message_iter_recurse(&iter, &iterattr);
587     dbg(0, "seems valid. signature: %s\n", dbus_message_iter_get_signature(&iterattr));
588     
589     if (attr.type > attr_type_item_begin && attr.type < attr_type_item_end)
590         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
591
592     else if (attr.type > attr_type_int_begin && attr.type < attr_type_boolean_begin)
593         if (dbus_message_iter_get_arg_type(&iterattr) == DBUS_TYPE_INT32)
594         {
595             dbus_message_iter_get_basic(&iterattr, &attr.u.num);
596             if (navit_set_attr(navit, &attr))
597                 return empty_reply(connection, message);
598         }
599
600     else if(attr.type > attr_type_boolean_begin && attr.type < attr_type_int_end)
601         if (dbus_message_iter_get_arg_type(&iterattr) == DBUS_TYPE_BOOLEAN)
602         {
603             dbus_message_iter_get_basic(&iterattr, &attr.u.num);
604             if (navit_set_attr(navit, &attr))
605                 return empty_reply(connection, message);
606         }
607
608 #if 0
609     else if(attr.type > attr_type_string_begin && attr.type < attr_type_string_end)
610         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
611
612     else if(attr.type > attr_type_special_begin && attr.type < attr_type_special_end)
613         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
614
615     else if(attr.type > attr_type_double_begin && attr.type < attr_type_double_end)
616         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
617
618     else if(attr.type > attr_type_coord_geo_begin && attr.type < attr_type_coord_geo_end)
619         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
620
621     else if(attr.type > attr_type_color_begin && attr.type < attr_type_color_end)
622         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
623
624     else if(attr.type > attr_type_object_begin && attr.type < attr_type_object_end)
625         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
626
627     else if(attr.type > attr_type_coord_begin && attr.type < attr_type_coord_end)
628         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
629
630     else if(attr.type > attr_type_pcoord_begin && attr.type < attr_type_pcoord_end)
631         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
632
633     else if(attr.type > attr_type_callback_begin && attr.type < attr_type_callback_end)
634         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
635 #endif
636     else {
637         dbg(0, "zomg really unhandled111\n");
638         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
639     }
640     
641     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
642 }
643
644 static DBusHandlerResult
645 request_navit_set_position(DBusConnection *connection, DBusMessage *message)
646 {
647         struct pcoord pc;
648         struct navit *navit;
649         DBusMessageIter iter;
650
651         navit = object_get_from_message(message, "navit");
652         if (! navit)
653                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
654
655         dbus_message_iter_init(message, &iter);
656         if (!pcoord_get_from_message(message, &iter, &pc))
657         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
658         
659         navit_set_position(navit, &pc);
660         return empty_reply(connection, message);
661 }
662
663 static DBusHandlerResult
664 request_navit_set_destination(DBusConnection *connection, DBusMessage *message)
665 {
666         struct pcoord pc;
667         struct navit *navit;
668         DBusMessageIter iter;
669         char *description;
670
671         navit = object_get_from_message(message, "navit");
672         if (! navit)
673                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
674
675         dbus_message_iter_init(message, &iter);
676         if (!pcoord_get_from_message(message, &iter, &pc))
677             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
678         
679     dbus_message_iter_next(&iter);
680         dbus_message_iter_get_basic(&iter, &description);
681         dbg(0, " destination -> %s\n", description);
682         
683         navit_set_destination(navit, &pc, description);
684         return empty_reply(connection, message);
685 }
686
687 static DBusHandlerResult
688 request_navit_evaluate(DBusConnection *connection, DBusMessage *message)
689 {
690         struct pcoord pc;
691         struct navit *navit;
692         char *command;
693         char *result;
694         struct attr attr;
695         DBusMessage *reply;
696         int error;
697
698         navit = object_get_from_message(message, "navit");
699         if (! navit)
700                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
701
702         attr.type=attr_navit;
703         attr.u.navit=navit;
704         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &command, DBUS_TYPE_INVALID))
705                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
706         result=command_evaluate_to_string(&attr, command, &error);
707         reply = dbus_message_new_method_return(message);
708         if (error)
709                 dbus_message_append_args(reply, DBUS_TYPE_INT32, &error, DBUS_TYPE_INVALID);
710         else
711                 dbus_message_append_args(reply, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID);
712         dbus_connection_send (connection, reply, NULL);
713         dbus_message_unref (reply);
714         return DBUS_HANDLER_RESULT_HANDLED;
715 }
716
717 struct dbus_method {
718         char *path;
719         char *method;
720         char *signature;
721     char *signature_name;
722     char *response;
723     char *response_name;
724         DBusHandlerResult(*func)(DBusConnection *connection, DBusMessage *message);
725 } dbus_methods[] = {
726         {"",        "iter",                "",        "",                                        "o",  "navit", request_main_iter},
727         {"",        "iter_destroy",        "o",       "navit",                                   "",   "",      request_main_iter_destroy},
728         {"",        "get_navit",           "o",       "navit",                                   "o",  "",      request_main_get_navit},
729         {".navit",  "draw",                "",        "",                                        "",   "",      request_navit_draw},
730         {".navit",  "add_message",         "s",       "message",                                 "",   "",      request_navit_add_message},
731         {".navit",  "set_center",          "s",       "(coordinates)",                           "",   "",      request_navit_set_center},
732         {".navit",  "set_center",          "(is)",    "(projection,coordinates)",                "",   "",      request_navit_set_center},
733         {".navit",  "set_center",          "(iii)",   "(projection,longitude,latitude)",         "",   "",      request_navit_set_center},
734         {".navit",  "set_center_screen",   "(ii)",    "(pixel_x,pixel_y)",                       "",   "",      request_navit_set_center_screen},
735         {".navit",  "set_layout",          "s",       "layoutname",                              "",   "",      request_navit_set_layout},
736         {".navit",  "zoom",                "i(ii)",   "factor(pixel_x,pixel_y)",                 "",   "",      request_navit_zoom},
737         {".navit",  "zoom",                "i",       "factor",                                  "",   "",      request_navit_zoom},
738         {".navit",  "resize",              "ii",      "upperleft,lowerright",                    "",   "",      request_navit_resize},
739         {".navit",  "get_attr",            "s",       "attribute",                               "v",  "value", request_navit_get_attr},
740         {".navit",  "set_attr",            "sv",      "attribute,value",                         "",   "",      request_navit_set_attr},
741         {".navit",  "set_position",        "s",       "(coordinates)",                           "",   "",      request_navit_set_position},
742         {".navit",  "set_position",        "(is)",    "(projection,coordinated)",                "",   "",      request_navit_set_position},
743         {".navit",  "set_position",        "(iii)",   "(projection,longitude,latitude)",         "",   "",      request_navit_set_position},
744         {".navit",  "set_destination",     "ss",      "coordinates,comment",                     "",   "",      request_navit_set_destination},
745         {".navit",  "set_destination",     "(is)s",   "(projection,coordinates)comment",         "",   "",      request_navit_set_destination},
746         {".navit",  "set_destination",     "(iii)s",  "(projection,longitude,latitude)comment",  "",   "",      request_navit_set_destination},
747         {".navit",  "evaluate",            "s",       "command",                                 "s",  "",     request_navit_evaluate},
748 #if 0
749     {".navit",  "toggle_announcer",    "",        "",                                        "",   "",      request_navit_toggle_announcer},
750         {".navit",  "toggle_announcer",    "i",       "",                                        "",   "",      request_navit_toggle_announcer},
751 #endif
752 };
753
754 static char *
755 generate_navitintrospectxml(void)
756 {
757     int i;
758     char *navitintrospectxml;
759     
760     // write header and make navit introspectable
761     navitintrospectxml = g_strdup_printf("%s%s%s\n", navitintrospectxml_head1, object_path, navitintrospectxml_head2);
762     
763     for (i = 0 ; i < sizeof(dbus_methods)/sizeof(struct dbus_method) ; i++) {
764         // start new interface if it's the first method or it changed
765         if ((i == 0) || strcmp(dbus_methods[i-1].path, dbus_methods[i].path))
766             navitintrospectxml = g_strconcat_printf(navitintrospectxml, "  <interface name=\"%s%s\">\n", service_name, dbus_methods[i].path);
767         
768         // start the new method
769         navitintrospectxml = g_strconcat_printf(navitintrospectxml, "    <method name=\"%s\">\n", dbus_methods[i].method);
770
771         // set input signature if existent
772         if (strcmp(dbus_methods[i].signature, ""))
773             navitintrospectxml = g_strconcat_printf(navitintrospectxml, "      <arg direction=\"in\" name=\"%s\" type=\"%s\" />\n", dbus_methods[i].signature_name, dbus_methods[i].signature);
774         
775         // set response signature if existent
776         if (strcmp(dbus_methods[i].response, ""))
777             navitintrospectxml = g_strconcat_printf(navitintrospectxml, "      <arg direction=\"out\" name=\"%s\" type=\"%s\" />\n", dbus_methods[i].response_name, dbus_methods[i].response);
778         
779         // close the method
780         navitintrospectxml = g_strconcat_printf(navitintrospectxml, "    </method>\n");
781         
782         // close the interface if we reached the last method or the interface changes
783         if ((sizeof(dbus_methods)/sizeof(struct dbus_method) == (i+1)) || strcmp(dbus_methods[i+1].path, dbus_methods[i].path))
784             navitintrospectxml = g_strconcat_printf(navitintrospectxml, "  </interface>\n\n");
785     }
786     // close the "mother tag"
787     navitintrospectxml = g_strconcat_printf(navitintrospectxml, "</node>\n");
788     
789     return navitintrospectxml;
790 }
791
792 static DBusHandlerResult
793 navit_handler_func(DBusConnection *connection, DBusMessage *message, void *user_data)
794 {
795         int i;
796         char *path;
797         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));
798         if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
799                 DBusMessage *reply;
800                 dbg(0,"Introspect\n");
801                 if (! strcmp(dbus_message_get_path(message), object_path)) {
802             char *navitintrospectxml = generate_navitintrospectxml();
803                         reply = dbus_message_new_method_return(message);
804                         dbus_message_append_args(reply, DBUS_TYPE_STRING, &navitintrospectxml, DBUS_TYPE_INVALID);
805                         dbus_connection_send (connection, reply, NULL);
806                         dbus_message_unref (reply);
807             g_free(navitintrospectxml);
808                         return DBUS_HANDLER_RESULT_HANDLED;
809                 }
810         }
811         
812     for (i = 0 ; i < sizeof(dbus_methods)/sizeof(struct dbus_method) ; i++) {
813                 path=g_strdup_printf("%s%s", service_name, dbus_methods[i].path);
814                 if (dbus_message_is_method_call(message, path, dbus_methods[i].method) &&
815                     dbus_message_has_signature(message, dbus_methods[i].signature)) {
816                         g_free(path);
817                         return dbus_methods[i].func(connection, message);
818                 }
819                 g_free(path);
820         }
821         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
822 }
823
824 static DBusObjectPathVTable dbus_navit_vtable = {
825         NULL,
826         navit_handler_func,
827         NULL
828 };
829
830 #if 0
831 DBusHandlerResult
832 filter(DBusConnection *connection, DBusMessage *message, void *user_data)
833 {
834         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));
835         if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
836         }
837         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
838 }
839 #endif
840
841 void plugin_init(void)
842 {
843         DBusError error;
844
845     object_hash=g_hash_table_new(g_str_hash, g_str_equal);
846         object_count=g_hash_table_new(g_str_hash, g_str_equal);
847         dbg(0,"enter 1\n");
848         dbus_error_init(&error);
849         connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
850         if (!connection) {
851                 dbg(0,"Failed to open connection to session message bus: %s\n", error.message);
852                 dbus_error_free(&error);
853                 return;
854         }
855         dbus_connection_setup_with_g_main(connection, NULL);
856 #if 0
857         dbus_connection_add_filter(connection, filter, NULL, NULL);
858         dbus_bus_add_match(connection, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
859 #endif
860         dbus_connection_register_fallback(connection, object_path, &dbus_navit_vtable, NULL);
861         dbus_bus_request_name(connection, service_name, 0, &error);
862         if (dbus_error_is_set(&error)) {
863                 dbg(0,"Failed to request name: %s", error.message);
864                 dbus_error_free (&error);
865         }
866 }