1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2010 Nokia Corporation 6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include <config.h> 27 #endif 28 29 #include <stdio.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <sys/socket.h> 33 #include <sys/ioctl.h> 34 35 #include <bluetooth/bluetooth.h> 36 #include <bluetooth/sdp.h> 37 38 #include <glib.h> 39 #include <dbus/dbus.h> 40 #include <gdbus.h> 41 42 #include "log.h" 43 44 #include "hcid.h" 45 #include "adapter.h" 46 #include "device.h" 47 #include "agent.h" 48 49 #define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */ 50 51 typedef enum { 52 AGENT_REQUEST_PASSKEY, 53 AGENT_REQUEST_CONFIRMATION, 54 AGENT_REQUEST_PINCODE, 55 AGENT_REQUEST_AUTHORIZE, 56 AGENT_REQUEST_CONFIRM_MODE, 57 AGENT_REQUEST_PAIRING_CONSENT, 58 } agent_request_type_t; 59 60 struct agent { 61 struct btd_adapter *adapter; 62 char *name; 63 char *path; 64 uint8_t capability; 65 struct agent_request *request; 66 int exited; 67 agent_remove_cb remove_cb; 68 void *remove_cb_data; 69 guint listener_id; 70 }; 71 72 struct agent_request { 73 agent_request_type_t type; 74 struct agent *agent; 75 DBusMessage *msg; 76 DBusPendingCall *call; 77 void *cb; 78 void *user_data; 79 GDestroyNotify destroy; 80 }; 81 82 static DBusConnection *connection = NULL; 83 84 static int request_fallback(struct agent_request *req, 85 DBusPendingCallNotifyFunction function); 86 87 static void agent_release(struct agent *agent) 88 { 89 DBusMessage *message; 90 91 DBG("Releasing agent %s, %s", agent->name, agent->path); 92 93 if (agent->request) 94 agent_cancel(agent); 95 96 message = dbus_message_new_method_call(agent->name, agent->path, 97 "org.bluez.Agent", "Release"); 98 if (message == NULL) { 99 error("Couldn't allocate D-Bus message"); 100 return; 101 } 102 103 g_dbus_send_message(connection, message); 104 } 105 106 static int send_cancel_request(struct agent_request *req) 107 { 108 DBusMessage *message; 109 110 DBG("Sending Cancel request to %s, %s", req->agent->name, 111 req->agent->path); 112 113 message = dbus_message_new_method_call(req->agent->name, req->agent->path, 114 "org.bluez.Agent", "Cancel"); 115 if (message == NULL) { 116 error("Couldn't allocate D-Bus message"); 117 return -ENOMEM; 118 } 119 120 g_dbus_send_message(connection, message); 121 122 return 0; 123 } 124 125 static void agent_request_free(struct agent_request *req, gboolean destroy) 126 { 127 if (req->msg) 128 dbus_message_unref(req->msg); 129 if (req->call) 130 dbus_pending_call_unref(req->call); 131 if (req->agent && req->agent->request) 132 req->agent->request = NULL; 133 if (destroy && req->destroy) 134 req->destroy(req->user_data); 135 g_free(req); 136 } 137 138 static void agent_exited(DBusConnection *conn, void *user_data) 139 { 140 struct agent *agent = user_data; 141 142 DBG("Agent exited without calling Unregister"); 143 144 agent->exited = TRUE; 145 146 agent_free(agent); 147 } 148 149 void agent_free(struct agent *agent) 150 { 151 if (!agent) 152 return; 153 154 if (agent->remove_cb) 155 agent->remove_cb(agent, agent->remove_cb_data); 156 157 if (agent->request) { 158 DBusError err; 159 agent_pincode_cb pincode_cb; 160 agent_cb cb; 161 162 dbus_error_init(&err); 163 dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled"); 164 165 switch (agent->request->type) { 166 case AGENT_REQUEST_PINCODE: 167 pincode_cb = agent->request->cb; 168 pincode_cb(agent, &err, NULL, agent->request->user_data); 169 break; 170 default: 171 cb = agent->request->cb; 172 cb(agent, &err, agent->request->user_data); 173 } 174 175 dbus_error_free(&err); 176 177 agent_cancel(agent); 178 } 179 180 if (!agent->exited) { 181 g_dbus_remove_watch(connection, agent->listener_id); 182 agent_release(agent); 183 } 184 185 g_free(agent->name); 186 g_free(agent->path); 187 188 g_free(agent); 189 } 190 191 struct agent *agent_create(struct btd_adapter *adapter, const char *name, 192 const char *path, uint8_t capability, 193 agent_remove_cb cb, void *remove_cb_data) 194 { 195 struct agent *agent; 196 197 agent = g_new0(struct agent, 1); 198 199 agent->adapter = adapter; 200 agent->name = g_strdup(name); 201 agent->path = g_strdup(path); 202 agent->capability = capability; 203 agent->remove_cb = cb; 204 agent->remove_cb_data = remove_cb_data; 205 206 agent->listener_id = g_dbus_add_disconnect_watch(connection, name, 207 agent_exited, agent, 208 NULL); 209 210 return agent; 211 } 212 213 static struct agent_request *agent_request_new(struct agent *agent, 214 agent_request_type_t type, 215 void *cb, 216 void *user_data, 217 GDestroyNotify destroy) 218 { 219 struct agent_request *req; 220 221 req = g_new0(struct agent_request, 1); 222 223 req->agent = agent; 224 req->type = type; 225 req->cb = cb; 226 req->user_data = user_data; 227 req->destroy = destroy; 228 229 return req; 230 } 231 232 int agent_cancel(struct agent *agent) 233 { 234 if (!agent->request) 235 return -EINVAL; 236 237 if (agent->request->call) 238 dbus_pending_call_cancel(agent->request->call); 239 240 if (!agent->exited) 241 send_cancel_request(agent->request); 242 243 agent_request_free(agent->request, TRUE); 244 agent->request = NULL; 245 246 return 0; 247 } 248 249 static void simple_agent_reply(DBusPendingCall *call, void *user_data) 250 { 251 struct agent_request *req = user_data; 252 struct agent *agent = req->agent; 253 DBusMessage *message; 254 DBusError err; 255 agent_cb cb = req->cb; 256 257 /* steal_reply will always return non-NULL since the callback 258 * is only called after a reply has been received */ 259 message = dbus_pending_call_steal_reply(call); 260 261 dbus_error_init(&err); 262 if (dbus_set_error_from_message(&err, message)) { 263 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 264 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 265 request_fallback(req, simple_agent_reply) == 0) { 266 dbus_error_free(&err); 267 return; 268 } 269 270 error("Agent replied with an error: %s, %s", 271 err.name, err.message); 272 273 cb(agent, &err, req->user_data); 274 275 if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { 276 agent_cancel(agent); 277 dbus_message_unref(message); 278 dbus_error_free(&err); 279 return; 280 } 281 282 dbus_error_free(&err); 283 goto done; 284 } 285 286 dbus_error_init(&err); 287 if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { 288 error("Wrong reply signature: %s", err.message); 289 cb(agent, &err, req->user_data); 290 dbus_error_free(&err); 291 goto done; 292 } 293 294 cb(agent, NULL, req->user_data); 295 done: 296 dbus_message_unref(message); 297 298 agent->request = NULL; 299 agent_request_free(req, TRUE); 300 } 301 302 static int agent_call_authorize(struct agent_request *req, 303 const char *device_path, 304 const char *uuid) 305 { 306 struct agent *agent = req->agent; 307 308 req->msg = dbus_message_new_method_call(agent->name, agent->path, 309 "org.bluez.Agent", "Authorize"); 310 if (!req->msg) { 311 error("Couldn't allocate D-Bus message"); 312 return -ENOMEM; 313 } 314 315 dbus_message_append_args(req->msg, 316 DBUS_TYPE_OBJECT_PATH, &device_path, 317 DBUS_TYPE_STRING, &uuid, 318 DBUS_TYPE_INVALID); 319 320 if (dbus_connection_send_with_reply(connection, req->msg, 321 &req->call, REQUEST_TIMEOUT) == FALSE) { 322 error("D-Bus send failed"); 323 return -EIO; 324 } 325 326 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 327 return 0; 328 } 329 330 int agent_authorize(struct agent *agent, 331 const char *path, 332 const char *uuid, 333 agent_cb cb, 334 void *user_data, 335 GDestroyNotify destroy) 336 { 337 struct agent_request *req; 338 int err; 339 340 if (agent->request) 341 return -EBUSY; 342 343 req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, 344 user_data, destroy); 345 346 err = agent_call_authorize(req, path, uuid); 347 if (err < 0) { 348 agent_request_free(req, FALSE); 349 return -ENOMEM; 350 } 351 352 agent->request = req; 353 354 DBG("authorize request was sent for %s", path); 355 356 return 0; 357 } 358 359 static void pincode_reply(DBusPendingCall *call, void *user_data) 360 { 361 struct agent_request *req = user_data; 362 struct agent *agent = req->agent; 363 struct btd_adapter *adapter = agent->adapter; 364 agent_pincode_cb cb = req->cb; 365 DBusMessage *message; 366 DBusError err; 367 bdaddr_t sba; 368 size_t len; 369 char *pin; 370 371 adapter_get_address(adapter, &sba); 372 373 /* steal_reply will always return non-NULL since the callback 374 * is only called after a reply has been received */ 375 message = dbus_pending_call_steal_reply(call); 376 377 dbus_error_init(&err); 378 if (dbus_set_error_from_message(&err, message)) { 379 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 380 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 381 request_fallback(req, pincode_reply) == 0) { 382 dbus_error_free(&err); 383 return; 384 } 385 386 error("Agent replied with an error: %s, %s", 387 err.name, err.message); 388 389 cb(agent, &err, NULL, req->user_data); 390 dbus_error_free(&err); 391 goto done; 392 } 393 394 dbus_error_init(&err); 395 if (!dbus_message_get_args(message, &err, 396 DBUS_TYPE_STRING, &pin, 397 DBUS_TYPE_INVALID)) { 398 error("Wrong passkey reply signature: %s", err.message); 399 cb(agent, &err, NULL, req->user_data); 400 dbus_error_free(&err); 401 goto done; 402 } 403 404 len = strlen(pin); 405 406 dbus_error_init(&err); 407 if (len < 1) { 408 error("Invalid PIN length (%zu) from agent", len); 409 dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs", 410 "Invalid passkey length"); 411 cb(agent, &err, NULL, req->user_data); 412 dbus_error_free(&err); 413 goto done; 414 } 415 416 cb(agent, NULL, pin, req->user_data); 417 418 done: 419 if (message) 420 dbus_message_unref(message); 421 422 dbus_pending_call_cancel(req->call); 423 agent->request = NULL; 424 agent_request_free(req, TRUE); 425 } 426 427 static int pincode_request_new(struct agent_request *req, const char *device_path, 428 dbus_bool_t numeric) 429 { 430 struct agent *agent = req->agent; 431 432 req->msg = dbus_message_new_method_call(agent->name, agent->path, 433 "org.bluez.Agent", "RequestPinCode"); 434 if (req->msg == NULL) { 435 error("Couldn't allocate D-Bus message"); 436 return -ENOMEM; 437 } 438 439 dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, 440 DBUS_TYPE_INVALID); 441 442 if (dbus_connection_send_with_reply(connection, req->msg, 443 &req->call, REQUEST_TIMEOUT) == FALSE) { 444 error("D-Bus send failed"); 445 return -EIO; 446 } 447 448 dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); 449 return 0; 450 } 451 452 int agent_request_pincode(struct agent *agent, struct btd_device *device, 453 agent_pincode_cb cb, void *user_data, 454 GDestroyNotify destroy) 455 { 456 struct agent_request *req; 457 const gchar *dev_path = device_get_path(device); 458 int err; 459 460 if (agent->request) 461 return -EBUSY; 462 463 req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, 464 user_data, destroy); 465 466 err = pincode_request_new(req, dev_path, FALSE); 467 if (err < 0) 468 goto failed; 469 470 agent->request = req; 471 472 return 0; 473 474 failed: 475 g_free(req); 476 return err; 477 } 478 479 static int confirm_mode_change_request_new(struct agent_request *req, 480 const char *mode) 481 { 482 struct agent *agent = req->agent; 483 484 req->msg = dbus_message_new_method_call(agent->name, agent->path, 485 "org.bluez.Agent", "ConfirmModeChange"); 486 if (req->msg == NULL) { 487 error("Couldn't allocate D-Bus message"); 488 return -ENOMEM; 489 } 490 491 dbus_message_append_args(req->msg, 492 DBUS_TYPE_STRING, &mode, 493 DBUS_TYPE_INVALID); 494 495 if (dbus_connection_send_with_reply(connection, req->msg, 496 &req->call, REQUEST_TIMEOUT) == FALSE) { 497 error("D-Bus send failed"); 498 return -EIO; 499 } 500 501 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 502 return 0; 503 } 504 505 int agent_confirm_mode_change(struct agent *agent, const char *new_mode, 506 agent_cb cb, void *user_data, 507 GDestroyNotify destroy) 508 { 509 struct agent_request *req; 510 int err; 511 512 if (agent->request) 513 return -EBUSY; 514 515 DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s", 516 agent->name, agent->path, new_mode); 517 518 req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE, 519 cb, user_data, destroy); 520 521 err = confirm_mode_change_request_new(req, new_mode); 522 if (err < 0) 523 goto failed; 524 525 agent->request = req; 526 527 return 0; 528 529 failed: 530 agent_request_free(req, FALSE); 531 return err; 532 } 533 534 static void passkey_reply(DBusPendingCall *call, void *user_data) 535 { 536 struct agent_request *req = user_data; 537 struct agent *agent = req->agent; 538 agent_passkey_cb cb = req->cb; 539 DBusMessage *message; 540 DBusError err; 541 uint32_t passkey; 542 543 /* steal_reply will always return non-NULL since the callback 544 * is only called after a reply has been received */ 545 message = dbus_pending_call_steal_reply(call); 546 547 dbus_error_init(&err); 548 if (dbus_set_error_from_message(&err, message)) { 549 if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || 550 g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && 551 request_fallback(req, passkey_reply) == 0) { 552 dbus_error_free(&err); 553 return; 554 } 555 556 error("Agent replied with an error: %s, %s", 557 err.name, err.message); 558 cb(agent, &err, 0, req->user_data); 559 dbus_error_free(&err); 560 goto done; 561 } 562 563 dbus_error_init(&err); 564 if (!dbus_message_get_args(message, &err, 565 DBUS_TYPE_UINT32, &passkey, 566 DBUS_TYPE_INVALID)) { 567 error("Wrong passkey reply signature: %s", err.message); 568 cb(agent, &err, 0, req->user_data); 569 dbus_error_free(&err); 570 goto done; 571 } 572 573 cb(agent, NULL, passkey, req->user_data); 574 575 done: 576 if (message) 577 dbus_message_unref(message); 578 579 dbus_pending_call_cancel(req->call); 580 agent->request = NULL; 581 agent_request_free(req, TRUE); 582 } 583 584 static int passkey_request_new(struct agent_request *req, 585 const char *device_path) 586 { 587 struct agent *agent = req->agent; 588 589 req->msg = dbus_message_new_method_call(agent->name, agent->path, 590 "org.bluez.Agent", "RequestPasskey"); 591 if (req->msg == NULL) { 592 error("Couldn't allocate D-Bus message"); 593 return -ENOMEM; 594 } 595 596 dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, 597 DBUS_TYPE_INVALID); 598 599 if (dbus_connection_send_with_reply(connection, req->msg, 600 &req->call, REQUEST_TIMEOUT) == FALSE) { 601 error("D-Bus send failed"); 602 return -EIO; 603 } 604 605 dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); 606 return 0; 607 } 608 609 int agent_request_passkey(struct agent *agent, struct btd_device *device, 610 agent_passkey_cb cb, void *user_data, 611 GDestroyNotify destroy) 612 { 613 struct agent_request *req; 614 const gchar *dev_path = device_get_path(device); 615 int err; 616 617 if (agent->request) 618 return -EBUSY; 619 620 DBG("Calling Agent.RequestPasskey: name=%s, path=%s", 621 agent->name, agent->path); 622 623 req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, 624 user_data, destroy); 625 626 err = passkey_request_new(req, dev_path); 627 if (err < 0) 628 goto failed; 629 630 agent->request = req; 631 632 return 0; 633 634 failed: 635 agent_request_free(req, FALSE); 636 return err; 637 } 638 639 static int confirmation_request_new(struct agent_request *req, 640 const char *device_path, 641 uint32_t passkey) 642 { 643 struct agent *agent = req->agent; 644 645 req->msg = dbus_message_new_method_call(agent->name, agent->path, 646 "org.bluez.Agent", "RequestConfirmation"); 647 if (req->msg == NULL) { 648 error("Couldn't allocate D-Bus message"); 649 return -ENOMEM; 650 } 651 652 dbus_message_append_args(req->msg, 653 DBUS_TYPE_OBJECT_PATH, &device_path, 654 DBUS_TYPE_UINT32, &passkey, 655 DBUS_TYPE_INVALID); 656 657 if (dbus_connection_send_with_reply(connection, req->msg, 658 &req->call, REQUEST_TIMEOUT) == FALSE) { 659 error("D-Bus send failed"); 660 return -EIO; 661 } 662 663 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 664 665 return 0; 666 } 667 668 int agent_request_confirmation(struct agent *agent, struct btd_device *device, 669 uint32_t passkey, agent_cb cb, 670 void *user_data, GDestroyNotify destroy) 671 { 672 struct agent_request *req; 673 const gchar *dev_path = device_get_path(device); 674 int err; 675 676 if (agent->request) 677 return -EBUSY; 678 679 DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u", 680 agent->name, agent->path, passkey); 681 682 req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb, 683 user_data, destroy); 684 685 err = confirmation_request_new(req, dev_path, passkey); 686 if (err < 0) 687 goto failed; 688 689 agent->request = req; 690 691 return 0; 692 693 failed: 694 agent_request_free(req, FALSE); 695 return err; 696 } 697 698 static int pairing_consent_request_new(struct agent_request *req, 699 const char *device_path) 700 { 701 struct agent *agent = req->agent; 702 703 req->msg = dbus_message_new_method_call(agent->name, agent->path, 704 "org.bluez.Agent", "RequestPairingConsent"); 705 if (req->msg == NULL) { 706 error("Couldn't allocate D-Bus message"); 707 return -ENOMEM; 708 } 709 710 dbus_message_append_args(req->msg, 711 DBUS_TYPE_OBJECT_PATH, &device_path, 712 DBUS_TYPE_INVALID); 713 714 if (dbus_connection_send_with_reply(connection, req->msg, 715 &req->call, REQUEST_TIMEOUT) == FALSE) { 716 error("D-Bus send failed"); 717 return -EIO; 718 } 719 720 dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); 721 722 return 0; 723 } 724 725 int agent_request_pairing_consent(struct agent *agent, struct btd_device *device, 726 agent_cb cb, void *user_data, 727 GDestroyNotify destroy) 728 { 729 struct agent_request *req; 730 const gchar *dev_path = device_get_path(device); 731 int err; 732 733 if (agent->request) 734 return -EBUSY; 735 736 DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s", 737 agent->name, agent->path); 738 739 req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb, 740 user_data, destroy); 741 742 err = pairing_consent_request_new(req, dev_path); 743 if (err < 0) 744 goto failed; 745 746 agent->request = req; 747 748 return 0; 749 750 failed: 751 agent_request_free(req, FALSE); 752 return err; 753 } 754 755 static int request_fallback(struct agent_request *req, 756 DBusPendingCallNotifyFunction function) 757 { 758 struct btd_adapter *adapter = req->agent->adapter; 759 struct agent *adapter_agent = adapter_get_agent(adapter); 760 DBusMessage *msg; 761 762 if (req->agent == adapter_agent || adapter_agent == NULL) 763 return -EINVAL; 764 765 dbus_pending_call_cancel(req->call); 766 dbus_pending_call_unref(req->call); 767 768 msg = dbus_message_copy(req->msg); 769 770 dbus_message_set_destination(msg, adapter_agent->name); 771 dbus_message_set_path(msg, adapter_agent->path); 772 773 if (dbus_connection_send_with_reply(connection, msg, 774 &req->call, REQUEST_TIMEOUT) == FALSE) { 775 error("D-Bus send failed"); 776 dbus_message_unref(msg); 777 return -EIO; 778 } 779 780 req->agent->request = NULL; 781 req->agent = adapter_agent; 782 req->agent->request = req; 783 784 dbus_message_unref(req->msg); 785 req->msg = msg; 786 787 dbus_pending_call_set_notify(req->call, function, req, NULL); 788 789 return 0; 790 } 791 792 int agent_display_passkey(struct agent *agent, struct btd_device *device, 793 uint32_t passkey) 794 { 795 DBusMessage *message; 796 const gchar *dev_path = device_get_path(device); 797 798 message = dbus_message_new_method_call(agent->name, agent->path, 799 "org.bluez.Agent", "DisplayPasskey"); 800 if (!message) { 801 error("Couldn't allocate D-Bus message"); 802 return -1; 803 } 804 805 dbus_message_append_args(message, 806 DBUS_TYPE_OBJECT_PATH, &dev_path, 807 DBUS_TYPE_UINT32, &passkey, 808 DBUS_TYPE_INVALID); 809 810 if (!g_dbus_send_message(connection, message)) { 811 error("D-Bus send failed"); 812 dbus_message_unref(message); 813 return -1; 814 } 815 816 return 0; 817 } 818 819 uint8_t agent_get_io_capability(struct agent *agent) 820 { 821 return agent->capability; 822 } 823 824 gboolean agent_matches(struct agent *agent, const char *name, const char *path) 825 { 826 if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path)) 827 return TRUE; 828 829 return FALSE; 830 } 831 832 gboolean agent_is_busy(struct agent *agent, void *user_data) 833 { 834 if (!agent->request) 835 return FALSE; 836 837 if (user_data && user_data != agent->request->user_data) 838 return FALSE; 839 840 return TRUE; 841 } 842 843 void agent_exit(void) 844 { 845 dbus_connection_unref(connection); 846 connection = NULL; 847 } 848 849 void agent_init(void) 850 { 851 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 852 } 853