00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define DBUS_API_SUBJECT_TO_CHANGE
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <dbus/dbus.h>
00026 #include <time.h>
00027 #include "include/alarm_dbus.h"
00028 #include "include/alarm_event.h"
00029
00030 #define _strdup(x) ((x) != NULL ? strdup(x) : NULL)
00031 #define NULL0(x) ((x) != NULL ? 1 : 0)
00032 #define ZERO0(x) ((x) != 0 ? 1 : 0)
00033 #define APPEND_ARG(msg, value, type, code) \
00034 while ((int)(value) != 0) { \
00035 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, \
00036 &property[(code)], \
00037 (type), &(value), DBUS_TYPE_INVALID)) { \
00038 error_code = ALARMD_ERROR_MEMORY; \
00039 return 0; \
00040 } \
00041 break; \
00042 }
00043
00044 static int _get_id(const char *name);
00045
00046 enum Properties {
00047 TIME,
00048 TITLE,
00049 MESSAGE,
00050 SOUND,
00051 ICON,
00052 INTERFACE,
00053 SERVICE,
00054 PATH,
00055 NAME,
00056 FLAGS,
00057 ACTION,
00058 RECURRENCE,
00059 RECURRENCE_COUNT,
00060 SNOOZE_INT,
00061 SNOOZE,
00062 COUNT
00063 };
00064
00065 static const char * const property[COUNT] = {
00066 "time",
00067 "title",
00068 "message",
00069 "sound",
00070 "icon",
00071 "interface",
00072 "service",
00073 "path",
00074 "name",
00075 "flags",
00076 "action",
00077 "recurr_interval",
00078 "recurr_count",
00079 "snooze_interval",
00080 "snooze",
00081 };
00082
00083 static alarm_error_t error_code;
00084
00085 static size_t strstrcount(const char *haystack, const char *needle)
00086 {
00087 size_t retval = 0;
00088 size_t needlelen = strlen(needle);
00089
00090 if (!haystack || !needle) {
00091 return 0;
00092 }
00093
00094 for (haystack = strstr(haystack, needle);
00095 haystack;
00096 haystack = strstr(haystack + needlelen, needle)) {
00097 retval++;
00098 }
00099
00100 return retval;
00101 }
00102
00103 static size_t strchrcount(const char *haystack, const char needle)
00104 {
00105 size_t retval = 0;
00106
00107 if (!haystack) {
00108 return retval;
00109 }
00110
00111 for (; *haystack; haystack++) {
00112 if (*haystack == needle) {
00113 retval++;
00114 }
00115 }
00116
00117 return retval;
00118 }
00119
00120 static size_t strspncount(const char *haystack, const char *needles)
00121 {
00122 size_t count = 0;
00123
00124 for (haystack = strpbrk(haystack, needles); haystack; haystack = strpbrk(haystack + 1, needles)) {
00125 count++;
00126 }
00127
00128 return count;
00129 }
00130
00131 static DBusMessage *_alarm_event_dbus_call(const char *method, int first_arg_type, ...)
00132 {
00133 DBusMessage *msg = NULL;
00134 DBusMessage *reply = NULL;
00135 DBusConnection *conn = NULL;
00136 va_list arg_list;
00137
00138 if (!method) {
00139 error_code = ALARMD_ERROR_INTERNAL;
00140 return NULL;
00141 }
00142
00143 conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
00144
00145 if (!conn) {
00146 error_code = ALARMD_ERROR_DBUS;
00147 return NULL;
00148 }
00149
00150 va_start(arg_list, first_arg_type);
00151
00152
00153 msg = dbus_message_new_method_call(ALARMD_SERVICE,
00154 ALARMD_PATH,
00155 ALARMD_INTERFACE,
00156 method);
00157
00158 if (!msg) {
00159 dbus_connection_close(conn);
00160 dbus_connection_unref(conn);
00161 error_code = ALARMD_ERROR_MEMORY;
00162 return NULL;
00163 }
00164
00165
00166 dbus_message_append_args_valist(msg, first_arg_type, arg_list);
00167
00168 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
00169
00170 dbus_connection_close(conn);
00171 dbus_connection_unref(conn);
00172
00173 dbus_message_unref(msg);
00174
00175 va_end(arg_list);
00176
00177 return reply;
00178 }
00179
00180 cookie_t alarm_event_add(alarm_event_t *event)
00181 {
00182 DBusConnection *conn;
00183 DBusMessage *msg;
00184 DBusMessage *reply;
00185 DBusError error;
00186 dbus_int32_t cookie;
00187 dbus_uint32_t event_arg_count = 0;
00188 dbus_uint32_t action_arg_count = 0;
00189 dbus_int64_t time64 = (dbus_int64_t)event->alarm_time;
00190 const char *event_name = NULL;
00191 const char *action_name = NULL;
00192
00193 error_code = ALARMD_SUCCESS;
00194
00195 if (!event) {
00196 error_code = ALARMD_ERROR_ARGUMENT;
00197 return 0;
00198 }
00199
00200 event_arg_count = ZERO0(event->recurrence) +
00201 ZERO0(event->recurrence_count) +
00202 ZERO0(event->snooze) + 2;
00203 action_arg_count = NULL0(event->title) +
00204 NULL0(event->message) +
00205 NULL0(event->sound) +
00206 NULL0(event->icon) +
00207 NULL0(event->dbus_interface) +
00208 NULL0(event->dbus_service) +
00209 NULL0(event->dbus_path) +
00210 NULL0(event->dbus_name) +
00211 NULL0(event->exec_name) + 1;
00212
00213 if (event->dbus_path == NULL && event->exec_name == NULL) {
00214 action_name = "/AlarmdActionDialog";
00215 } else if (event->dbus_path == NULL) {
00216 action_name = "/AlarmdActionExec";
00217 } else {
00218 action_name = "/AlarmdActionDbus";
00219 }
00220
00221 if (event->recurrence != 0) {
00222 event_name = "/AlarmdEventRecurring";
00223 } else {
00224 event_name = "/AlarmdEvent";
00225 }
00226
00227
00228 msg = dbus_message_new_method_call(ALARMD_SERVICE,
00229 ALARMD_PATH,
00230 ALARMD_INTERFACE,
00231 ALARM_EVENT_ADD);
00232
00233 if (msg == NULL) {
00234 error_code = ALARMD_ERROR_MEMORY;
00235 return 0;
00236 }
00237
00238 if (!dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &event_name,
00239 DBUS_TYPE_UINT32, &event_arg_count,
00240 DBUS_TYPE_STRING, &property[TIME],
00241 DBUS_TYPE_INT64, &time64,
00242 DBUS_TYPE_STRING, &property[ACTION],
00243 DBUS_TYPE_OBJECT_PATH, &action_name,
00244 DBUS_TYPE_UINT32, &action_arg_count,
00245 DBUS_TYPE_STRING, &property[FLAGS],
00246 DBUS_TYPE_INT32, &event->flags,
00247 DBUS_TYPE_INVALID)) {
00248 error_code = ALARMD_ERROR_MEMORY;
00249 dbus_message_unref(msg);
00250 return 0;
00251 }
00252
00253
00254 APPEND_ARG(msg, event->title, DBUS_TYPE_STRING, TITLE);
00255 APPEND_ARG(msg, event->message, DBUS_TYPE_STRING, MESSAGE);
00256 APPEND_ARG(msg, event->sound, DBUS_TYPE_STRING, SOUND);
00257 APPEND_ARG(msg, event->icon, DBUS_TYPE_STRING, ICON);
00258 APPEND_ARG(msg, event->dbus_interface, DBUS_TYPE_STRING, INTERFACE);
00259 APPEND_ARG(msg, event->dbus_service, DBUS_TYPE_STRING, SERVICE);
00260 APPEND_ARG(msg, event->dbus_path, DBUS_TYPE_STRING, PATH);
00261 APPEND_ARG(msg, event->dbus_name, DBUS_TYPE_STRING, NAME);
00262 APPEND_ARG(msg, event->exec_name, DBUS_TYPE_STRING, PATH);
00263
00264
00265 APPEND_ARG(msg, event->recurrence, DBUS_TYPE_UINT32, RECURRENCE);
00266 APPEND_ARG(msg, event->recurrence_count, DBUS_TYPE_INT32, RECURRENCE_COUNT);
00267 APPEND_ARG(msg, event->snooze, DBUS_TYPE_UINT32, SNOOZE_INT);
00268
00269 conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
00270
00271 if (conn == NULL) {
00272 dbus_message_unref(msg);
00273 error_code = ALARMD_ERROR_DBUS;
00274 return 0;
00275 }
00276
00277 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
00278 dbus_connection_close(conn);
00279 dbus_connection_unref(conn);
00280 dbus_message_unref(msg);
00281
00282 if (reply == NULL) {
00283 error_code = ALARMD_ERROR_CONNECTION;
00284 return 0;
00285 }
00286
00287 dbus_error_init(&error);
00288 dbus_message_get_args(reply, &error,
00289 DBUS_TYPE_INT32, &cookie,
00290 DBUS_TYPE_INVALID);
00291
00292 if (dbus_error_is_set(&error)) {
00293 dbus_error_free(&error);
00294 dbus_message_unref(reply);
00295 error_code = ALARMD_ERROR_INTERNAL;
00296 return 0;
00297 }
00298
00299 dbus_message_unref(reply);
00300
00301 return cookie;
00302 }
00303
00304 int alarm_event_del(cookie_t event_cookie)
00305 {
00306 DBusMessage *reply;
00307 DBusError error;
00308 dbus_bool_t success = 0;
00309
00310 error_code = ALARMD_SUCCESS;
00311
00312 if (!event_cookie) {
00313 return 0;
00314 }
00315
00316 reply = _alarm_event_dbus_call(ALARM_EVENT_DEL,
00317 DBUS_TYPE_INT32, &event_cookie,
00318 DBUS_TYPE_INVALID);
00319
00320 if (reply == NULL) {
00321 return 0;
00322 }
00323
00324 dbus_error_init(&error);
00325 dbus_message_get_args(reply, &error,
00326 DBUS_TYPE_BOOLEAN, &success,
00327 DBUS_TYPE_INVALID);
00328
00329 if (dbus_error_is_set(&error)) {
00330 dbus_error_free(&error);
00331 dbus_message_unref(reply);
00332 error_code = ALARMD_ERROR_INTERNAL;
00333 return 0;
00334 }
00335
00336 dbus_message_unref(reply);
00337
00338 return success;
00339 }
00340
00341 cookie_t *alarm_event_query(const time_t first, const time_t last,
00342 int32_t flag_mask, int32_t flags)
00343 {
00344 DBusMessage *reply;
00345 DBusMessageIter iter;
00346 DBusMessageIter sub;
00347 int count = 0, i;
00348 cookie_t *retval;
00349
00350 dbus_int64_t first_64 = first;
00351 dbus_int64_t last_64 = last;
00352
00353 error_code = ALARMD_SUCCESS;
00354
00355 reply = _alarm_event_dbus_call(ALARM_EVENT_QUERY,
00356 DBUS_TYPE_UINT64, &first_64,
00357 DBUS_TYPE_UINT64, &last_64,
00358 DBUS_TYPE_INT32, &flag_mask,
00359 DBUS_TYPE_INT32, &flags,
00360 DBUS_TYPE_INVALID);
00361
00362 if (reply == NULL) {
00363 return NULL;
00364 } else if (!dbus_message_iter_init(reply, &iter)) {
00365 dbus_message_unref(reply);
00366 error_code = ALARMD_ERROR_INTERNAL;
00367 return NULL;
00368 }
00369
00370 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
00371 dbus_message_iter_recurse(&iter, &sub);
00372 count = dbus_message_iter_get_array_len(&sub);
00373 retval = (cookie_t *)calloc(count + 1, sizeof(cookie_t));
00374
00375 for (i = 0; i < count; i++) {
00376 if (dbus_message_iter_get_arg_type(&sub) !=
00377 DBUS_TYPE_INT32) {
00378 break;
00379 }
00380 dbus_message_iter_get_basic(&sub, &retval[i]);
00381 dbus_message_iter_next(&sub);
00382 }
00383 } else {
00384 retval = (cookie_t *)calloc(1, sizeof(cookie_t));
00385 }
00386
00387 dbus_message_unref(reply);
00388
00389 return retval;
00390 }
00391
00392 alarm_event_t *alarm_event_get(cookie_t event_cookie)
00393 {
00394 DBusMessage *reply;
00395 DBusMessageIter iter;
00396 alarm_event_t *retval = NULL;
00397
00398 const char *name;
00399 const char *value_string;
00400 dbus_uint64_t value_u64;
00401 dbus_uint32_t value_u32;
00402 dbus_uint32_t arg_count;
00403 unsigned int i;
00404
00405 unsigned int is_exec = 0;
00406
00407 error_code = ALARMD_SUCCESS;
00408
00409 reply = _alarm_event_dbus_call(ALARM_EVENT_GET,
00410 DBUS_TYPE_INT32, &event_cookie,
00411 DBUS_TYPE_INVALID);
00412
00413 if (reply == NULL) {
00414 return NULL;
00415 }
00416
00417 if (!dbus_message_iter_init(reply, &iter)) {
00418 dbus_message_unref(reply);
00419 error_code = ALARMD_ERROR_INTERNAL;
00420 return NULL;
00421 }
00422
00423 if (!dbus_message_iter_next(&iter)) {
00424 dbus_message_unref(reply);
00425 error_code = ALARMD_ERROR_INTERNAL;
00426 return NULL;
00427 }
00428 dbus_message_iter_get_basic(&iter, &arg_count);
00429 dbus_message_iter_next(&iter);
00430
00431 retval = (alarm_event_t *)calloc(1, sizeof(alarm_event_t));
00432
00433 for (i = 0; i < arg_count; i++) {
00434 dbus_message_iter_get_basic(&iter, &name);
00435 dbus_message_iter_next(&iter);
00436 #define dbus_message_iter_get_string(iter, var) \
00437 dbus_message_iter_get_basic(iter, &value_string); \
00438 var = _strdup(value_string); \
00439 value_string = NULL;
00440 switch (_get_id(name)) {
00441 case TITLE:
00442 dbus_message_iter_get_string(&iter, retval->title);
00443 break;
00444 case MESSAGE:
00445 dbus_message_iter_get_string(&iter, retval->message);
00446 break;
00447 case SOUND:
00448 dbus_message_iter_get_string(&iter, retval->sound);
00449 break;
00450 case ICON:
00451 dbus_message_iter_get_string(&iter, retval->icon);
00452 break;
00453 case INTERFACE:
00454 dbus_message_iter_get_string(&iter, retval->dbus_interface);
00455 break;
00456 case PATH:
00457 if (is_exec) {
00458 dbus_message_iter_get_string(&iter, retval->exec_name);
00459 } else {
00460 dbus_message_iter_get_string(&iter, retval->dbus_path);
00461 }
00462 break;
00463 case NAME:
00464 dbus_message_iter_get_string(&iter, retval->dbus_name);
00465 break;
00466 case FLAGS:
00467 dbus_message_iter_get_basic(&iter, &retval->flags);
00468 break;
00469 case RECURRENCE:
00470 dbus_message_iter_get_basic(&iter, &retval->recurrence);
00471 break;
00472 case RECURRENCE_COUNT:
00473 dbus_message_iter_get_basic(&iter, &retval->recurrence_count);
00474 break;
00475 case SNOOZE_INT:
00476 dbus_message_iter_get_basic(&iter, &retval->snooze);
00477 break;
00478 case SNOOZE:
00479 dbus_message_iter_get_basic(&iter, &retval->snoozed);
00480 break;
00481 case TIME:
00482 dbus_message_iter_get_basic(&iter, &value_u64);
00483 retval->alarm_time = (time_t)value_u64;
00484 break;
00485 case ACTION:
00486 dbus_message_iter_get_basic(&iter, &value_string);
00487 if (strcmp(value_string, "/AlarmdActionExec") == 0) {
00488 is_exec = 1;
00489 }
00490 dbus_message_iter_next(&iter);
00491 dbus_message_iter_get_basic(&iter, &value_u32);
00492 arg_count += value_u32;
00493 break;
00494 default:
00495 break;
00496 }
00497 if (!dbus_message_iter_next(&iter)) {
00498 break;
00499 }
00500 }
00501
00502 dbus_message_unref(reply);
00503
00504 return retval;
00505 }
00506
00507 void alarm_event_free(alarm_event_t *event)
00508 {
00509 if (event == NULL) {
00510 return;
00511 }
00512
00513 if (event->title) {
00514 free(event->title);
00515 }
00516 if (event->message) {
00517 free(event->message);
00518 }
00519 if (event->sound) {
00520 free(event->sound);
00521 }
00522 if (event->icon) {
00523 free(event->icon);
00524 }
00525 if (event->dbus_interface) {
00526 free(event->dbus_interface);
00527 }
00528 if (event->dbus_service) {
00529 free(event->dbus_service);
00530 }
00531 if (event->dbus_path) {
00532 free(event->dbus_path);
00533 }
00534 if (event->dbus_name) {
00535 free(event->dbus_name);
00536 }
00537 if (event->exec_name) {
00538 free(event->exec_name);
00539 }
00540
00541 free(event);
00542 }
00543
00544 static int _get_id(const char *name) {
00545 unsigned int i = 0;
00546
00547 if (name == NULL) {
00548 return COUNT;
00549 }
00550
00551 for (i = 0; i < COUNT; i++) {
00552 if (strcmp(name, property[i]) == 0) {
00553 break;
00554 }
00555 }
00556
00557 return i;
00558 }
00559
00560 char *alarm_escape_string(const char *string)
00561 {
00562 size_t new_len;
00563 char *retval;
00564 char *iter;
00565
00566 if (!string) {
00567 return NULL;
00568 }
00569
00570 new_len = strlen(string) + strspncount(string, "\\{}");
00571 retval = malloc(new_len + 1);
00572 iter = retval;
00573
00574 for (; *string; string++, iter++) {
00575 switch (*string) {
00576 case '\\':
00577 case '{':
00578 case '}':
00579 *iter = '\\';
00580 iter++;
00581 default:
00582 *iter = *string;
00583 }
00584 }
00585 *iter = '\0';
00586
00587 return retval;
00588 }
00589
00590 static void _alarm_do_unescape(const char *read, char *write)
00591 {
00592 while (*read) {
00593 if (*read == '\\' && read[1]) {
00594 read++;
00595 }
00596
00597 *write = *read;
00598 write++;
00599 read++;
00600 }
00601 *write = '\0';
00602 }
00603
00604 char *alarm_unescape_string_noalloc(char *string)
00605 {
00606 if (!string) {
00607 return string;
00608 }
00609
00610 _alarm_do_unescape(string, string);
00611
00612 return string;
00613 }
00614
00615 char *alarm_unescape_string(const char *string)
00616 {
00617 size_t len;
00618 char *retval;
00619
00620 if (!string) {
00621 return NULL;
00622 }
00623
00624 len = strlen(string)
00625 - strchrcount(string, '\\')
00626 + strstrcount(string, "\\\\");
00627 retval = malloc(len + 1);
00628
00629 _alarm_do_unescape(string, retval);
00630
00631 return retval;
00632 }
00633
00634 alarm_error_t alarmd_get_error(void)
00635 {
00636 return error_code;
00637 }
00638
00639 int alarmd_set_default_snooze(unsigned int snooze)
00640 {
00641 DBusMessage *reply;
00642 dbus_bool_t success;
00643 DBusError error;
00644
00645 error_code = ALARMD_SUCCESS;
00646
00647 if (snooze == 0) {
00648 error_code = ALARMD_ERROR_ARGUMENT;
00649 return 0;
00650 }
00651
00652 reply = _alarm_event_dbus_call(ALARMD_SNOOZE_SET, DBUS_TYPE_UINT32,
00653 &snooze, DBUS_TYPE_INVALID);
00654
00655 if (reply == NULL) {
00656 return 0;
00657 }
00658
00659 dbus_error_init(&error);
00660 dbus_message_get_args(reply, &error,
00661 DBUS_TYPE_BOOLEAN, &success,
00662 DBUS_TYPE_INVALID);
00663
00664 if (dbus_error_is_set(&error)) {
00665 dbus_error_free(&error);
00666 dbus_message_unref(reply);
00667 error_code = ALARMD_ERROR_INTERNAL;
00668 return 0;
00669 }
00670 dbus_message_unref(reply);
00671
00672 if (!success) {
00673 error_code = ALARMD_ERROR_INTERNAL;
00674 }
00675
00676 return success;
00677 }
00678
00679 unsigned int alarmd_get_default_snooze(void)
00680 {
00681 DBusMessage *reply;
00682 dbus_uint32_t snooze;
00683 DBusError error;
00684
00685 error_code = ALARMD_SUCCESS;
00686
00687 if (snooze == 0) {
00688 error_code = ALARMD_ERROR_ARGUMENT;
00689 return 0;
00690 }
00691
00692 reply = _alarm_event_dbus_call(ALARMD_SNOOZE_GET, DBUS_TYPE_INVALID);
00693
00694 if (reply == NULL) {
00695 return 0;
00696 }
00697
00698 dbus_error_init(&error);
00699 dbus_message_get_args(reply, &error,
00700 DBUS_TYPE_UINT32, &snooze,
00701 DBUS_TYPE_INVALID);
00702
00703 if (dbus_error_is_set(&error)) {
00704 dbus_error_free(&error);
00705 dbus_message_unref(reply);
00706 error_code = ALARMD_ERROR_INTERNAL;
00707 return 0;
00708 }
00709 dbus_message_unref(reply);
00710
00711 if (snooze == 0) {
00712 error_code = ALARMD_ERROR_INTERNAL;
00713 }
00714
00715 return snooze;
00716 }