Fix activated status toggling
[timedsilencer] / alarmd_backend.h
1 /*
2  * This file is part of TimedSilencer.
3  *
4  *  TimedSilencer is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  TimedSilencer is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with TimedSilencer.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #ifndef ALARMD_TALKER_H
19 #define ALARMD_TALKER_H
20
21 #include <QTime>
22 #include <QString>
23 #include <QSettings>
24 #include <QPair>
25 #include <alarmd/libalarm.h>
26 #include <dbus-1.0/dbus/dbus-protocol.h>
27 #include <time.h>
28
29 #include "phone_profile.h"
30 #include "dbus_backend.h"
31 #include "profileevent.h"
32
33 // Alarmd documentation found at:
34 // http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Generic_Platform_Components/Alarm_Framework
35 class AlarmdBackend : public QObject {
36   Q_OBJECT
37 private:
38   static time_t toTime_t(const QTime &t) {
39     int time_diff = QTime::currentTime().secsTo(t);
40     if(time_diff < 0) {
41       // Add 24 hours
42       time_diff += 86400;
43     }
44     qDebug("time diff: %d", time_diff);
45     return (time_t) time(0) + time_diff;
46   }
47
48   static uint32_t daysToMask(QList<int> days) {
49     uint32_t mask = 0;
50     foreach(const int& d, days) {
51       switch(d) {
52       case MON:
53         mask |= ALARM_RECUR_WDAY_MON;
54         break;
55       case TUE:
56         mask |= ALARM_RECUR_WDAY_TUE;
57         break;
58       case WED:
59         mask |= ALARM_RECUR_WDAY_WED;
60         break;
61       case THU:
62         mask |= ALARM_RECUR_WDAY_THU;
63         break;
64       case FRI:
65         mask |= ALARM_RECUR_WDAY_FRI;
66         break;
67       case SAT:
68         mask |= ALARM_RECUR_WDAY_SAT;
69         break;
70       case SUN:
71         mask |= ALARM_RECUR_WDAY_SUN;
72         break;
73       default:
74         Q_ASSERT(0); // Should never go here
75         mask |= ALARM_RECUR_WDAY_ALL;
76         break;
77       }
78     }
79     return mask;
80   }
81
82 public:
83   // Is only called on program uninstall
84   static void deleteAllEvents() {
85     QSettings settings("TimedSilencer", "TimedSilencer");
86     QHash<QString, QVariant> events = settings.value("events").toHash();
87     foreach(QVariant var_ev, events) {
88       ProfileEvent *pe = ProfileEvent::load(var_ev);
89       foreach(const long &cookie, pe->alarmd_cookies) {
90         qDebug("Unregistering event with cookie %ld", cookie);
91         alarmd_event_del(cookie);
92       }
93       delete pe;
94     }
95     // Save in QSettings
96     events.clear();
97     settings.setValue("events", events);
98   }
99
100   static void deleteEvents(QByteArray event_id) {
101     deleteEvents(ProfileEvent::findByID(event_id));
102   }
103
104   static void deleteEvents(ProfileEvent *pe) {
105     // unregistering events
106     foreach(const long &cookie, pe->alarmd_cookies) {
107       qDebug("Unregistering event with cookie %ld", cookie);
108       alarmd_event_del(cookie);
109     }
110     pe->alarmd_cookies.clear();
111     ProfileEvent::clearCookies(pe->getID());
112   }
113
114   static void setProfileEvents(QByteArray event_id) {
115     setProfileEvents(ProfileEvent::findByID(event_id));
116   }
117
118   static bool checkIfStillActive(ProfileEvent *pe) {
119     Q_ASSERT(pe->activated);
120     foreach(const long &cookie, pe->alarmd_cookies) {
121       alarm_event_t *eve = 0;
122       if((eve = alarmd_event_get(cookie)) != 0) {
123         // Free all dynamic memory associated with the alarm event
124         alarm_event_delete(eve);
125         return true;
126       }
127     }
128     return false;
129   }
130
131   static void setProfileEvents(ProfileEvent *pe) {
132     Q_ASSERT(pe->activated);
133     // First clear old alarmd events
134     foreach(const long &cookie, pe->alarmd_cookies) {
135       qDebug("Unregistering event with cookie %ld", cookie);
136       alarmd_event_del(cookie);
137     }
138     pe->alarmd_cookies.clear();
139     // Then setting new events
140     long c1 = newProfileEvent(SILENT, pe->from_time, pe->days);
141     Q_ASSERT(c1 > 0);
142     if(c1 > 0)
143       pe->alarmd_cookies << c1;
144     long c2 = newProfileEvent(GENERAL, pe->to_time, pe->days);
145     Q_ASSERT(c2 > 0);
146     if(c2 > 0)
147       pe->alarmd_cookies << c2;
148     // Save in QSettings
149     ProfileEvent::setCookies(pe->getID(), pe->alarmd_cookies);
150     // Set Profile to SILENT if we are currently in the silent time slot
151     if(pe->affectsCurrentTime())
152       DBusBackend::setProfile(SILENT);
153   }
154
155 protected:
156   static long newProfileEvent(Profile p, const QTime &event_time, QList<int> days) {
157     Q_ASSERT(!days.empty());
158     if(days.empty()) days << NEVER;
159     // Create the default alarm struct.
160     alarm_event_t *newEvent = alarm_event_create();
161     // Set the APP ID
162     alarm_event_set_alarm_appid(newEvent, "TimedSilencer");
163     // Set the title
164     if(p == SILENT)
165       alarm_event_set_title(newEvent, "silent_profile");
166     else
167       alarm_event_set_title(newEvent, "general_profile");
168     // Timing
169     if(days.first() == EVERY_DAY) {
170       newEvent->recur_secs = 86400; // 24 hours
171       newEvent->recur_count = -1; // Reoccur infinitely
172       newEvent->alarm_time = toTime_t(event_time); // Set event time
173     } else {
174       if(days.first() == NEVER) {
175         newEvent->alarm_time = toTime_t(event_time); // Set event time
176       } else {
177         newEvent->recur_secs = 0; // We re not using this way for recurrence
178         alarm_recur_t* recur = alarm_event_add_recurrences(newEvent, 1);
179         // Set event time
180         recur->mask_hour |= (1ul << event_time.hour());
181         recur->mask_min |= (1ull << event_time.minute());
182         recur->mask_wday |= daysToMask(days);
183       }
184     }
185     //Add 1 action to our alarm event, and assign it to the "act" variable
186     alarm_action_t *act = alarm_event_add_actions(newEvent, 1);
187     // Actions are documented here:
188     // http://maemo.org/api_refs/5.0/5.0-final/libalarm/libalarm_8h.html#cc8e6f439d134448001132132476683c910f7626ec85a4170659b53fa2f0abc7
189     //Setup this action to be an "DBus command" one; also set it up to use DBUS auto-activation.
190     act->flags = ALARM_ACTION_WHEN_TRIGGERED | ALARM_ACTION_DBUS_USE_ACTIVATION | ALARM_ACTION_TYPE_DBUS;
191
192     //Setup the DBus params for this action
193     alarm_action_set_dbus_interface(act, "com.nokia.profiled");
194     alarm_action_set_dbus_service(act, "com.nokia.profiled");
195     alarm_action_set_dbus_path(act, "/com/nokia/profiled");
196     alarm_action_set_dbus_name(act, "set_profile");
197
198     if(p == SILENT) {
199       const char* param = "silent";
200       alarm_action_set_dbus_args(act, DBUS_TYPE_STRING, &param, DBUS_TYPE_INVALID);
201     } else {
202       const char* param = "general";
203       alarm_action_set_dbus_args(act, DBUS_TYPE_STRING, &param, DBUS_TYPE_INVALID);
204     }
205
206     // Finally with everything setup, try to add your event to the alarm queue
207     long cookie = alarmd_event_add(newEvent);
208     // Free all dynamic memory associated with the alarm event
209     alarm_event_delete(newEvent);
210     return cookie;
211   }
212 };
213
214 #endif // ALARMD_TALKER_H