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