1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * SPDX-FileCopyrightText: (C) 2020 Red Hat (www.redhat.com)
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  */
6 
7 #include "evolution-ews-config.h"
8 
9 #include <stdio.h>
10 
11 #include "camel/camel.h"
12 
13 #include "camel-m365-message-info.h"
14 
15 struct _CamelM365MessageInfoPrivate {
16 	guint32 server_flags;
17 	gint32 item_type;
18 	gchar *change_key;
19 };
20 
21 enum {
22 	PROP_0,
23 	PROP_SERVER_FLAGS,
24 	PROP_ITEM_TYPE,
25 	PROP_CHANGE_KEY,
26 };
27 
G_DEFINE_TYPE_WITH_PRIVATE(CamelM365MessageInfo,camel_m365_message_info,CAMEL_TYPE_MESSAGE_INFO_BASE)28 G_DEFINE_TYPE_WITH_PRIVATE (CamelM365MessageInfo, camel_m365_message_info, CAMEL_TYPE_MESSAGE_INFO_BASE)
29 
30 static CamelMessageInfo *
31 m365_message_info_clone (const CamelMessageInfo *mi,
32 			 CamelFolderSummary *assign_summary)
33 {
34 	CamelMessageInfo *result;
35 
36 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (mi), NULL);
37 
38 	result = CAMEL_MESSAGE_INFO_CLASS (camel_m365_message_info_parent_class)->clone (mi, assign_summary);
39 	if (!result)
40 		return NULL;
41 
42 	if (CAMEL_IS_M365_MESSAGE_INFO (result)) {
43 		CamelM365MessageInfo *omi, *omi_result;
44 
45 		omi = CAMEL_M365_MESSAGE_INFO (mi);
46 		omi_result = CAMEL_M365_MESSAGE_INFO (result);
47 
48 		camel_m365_message_info_set_server_flags (omi_result, camel_m365_message_info_get_server_flags (omi));
49 		camel_m365_message_info_set_item_type (omi_result, camel_m365_message_info_get_item_type (omi));
50 		camel_m365_message_info_take_change_key (omi_result, camel_m365_message_info_dup_change_key (omi));
51 	}
52 
53 	return result;
54 }
55 
56 static gboolean
m365_message_info_load(CamelMessageInfo * mi,const CamelMIRecord * record,gchar ** bdata_ptr)57 m365_message_info_load (CamelMessageInfo *mi,
58 			const CamelMIRecord *record,
59 			/* const */ gchar **bdata_ptr)
60 {
61 	CamelM365MessageInfo *omi;
62 
63 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (mi), FALSE);
64 	g_return_val_if_fail (record != NULL, FALSE);
65 	g_return_val_if_fail (bdata_ptr != NULL, FALSE);
66 
67 	if (!CAMEL_MESSAGE_INFO_CLASS (camel_m365_message_info_parent_class)->load ||
68 	    !CAMEL_MESSAGE_INFO_CLASS (camel_m365_message_info_parent_class)->load (mi, record, bdata_ptr))
69 		return FALSE;
70 
71 	omi = CAMEL_M365_MESSAGE_INFO (mi);
72 
73 	if (*bdata_ptr) {
74 		gchar **values;
75 
76 		values = g_strsplit (*bdata_ptr, " ", -1);
77 
78 		if (values && values[0] && values[1] && values[2]) {
79 			camel_m365_message_info_set_server_flags (omi, g_ascii_strtoll (values[0], NULL, 10));
80 			camel_m365_message_info_set_item_type (omi, g_ascii_strtoll (values[1], NULL, 10));
81 			camel_m365_message_info_set_change_key (omi, values[2]);
82 		}
83 
84 		g_strfreev (values);
85 	}
86 
87 	return TRUE;
88 }
89 
90 static gboolean
m365_message_info_save(const CamelMessageInfo * mi,CamelMIRecord * record,GString * bdata_str)91 m365_message_info_save (const CamelMessageInfo *mi,
92 			CamelMIRecord *record,
93 			GString *bdata_str)
94 {
95 	CamelM365MessageInfo *omi;
96 
97 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (mi), FALSE);
98 	g_return_val_if_fail (record != NULL, FALSE);
99 	g_return_val_if_fail (bdata_str != NULL, FALSE);
100 
101 	if (!CAMEL_MESSAGE_INFO_CLASS (camel_m365_message_info_parent_class)->save ||
102 	    !CAMEL_MESSAGE_INFO_CLASS (camel_m365_message_info_parent_class)->save (mi, record, bdata_str))
103 		return FALSE;
104 
105 	omi = CAMEL_M365_MESSAGE_INFO (mi);
106 
107 	g_string_append_printf (bdata_str, "%u %d %s",
108 		camel_m365_message_info_get_server_flags (omi),
109 		camel_m365_message_info_get_item_type (omi),
110 		camel_m365_message_info_get_change_key (omi));
111 
112 	return TRUE;
113 }
114 
115 static void
m365_message_info_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)116 m365_message_info_set_property (GObject *object,
117 				guint property_id,
118 				const GValue *value,
119 				GParamSpec *pspec)
120 {
121 	CamelM365MessageInfo *omi = CAMEL_M365_MESSAGE_INFO (object);
122 
123 	switch (property_id) {
124 	case PROP_SERVER_FLAGS:
125 		camel_m365_message_info_set_server_flags (omi, g_value_get_uint (value));
126 		return;
127 
128 	case PROP_ITEM_TYPE:
129 		camel_m365_message_info_set_item_type (omi, g_value_get_int (value));
130 		return;
131 
132 	case PROP_CHANGE_KEY:
133 		camel_m365_message_info_set_change_key (omi, g_value_get_string (value));
134 		return;
135 	}
136 
137 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
138 }
139 
140 static void
m365_message_info_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)141 m365_message_info_get_property (GObject *object,
142 				guint property_id,
143 				GValue *value,
144 				GParamSpec *pspec)
145 {
146 	CamelM365MessageInfo *omi = CAMEL_M365_MESSAGE_INFO (object);
147 
148 	switch (property_id) {
149 
150 	case PROP_SERVER_FLAGS:
151 		g_value_set_uint (value, camel_m365_message_info_get_server_flags (omi));
152 		return;
153 
154 	case PROP_ITEM_TYPE:
155 		g_value_set_int (value, camel_m365_message_info_get_item_type (omi));
156 		return;
157 
158 	case PROP_CHANGE_KEY:
159 		g_value_take_string (value, camel_m365_message_info_dup_change_key (omi));
160 		return;
161 	}
162 
163 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
164 }
165 
166 static void
m365_message_info_dispose(GObject * object)167 m365_message_info_dispose (GObject *object)
168 {
169 	CamelM365MessageInfo *omi = CAMEL_M365_MESSAGE_INFO (object);
170 
171 	g_free (omi->priv->change_key);
172 	omi->priv->change_key = NULL;
173 
174 	/* Chain up to parent's method. */
175 	G_OBJECT_CLASS (camel_m365_message_info_parent_class)->dispose (object);
176 }
177 
178 static void
camel_m365_message_info_class_init(CamelM365MessageInfoClass * class)179 camel_m365_message_info_class_init (CamelM365MessageInfoClass *class)
180 {
181 	CamelMessageInfoClass *mi_class;
182 	GObjectClass *object_class;
183 
184 	mi_class = CAMEL_MESSAGE_INFO_CLASS (class);
185 	mi_class->clone = m365_message_info_clone;
186 	mi_class->load = m365_message_info_load;
187 	mi_class->save = m365_message_info_save;
188 
189 	object_class = G_OBJECT_CLASS (class);
190 	object_class->set_property = m365_message_info_set_property;
191 	object_class->get_property = m365_message_info_get_property;
192 	object_class->dispose = m365_message_info_dispose;
193 
194 	/*
195 	 * CamelM365MessageInfo:server-flags
196 	 *
197 	 * Last known server flags of the message.
198 	 */
199 	g_object_class_install_property (
200 		object_class,
201 		PROP_SERVER_FLAGS,
202 		g_param_spec_uint (
203 			"server-flags",
204 			"Server Flags",
205 			NULL,
206 			0, G_MAXUINT32, 0,
207 			G_PARAM_READWRITE));
208 
209 	/*
210 	 * CamelM365MessageInfo:item-type
211 	 *
212 	 * Item type of the message.
213 	 */
214 	g_object_class_install_property (
215 		object_class,
216 		PROP_ITEM_TYPE,
217 		g_param_spec_int (
218 			"item-type",
219 			"Item Type",
220 			NULL,
221 			0, G_MAXINT32, 0,
222 			G_PARAM_READWRITE));
223 
224 	/*
225 	 * CamelM365MessageInfo:change-key
226 	 *
227 	 * Change key of the message on the server.
228 	 */
229 	g_object_class_install_property (
230 		object_class,
231 		PROP_CHANGE_KEY,
232 		g_param_spec_string (
233 			"change-key",
234 			"Change Key",
235 			NULL,
236 			NULL,
237 			G_PARAM_READWRITE));
238 }
239 
240 static void
camel_m365_message_info_init(CamelM365MessageInfo * omi)241 camel_m365_message_info_init (CamelM365MessageInfo *omi)
242 {
243 	omi->priv = camel_m365_message_info_get_instance_private (omi);
244 }
245 
246 guint32
camel_m365_message_info_get_server_flags(const CamelM365MessageInfo * omi)247 camel_m365_message_info_get_server_flags (const CamelM365MessageInfo *omi)
248 {
249 	CamelMessageInfo *mi;
250 	guint32 result;
251 
252 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), 0);
253 
254 	mi = CAMEL_MESSAGE_INFO (omi);
255 
256 	camel_message_info_property_lock (mi);
257 	result = omi->priv->server_flags;
258 	camel_message_info_property_unlock (mi);
259 
260 	return result;
261 }
262 
263 gboolean
camel_m365_message_info_set_server_flags(CamelM365MessageInfo * omi,guint32 server_flags)264 camel_m365_message_info_set_server_flags (CamelM365MessageInfo *omi,
265 					  guint32 server_flags)
266 {
267 	CamelMessageInfo *mi;
268 	gboolean changed;
269 
270 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), FALSE);
271 
272 	mi = CAMEL_MESSAGE_INFO (omi);
273 
274 	camel_message_info_property_lock (mi);
275 
276 	changed = omi->priv->server_flags != server_flags;
277 
278 	if (changed)
279 		omi->priv->server_flags = server_flags;
280 
281 	camel_message_info_property_unlock (mi);
282 
283 	if (changed && !camel_message_info_get_abort_notifications (mi)) {
284 		g_object_notify (G_OBJECT (omi), "server-flags");
285 		camel_message_info_set_dirty (mi, TRUE);
286 	}
287 
288 	return changed;
289 }
290 
291 gint32
camel_m365_message_info_get_item_type(const CamelM365MessageInfo * omi)292 camel_m365_message_info_get_item_type (const CamelM365MessageInfo *omi)
293 {
294 	CamelMessageInfo *mi;
295 	gint32 result;
296 
297 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), 0);
298 
299 	mi = CAMEL_MESSAGE_INFO (omi);
300 
301 	camel_message_info_property_lock (mi);
302 	result = omi->priv->item_type;
303 	camel_message_info_property_unlock (mi);
304 
305 	return result;
306 }
307 
308 gboolean
camel_m365_message_info_set_item_type(CamelM365MessageInfo * omi,gint32 item_type)309 camel_m365_message_info_set_item_type (CamelM365MessageInfo *omi,
310 				       gint32 item_type)
311 {
312 	CamelMessageInfo *mi;
313 	gboolean changed;
314 
315 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), FALSE);
316 
317 	mi = CAMEL_MESSAGE_INFO (omi);
318 
319 	camel_message_info_property_lock (mi);
320 
321 	changed = omi->priv->item_type != item_type;
322 
323 	if (changed)
324 		omi->priv->item_type = item_type;
325 
326 	camel_message_info_property_unlock (mi);
327 
328 	if (changed && !camel_message_info_get_abort_notifications (mi)) {
329 		g_object_notify (G_OBJECT (omi), "item-type");
330 		camel_message_info_set_dirty (mi, TRUE);
331 	}
332 
333 	return changed;
334 }
335 
336 const gchar *
camel_m365_message_info_get_change_key(const CamelM365MessageInfo * omi)337 camel_m365_message_info_get_change_key (const CamelM365MessageInfo *omi)
338 {
339 	CamelMessageInfo *mi;
340 	const gchar *result;
341 
342 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), NULL);
343 
344 	mi = CAMEL_MESSAGE_INFO (omi);
345 
346 	camel_message_info_property_lock (mi);
347 	result = omi->priv->change_key;
348 	camel_message_info_property_unlock (mi);
349 
350 	return result;
351 }
352 
353 gchar *
camel_m365_message_info_dup_change_key(const CamelM365MessageInfo * omi)354 camel_m365_message_info_dup_change_key (const CamelM365MessageInfo *omi)
355 {
356 	CamelMessageInfo *mi;
357 	gchar *result;
358 
359 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), NULL);
360 
361 	mi = CAMEL_MESSAGE_INFO (omi);
362 
363 	camel_message_info_property_lock (mi);
364 	result = g_strdup (omi->priv->change_key);
365 	camel_message_info_property_unlock (mi);
366 
367 	return result;
368 }
369 
370 gboolean
camel_m365_message_info_set_change_key(CamelM365MessageInfo * omi,const gchar * change_key)371 camel_m365_message_info_set_change_key (CamelM365MessageInfo *omi,
372 					const gchar *change_key)
373 {
374 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), FALSE);
375 
376 	return camel_m365_message_info_take_change_key (omi, g_strdup (change_key));
377 }
378 
379 gboolean
camel_m365_message_info_take_change_key(CamelM365MessageInfo * omi,gchar * change_key)380 camel_m365_message_info_take_change_key (CamelM365MessageInfo *omi,
381 					 gchar *change_key)
382 {
383 	CamelMessageInfo *mi;
384 	gboolean changed;
385 
386 	g_return_val_if_fail (CAMEL_IS_M365_MESSAGE_INFO (omi), FALSE);
387 
388 	mi = CAMEL_MESSAGE_INFO (omi);
389 
390 	camel_message_info_property_lock (mi);
391 
392 	changed = g_strcmp0 (omi->priv->change_key, change_key) != 0;
393 
394 	if (changed) {
395 		g_free (omi->priv->change_key);
396 		omi->priv->change_key = change_key;
397 	} else if (change_key != omi->priv->change_key) {
398 		g_free (change_key);
399 	}
400 
401 	camel_message_info_property_unlock (mi);
402 
403 	if (changed && !camel_message_info_get_abort_notifications (mi)) {
404 		g_object_notify (G_OBJECT (omi), "change-key");
405 		camel_message_info_set_dirty (mi, TRUE);
406 	}
407 
408 	return changed;
409 }
410