1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2016 the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #include "claws-features.h"
22 #endif
23 
24 #ifdef ENABLE_NLS
25 #include <glib/gi18n.h>
26 #else
27 #define _(a) (a)
28 #define N_(a) (a)
29 #endif
30 
31 #include "defs.h"
32 #include "account.h"
33 #include "folder_item_prefs.h"
34 #include "prefs_account.h"
35 #include "prefs_common.h"
36 #include "alertpanel.h"
37 
38 static gint starting_config_version = 0;
39 
_version_check(gint ver)40 gboolean _version_check(gint ver)
41 {
42 	if (ver > CLAWS_CONFIG_VERSION) {
43 		gchar *msg;
44 		gchar *markup;
45 		AlertValue av;
46 
47 		markup = g_strdup_printf(
48 			"<a href=\"%s\"><span underline=\"none\">",
49 			CONFIG_VERSIONS_URI);
50 		msg = g_strdup_printf(
51 			_("Your Claws Mail configuration is from a newer "
52 			  "version than the version which you are currently "
53 			  "using.\n\n"
54 			  "This is not recommended.\n\n"
55 			  "For further information see the %sClaws Mail "
56 			  "website%s.\n\n"
57 			  "Do you want to exit now?"),
58 			  markup, "</span></a>");
59 		g_free(markup);
60 		av = alertpanel_full(_("Configuration warning"), msg,
61 					GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND,
62 					FALSE, NULL, ALERT_ERROR);
63 		g_free(msg);
64 
65 		if (av != G_ALERTDEFAULT)
66 			return FALSE; /* abort startup */
67 
68 		return TRUE; /* hic sunt dracones */
69 	}
70 
71 	return TRUE;
72 }
73 
_update_config_common(gint version)74 static void _update_config_common(gint version)
75 {
76 	debug_print("Updating config version %d to %d.\n", version, version + 1);
77 
78 	switch (version) {
79 		case 1:
80 
81 			/* The autochk_interval preference is now
82 			 * interpreted as seconds instead of minutes */
83 			prefs_common.autochk_itv *= 60;
84 
85 			break;
86 
87 		default:
88 
89 			/* NOOP */
90 
91 			break;
92 	}
93 }
94 
_update_config_account(PrefsAccount * ac_prefs,gint version)95 static void _update_config_account(PrefsAccount *ac_prefs, gint version)
96 {
97 	debug_print("Account '%s': Updating config version from %d to %d.\n",
98 			ac_prefs->account_name, version, version + 1);
99 
100 	switch (version) {
101 		case 0:
102 
103 			/* Removing A_APOP and A_RPOP from RecvProtocol enum,
104 			 * protocol numbers above A_POP3 need to be adjusted.
105 			 *
106 			 * In config_version=0:
107 			 * A_POP3 is 0,
108 			 * A_APOP is 1,
109 			 * A_RPOP is 2,
110 			 * A_IMAP and the rest are from 3 up.
111 			 * We can't use the macros, since they may change in the
112 			 * future. Numbers do not change. :) */
113 			if (ac_prefs->protocol == 1) {
114 				ac_prefs->protocol = 0;
115 			} else if (ac_prefs->protocol > 2) {
116 				/* A_IMAP and above gets bumped down by 2. */
117 				ac_prefs->protocol -= 2;
118 			}
119 
120 			break;
121 
122 		case 2:
123 
124 			/* Introducing per-account mail check intervals, and separating
125 			 * recv_at_getall from autocheck function.
126 			 *
127 			 * If recv_at_getall is TRUE, the account's autocheck will be
128 			 * enabled, following global autocheck interval.
129 			 *
130 			 * The account's own autocheck interval will be set to the
131 			 * same value as the global interval, but will not be used.
132 			 *
133 			 * recv_at_getall will remain enabled, but will only be used
134 			 * to determine whether or not to include this account for
135 			 * manual 'Get all' check. */
136 			ac_prefs->autochk_itv = prefs_common_get_prefs()->autochk_itv;
137 			ac_prefs->autochk_use_custom = FALSE;
138 			if (ac_prefs->recv_at_getall) {
139 				ac_prefs->autochk_use_default = TRUE;
140 			} else {
141 				ac_prefs->autochk_use_default = FALSE;
142 			}
143 
144 			break;
145 
146 		case 3:
147 			/* With the introduction of OAuth2 support, the APOP option
148 			 * (use_apop_auth) has been swallowed into a combobox and
149 			 * renamed */
150 			if (ac_prefs->use_apop_auth == 1) {
151 				ac_prefs->use_pop_auth = 1;
152 				ac_prefs->pop_auth_type = 1;
153 			}
154 			break;
155 		default:
156 
157 			/* NOOP */
158 
159 			break;
160 	}
161 
162 	ac_prefs->config_version = version + 1;
163 }
164 
_update_config_password_store(gint version)165 static void _update_config_password_store(gint version)
166 {
167 	debug_print("Password store: Updating config version from %d to %d.\n",
168 			version, version + 1);
169 
170 	switch (version) {
171 		/* nothing here yet */
172 
173 		default:
174 
175 			/* NOOP */
176 
177 			break;
178 	}
179 }
180 
_update_config_folderlist(gint version)181 static void _update_config_folderlist(gint version)
182 {
183 	debug_print("Folderlist: Updating config version from %d to %d.\n",
184 			version, version + 1);
185 
186 	switch (version) {
187 		/* nothing here yet */
188 
189 		default:
190 
191 			/* NOOP */
192 
193 			break;
194 	}
195 }
196 
_update_config_folder_item(FolderItem * item,gint version)197 static void _update_config_folder_item(FolderItem *item,
198 		gint version)
199 {
200 	debug_print("Updating config_version from %d to %d.\n",
201 			version, version + 1);
202 
203 	switch (version) {
204 		/* nothing here yet */
205 
206 		default:
207 
208 			/* NOOP */
209 
210 			break;
211 	}
212 }
213 
prefs_update_config_version_common()214 int prefs_update_config_version_common()
215 {
216 	gint ver = prefs_common_get_prefs()->config_version;
217 
218 	/* Store the starting version number for other components'
219 	 * migration functions. */
220 	starting_config_version = ver;
221 
222 	if (!_version_check(ver))
223 		return -1;
224 
225 	debug_print("Starting config update at config_version %d.\n", ver);
226 	if (ver == CLAWS_CONFIG_VERSION) {
227 		debug_print("No update necessary, already at latest config_version.\n");
228 		return 0; /* nothing to do */
229 	}
230 
231 	while (ver < CLAWS_CONFIG_VERSION) {
232 		_update_config_common(ver++);
233 		prefs_common_get_prefs()->config_version = ver;
234 	}
235 
236 	debug_print("Config update done.\n");
237 	return 1; /* update done */
238 }
239 
prefs_update_config_version_accounts()240 int prefs_update_config_version_accounts()
241 {
242 	GList *cur;
243 	PrefsAccount *ac_prefs;
244 
245 	for (cur = account_get_list(); cur != NULL; cur = cur->next) {
246 		ac_prefs = (PrefsAccount *)cur->data;
247 
248 		if (ac_prefs->config_version == -1) {
249 			/* There was no config_version stored in the config, let's
250 			 * assume config_version same as what clawsrc started at
251 			 * this session, to avoid breaking the configuration by
252 			 * "upgrading" it unnecessarily. */
253 			debug_print("Account '%s': config_version not saved, using one from clawsrc: %d\n", ac_prefs->account_name, starting_config_version);
254 			ac_prefs->config_version = starting_config_version;
255 		}
256 
257 		gint ver = ac_prefs->config_version;
258 
259 		debug_print("Account '%s': Starting config update at config_version %d.\n", ac_prefs->account_name, ver);
260 
261 		if (!_version_check(ver))
262 			return -1;
263 
264 		if (ver == CLAWS_CONFIG_VERSION) {
265 			debug_print("Account '%s': No update necessary, already at latest config_version.\n", ac_prefs->account_name);
266 			continue;
267 		}
268 
269 		while (ver < CLAWS_CONFIG_VERSION) {
270 			_update_config_account(ac_prefs, ver++);
271 		}
272 	}
273 
274 	debug_print("Accounts config update done.\n");
275 	return 1;
276 }
277 
prefs_update_config_version_password_store(gint from_version)278 int prefs_update_config_version_password_store(gint from_version)
279 {
280 	gint ver = from_version;
281 
282 	if (ver == -1) {
283 		/* There was no config_version stored in the config, let's assume
284 		 * config_version same as what clawsrc started at this session,
285 		 * to avoid breaking the configuration by "upgrading" it unnecessarily. */
286 		debug_print("Password store: config_version not saved, using one from clawsrc: %d\n", starting_config_version);
287 		ver = starting_config_version;
288 	}
289 
290 	debug_print("Starting config update at config_version %d.\n", ver);
291 
292 	if (!_version_check(ver))
293 		return -1;
294 
295 	if (ver == CLAWS_CONFIG_VERSION) {
296 		debug_print("No update necessary, already at latest config_version.\n");
297 		return 0; /* nothing to do */
298 	}
299 
300 	while (ver < CLAWS_CONFIG_VERSION) {
301 		_update_config_password_store(ver++);
302 	}
303 
304 	debug_print("Passwordstore config update done.\n");
305 	return 1;
306 }
307 
prefs_update_config_version_folderlist(gint from_version)308 int prefs_update_config_version_folderlist(gint from_version)
309 {
310 	gint ver = from_version;
311 
312 	if (ver == -1) {
313 		/* There was no config_version stored in the config, let's assume
314 		 * config_version same as what clawsrc started at this session,
315 		 * to avoid breaking the configuration by "upgrading" it unnecessarily. */
316 		debug_print("Folderlist: config_version not saved, using one from clawsrc: %d\n", starting_config_version);
317 		ver = starting_config_version;
318 	}
319 
320 	debug_print("Starting config_update at config_version %d,\n", ver);
321 
322 	if (!_version_check(ver))
323 		return -1;
324 
325 	if (ver == CLAWS_CONFIG_VERSION) {
326 		debug_print("No update necessary, already at latest config_version.\n");
327 		return 0; /* nothing to do */
328 	}
329 
330 	while (ver < CLAWS_CONFIG_VERSION) {
331 		_update_config_folderlist(ver++);
332 	}
333 
334 	debug_print("Folderlist config update done.\n");
335 	return 1;
336 }
337 
prefs_update_config_version_folder_item(FolderItem * item)338 int prefs_update_config_version_folder_item(FolderItem *item)
339 {
340 	gint ver;
341 	gchar *id;
342 
343 	cm_return_val_if_fail(item != NULL, 0);
344 
345 	id = folder_item_get_identifier(item);
346 
347 	if (item->prefs->config_version == -1) {
348 		/* There was no config_version stored in the config, let's assume
349 		 * config_version same as what clawsrc started at this session,
350 		 * to avoid breaking the configuration by "upgrading" it unnecessarily. */
351 		debug_print("Folder item '%s': config_version not saved, using one from clawsrc: %d\n", id, starting_config_version);
352 		item->prefs->config_version = starting_config_version;
353 	}
354 
355 	ver = item->prefs->config_version;
356 
357 	if (!_version_check(ver)) {
358 		g_free(id);
359 		return -1;
360 	}
361 
362 	if (ver == CLAWS_CONFIG_VERSION) {
363 		debug_print("Folder item '%s': No update necessary, already at latest config_version %d.\n", id, ver);
364 		g_free(id);
365 		return 0; /* nothing to do */
366 	}
367 
368 	debug_print("Folder item '%s': starting config_update at version %d.\n",
369 			id, ver);
370 	g_free(id);
371 
372 	while (ver < CLAWS_CONFIG_VERSION) {
373 		_update_config_folder_item(item, ver++);
374 	}
375 
376 	debug_print("Folder item config update done.\n");
377 	return 0;
378 }
379