/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* Various utilities for the mbox provider */ /* * Authors : * Bertrand Guiheneuf * * Copyright (C) 1999 Helix Code. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /* "xev" stands for x-evolution, which is the name of the * evolution specific header where are stored informations * like : * - mail status * - mail uid * ... * * * The evolution line ha10s the following format : * * X-Evolution:XXXXX-X * \___/ \/ * UID ---' `- Status * * the UID is internally used as a 32 bits long integer, but only the first 24 bits are * used. The UID is coded as a string on 4 characters. Each character is a 6 bits * integer coded using the b64 alphabet. * */ #include #include #include #include #include #include #include #include "camel-mbox-utils.h" #include "camel-mbox-parser.h" static gchar b64_alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static void uid_to_string (guint32 uid, gchar string[4]) { string [0] = b64_alphabet [(uid >> 18) & 0x3f]; string [1] = b64_alphabet [(uid >> 12) & 0x3f]; string [2] = b64_alphabet [(uid >> 6) & 0x3f]; string [3] = b64_alphabet [(uid ) & 0x3f]; } static guint32 string_to_uid (gchar *string) { guint32 i; i = (((string [0] >= 97) ? ( string [0] - 71 ) : ((string [0] >= 65) ? ( string [0] - 65 ) : ((string [0] >= 48) ? ( string [0] + 4 ) : ((string [0] == 43) ? 62 : 63 )))) << 18) + (((string [1] >= 97) ? ( string [1] - 71 ) : ((string [1] >= 65) ? ( string [1] - 65 ) : ((string [1] >= 48) ? ( string [1] + 4 ) : ((string [1] == 43) ? 62 : 63 )))) << 12) + ((((string [2] >= 97) ? ( string [2] - 71 ) : ((string [2] >= 65) ? ( string [2] - 65 ) : ((string [2] >= 48) ? ( string [2] + 4 ) : ((string [2] == 43) ? 62 : 63 ))))) << 6) + (((string [3] >= 97) ? ( string [3] - 71 ) : ((string [3] >= 65) ? ( string [3] - 65 ) : ((string [3] >= 48) ? ( string [3] + 4 ) : ((string [3] == 43) ? 62 : 63 ))))); return i; } static gchar flag_to_string (guchar status) { return b64_alphabet [status & 0x3f]; } static guchar string_to_flag (gchar string) { return (string >= 97) ? ( string - 71 ) : ((string >= 65) ? ( string - 65 ) : ((string >= 48) ? ( string + 4 ) : ((string == 43) ? 62 : 63 ))); } void camel_mbox_xev_parse_header_content (gchar header_content[6], guint32 *uid, guchar status) { /* we assume that the first 4 characters of the header content are actually the uid stuff. If somebody messed with it ... toooo bad. */ *uid = string_to_uid (header_content); status = string_to_flag (header_content[5]); } void camel_mbox_xev_write_header_content (gchar header_content[6], guint32 uid, guchar status) { uid_to_string (uid, header_content); header_content[5] = flag_to_string (status); header_content[4] = '-'; } static void copy_file_chunk (gint fd_src, gint fd_dest, glong nb_bytes, CamelException *ex) { gchar buffer [1000]; glong nb_to_read; glong nb_read, v; nb_to_read = nb_bytes; while (nb_to_read > 0) { do { nb_read = read (fd_src, buffer, MAX (1000, nb_to_read)); } while (nb_read == -1 && errno == EINTR); if (nb_read == -1) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, "could read from the mbox file"); return; } nb_to_read -= nb_read; do { v = write (fd_dest, buffer, nb_read); } while (v == -1 && errno == EINTR); if (v == -1) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, "could write to the mbox copy file"); return; } } } glong camel_mbox_write_xev (gchar *mbox_file_name, GArray *summary_information, glong next_uid, CamelException *ex) { gint cur_msg; CamelMboxParserMessageInfo *cur_msg_info; gint fd1, fd2; guint bytes_to_copy = 0; glong next_free_uid; gchar xev_header[20] = "X-Evolution:XXXX-X\n"; gchar *tmp_file_name; gchar *tmp_file_name_secure; gint rename_result; gint unlink_result; tmp_file_name = g_strdup_printf ("__%s__.ev_tmp", mbox_file_name); tmp_file_name_secure = g_strdup_printf ("__%s__.ev_tmp_secure", mbox_file_name); fd1 = open (mbox_file_name, O_RDONLY); fd2 = open (tmp_file_name, O_RDWR); next_free_uid = next_uid; for (cur_msg = 0; cur_msg < summary_information->len; cur_msg++) { cur_msg_info = (CamelMboxParserMessageInfo *)(summary_information->data) + cur_msg; if (cur_msg_info->x_evolution) { bytes_to_copy += cur_msg_info->size; } else { bytes_to_copy += cur_msg_info->end_of_headers_offset; copy_file_chunk (fd1, fd2, bytes_to_copy, ex); if (camel_exception_get_id (ex)) { close (fd1); close (fd2); goto end; } camel_mbox_xev_write_header_content (xev_header + 12, next_free_uid++, 0); write (fd2, xev_header, 19); bytes_to_copy = cur_msg_info->size - cur_msg_info->end_of_headers_offset; cur_msg_info->size += 19; cur_msg_info->x_evolution_offset = cur_msg_info->end_of_headers_offset; cur_msg_info->x_evolution = g_strdup_printf ("%.6s", xev_header + 12); cur_msg_info->end_of_headers_offset += 19; } } if (bytes_to_copy > 0) copy_file_chunk (fd1, fd2, bytes_to_copy, ex); /* close the original file as well as the newly created one */ close (fd1); close (fd2); /* replace the mbox file with the temporary file we just created */ /* first rename the old mbox file to a temporary file */ rename_result = rename (mbox_file_name, tmp_file_name_secure); if (rename_result == -1) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, "could not rename the mbox file to a temporary file"); goto end; } /* then rename the newly created mbox file to the name of the original one */ rename_result = rename (tmp_file_name, mbox_file_name); if (rename_result == -1) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, "could not rename the X-Evolution fed file to the mbox file"); goto end; } /* finally, remove the old renamed mbox file */ unlink_result = unlink (tmp_file_name_secure); if (unlink_result == -1) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, "could not remove the saved original mbox file"); goto end; } end: /* free everything and return */ g_free (tmp_file_name); g_free (tmp_file_name_secure); return next_free_uid; }