Home | History | Annotate | Download | only in tools
      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 (at) 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_unref (connection);
    488 
    489   exit (0);
    490 }
    491