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