Main Page | Data Structures | File List | Data Fields | Globals

alarm_event.c

Go to the documentation of this file.
00001 /**
00002  * This file is part of alarmd
00003  *
00004  * Contact Person: David Weinehall <david.weinehall@nokia.com>
00005  *
00006  * Copyright (C) 2006 Nokia Corporation
00007  * alarmd and libalarm are free software; you can redistribute them
00008  * and/or modify them under the terms of the GNU Lesser General Public
00009  * License version 2.1 as published by the Free Software Foundation.
00010  *
00011  * alarmd and libalarm are distributed in the hope that they will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this software; if not, write to the Free
00018  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00019  * 02110-1301 USA
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   /* Create new dbus method call to multimedia. */
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   /* Append given arguments. */
00166   dbus_message_append_args_valist(msg, first_arg_type, arg_list);
00167   /* Put the message to dbus queue. */
00168   reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
00169   /* Close the connection. */
00170   dbus_connection_close(conn);
00171   dbus_connection_unref(conn);
00172   /* Unref (free) the message. */
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         /* Create new dbus method call to multimedia. */
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         /* Action arguments. */
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         /* Event arguments. */
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 }

Generated on Thu Dec 21 18:23:30 2006 for Alarmd by  doxygen 1.4.2