* s/D-BUS/D-Bus/g
[platform/upstream/dbus.git] / tools / dbus-send.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <dbus/dbus.h>
27
28 #include "dbus-print-message.h"
29
30 static const char *appname;
31
32 static void
33 usage (int ecode)
34 {
35   fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=NAME] [--type=TYPE] [--print-reply=(literal)] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname);
36   exit (ecode);
37 }
38
39 static void
40 append_arg (DBusMessageIter *iter, int type, const char *value)
41 {
42   dbus_uint16_t uint16;
43   dbus_int16_t int16;
44   dbus_uint32_t uint32;
45   dbus_int32_t int32;
46   dbus_uint64_t uint64;
47   dbus_int64_t int64;
48   double d;
49   unsigned char byte;
50   dbus_bool_t v_BOOLEAN;
51   
52   /* FIXME - we are ignoring OOM returns on all these functions */
53   switch (type)
54     {
55     case DBUS_TYPE_BYTE:
56       byte = strtoul (value, NULL, 0);
57       dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &byte);
58       break;
59
60     case DBUS_TYPE_DOUBLE:
61       d = strtod (value, NULL);
62       dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &d);
63       break;
64
65     case DBUS_TYPE_INT16:
66       int16 = strtol (value, NULL, 0);
67       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &int16);
68       break;
69
70     case DBUS_TYPE_UINT16:
71       uint16 = strtoul (value, NULL, 0);
72       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &uint16);
73       break;
74
75     case DBUS_TYPE_INT32:
76       int32 = strtol (value, NULL, 0);
77       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &int32);
78       break;
79
80     case DBUS_TYPE_UINT32:
81       uint32 = strtoul (value, NULL, 0);
82       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &uint32);
83       break;
84
85     case DBUS_TYPE_INT64:
86       int64 = strtoll (value, NULL, 0);
87       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &int64);
88       break;
89
90     case DBUS_TYPE_UINT64:
91       uint64 = strtoull (value, NULL, 0);
92       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &uint64);
93       break;
94
95     case DBUS_TYPE_STRING:
96       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &value);
97       break;
98
99     case DBUS_TYPE_OBJECT_PATH:
100       dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &value);
101       break;
102
103     case DBUS_TYPE_BOOLEAN:
104       if (strcmp (value, "true") == 0)
105         {
106           v_BOOLEAN = TRUE;
107           dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN);
108         }
109       else if (strcmp (value, "false") == 0)
110         {
111           v_BOOLEAN = FALSE;
112           dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN);
113         }
114       else
115         {
116           fprintf (stderr, "%s: Expected \"true\" or \"false\" instead of \"%s\"\n", appname, value);
117           exit (1);
118         }
119       break;
120
121     default:
122       fprintf (stderr, "%s: Unsupported data type %c\n", appname, (char) type);
123       exit (1);
124     }
125 }
126
127 static void
128 append_array (DBusMessageIter *iter, int type, const char *value)
129 {
130   const char *val;
131   char *dupval = strdup (value);
132
133   val = strtok (dupval, ",");
134   while (val != NULL)
135     {
136       append_arg (iter, type, val);
137       val = strtok (NULL, ",");
138     }
139   free (dupval);
140 }
141
142 static void
143 append_dict (DBusMessageIter *iter, int keytype, int valtype, const char *value)
144 {
145   const char *val;
146   char *dupval = strdup (value);
147
148   val = strtok (dupval, ",");
149   while (val != NULL)
150     {
151       DBusMessageIter subiter;
152       char sig[3];
153       sig[0] = keytype;
154       sig[1] = valtype;
155       sig[2] = '\0';
156       
157       dbus_message_iter_open_container (iter,
158                                         DBUS_TYPE_DICT_ENTRY,
159                                         sig,
160                                         &subiter);
161
162       append_arg (&subiter, keytype, val);
163       val = strtok (NULL, ",");
164       if (val == NULL)
165         {
166           fprintf (stderr, "%s: Malformed dictionary\n", appname);
167           exit (1);
168         }
169       append_arg (&subiter, valtype, val);
170
171       dbus_message_iter_close_container (iter, &subiter);
172       val = strtok (NULL, ",");
173     } 
174   free (dupval);
175 }
176
177 static int
178 type_from_name (const char *arg)
179 {
180   int type;
181   if (!strcmp (arg, "string"))
182     type = DBUS_TYPE_STRING;
183   else if (!strcmp (arg, "int16"))
184     type = DBUS_TYPE_INT16;
185   else if (!strcmp (arg, "uint16"))
186     type = DBUS_TYPE_UINT16;
187   else if (!strcmp (arg, "int32"))
188     type = DBUS_TYPE_INT32;
189   else if (!strcmp (arg, "uint32"))
190     type = DBUS_TYPE_UINT32;
191   else if (!strcmp (arg, "int64"))
192     type = DBUS_TYPE_INT64;
193   else if (!strcmp (arg, "uint64"))
194     type = DBUS_TYPE_UINT64;
195   else if (!strcmp (arg, "double"))
196     type = DBUS_TYPE_DOUBLE;
197   else if (!strcmp (arg, "byte"))
198     type = DBUS_TYPE_BYTE;
199   else if (!strcmp (arg, "boolean"))
200     type = DBUS_TYPE_BOOLEAN;
201   else if (!strcmp (arg, "objpath"))
202     type = DBUS_TYPE_OBJECT_PATH;
203   else
204     {
205       fprintf (stderr, "%s: Unknown type \"%s\"\n", appname, arg);
206       exit (1);
207     }
208   return type;
209 }
210
211 int
212 main (int argc, char *argv[])
213 {
214   DBusConnection *connection;
215   DBusError error;
216   DBusMessage *message;
217   int print_reply;
218   int print_reply_literal;
219   int reply_timeout;
220   DBusMessageIter iter;
221   int i;
222   DBusBusType type = DBUS_BUS_SESSION;
223   const char *dest = NULL;
224   const char *name = NULL;
225   const char *path = NULL;
226   int message_type = DBUS_MESSAGE_TYPE_SIGNAL;
227   const char *type_str = NULL;
228
229   appname = argv[0];
230   
231   if (argc < 3)
232     usage (1);
233
234   print_reply = FALSE;
235   print_reply_literal = FALSE;
236   reply_timeout = -1;
237   
238   for (i = 1; i < argc && name == NULL; i++)
239     {
240       char *arg = argv[i];
241
242       if (strcmp (arg, "--system") == 0)
243         type = DBUS_BUS_SYSTEM;
244       else if (strcmp (arg, "--session") == 0)
245         type = DBUS_BUS_SESSION;
246       else if (strncmp (arg, "--print-reply", 13) == 0)
247         {
248           print_reply = TRUE;
249           message_type = DBUS_MESSAGE_TYPE_METHOD_CALL;
250           if (*(arg + 13) != '\0')
251             print_reply_literal = TRUE;
252         }
253       else if (strstr (arg, "--reply-timeout=") == arg)
254         {
255           reply_timeout = strtol (strchr (arg, '=') + 1,
256                                   NULL, 10);
257         }
258       else if (strstr (arg, "--dest=") == arg)
259         dest = strchr (arg, '=') + 1;
260       else if (strstr (arg, "--type=") == arg)
261         type_str = strchr (arg, '=') + 1;
262       else if (!strcmp(arg, "--help"))
263         usage (0);
264       else if (arg[0] == '-')
265         usage (1);
266       else if (path == NULL)
267         path = arg;
268       else if (name == NULL)
269         name = arg;
270       else
271         usage (1);
272     }
273
274   if (name == NULL)
275     usage (1);
276
277   if (type_str != NULL)
278     {
279       message_type = dbus_message_type_from_string (type_str);
280       if (!(message_type == DBUS_MESSAGE_TYPE_METHOD_CALL ||
281             message_type == DBUS_MESSAGE_TYPE_SIGNAL))
282         {
283           fprintf (stderr, "Message type \"%s\" is not supported\n",
284                    type_str);
285           exit (1);
286         }
287     }
288   
289   dbus_error_init (&error);
290   connection = dbus_bus_get (type, &error);
291   if (connection == NULL)
292     {
293       fprintf (stderr, "Failed to open connection to %s message bus: %s\n",
294                (type == DBUS_BUS_SYSTEM) ? "system" : "session",
295                error.message);
296       dbus_error_free (&error);
297       exit (1);
298     }
299
300   if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL)
301     {
302       char *last_dot;
303
304       last_dot = strrchr (name, '.');
305       if (last_dot == NULL)
306         {
307           fprintf (stderr, "Must use org.mydomain.Interface.Method notation, no dot in \"%s\"\n",
308                    name);
309           exit (1);
310         }
311       *last_dot = '\0';
312       
313       message = dbus_message_new_method_call (NULL,
314                                               path,
315                                               name,
316                                               last_dot + 1);
317       dbus_message_set_auto_start (message, TRUE);
318     }
319   else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL)
320     {
321       char *last_dot;
322
323       last_dot = strrchr (name, '.');
324       if (last_dot == NULL)
325         {
326           fprintf (stderr, "Must use org.mydomain.Interface.Signal notation, no dot in \"%s\"\n",
327                    name);
328           exit (1);
329         }
330       *last_dot = '\0';
331       
332       message = dbus_message_new_signal (path, name, last_dot + 1);
333     }
334   else
335     {
336       fprintf (stderr, "Internal error, unknown message type\n");
337       exit (1);
338     }
339
340   if (message == NULL)
341     {
342       fprintf (stderr, "Couldn't allocate D-Bus message\n");
343       exit (1);
344     }
345
346   if (dest && !dbus_message_set_destination (message, dest))
347     {
348       fprintf (stderr, "Not enough memory\n");
349       exit (1);
350     }
351   
352   dbus_message_iter_init_append (message, &iter);
353
354   while (i < argc)
355     {
356       char *arg;
357       char *c;
358       int type;
359       int secondary_type;
360       int container_type;
361       DBusMessageIter *target_iter;
362       DBusMessageIter container_iter;
363
364       type = DBUS_TYPE_INVALID;
365       arg = argv[i++];
366       c = strchr (arg, ':');
367
368       if (c == NULL)
369         {
370           fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
371           exit (1);
372         }
373
374       *(c++) = 0;
375
376       container_type = DBUS_TYPE_INVALID;
377
378       if (strcmp (arg, "variant") == 0)
379         container_type = DBUS_TYPE_VARIANT;
380       else if (strcmp (arg, "array") == 0)
381         container_type = DBUS_TYPE_ARRAY;
382       else if (strcmp (arg, "dict") == 0)
383         container_type = DBUS_TYPE_DICT_ENTRY;
384
385       if (container_type != DBUS_TYPE_INVALID)
386         {
387           arg = c;
388           c = strchr (arg, ':');
389           if (c == NULL)
390             {
391               fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
392               exit (1);
393             }
394           *(c++) = 0;
395         }
396
397       if (arg[0] == 0)
398         type = DBUS_TYPE_STRING;
399       else
400         type = type_from_name (arg);
401
402       if (container_type == DBUS_TYPE_DICT_ENTRY)
403         {
404           char sig[5];
405           arg = c;
406           c = strchr (c, ':');
407           if (c == NULL)
408             {
409               fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg);
410               exit (1);
411             }
412           *(c++) = 0;
413           secondary_type = type_from_name (arg);
414           sig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR;
415           sig[1] = type;
416           sig[2] = secondary_type;
417           sig[3] = DBUS_DICT_ENTRY_END_CHAR;
418           sig[4] = '\0';
419           dbus_message_iter_open_container (&iter,
420                                             DBUS_TYPE_ARRAY,
421                                             sig,
422                                             &container_iter);
423           target_iter = &container_iter;
424         }
425       else if (container_type != DBUS_TYPE_INVALID)
426         {
427           char sig[2];
428           sig[0] = type;
429           sig[1] = '\0';
430           dbus_message_iter_open_container (&iter,
431                                             container_type,
432                                             sig,
433                                             &container_iter);
434           target_iter = &container_iter;
435         }
436       else
437         target_iter = &iter;
438
439       if (container_type == DBUS_TYPE_ARRAY)
440         {
441           append_array (target_iter, type, c);
442         }
443       else if (container_type == DBUS_TYPE_DICT_ENTRY)
444         {
445           append_dict (target_iter, type, secondary_type, c);
446         }
447       else
448         append_arg (target_iter, type, c);
449
450       if (container_type != DBUS_TYPE_INVALID)
451         {
452           dbus_message_iter_close_container (&iter,
453                                              &container_iter);
454         }
455     }
456
457   if (print_reply)
458     {
459       DBusMessage *reply;
460
461       dbus_error_init (&error);
462       reply = dbus_connection_send_with_reply_and_block (connection,
463                                                          message, reply_timeout,
464                                                          &error);
465       if (dbus_error_is_set (&error))
466         {
467           fprintf (stderr, "Error %s: %s\n",
468                    error.name,
469                    error.message);
470           exit (1);
471         }
472
473       if (reply)
474         {
475           print_message (reply, print_reply_literal);
476           dbus_message_unref (reply);
477         }
478     }
479   else
480     {
481       dbus_connection_send (connection, message, NULL);
482       dbus_connection_flush (connection);
483     }
484
485   dbus_message_unref (message);
486
487   dbus_connection_close (connection);
488
489   exit (0);
490 }