detect loops across several messages
[claws.git] / src / common / prefs.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2002 Hiroyuki Yamamoto
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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27
28 #include "prefs.h"
29 #include "utils.h"
30
31 PrefFile *prefs_read_open(const gchar *path)
32 {
33         PrefFile *pfile;
34         gchar *tmppath;
35         FILE *fp;
36
37         g_return_val_if_fail(path != NULL, NULL);
38
39         if ((fp = fopen(path, "rb")) == NULL) {
40                 FILE_OP_ERROR(tmppath, "fopen");
41                 return NULL;
42         }
43
44         pfile = g_new(PrefFile, 1);
45         pfile->fp = fp;
46         pfile->orig_fp = NULL;
47         pfile->path = g_strdup(path);
48         pfile->writing = FALSE;
49
50         return pfile;
51 }
52
53 PrefFile *prefs_write_open(const gchar *path)
54 {
55         PrefFile *pfile;
56         gchar *tmppath;
57         FILE *fp;
58
59         g_return_val_if_fail(path != NULL, NULL);
60
61         if (prefs_is_readonly(path)) {
62                 g_warning("no permission - %s\n", path);
63                 return NULL;
64         }
65
66         tmppath = g_strconcat(path, ".tmp", NULL);
67         if ((fp = fopen(tmppath, "wb")) == NULL) {
68                 FILE_OP_ERROR(tmppath, "fopen");
69                 g_free(tmppath);
70                 return NULL;
71         }
72
73         if (change_file_mode_rw(fp, tmppath) < 0)
74                 FILE_OP_ERROR(tmppath, "chmod");
75
76         g_free(tmppath);
77
78         pfile = g_new(PrefFile, 1);
79         pfile->fp = fp;
80         pfile->orig_fp = NULL;
81         pfile->path = g_strdup(path);
82         pfile->writing = TRUE;
83
84         return pfile;
85 }
86
87 gint prefs_file_close(PrefFile *pfile)
88 {
89         FILE *fp, *orig_fp;
90         gchar *path;
91         gchar *tmppath;
92         gchar *bakpath = NULL;
93         gchar buf[BUFFSIZE];
94
95         g_return_val_if_fail(pfile != NULL, -1);
96
97         fp = pfile->fp;
98         orig_fp = pfile->orig_fp;
99         path = pfile->path;
100         g_free(pfile);
101
102         if (!pfile->writing) {
103                 fclose(fp);
104                 return 0;
105         }
106
107         if (orig_fp) {
108                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
109                         /* next block */
110                         if (buf[0] == '[') {
111                                 if (fputs(buf, fp)  == EOF) {
112                                         g_warning("failed to write configuration to file\n");
113                                         fclose(orig_fp);
114                                         prefs_file_close_revert(pfile);
115                                 
116                                         return -1;
117                                 }
118                                 break;
119                         }
120                 }
121                 
122                 while (fgets(buf, sizeof(buf), orig_fp) != NULL)
123                         if (fputs(buf, fp) == EOF) {
124                                 g_warning("failed to write configuration to file\n");
125                                 fclose(orig_fp);
126                                 prefs_file_close_revert(pfile);                 
127                                 
128                                 return -1;
129                         }
130         }
131
132         tmppath = g_strconcat(path, ".tmp", NULL);
133         if (fclose(fp) == EOF) {
134                 FILE_OP_ERROR(tmppath, "fclose");
135                 unlink(tmppath);
136                 g_free(path);
137                 g_free(tmppath);
138                 return -1;
139         }
140
141         if (is_file_exist(path)) {
142                 bakpath = g_strconcat(path, ".bak", NULL);
143                 if (rename(path, bakpath) < 0) {
144                         FILE_OP_ERROR(path, "rename");
145                         unlink(tmppath);
146                         g_free(path);
147                         g_free(tmppath);
148                         g_free(bakpath);
149                         return -1;
150                 }
151         }
152
153         if (rename(tmppath, path) < 0) {
154                 FILE_OP_ERROR(tmppath, "rename");
155                 unlink(tmppath);
156                 g_free(path);
157                 g_free(tmppath);
158                 g_free(bakpath);
159                 return -1;
160         }
161
162         g_free(path);
163         g_free(tmppath);
164         g_free(bakpath);
165         return 0;
166 }
167
168 gint prefs_file_close_revert(PrefFile *pfile)
169 {
170         gchar *tmppath;
171
172         g_return_val_if_fail(pfile != NULL, -1);
173
174         if (pfile->orig_fp)
175                 fclose(pfile->orig_fp);
176         if (pfile->writing)
177                 tmppath = g_strconcat(pfile->path, ".tmp", NULL);
178         fclose(pfile->fp);
179         if (pfile->writing) {
180                 if (unlink(tmppath) < 0) FILE_OP_ERROR(tmppath, "unlink");
181                 g_free(tmppath);
182         }
183         g_free(pfile->path);
184         g_free(pfile);
185
186         return 0;
187 }
188
189 gboolean prefs_is_readonly(const gchar * path)
190 {
191         if (path == NULL)
192                 return TRUE;
193
194         return (access(path, W_OK) != 0 && access(path, F_OK) == 0);
195 }
196
197 gboolean prefs_rc_is_readonly(const gchar * rcfile)
198 {
199         gboolean result;
200         gchar * rcpath;
201
202         if (rcfile == NULL)
203                 return TRUE;
204
205         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
206         result = prefs_is_readonly(rcpath);
207         g_free(rcpath);
208
209         return result;
210 }
211
212 gint prefs_set_block_label(PrefFile *pfile, const gchar *label)
213 {
214         gchar *block_label;
215         gchar buf[BUFFSIZE];
216         
217         block_label = g_strdup_printf("[%s]", label);
218         if (!pfile->writing) {
219                 while (fgets(buf, sizeof(buf), pfile->fp) != NULL) {
220                         gint val;
221                         
222                         val = strncmp(buf, block_label, strlen(block_label));
223                         if (val == 0) {
224                                 debug_print("Found %s\n", block_label);
225                                 break;
226                         }
227                 }
228         } else {
229                 if ((pfile->orig_fp = fopen(pfile->path, "rb")) != NULL) {
230                         gboolean block_matched = FALSE;
231
232                         while (fgets(buf, sizeof(buf), pfile->orig_fp) != NULL) {
233                                 gint val;
234                                 
235                                 val = strncmp(buf, block_label, strlen(block_label));
236                                 if (val == 0) {
237                                         debug_print("Found %s\n", block_label);
238                                         block_matched = TRUE;
239                                         break;
240                                 } else {
241                                         if (fputs(buf, pfile->fp) == EOF) {
242                                                 g_warning("failed to write configuration to file\n");
243                                                 fclose(pfile->orig_fp);
244                                                 prefs_file_close_revert(pfile);
245                                                 g_free(block_label);
246                                                 
247                                                 return -1;
248                                         }
249                                 }
250                         }
251                         
252                         if (!block_matched) {
253                                 fclose(pfile->orig_fp);
254                                 pfile->orig_fp = NULL;
255                         }
256                         
257                         if (fputs(block_label, pfile->fp) == EOF ||
258                             fputc('\n', pfile->fp) == EOF) {
259                                 g_warning("failed to write configuration to file\n");
260                                 fclose(pfile->orig_fp);
261                                 prefs_file_close_revert(pfile);
262                                 g_free(block_label);
263                                                 
264                                 return -1;
265                         }
266                 }
267         }
268
269         g_free(block_label);
270
271         return 0;
272 }