1 /*
2  * e-source-alarms.c
3  *
4  * This library is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library. If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 /**
19  * SECTION: e-source-alarms
20  * @include: libedataserver/libedataserver.h
21  * @short_description: #ESource extension for alarm state
22  *
23  * The #ESourceAlarms extension tracks alarm state for a calendar.
24  *
25  * Access the extension as follows:
26  *
27  * |[
28  *   #include <libedataserver/libedataserver.h>
29  *
30  *   ESourceAlarms *extension;
31  *
32  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_ALARMS);
33  * ]|
34  **/
35 
36 #include "e-source-alarms.h"
37 
38 struct _ESourceAlarmsPrivate {
39 	gboolean include_me;
40 	gchar *last_notified;
41 };
42 
43 enum {
44 	PROP_0,
45 	PROP_INCLUDE_ME,
46 	PROP_LAST_NOTIFIED
47 };
48 
G_DEFINE_TYPE_WITH_PRIVATE(ESourceAlarms,e_source_alarms,E_TYPE_SOURCE_EXTENSION)49 G_DEFINE_TYPE_WITH_PRIVATE (
50 	ESourceAlarms,
51 	e_source_alarms,
52 	E_TYPE_SOURCE_EXTENSION)
53 
54 static void
55 source_alarms_set_property (GObject *object,
56                             guint property_id,
57                             const GValue *value,
58                             GParamSpec *pspec)
59 {
60 	switch (property_id) {
61 		case PROP_INCLUDE_ME:
62 			e_source_alarms_set_include_me (
63 				E_SOURCE_ALARMS (object),
64 				g_value_get_boolean (value));
65 			return;
66 
67 		case PROP_LAST_NOTIFIED:
68 			e_source_alarms_set_last_notified (
69 				E_SOURCE_ALARMS (object),
70 				g_value_get_string (value));
71 			return;
72 	}
73 
74 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
75 }
76 
77 static void
source_alarms_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)78 source_alarms_get_property (GObject *object,
79                             guint property_id,
80                             GValue *value,
81                             GParamSpec *pspec)
82 {
83 	switch (property_id) {
84 		case PROP_INCLUDE_ME:
85 			g_value_set_boolean (
86 				value,
87 				e_source_alarms_get_include_me (
88 				E_SOURCE_ALARMS (object)));
89 			return;
90 
91 		case PROP_LAST_NOTIFIED:
92 			g_value_take_string (
93 				value,
94 				e_source_alarms_dup_last_notified (
95 				E_SOURCE_ALARMS (object)));
96 			return;
97 	}
98 
99 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
100 }
101 
102 static void
source_alarms_finalize(GObject * object)103 source_alarms_finalize (GObject *object)
104 {
105 	ESourceAlarmsPrivate *priv;
106 
107 	priv = E_SOURCE_ALARMS (object)->priv;
108 
109 	g_free (priv->last_notified);
110 
111 	/* Chain up to parent's finalize() method. */
112 	G_OBJECT_CLASS (e_source_alarms_parent_class)->finalize (object);
113 }
114 
115 static void
e_source_alarms_class_init(ESourceAlarmsClass * class)116 e_source_alarms_class_init (ESourceAlarmsClass *class)
117 {
118 	GObjectClass *object_class;
119 	ESourceExtensionClass *extension_class;
120 
121 	object_class = G_OBJECT_CLASS (class);
122 	object_class->set_property = source_alarms_set_property;
123 	object_class->get_property = source_alarms_get_property;
124 	object_class->finalize = source_alarms_finalize;
125 
126 	extension_class = E_SOURCE_EXTENSION_CLASS (class);
127 	extension_class->name = E_SOURCE_EXTENSION_ALARMS;
128 
129 	g_object_class_install_property (
130 		object_class,
131 		PROP_INCLUDE_ME,
132 		g_param_spec_boolean (
133 			"include-me",
134 			"IncludeMe",
135 			"Include this source in alarm notifications",
136 			TRUE,
137 			G_PARAM_READWRITE |
138 			G_PARAM_CONSTRUCT |
139 			G_PARAM_EXPLICIT_NOTIFY |
140 			G_PARAM_STATIC_STRINGS |
141 			E_SOURCE_PARAM_SETTING));
142 
143 	g_object_class_install_property (
144 		object_class,
145 		PROP_LAST_NOTIFIED,
146 		g_param_spec_string (
147 			"last-notified",
148 			"LastNotified",
149 			"Last alarm notification (in ISO 8601 format)",
150 			NULL,
151 			G_PARAM_READWRITE |
152 			G_PARAM_CONSTRUCT |
153 			G_PARAM_EXPLICIT_NOTIFY |
154 			G_PARAM_STATIC_STRINGS |
155 			E_SOURCE_PARAM_SETTING));
156 }
157 
158 static void
e_source_alarms_init(ESourceAlarms * extension)159 e_source_alarms_init (ESourceAlarms *extension)
160 {
161 	extension->priv = e_source_alarms_get_instance_private (extension);
162 }
163 
164 /**
165  * e_source_alarms_get_include_me:
166  * @extension: an #ESourceAlarms
167  *
168  * Returns whether the user should be alerted about upcoming appointments
169  * in the calendar described by the #ESource to which @extension belongs.
170  *
171  * Alarm daemons such as evolution-alarm-notify can use this property to
172  * decide which calendars to query for upcoming appointments.
173  *
174  * Returns: whether to show alarms for upcoming appointments
175  *
176  * Since: 3.6
177  **/
178 gboolean
e_source_alarms_get_include_me(ESourceAlarms * extension)179 e_source_alarms_get_include_me (ESourceAlarms *extension)
180 {
181 	g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), FALSE);
182 
183 	return extension->priv->include_me;
184 }
185 
186 /**
187  * e_source_alarms_set_include_me:
188  * @extension: an #ESourceAlarms
189  * @include_me: whether to show alarms for upcoming appointments
190  *
191  * Sets whether the user should be alerted about upcoming appointments in
192  * the calendar described by the #ESource to which @extension belongs.
193  *
194  * Alarm daemons such as evolution-alarm-notify can use this property to
195  * decide which calendars to query for upcoming appointments.
196  *
197  * Since: 3.6
198  **/
199 void
e_source_alarms_set_include_me(ESourceAlarms * extension,gboolean include_me)200 e_source_alarms_set_include_me (ESourceAlarms *extension,
201                                 gboolean include_me)
202 {
203 	g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
204 
205 	if (extension->priv->include_me == include_me)
206 		return;
207 
208 	extension->priv->include_me = include_me;
209 
210 	g_object_notify (G_OBJECT (extension), "include-me");
211 }
212 
213 /**
214  * e_source_alarms_get_last_notified:
215  * @extension: an #ESourceAlarms
216  *
217  * Returns an ISO 8601 formatted timestamp of when the user was last
218  * alerted about an upcoming appointment in the calendar described by
219  * the #ESource to which @extension belongs.  If no valid timestamp
220  * has been set, the function will return %NULL.
221  *
222  * Returns: (nullable): an ISO 8601 timestamp, or %NULL
223  *
224  * Since: 3.6
225  **/
226 const gchar *
e_source_alarms_get_last_notified(ESourceAlarms * extension)227 e_source_alarms_get_last_notified (ESourceAlarms *extension)
228 {
229 	g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), NULL);
230 
231 	return extension->priv->last_notified;
232 }
233 
234 /**
235  * e_source_alarms_dup_last_notified:
236  * @extension: an #ESourceAlarms
237  *
238  * Thread-safe variation of e_source_alarms_get_last_notified().
239  * Use this function when accessing @extension from multiple threads.
240  *
241  * The returned string should be freed with g_free() when no longer needed.
242  *
243  * Returns: (nullable): a newly-allocated copy of #ESourceAlarms:last-notified
244  *
245  * Since: 3.6
246  **/
247 gchar *
e_source_alarms_dup_last_notified(ESourceAlarms * extension)248 e_source_alarms_dup_last_notified (ESourceAlarms *extension)
249 {
250 	const gchar *protected;
251 	gchar *duplicate;
252 
253 	g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), NULL);
254 
255 	e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
256 
257 	protected = e_source_alarms_get_last_notified (extension);
258 	duplicate = g_strdup (protected);
259 
260 	e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
261 
262 	return duplicate;
263 }
264 
265 /**
266  * e_source_alarms_set_last_notified:
267  * @extension: an #ESourceAlarms
268  * @last_notified: (nullable): an ISO 8601 timestamp, or %NULL
269  *
270  * Sets an ISO 8601 formatted timestamp of when the user was last
271  * alerted about an upcoming appointment in the calendar described
272  * by the #ESource to which @extension belongs.
273  *
274  * If @last_notified is non-%NULL, the function will validate the
275  * timestamp before setting the #ESourceAlarms:last-notified property.
276  * Invalid timestamps are discarded with a runtime warning.
277  *
278  * Generally, this function should only be called by an alarm daemon
279  * such as evolution-alarm-notify.
280  *
281  * Since: 3.6
282  **/
283 void
e_source_alarms_set_last_notified(ESourceAlarms * extension,const gchar * last_notified)284 e_source_alarms_set_last_notified (ESourceAlarms *extension,
285                                    const gchar *last_notified)
286 {
287 	g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
288 
289 	if (last_notified && !*last_notified)
290 		last_notified = NULL;
291 
292 	if (last_notified != NULL) {
293 		GTimeVal time_val;
294 
295 		if (!g_time_val_from_iso8601 (last_notified, &time_val)) {
296 			g_warning (
297 				"%s: Invalid timestamp: '%s'",
298 				G_STRFUNC, last_notified);
299 			return;
300 		}
301 	}
302 
303 	e_source_extension_property_lock (E_SOURCE_EXTENSION (extension));
304 
305 	if (g_strcmp0 (extension->priv->last_notified, last_notified) == 0) {
306 		e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
307 		return;
308 	}
309 
310 	g_free (extension->priv->last_notified);
311 	extension->priv->last_notified = g_strdup (last_notified);
312 
313 	e_source_extension_property_unlock (E_SOURCE_EXTENSION (extension));
314 
315 	g_object_notify (G_OBJECT (extension), "last-notified");
316 }
317