Mirror of Awesome WM window manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dbus.c 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. /*
  2. * dbus.c - awesome dbus support
  3. *
  4. * Copyright © 2008-2009 Julien Danjou <julien@danjou.info>
  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 along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. */
  21. /** awesome D-Bus API
  22. * @author Julien Danjou &lt;julien@danjou.info&gt;
  23. * @copyright 2008-2009 Julien Danjou
  24. * @module dbus
  25. */
  26. #include "config.h"
  27. #include "dbus.h"
  28. #include <glib.h>
  29. #ifdef WITH_DBUS
  30. #include <dbus/dbus.h>
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #include "event.h"
  34. #include "luaa.h"
  35. static DBusConnection *dbus_connection_session = NULL;
  36. static DBusConnection *dbus_connection_system = NULL;
  37. static GSource *session_source = NULL;
  38. static GSource *system_source = NULL;
  39. static signal_array_t dbus_signals;
  40. /** Clean up the D-Bus connection data members
  41. * \param dbus_connection The D-Bus connection to clean up
  42. * \param source The D-Bus source
  43. */
  44. static void
  45. a_dbus_cleanup_bus(DBusConnection *dbus_connection, GSource **source)
  46. {
  47. if(!dbus_connection)
  48. return;
  49. if (*source != NULL)
  50. g_source_destroy(*source);
  51. *source = NULL;
  52. /* This is a shared connection owned by libdbus
  53. * Do not close it, only unref
  54. */
  55. dbus_connection_unref(dbus_connection);
  56. }
  57. /** Iterate through the D-Bus messages counting each or traverse each sub message.
  58. * \param L The Lua VM state.
  59. * \param iter The D-Bus message iterator pointer
  60. * \return The number of arguments in the iterator
  61. */
  62. static int
  63. a_dbus_message_iter(lua_State *L, DBusMessageIter *iter)
  64. {
  65. int nargs = 0;
  66. do
  67. {
  68. switch(dbus_message_iter_get_arg_type(iter))
  69. {
  70. default:
  71. lua_pushnil(L);
  72. nargs++;
  73. break;
  74. case DBUS_TYPE_INVALID:
  75. break;
  76. case DBUS_TYPE_VARIANT:
  77. {
  78. DBusMessageIter subiter;
  79. dbus_message_iter_recurse(iter, &subiter);
  80. a_dbus_message_iter(L, &subiter);
  81. }
  82. nargs++;
  83. break;
  84. case DBUS_TYPE_DICT_ENTRY:
  85. {
  86. DBusMessageIter subiter;
  87. /* initialize a sub iterator */
  88. dbus_message_iter_recurse(iter, &subiter);
  89. /* create a new table to store the dict */
  90. a_dbus_message_iter(L, &subiter);
  91. }
  92. nargs++;
  93. break;
  94. case DBUS_TYPE_STRUCT:
  95. {
  96. DBusMessageIter subiter;
  97. /* initialize a sub iterator */
  98. dbus_message_iter_recurse(iter, &subiter);
  99. int n = a_dbus_message_iter(L, &subiter);
  100. /* create a new table to store all the value */
  101. lua_createtable(L, n, 0);
  102. /* move the table before array elements */
  103. lua_insert(L, - n - 1);
  104. for(int i = n; i > 0; i--)
  105. lua_rawseti(L, - i - 1, i);
  106. }
  107. nargs++;
  108. break;
  109. case DBUS_TYPE_ARRAY:
  110. {
  111. int array_type = dbus_message_iter_get_element_type(iter);
  112. if(dbus_type_is_fixed(array_type))
  113. {
  114. DBusMessageIter sub;
  115. dbus_message_iter_recurse(iter, &sub);
  116. switch(array_type)
  117. {
  118. int datalen;
  119. #define DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(type, dbustype, pusher) \
  120. case dbustype: \
  121. { \
  122. const type *data; \
  123. dbus_message_iter_get_fixed_array(&sub, &data, &datalen); \
  124. lua_createtable(L, datalen, 0); \
  125. for(int i = 0; i < datalen; i++) \
  126. { \
  127. pusher(L, data[i]); \
  128. lua_rawseti(L, -2, i + 1); \
  129. } \
  130. } \
  131. break;
  132. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(int16_t, DBUS_TYPE_INT16, lua_pushinteger)
  133. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(uint16_t, DBUS_TYPE_UINT16, lua_pushinteger)
  134. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(int32_t, DBUS_TYPE_INT32, lua_pushinteger)
  135. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(uint32_t, DBUS_TYPE_UINT32, lua_pushinteger)
  136. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(int64_t, DBUS_TYPE_INT64, lua_pushinteger)
  137. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(uint64_t, DBUS_TYPE_UINT64, lua_pushinteger)
  138. DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT(double, DBUS_TYPE_DOUBLE, lua_pushnumber)
  139. #undef DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER_OR_INT
  140. case DBUS_TYPE_BYTE:
  141. {
  142. const char *c;
  143. dbus_message_iter_get_fixed_array(&sub, &c, &datalen);
  144. lua_pushlstring(L, c, datalen);
  145. }
  146. break;
  147. case DBUS_TYPE_BOOLEAN:
  148. {
  149. const dbus_bool_t *b;
  150. dbus_message_iter_get_fixed_array(&sub, &b, &datalen);
  151. lua_createtable(L, datalen, 0);
  152. for(int i = 0; i < datalen; i++)
  153. {
  154. lua_pushboolean(L, b[i]);
  155. lua_rawseti(L, -2, i + 1);
  156. }
  157. }
  158. break;
  159. }
  160. }
  161. else if(array_type == DBUS_TYPE_DICT_ENTRY)
  162. {
  163. DBusMessageIter subiter;
  164. /* initialize a sub iterator */
  165. dbus_message_iter_recurse(iter, &subiter);
  166. /* get the keys and the values
  167. * n is the number of entry in dict */
  168. int n = a_dbus_message_iter(L, &subiter);
  169. /* create a new table to store all the value */
  170. lua_createtable(L, n, 0);
  171. /* move the table before array elements */
  172. lua_insert(L, - (n * 2) - 1);
  173. for(int i = 0; i < n; i ++)
  174. lua_rawset(L, - (n * 2) - 1 + i * 2);
  175. }
  176. else
  177. {
  178. DBusMessageIter subiter;
  179. /* prepare to dig into the array*/
  180. dbus_message_iter_recurse(iter, &subiter);
  181. /* now iterate over every element of the array */
  182. int n = a_dbus_message_iter(L, &subiter);
  183. /* create a new table to store all the value */
  184. lua_createtable(L, n, 0);
  185. /* move the table before array elements */
  186. lua_insert(L, - n - 1);
  187. for(int i = n; i > 0; i--)
  188. lua_rawseti(L, - i - 1, i);
  189. }
  190. }
  191. nargs++;
  192. break;
  193. case DBUS_TYPE_BOOLEAN:
  194. {
  195. dbus_bool_t b;
  196. dbus_message_iter_get_basic(iter, &b);
  197. lua_pushboolean(L, b);
  198. }
  199. nargs++;
  200. break;
  201. case DBUS_TYPE_BYTE:
  202. {
  203. char c;
  204. dbus_message_iter_get_basic(iter, &c);
  205. lua_pushlstring(L, &c, 1);
  206. }
  207. nargs++;
  208. break;
  209. #define DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(type, dbustype, pusher) \
  210. case dbustype: \
  211. { \
  212. type ui; \
  213. dbus_message_iter_get_basic(iter, &ui); \
  214. pusher(L, ui); \
  215. } \
  216. nargs++; \
  217. break;
  218. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(int16_t, DBUS_TYPE_INT16, lua_pushinteger)
  219. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(uint16_t, DBUS_TYPE_UINT16, lua_pushinteger)
  220. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(int32_t, DBUS_TYPE_INT32, lua_pushinteger)
  221. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(uint32_t, DBUS_TYPE_UINT32, lua_pushinteger)
  222. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(int64_t, DBUS_TYPE_INT64, lua_pushinteger)
  223. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(uint64_t, DBUS_TYPE_UINT64, lua_pushinteger)
  224. DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT(double, DBUS_TYPE_DOUBLE, lua_pushnumber)
  225. #undef DBUS_MSG_HANDLE_TYPE_NUMBER_OR_INT
  226. case DBUS_TYPE_STRING:
  227. {
  228. char *s;
  229. dbus_message_iter_get_basic(iter, &s);
  230. lua_pushstring(L, s);
  231. }
  232. nargs++;
  233. break;
  234. }
  235. } while(dbus_message_iter_next(iter));
  236. return nargs;
  237. }
  238. static bool
  239. a_dbus_convert_value(lua_State *L, int idx, DBusMessageIter *iter)
  240. {
  241. /* i is the type name, i+1 the value */
  242. size_t len;
  243. const char *type = lua_tolstring(L, idx, &len);
  244. if(!type || len < 1)
  245. return false;
  246. switch(*type)
  247. {
  248. case DBUS_TYPE_ARRAY:
  249. {
  250. DBusMessageIter subiter;
  251. dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
  252. type + 1,
  253. &subiter);
  254. int arraylen = luaA_rawlen(L, idx + 1);
  255. if(arraylen % 2 != 0)
  256. {
  257. luaA_warn(L,
  258. "your D-Bus signal handling method returned wrong number of arguments");
  259. return false;
  260. }
  261. /* Push the array */
  262. lua_pushvalue(L, idx + 1);
  263. for(int i = 1; i < arraylen; i += 2)
  264. {
  265. lua_rawgeti(L, -1, i);
  266. lua_rawgeti(L, -2, i + 1);
  267. if(!a_dbus_convert_value(L, -2, &subiter))
  268. return false;
  269. lua_pop(L, 2);
  270. }
  271. /* Remove the array */
  272. lua_pop(L, 1);
  273. dbus_message_iter_close_container(iter, &subiter);
  274. }
  275. break;
  276. case DBUS_TYPE_BOOLEAN:
  277. {
  278. dbus_bool_t b = lua_toboolean(L, idx + 1);
  279. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &b);
  280. }
  281. break;
  282. case DBUS_TYPE_STRING:
  283. {
  284. const char *s = lua_tostring(L, idx + 1);
  285. if(!s || !dbus_validate_utf8(s, NULL)) {
  286. luaA_warn(L, "Your D-Bus signal handling method returned an invalid string");
  287. return false;
  288. }
  289. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
  290. }
  291. break;
  292. #define DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(type, dbustype) \
  293. case dbustype: \
  294. { \
  295. type num = lua_tonumber(L, idx + 1); \
  296. dbus_message_iter_append_basic(iter, dbustype, &num); \
  297. } \
  298. break;
  299. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint8_t, DBUS_TYPE_BYTE)
  300. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int16_t, DBUS_TYPE_INT16)
  301. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint16_t, DBUS_TYPE_UINT16)
  302. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int32_t, DBUS_TYPE_INT32)
  303. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint32_t, DBUS_TYPE_UINT32)
  304. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int64_t, DBUS_TYPE_INT64)
  305. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint64_t, DBUS_TYPE_UINT64)
  306. DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(double, DBUS_TYPE_DOUBLE)
  307. #undef DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER
  308. }
  309. return true;
  310. }
  311. /** Process a single request from D-Bus
  312. * \param dbus_connection The connection to the D-Bus server.
  313. * \param msg The D-Bus message request being sent to the D-Bus connection.
  314. */
  315. static void
  316. a_dbus_process_request(DBusConnection *dbus_connection, DBusMessage *msg)
  317. {
  318. const char *interface = dbus_message_get_interface(msg);
  319. lua_State *L = globalconf_get_lua_State();
  320. int old_top = lua_gettop(L);
  321. lua_createtable(L, 0, 5);
  322. switch(dbus_message_get_type(msg))
  323. {
  324. case DBUS_MESSAGE_TYPE_SIGNAL:
  325. lua_pushliteral(L, "signal");
  326. break;
  327. case DBUS_MESSAGE_TYPE_METHOD_CALL:
  328. lua_pushliteral(L, "method_call");
  329. break;
  330. case DBUS_MESSAGE_TYPE_METHOD_RETURN:
  331. lua_pushliteral(L, "method_return");
  332. break;
  333. case DBUS_MESSAGE_TYPE_ERROR:
  334. lua_pushliteral(L, "error");
  335. break;
  336. default:
  337. lua_pushliteral(L, "unknown");
  338. break;
  339. }
  340. lua_setfield(L, -2, "type");
  341. lua_pushstring(L, interface);
  342. lua_setfield(L, -2, "interface");
  343. const char *s = dbus_message_get_path(msg);
  344. lua_pushstring(L, s);
  345. lua_setfield(L, -2, "path");
  346. s = dbus_message_get_member(msg);
  347. lua_pushstring(L, s);
  348. lua_setfield(L, -2, "member");
  349. s = dbus_message_get_sender(msg);
  350. if(s != NULL) {
  351. lua_pushstring(L, s);
  352. lua_setfield(L, -2, "sender");
  353. }
  354. if(dbus_connection == dbus_connection_system)
  355. lua_pushliteral(L, "system");
  356. else
  357. lua_pushliteral(L, "session");
  358. lua_setfield(L, -2, "bus");
  359. /* + 1 for the table above */
  360. DBusMessageIter iter;
  361. int nargs = 1;
  362. if(dbus_message_iter_init(msg, &iter))
  363. nargs += a_dbus_message_iter(L, &iter);
  364. if(dbus_message_get_no_reply(msg))
  365. {
  366. signal_t *sigfound = signal_array_getbyname(&dbus_signals, interface);
  367. /* emit signals */
  368. if(sigfound)
  369. signal_object_emit(L, &dbus_signals, NONULL(interface), nargs);
  370. }
  371. else
  372. {
  373. signal_t *sig = signal_array_getbyname(&dbus_signals, interface);
  374. if(sig)
  375. {
  376. /* there can be only ONE handler to send reply */
  377. void *func = (void *) sig->sigfuncs.tab[0];
  378. int n = lua_gettop(L) - nargs;
  379. luaA_object_push(L, (void *) func);
  380. luaA_dofunction(L, nargs, LUA_MULTRET);
  381. n -= lua_gettop(L);
  382. DBusMessage *reply = dbus_message_new_method_return(msg);
  383. dbus_message_iter_init_append(reply, &iter);
  384. if(n % 2 != 0)
  385. {
  386. luaA_warn(L,
  387. "your D-Bus signal handling method returned wrong number of arguments");
  388. /* Restore stack */
  389. lua_settop(L, old_top);
  390. return;
  391. }
  392. /* i is negative */
  393. for(int i = n; i < 0; i += 2)
  394. {
  395. if(!a_dbus_convert_value(L, i, &iter))
  396. {
  397. luaA_warn(L, "your D-Bus signal handling method returned bad data");
  398. /* Restore stack */
  399. lua_settop(L, old_top);
  400. return;
  401. }
  402. lua_remove(L, i);
  403. lua_remove(L, i + 1);
  404. }
  405. dbus_connection_send(dbus_connection, reply, NULL);
  406. dbus_message_unref(reply);
  407. }
  408. }
  409. /* Restore stack */
  410. lua_settop(L, old_top);
  411. }
  412. /** Attempt to process all the requests in the D-Bus connection.
  413. * \param dbus_connection The D-Bus connection to process from
  414. * \param source The D-Bus source
  415. */
  416. static void
  417. a_dbus_process_requests_on_bus(DBusConnection *dbus_connection, GSource **source)
  418. {
  419. DBusMessage *msg;
  420. int nmsg = 0;
  421. while(true)
  422. {
  423. dbus_connection_read_write(dbus_connection, 0);
  424. if(!(msg = dbus_connection_pop_message(dbus_connection)))
  425. break;
  426. if(dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected"))
  427. {
  428. a_dbus_cleanup_bus(dbus_connection, source);
  429. dbus_message_unref(msg);
  430. return;
  431. }
  432. else
  433. a_dbus_process_request(dbus_connection, msg);
  434. dbus_message_unref(msg);
  435. nmsg++;
  436. }
  437. if(nmsg)
  438. dbus_connection_flush(dbus_connection);
  439. }
  440. static gboolean
  441. a_dbus_process_requests_session(gpointer data)
  442. {
  443. a_dbus_process_requests_on_bus(dbus_connection_session, &session_source);
  444. return TRUE;
  445. }
  446. static gboolean
  447. a_dbus_process_requests_system(gpointer data)
  448. {
  449. a_dbus_process_requests_on_bus(dbus_connection_system, &system_source);
  450. return TRUE;
  451. }
  452. /** Attempt to request a D-Bus name.
  453. * \param dbus_connection The application's connection to D-Bus.
  454. * \param name The D-Bus connection name to be requested.
  455. * \return true if the name is primary owner or the name is already
  456. * the owner, otherwise false.
  457. */
  458. static bool
  459. a_dbus_request_name(DBusConnection *dbus_connection, const char *name)
  460. {
  461. DBusError err;
  462. if(!dbus_connection)
  463. return false;
  464. dbus_error_init(&err);
  465. int ret = dbus_bus_request_name(dbus_connection, name, 0, &err);
  466. if(dbus_error_is_set(&err))
  467. {
  468. warn("failed to request D-Bus name: %s", err.message);
  469. dbus_error_free(&err);
  470. return false;
  471. }
  472. switch(ret)
  473. {
  474. case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
  475. return true;
  476. case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
  477. warn("already primary D-Bus name owner for %s", name);
  478. return true;
  479. }
  480. return false;
  481. }
  482. /** Attempt to release the D-Bus name owner
  483. * \param dbus_connection The application's connection to the D-Bus
  484. * \param name The name to be released
  485. * \return True on success. False if the name is not
  486. * the owner, or does not exist.
  487. */
  488. static bool
  489. a_dbus_release_name(DBusConnection *dbus_connection, const char *name)
  490. {
  491. DBusError err;
  492. if(!dbus_connection)
  493. return false;
  494. dbus_error_init(&err);
  495. int ret = dbus_bus_release_name(dbus_connection, name, &err);
  496. if(dbus_error_is_set(&err))
  497. {
  498. warn("failed to release D-Bus name: %s", err.message);
  499. dbus_error_free(&err);
  500. return false;
  501. }
  502. switch(ret)
  503. {
  504. case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
  505. warn("not primary D-Bus name owner for %s", name);
  506. return false;
  507. case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
  508. warn("non existent D-Bus name: %s", name);
  509. return false;
  510. }
  511. return true;
  512. }
  513. /** Attempt to create a new connection to D-Bus
  514. * \param type The bus type to use when connecting to D-Bus
  515. * \param type_name The bus type name eg: "session" or "system"
  516. * \param cb Function callback to use when processing requests
  517. * \param source A new GSource that will be used for watching the dbus connection.
  518. * \return The requested D-Bus connection on success, NULL on failure.
  519. */
  520. static DBusConnection *
  521. a_dbus_connect(DBusBusType type, const char *type_name, GSourceFunc cb, GSource **source)
  522. {
  523. int fd;
  524. DBusConnection *dbus_connection;
  525. DBusError err;
  526. dbus_error_init(&err);
  527. dbus_connection = dbus_bus_get(type, &err);
  528. if(dbus_error_is_set(&err))
  529. {
  530. warn("Could not connect to D-Bus %s bus: %s", type_name, err.message);
  531. dbus_connection = NULL;
  532. dbus_error_free(&err);
  533. }
  534. else
  535. {
  536. dbus_connection_set_exit_on_disconnect(dbus_connection, false);
  537. if(dbus_connection_get_unix_fd(dbus_connection, &fd))
  538. {
  539. GIOChannel *channel = g_io_channel_unix_new(fd);
  540. *source = g_io_create_watch(channel, G_IO_IN);
  541. g_io_channel_unref(channel);
  542. g_source_set_callback(*source, cb, NULL, NULL);
  543. g_source_attach(*source, NULL);
  544. fcntl(fd, F_SETFD, FD_CLOEXEC);
  545. }
  546. else
  547. {
  548. warn("cannot get D-Bus connection file descriptor");
  549. a_dbus_cleanup_bus(dbus_connection, source);
  550. }
  551. }
  552. return dbus_connection;
  553. }
  554. /** Initialize the D-Bus session and system
  555. */
  556. void
  557. a_dbus_init(void)
  558. {
  559. dbus_connection_session = a_dbus_connect(DBUS_BUS_SESSION, "session",
  560. a_dbus_process_requests_session, &session_source);
  561. dbus_connection_system = a_dbus_connect(DBUS_BUS_SYSTEM, "system",
  562. a_dbus_process_requests_system, &system_source);
  563. }
  564. /** Cleanup the D-Bus session and system
  565. */
  566. void
  567. a_dbus_cleanup(void)
  568. {
  569. a_dbus_cleanup_bus(dbus_connection_session, &session_source);
  570. a_dbus_cleanup_bus(dbus_connection_system, &system_source);
  571. }
  572. /** Retrieve the D-Bus bus by its name.
  573. * \param name The name of the bus.
  574. * \return The corresponding D-Bus connection.
  575. */
  576. static DBusConnection *
  577. a_dbus_bus_getbyname(lua_State *L, const char *name)
  578. {
  579. if(A_STREQ(name, "system"))
  580. return dbus_connection_system;
  581. if(A_STREQ(name, "session"))
  582. return dbus_connection_session;
  583. luaL_error(L, "Unknown dbus connection '%s', only 'system' and 'session' are valid", name);
  584. return NULL;
  585. }
  586. /** Register a D-Bus name to receive messages from.
  587. *
  588. * @param bus A string indicating if we are using system or session bus.
  589. * @param name A string with the name of the D-Bus name to register.
  590. * @return True if everything worked fine, false otherwise.
  591. * @function request_name
  592. */
  593. static int
  594. luaA_dbus_request_name(lua_State *L)
  595. {
  596. const char *bus = luaL_checkstring(L, 1);
  597. const char *name = luaL_checkstring(L, 2);
  598. DBusConnection *dbus_connection = a_dbus_bus_getbyname(L, bus);
  599. lua_pushboolean(L, a_dbus_request_name(dbus_connection, name));
  600. return 1;
  601. }
  602. /** Release a D-Bus name.
  603. *
  604. * @param bus A string indicating if we are using system or session bus.
  605. * @param name A string with the name of the D-Bus name to unregister.
  606. * @return True if everything worked fine, false otherwise.
  607. * @function release_name
  608. */
  609. static int
  610. luaA_dbus_release_name(lua_State *L)
  611. {
  612. const char *bus = luaL_checkstring(L, 1);
  613. const char *name = luaL_checkstring(L, 2);
  614. DBusConnection *dbus_connection = a_dbus_bus_getbyname(L, bus);
  615. lua_pushboolean(L, a_dbus_release_name(dbus_connection, name));
  616. return 1;
  617. }
  618. /** Add a match rule to match messages going through the message bus.
  619. *
  620. * @param bus A string indicating if we are using system or session bus.
  621. * @param name A string with the name of the match rule.
  622. * @function add_match
  623. */
  624. static int
  625. luaA_dbus_add_match(lua_State *L)
  626. {
  627. const char *bus = luaL_checkstring(L, 1);
  628. const char *name = luaL_checkstring(L, 2);
  629. DBusConnection *dbus_connection = a_dbus_bus_getbyname(L, bus);
  630. if(dbus_connection)
  631. {
  632. dbus_bus_add_match(dbus_connection, name, NULL);
  633. dbus_connection_flush(dbus_connection);
  634. }
  635. return 0;
  636. }
  637. /** Remove a previously added match rule "by value"
  638. * (the most recently-added identical rule gets removed).
  639. *
  640. * @param bus A string indicating if we are using system or session bus.
  641. * @param name A string with the name of the match rule.
  642. * @function remove_match
  643. */
  644. static int
  645. luaA_dbus_remove_match(lua_State *L)
  646. {
  647. const char *bus = luaL_checkstring(L, 1);
  648. const char *name = luaL_checkstring(L, 2);
  649. DBusConnection *dbus_connection = a_dbus_bus_getbyname(L, bus);
  650. if(dbus_connection)
  651. {
  652. dbus_bus_remove_match(dbus_connection, name, NULL);
  653. dbus_connection_flush(dbus_connection);
  654. }
  655. return 0;
  656. }
  657. /** Add a signal receiver on the D-Bus.
  658. *
  659. * @param interface A string with the interface name.
  660. * @param func The function to call.
  661. * @return true on success, nil + error if the signal could not be connected
  662. * because another function is already connected.
  663. * @function connect_signal
  664. */
  665. static int
  666. luaA_dbus_connect_signal(lua_State *L)
  667. {
  668. const char *name = luaL_checkstring(L, 1);
  669. luaA_checkfunction(L, 2);
  670. signal_t *sig = signal_array_getbyname(&dbus_signals, name);
  671. if(sig) {
  672. luaA_warn(L, "cannot add signal %s on D-Bus, already existing", name);
  673. lua_pushnil(L);
  674. lua_pushfstring(L, "cannot add signal %s on D-Bus, already existing", name);
  675. return 2;
  676. } else {
  677. signal_connect(&dbus_signals, name, luaA_object_ref(L, 2));
  678. lua_pushboolean(L, 1);
  679. return 1;
  680. }
  681. }
  682. /** Remove a signal receiver on the D-Bus.
  683. *
  684. * @param interface A string with the interface name.
  685. * @param func The function to call.
  686. * @function disconnect_signal
  687. */
  688. static int
  689. luaA_dbus_disconnect_signal(lua_State *L)
  690. {
  691. const char *name = luaL_checkstring(L, 1);
  692. luaA_checkfunction(L, 2);
  693. const void *func = lua_topointer(L, 2);
  694. if (signal_disconnect(&dbus_signals, name, func))
  695. luaA_object_unref(L, func);
  696. return 0;
  697. }
  698. /** Emit a signal on the D-Bus.
  699. *
  700. * @param bus A string indicating if we are using system or session bus.
  701. * @param path A string with the dbus path.
  702. * @param interface A string with the dbus interface.
  703. * @param method A string with the dbus method name.
  704. * @param type_1st_arg type of 1st argument
  705. * @param value_1st_arg value of 1st argument
  706. * @param type_2nd_arg type of 2nd argument
  707. * @param value_2nd_arg value of 2nd argument
  708. * ... etc
  709. * @function emit_signal
  710. */
  711. static int
  712. luaA_dbus_emit_signal(lua_State *L)
  713. {
  714. const char *bus_name = luaL_checkstring(L, 1);
  715. const char *path = luaL_checkstring(L, 2);
  716. const char *itface = luaL_checkstring(L, 3);
  717. const char *name = luaL_checkstring(L, 4);
  718. DBusConnection *dbus_connection = a_dbus_bus_getbyname(L, bus_name);
  719. DBusMessage* msg = dbus_message_new_signal(path, itface, name);
  720. if (msg == NULL) {
  721. luaA_warn(L, "your D-Bus signal emitting method error'd");
  722. return 0;
  723. }
  724. DBusMessageIter iter;
  725. dbus_message_iter_init_append(msg, &iter);
  726. int top = lua_gettop(L);
  727. int nargs = top - 4;
  728. if(nargs % 2 != 0)
  729. {
  730. luaA_warn(L, "your D-Bus signal emitting method has wrong number of arguments");
  731. dbus_message_unref(msg);
  732. lua_pushboolean(L, 0);
  733. return 1;
  734. }
  735. for(int i = 5; i < top; i += 2) {
  736. if(!a_dbus_convert_value(L, i, &iter))
  737. {
  738. luaA_warn(L, "your D-Bus signal emitting method has bad argument type");
  739. dbus_message_unref(msg);
  740. lua_pushboolean(L, 0);
  741. return 1;
  742. }
  743. }
  744. dbus_connection_send(dbus_connection, msg, NULL);
  745. dbus_message_unref(msg);
  746. dbus_connection_flush(dbus_connection);
  747. lua_pushboolean(L, 1);
  748. return 1;
  749. }
  750. const struct luaL_Reg awesome_dbus_lib[] =
  751. {
  752. { "request_name", luaA_dbus_request_name },
  753. { "release_name", luaA_dbus_release_name },
  754. { "add_match", luaA_dbus_add_match },
  755. { "remove_match", luaA_dbus_remove_match },
  756. { "connect_signal", luaA_dbus_connect_signal },
  757. { "disconnect_signal", luaA_dbus_disconnect_signal },
  758. { "emit_signal", luaA_dbus_emit_signal },
  759. { "__index", luaA_default_index },
  760. { "__newindex", luaA_default_newindex },
  761. { NULL, NULL }
  762. };
  763. #else /* WITH_DBUS */
  764. /** Empty stub if dbus is not enabled */
  765. void
  766. a_dbus_init(void)
  767. {
  768. }
  769. /** Empty stub if dbus is not enabled */
  770. void
  771. a_dbus_cleanup(void)
  772. {
  773. }
  774. #endif
  775. // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80