f4cbe3489980626192876bca200dc46cd1dd37f2
[platform/upstream/evolution-data-server.git] / camel / providers / mbox / camel-mbox-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Various utilities for the mbox provider */
3
4 /* 
5  * Authors : 
6  *   Bertrand Guiheneuf <bertrand@helixcode.com>
7  *
8  * Copyright (C) 1999 Helix Code.
9  *
10  * This program is free software; you can redistribute it and/or 
11  * modify it under the terms of the GNU General Public License as 
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23  * USA
24  */
25
26
27 /* "xev" stands for x-evolution, which is the name of the
28  * evolution specific header where are stored informations
29  * like : 
30  *   - mail status 
31  *   - mail uid 
32  *  ...
33  *
34  *
35  * The evolution line ha10s the following format :
36  *
37  *   X-Evolution:XXXXX-X
38  *               \___/ \/
39  *          UID ---'    `- Status 
40  * 
41  * the UID is internally used as a 32 bits long integer, but only the first 24 bits are 
42  * used. The UID is coded as a string on 4 characters. Each character is a 6 bits 
43  * integer coded using the b64 alphabet. 
44  *
45  */
46
47
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <errno.h>
54 #include <string.h>
55
56
57 #include <glib.h>
58 #include "camel-mbox-utils.h"
59 #include "camel-mbox-parser.h"
60
61
62
63 static gchar b64_alphabet[64] = 
64 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
65
66
67
68 static void 
69 uid_to_string (guint32 uid, gchar string[4])
70 {
71         
72         string [0] = b64_alphabet [(uid >> 18) & 0x3f];
73         string [1] = b64_alphabet [(uid >> 12) & 0x3f];
74         string [2] = b64_alphabet [(uid >>  6) & 0x3f];
75         string [3] = b64_alphabet [(uid      ) & 0x3f];
76 }
77
78
79 static guint32
80 string_to_uid (gchar *string)
81 {
82         guint32 i;
83         
84         i = 
85                 (((string [0] >= 97) ? ( string [0] - 71 ) :
86                  ((string [0] >= 65) ? ( string [0] - 65 ) :
87                   ((string [0] >= 48) ? ( string [0] + 4 ) :
88                    ((string [0] == 43) ? 62 : 63 )))) << 18)            
89                 
90                 + (((string [1] >= 97) ? ( string [1] - 71 ) :
91                    ((string [1] >= 65) ? ( string [1] - 65 ) :
92                     ((string [1] >= 48) ? ( string [1] + 4 ) :
93                      ((string [1] == 43) ? 62 : 63 )))) << 12)
94                 
95                 
96                 + ((((string [2] >= 97) ? ( string [2] - 71 ) :
97                    ((string [2] >= 65) ? ( string [2] - 65 ) :
98                     ((string [2] >= 48) ? ( string [2] + 4 ) :
99                      ((string [2] == 43) ? 62 : 63 ))))) << 6)
100                 
101                 
102                 + (((string [3] >= 97) ? ( string [3] - 71 ) :
103                    ((string [3] >= 65) ? ( string [3] - 65 ) :
104                     ((string [3] >= 48) ? ( string [3] + 4 ) :
105                      ((string [3] == 43) ? 62 : 63 )))));
106         
107         return i;
108         
109 }
110
111
112 static gchar
113 flag_to_string (guchar status)
114 {
115         return b64_alphabet [status & 0x3f];
116 }
117
118
119 static guchar
120 string_to_flag (gchar string)
121 {       
122         return (string >= 97) ? ( string - 71 ) :
123                 ((string >= 65) ? ( string - 65 ) :
124                  ((string >= 48) ? ( string + 4 ) :
125                   ((string == 43) ? 62 : 63 )));
126 }
127
128
129
130
131
132 void 
133 camel_mbox_xev_parse_header_content (gchar header_content[6], 
134                                      guint32 *uid, 
135                                      guchar status)
136 {
137         
138         /* we assume that the first 4 characters of the header content 
139            are actually the uid stuff. If somebody messed with it ...
140            toooo bad. 
141         */
142         *uid = string_to_uid (header_content);
143         status = string_to_flag (header_content[5]);
144 }
145
146 void 
147 camel_mbox_xev_write_header_content (gchar header_content[6], 
148                                      guint32 uid, 
149                                      guchar status)
150 {
151         uid_to_string (uid, header_content);
152         header_content[5] = flag_to_string (status);
153         header_content[4] = '-';
154 }
155
156
157
158
159
160
161 static void 
162 copy_file_chunk (gint fd_src,
163                  gint fd_dest, 
164                  glong nb_bytes, 
165                  CamelException *ex)
166 {
167         gchar buffer [1000];
168         glong nb_to_read;
169         glong nb_read, v;
170         
171         
172         nb_to_read = nb_bytes;
173         while (nb_to_read > 0) {
174                 
175                 do {
176                         nb_read = read (fd_src, buffer, MIN (1000, nb_to_read));
177                 } while (nb_read == -1 && errno == EINTR);
178                 
179                 if (nb_read == -1) {
180                         camel_exception_set (ex, 
181                                              CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
182                                              "could read from the mbox file");
183                         return;
184                 }
185
186
187                 nb_to_read -= nb_read;
188
189                 do {
190                         v = write (fd_dest, buffer, nb_read);
191                 } while (v == -1 && errno == EINTR);
192
193                 if (v == -1) {
194                         camel_exception_setv (ex, 
195                                              CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
196                                              "could not write to the mbox copy file\n"
197                                               "Full error is : %s\n",
198                                               strerror (errno));
199                         return;
200                 }
201
202                 
203         }
204         
205         
206         
207 }
208
209
210 glong
211 camel_mbox_write_xev (gchar *mbox_file_name,
212                       GArray *summary_information, 
213                       glong  next_uid, 
214                       CamelException *ex)
215 {
216         gint cur_msg;
217         CamelMboxParserMessageInfo *cur_msg_info;
218         gint fd1, fd2;
219         guint bytes_to_copy = 0;
220         glong cur_pos = 0;
221         glong cur_offset = 0;
222         glong end_of_last_message;
223         glong next_free_uid;
224         gchar xev_header[20] = "X-Evolution:XXXX-X\n";
225         gchar *tmp_file_name;
226         gchar *tmp_file_name_secure;
227         gint rename_result;
228         gint unlink_result;
229         
230         tmp_file_name = g_strdup_printf ("%s__.ev_tmp", mbox_file_name);
231         tmp_file_name_secure = g_strdup_printf ("%s__.ev_tmp_secure", mbox_file_name);
232
233         fd1 = open (mbox_file_name, O_RDONLY);
234         fd2 = open (tmp_file_name, O_WRONLY | O_CREAT | O_TRUNC );
235         if (fd2 == -1) {
236                         camel_exception_setv (ex, 
237                                              CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
238                                              "could not create the temporary mbox copy file\n"
239                                               "\t%s\n"
240                                               "Full error is : %s\n",
241                                               tmp_file_name,
242                                               strerror (errno));
243                         return next_uid;
244                 }
245         
246         next_free_uid = next_uid;
247         for (cur_msg = 0; cur_msg < summary_information->len; cur_msg++) {
248                 
249                 cur_msg_info = (CamelMboxParserMessageInfo *)(summary_information->data) + cur_msg;
250                 end_of_last_message = cur_msg_info->message_position + cur_msg_info->size;
251
252                 if ( !cur_msg_info->x_evolution) {
253                         
254                         bytes_to_copy = cur_msg_info->message_position 
255                                 + cur_msg_info->end_of_headers_offset
256                                 - cur_pos;
257
258                         cur_pos = cur_msg_info->message_position 
259                                 + cur_msg_info->end_of_headers_offset;
260
261                         copy_file_chunk (fd1, fd2, bytes_to_copy, ex);
262                         if (camel_exception_get_id (ex)) {
263                                 close (fd1);
264                                 close (fd2);
265                                 goto end;
266                         }
267                         
268                         printf ("Writing the x-ev header\n");
269                         printf ("Current message number : %d\n", cur_msg);
270                         camel_mbox_xev_write_header_content (xev_header + 12, next_free_uid++, 0);
271                         write (fd2, xev_header, 19);
272                         cur_offset += 19;
273                         cur_msg_info->size += 19;
274                         cur_msg_info->x_evolution_offset = cur_msg_info->end_of_headers_offset;
275                         cur_msg_info->x_evolution = g_strdup_printf ("%.6s", xev_header + 12);
276                         cur_msg_info->end_of_headers_offset += 19;
277                 } 
278                 cur_msg_info->message_position += cur_offset;
279         }
280
281         bytes_to_copy = end_of_last_message - cur_pos;
282                 copy_file_chunk (fd1, fd2, bytes_to_copy, ex);
283
284
285         /* close the original file as well as the 
286            newly created one */
287         close (fd1);
288         close (fd2);
289         
290
291
292         /* replace the mbox file with the temporary
293            file we just created */ 
294
295         /* first rename the old mbox file to a temporary file */
296         rename_result = rename (mbox_file_name, tmp_file_name_secure);
297         if (rename_result == -1) {
298                 camel_exception_set (ex, 
299                                      CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
300                                      "could not rename the mbox file to a temporary file");
301                 goto end;
302         }
303         
304         /* then rename the newly created mbox file to the name 
305            of the original one */
306         rename_result = rename (tmp_file_name, mbox_file_name);
307         if (rename_result == -1) {
308                 camel_exception_set (ex, 
309                                      CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
310                                      "could not rename the X-Evolution fed file to the mbox file");
311                 goto end;
312         }
313
314         /* finally, remove the old renamed mbox file */
315         unlink_result = unlink (tmp_file_name_secure);
316         if (unlink_result == -1) {
317                 camel_exception_set (ex, 
318                                      CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
319                                      "could not remove the saved original mbox file");
320                 goto end;
321         }
322
323
324  end: /* free everything and return */
325         
326         g_free (tmp_file_name);
327         g_free (tmp_file_name_secure);
328         return next_free_uid;
329 }
330
331
332
333
334
335
336
337