check: remove 'return sth' from void function
[platform/upstream/dbus.git] / tools / dbus-send.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-send.c  Utility program to send messages from the command line
3  *
4  * Copyright (C) 2003 Philip Blundell <philb@gnu.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <dbus/dbus.h>
28 #include "dbus/dbus-internals.h"
29
30 #ifndef HAVE_STRTOLL
31 #undef strtoll
32 #define strtoll mystrtoll
33 #include "strtoll.c"
34 #endif
35
36 #ifndef HAVE_STRTOULL
37 #undef strtoull
38 #define strtoull mystrtoull
39 #include "strtoull.c"
40 #endif
41
42 #ifdef DBUS_WINCE
43 #ifndef strdup
44 #define strdup _strdup
45 #endif
46 #endif
47
48 #include "dbus-print-message.h"
49
50 static const char *appname;
51
52 static void usage (int ecode) _DBUS_GNUC_NORETURN;
53
54 static void
55 usage (int ecode)
56 {
57   fprintf (stderr, "Usage: %s [--help] [--system | --session | --bus=ADDRESS | --peer=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply[=literal]] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname);
58   exit (ecode);
59 }
60
61 /* Abort on any allocation failure; there is nothing else we can do. */
62 static void
63 handle_oom (dbus_bool_t success)
64 {
65   if (!success)
66     {
67       fprintf (stderr, "%s: Ran out of memory\n", appname);
68       exit (1);
69     }
70 }
71
72 static void
73 append_arg (DBusMessageIter *iter, int type, const char *value)
74 {
75   dbus_uint16_t uint16;
76   dbus_int16_t int16;
77   dbus_uint32_t uint32;
78   dbus_int32_t int32;
79   dbus_uint64_t uint64;
80   dbus_int64_t int64;
81   double d;
82   unsigned char byte;
83   dbus_bool_t v_BOOLEAN;
84   dbus_bool_t ret;
85
86   switch (type)
87     {
88     case DBUS_TYPE_BYTE:
89       byte = strtoul (value, NULL, 0);
90       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &byte);
91       break;
92
93     case DBUS_TYPE_DOUBLE:
94       d = strtod (value, NULL);
95       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &d);
96       break;
97
98     case DBUS_TYPE_INT16:
99       int16 = strtol (value, NULL, 0);
100       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &int16);
101       break;
102
103     case DBUS_TYPE_UINT16:
104       uint16 = strtoul (value, NULL, 0);
105       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &uint16);
106       break;
107
108     case DBUS_TYPE_INT32:
109       int32 = strtol (value, NULL, 0);
110       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &int32);
111       break;
112
113     case DBUS_TYPE_UINT32:
114       uint32 = strtoul (value, NULL, 0);
115       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &uint32);
116       break;
117
118     case DBUS_TYPE_INT64:
119       int64 = strtoll (value, NULL, 0);
120       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &int64);
121       break;
122
123     case DBUS_TYPE_UINT64:
124       uint64 = strtoull (value, NULL, 0);
125       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &uint64);
126       break;
127
128     case DBUS_TYPE_STRING:
129       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &value);
130       break;
131
132     case DBUS_TYPE_OBJECT_PATH:
133       ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &value);
134       break;
135
136     case DBUS_TYPE_BOOLEAN:
137       if (strcmp (value, "true") == 0)
138         {
139           v_BOOLEAN = TRUE;
140           ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN);
141         }
142       else if (strcmp (value, "false") == 0)
143         {
144           v_BOOLEAN = FALSE;
145           ret = dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN);
146         }
147       else
148         {
149           fprintf (stderr, "%s: Expected \"true\" or \"false\" instead of \"%s\"\n", appname, value);
150           exit (1);
151         }
152       break;
153
154     default:
155       fprintf (stderr, "%s: Unsupported data type %c\n", appname, (char) type);
156       exit (1);
157     }
158
159   handle_oom (ret);
160 }
161
162 static void
163 append_array (DBusMessageIter *iter, int type, const char *value)
164 {
165   const char *val;
166   char *dupval = strdup (value);
167
168   handle_oom (dupval != NULL);
169
170   val = strtok (dupval, ",");
171   while (val != NULL)
172     {
173       append_arg (iter, type, val);
174       val = strtok (NULL, ",");
175     }
176   free (dupval);
177 }
178
179 static void
180 append_dict (DBusMessageIter *iter, int keytype, int valtype, const char *value)
181 {
182   const char *val;
183   char *dupval = strdup (value);
184
185   handle_oom (dupval != NULL);
186
187   val = strtok (dupval, ",");
188   while (val != NULL)
189     {
190       DBusMessageIter subiter;
191       
192       handle_oom (dbus_message_iter_open_container (iter,
193                                                     DBUS_TYPE_DICT_ENTRY,
194                                                     NULL,
195                                                     &subiter));
196
197       append_arg (&subiter, keytype, val);
198       val = strtok (NULL, ",");
199       if (val == NULL)
200         {
201           fprintf (stderr, "%s: Malformed dictionary\n", appname);
202           exit (1);
203         }
204       append_arg (&subiter, valtype, val);
205
206       handle_oom (dbus_message_iter_close_container (iter, &subiter));
207       val = strtok (NULL, ",");
208     } 
209   free (dupval);
210 }
211
212 static int
213 type_from_name (const char *arg)
214 {
215   int type;
216   if (!strcmp (arg, "string"))
217     type = DBUS_TYPE_STRING;
218   else if (!strcmp (arg, "int16"))
219     type = DBUS_TYPE_INT16;
220   else if (!strcmp (arg, "uint16"))
221     type = DBUS_TYPE_UINT16;
222   else if (!strcmp (arg, "int32"))
223     type = DBUS_TYPE_INT32;
224   else if (!strcmp (arg, "uint32"))
225     type = DBUS_TYPE_UINT32;
226   else if (!strcmp (arg, "int64"))
227     type = DBUS_TYPE_INT64;
228   else if (!strcmp (arg, "uint64"))
229     type = DBUS_TYPE_UINT64;
230   else if (!strcmp (arg, "double"))
231     type = DBUS_TYPE_DOUBLE;
232   else if (!strcmp (arg, "byte"))
233     type = DBUS_TYPE_BYTE;
234   else if (!strcmp (arg, "boolean"))
235     type = DBUS_TYPE_BOOLEAN;
236   else if (!strcmp (arg, "objpath"))
237     type = DBUS_TYPE_OBJECT_PATH;
238   else
239     {
240       fprintf (stderr, "%s: Unknown type \"%s\"\n", appname, arg);
241       exit (1);
242     }
243   return type;
244 }
245
246 int
247 main (int argc, char *argv[])
248 {
249   DBusConnection *connection;
250   DBusError error;
251   DBusMessage *message;
252   dbus_bool_t print_reply;
253   dbus_bool_t print_reply_literal;
254   int reply_timeout;
255   DBusMessageIter iter;
256   int i;
257   DBusBusType type = DBUS_BUS_SESSION;
258   const char *dest = NULL;
259   const char *name = NULL;
260   const char *path = NULL;
261   int message_type = DBUS_MESSAGE_TYPE_SIGNAL;
262   const char *type_str = NULL;
263   const char *address = NULL;
264   int is_bus = FALSE;
265   int session_or_system = FALSE;
266
267   appname = argv[0];
268   
269   if (argc < 3)
270     usage (1);
271
272   print_reply = FALSE;
273   print_reply_literal = FALSE;
274   reply_timeout = -1;
275   
276   for (i = 1; i < argc && name == NULL; i++)
277     {
278       char *arg = argv[i];
279
280       if (strcmp (arg, "--system") == 0)
281         {
282           type = DBUS_BUS_SYSTEM;
283           session_or_system = TRUE;
284         }
285       else if (strcmp (arg, "--session") == 0)
286         {
287           type = DBUS_BUS_SESSION;
288           session_or_system = TRUE;
289         }
290       else if ((strstr (arg, "--bus=") == arg) || (strstr (arg, "--peer=") == arg) || (strstr (arg, "--address=") == arg))
291         {
292           /* Check for peer first, to avoid the GCC -Wduplicated-branches
293            * warning.
294            */
295           if (arg[2] == 'p') /* peer */
296             {
297               is_bus = FALSE;
298             }
299           else if (arg[2] == 'b') /* bus */
300             {
301               is_bus = TRUE;
302             }
303           else /* address; keeping backwards compatibility */
304             {
305               is_bus = FALSE;
306             }
307
308           address = strchr (arg, '=') + 1;
309
310           if (address[0] == '\0')
311             {
312               fprintf (stderr, "\"--peer=\" and \"--bus=\" require an ADDRESS\n");
313               usage (1);
314             }
315         }
316       else if (strncmp (arg, "--print-reply", 13) == 0)
317         {
318           print_reply = TRUE;
319           message_type = DBUS_MESSAGE_TYPE_METHOD_CALL;
320           if (strcmp (arg + 13, "=literal") == 0)
321             print_reply_literal = TRUE;
322           else if (*(arg + 13) != '\0')
323             {
324               fprintf (stderr, "invalid value (%s) of \"--print-reply\"\n", arg + 13);
325               usage (1);
326             }
327         }
328       else if (strstr (arg, "--reply-timeout=") == arg)
329         {
330           if (*(strchr (arg, '=') + 1) == '\0')
331             {
332               fprintf (stderr, "\"--reply-timeout=\" requires an MSEC\n");
333               usage (1);
334             }
335           reply_timeout = strtol (strchr (arg, '=') + 1,
336                                   NULL, 10);
337           if (reply_timeout <= 0)
338             {
339               fprintf (stderr, "invalid value (%s) of \"--reply-timeout\"\n",
340                        strchr (arg, '=') + 1);
341               usage (1);
342             }
343         }
344       else if (strstr (arg, "--dest=") == arg)
345         {
346           if (*(strchr (arg, '=') + 1) == '\0')
347             {
348               fprintf (stderr, "\"--dest=\" requires an NAME\n");
349               usage (1);
350             }
351           dest = strchr (arg, '=') + 1;
352         }
353       else if (strstr (arg, "--type=") == arg)
354         type_str = strchr (arg, '=') + 1;
355       else if (!strcmp(arg, "--help"))
356         usage (0);
357       else if (arg[0] == '-')
358         usage (1);
359       else if (path == NULL)
360         path = arg;
361       else /* name == NULL guaranteed by the 'while' loop */
362         name = arg;
363     }
364
365   if (name == NULL)
366     usage (1);
367
368   if (session_or_system &&
369       (address != NULL))
370     {
371       fprintf (stderr, "\"--peer\" and \"--bus\" may not be used with \"--system\" or \"--session\"\n");
372       usage (1);
373     }
374
375   if (type_str != NULL)
376     {
377       message_type = dbus_message_type_from_string (type_str);
378       if (!(message_type == DBUS_MESSAGE_TYPE_METHOD_CALL ||
379             message_type == DBUS_MESSAGE_TYPE_SIGNAL))
380         {
381           fprintf (stderr, "Message type \"%s\" is not supported\n",
382                    type_str);
383           exit (1);
384         }
385     }
386   
387   dbus_error_init (&error);
388
389   if (dest && !dbus_validate_bus_name (dest, &error))
390     {
391       fprintf (stderr, "invalid value (%s) of \"--dest\"\n", dest);
392       usage (1);
393     }
394
395   if (address != NULL)
396     {
397       connection = dbus_connection_open (address, &error);
398     }
399   else
400     {
401       connection = dbus_bus_get (type, &error);
402     }
403
404   if (connection == NULL)
405     {
406       fprintf (stderr, "Failed to open connection to \"%s\" message bus: %s\n",
407                (address != NULL) ? address :
408                  ((type == DBUS_BUS_SYSTEM) ? "system" : "session"),
409                error.message);
410       dbus_error_free (&error);
411       exit (1);
412     }
413   else if ((address != NULL) && is_bus)
414     {
415       if (!dbus_bus_register (connection, &error))
416         {
417           fprintf (stderr, "Failed to register on connection to \"%s\" message bus: %s\n",
418                    address, error.message);
419           dbus_error_free (&error);
420           exit (1);
421         }
422     }
423
424   if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL)
425     {
426       char *last_dot;
427
428       last_dot = strrchr (name, '.');
429       if (last_dot == NULL)
430         {
431           fprintf (stderr, "Must use org.mydomain.Interface.Method notation, no dot in \"%s\"\n",
432                    name);
433           exit (1);
434         }
435       *last_dot = '\0';
436       
437       message = dbus_message_new_method_call (NULL,
438                                               path,
439                                               name,
440                                               last_dot + 1);
441       handle_oom (message != NULL);
442       dbus_message_set_auto_start (message, TRUE);
443     }
444   else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL)
445     {
446       char *last_dot;
447
448       last_dot = strrchr (name, '.');
449       if (last_dot == NULL)
450         {
451           fprintf (stderr, "Must use org.mydomain.Interface.Signal notation, no dot in \"%s\"\n",
452                    name);
453           exit (1);
454         }
455       *last_dot = '\0';
456       
457       message = dbus_message_new_signal (path, name, last_dot + 1);
458       handle_oom (message != NULL);
459     }
460   else
461     {
462       fprintf (stderr, "Internal error, unknown message type\n");
463       exit (1);
464     }
465
466   if (message == NULL)
467     {
468       fprintf (stderr, "Couldn't allocate D-Bus message\n");
469       exit (1);
470     }
471
472   if (dest && !dbus_message_set_destination (message, dest))
473     {
474       fprintf (stderr, "Not enough memory\n");
475       exit (1);
476     }
477   
478   dbus_message_iter_init_append (message, &iter);
479
480   while (i < argc)
481     {
482       char *arg;
483       char *c;
484       int type2;
485       int secondary_type;
486       int container_type;
487       DBusMessageIter *target_iter;
488       DBusMessageIter container_iter;
489
490       type2 = DBUS_TYPE_INVALID;
491       secondary_type = DBUS_TYPE_INVALID;
492       arg = argv[i++];
493       c = strchr (arg, ':');
494
495       if (c == NULL)
496         {
497           fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
498           exit (1);
499         }
500
501       *(c++) = 0;
502
503       container_type = DBUS_TYPE_INVALID;
504
505       if (strcmp (arg, "variant") == 0)
506         container_type = DBUS_TYPE_VARIANT;
507       else if (strcmp (arg, "array") == 0)
508         container_type = DBUS_TYPE_ARRAY;
509       else if (strcmp (arg, "dict") == 0)
510         container_type = DBUS_TYPE_DICT_ENTRY;
511
512       if (container_type != DBUS_TYPE_INVALID)
513         {
514           arg = c;
515           c = strchr (arg, ':');
516           if (c == NULL)
517             {
518               fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
519               exit (1);
520             }
521           *(c++) = 0;
522         }
523
524       if (arg[0] == 0)
525         type2 = DBUS_TYPE_STRING;
526       else
527         type2 = type_from_name (arg);
528
529       if (container_type == DBUS_TYPE_DICT_ENTRY)
530         {
531           char sig[5];
532           arg = c;
533           c = strchr (c, ':');
534           if (c == NULL)
535             {
536               fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
537               exit (1);
538             }
539           *(c++) = 0;
540           secondary_type = type_from_name (arg);
541           sig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR;
542           sig[1] = type2;
543           sig[2] = secondary_type;
544           sig[3] = DBUS_DICT_ENTRY_END_CHAR;
545           sig[4] = '\0';
546           handle_oom (dbus_message_iter_open_container (&iter,
547                                                         DBUS_TYPE_ARRAY,
548                                                         sig,
549                                                         &container_iter));
550           target_iter = &container_iter;
551         }
552       else if (container_type != DBUS_TYPE_INVALID)
553         {
554           char sig[2];
555           sig[0] = type2;
556           sig[1] = '\0';
557           handle_oom (dbus_message_iter_open_container (&iter,
558                                                         container_type,
559                                                         sig,
560                                                         &container_iter));
561           target_iter = &container_iter;
562         }
563       else
564         target_iter = &iter;
565
566       if (container_type == DBUS_TYPE_ARRAY)
567         {
568           append_array (target_iter, type2, c);
569         }
570       else if (container_type == DBUS_TYPE_DICT_ENTRY)
571         {
572           _dbus_assert (secondary_type != DBUS_TYPE_INVALID);
573           append_dict (target_iter, type2, secondary_type, c);
574         }
575       else
576         append_arg (target_iter, type2, c);
577
578       if (container_type != DBUS_TYPE_INVALID)
579         {
580           handle_oom (dbus_message_iter_close_container (&iter,
581                                                          &container_iter));
582         }
583     }
584
585   if (print_reply)
586     {
587       DBusMessage *reply;
588
589       dbus_error_init (&error);
590       reply = dbus_connection_send_with_reply_and_block (connection,
591                                                          message, reply_timeout,
592                                                          &error);
593       if (dbus_error_is_set (&error))
594         {
595           fprintf (stderr, "Error %s: %s\n",
596                    error.name,
597                    error.message);
598           exit (1);
599         }
600
601       if (reply)
602         {
603           long sec, usec;
604
605           _dbus_get_real_time (&sec, &usec);
606           print_message (reply, print_reply_literal, sec, usec);
607           dbus_message_unref (reply);
608         }
609     }
610   else
611     {
612       dbus_connection_send (connection, message, NULL);
613       dbus_connection_flush (connection);
614     }
615
616   dbus_message_unref (message);
617
618   dbus_connection_unref (connection);
619
620   exit (0);
621 }