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