/*===========================================================================* * * * sflmime.c - * * * * Copyright (c) 1991-2003 iMatix Corporation * * * * ------------------ GPL Licensed Source Code ------------------ * * iMatix makes this software available under the GNU General * * Public License (GPL) license for open source projects. For * * details of the GPL license please see www.gnu.org or read the * * file license.gpl provided in this package. * * * * 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 in the file 'license.gpl'; if * * not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * * * * You can also license this software under iMatix's General Terms * * of Business (GTB) for commercial projects. If you have not * * explicitly licensed this software under the iMatix GTB you may * * only use it under the terms of the GNU General Public License. * * * * For more information, send an email to info@imatix.com. * * -------------------------------------------------------------- * *===========================================================================*/ #include "prelude.h" /* Universal header file */ #include "sfldate.h" /* Date and time functions */ #include "sflmime.h" /* Prototypes for functions */ #include "sflprint.h" /* snprintf functions */ /* Function prototypes */ static void init_conversion_tables (void); static int find_month (char *month); /* Global variables used in this source file only */ static char *months [] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char *days [] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static byte char_to_base64 [128]; static char base64_to_char [64]; static Bool tables_initialised = FALSE; /* ---------------------------------------------------------------------[<]- Function: encode_base64 Synopsis: Encodes a source buffer in Base 64 and stores the result in the target buffer. The target buffer must be at least 1/3rd longer than the amount of data in the source buffer. The base64 data consists of portable printable characters as defined in RFC 1521. Returns the number of bytes output into the target buffer. ---------------------------------------------------------------------[>]-*/ size_t encode_base64 (const byte *source, byte *target, size_t source_size) { size_t target_size = 0; /* Length of target buffer */ int nb_block; /* Total number of blocks */ byte *p_source, /* Pointer to source buffer */ *p_target, /* Pointer to target buffer */ value; /* Value of Base64 byte */ ASSERT (source); ASSERT (target); if (source_size == 0) return (0); if (!tables_initialised) init_conversion_tables (); /* Bit positions | byte 1 | byte 2 | byte 3 | source block 87654321 87654321 87654321 -> 3 bytes of 8 bits | byte 1 | byte 2 | byte 3 | byte 4 | Encoded block 876543 218765 432187 654321 -> 4 bytes of 6 bits */ nb_block = (int) (source_size / 3); /* Check if we have a partially-filled block */ if (nb_block * 3 != (int) source_size) nb_block++; target_size = (size_t) nb_block * 4; target [target_size] = '\0'; p_source = (byte *) source; /* Point to start of buffers */ p_target = target; while (nb_block--) { /* Byte 1 */ value = *p_source >> 2; *p_target++ = base64_to_char [value]; /* Byte 2 */ value = (*p_source++ & 0x03) << 4; if ((size_t) (p_source - source) < source_size) value |= (*p_source & 0xF0) >> 4; *p_target++ = base64_to_char [value]; /* Byte 3 - pad the buffer with '=' if block not completed */ if ((size_t) (p_source - source) < source_size) { value = (*p_source++ & 0x0F) << 2; if ((size_t) (p_source - source) < source_size) value |= (*p_source & 0xC0) >> 6; *p_target++ = base64_to_char [value]; } else *p_target++ = '='; /* Byte 4 - pad the buffer with '=' if block not completed */ if ((size_t) (p_source - source) < source_size) { value = *p_source++ & 0x3F; *p_target++ = base64_to_char [value]; } else *p_target++ = '='; } return (target_size); } /* ---------------------------------------------------------------------[<]- Function: decode_base64 Synopsis: Decodes a block of Base 64 data and stores the resulting binary data in a target buffer. The target buffer must be at least 3/4 the size of the base 64 data. Returns the number of characters output into the target buffer. ---------------------------------------------------------------------[>]-*/ size_t decode_base64 (const byte *source, byte *target, size_t source_size) { size_t target_size = 0; /* Length of target buffer */ int nb_block; /* Total number of block */ byte value, /* Value of Base64 byte */ *p_source, /* Pointer in source buffer */ *p_target; /* Pointer in target buffer */ ASSERT (source); ASSERT (target); if (source_size == 0) return (0); if (!tables_initialised) init_conversion_tables (); /* Bit positions | byte 1 | byte 2 | byte 3 | byte 4 | Encoded block 654321 654321 654321 654321 -> 4 bytes of 6 bits | byte 1 | byte 2 | byte 3 | Decoded block 65432165 43216543 21654321 -> 3 bytes of 8 bits */ nb_block = source_size / 4; target_size = (size_t) nb_block * 3; target [target_size] = '\0'; p_source = (byte *) source; /* Point to start of buffers */ p_target = target; while (nb_block--) { /* Byte 1 */ *p_target = char_to_base64 [(byte) *p_source++] << 2; value = char_to_base64 [(byte) *p_source++]; *p_target++ += ((value & 0x30) >> 4); /* Byte 2 */ *p_target = ((value & 0x0F) << 4); value = char_to_base64 [(byte) *p_source++]; *p_target++ += ((value & 0x3C) >> 2); /* Byte 3 */ *p_target = (value & 0x03) << 6; value = char_to_base64 [(byte) *p_source++]; *p_target++ += value; } return (target_size); } /* ------------------------------------------------------------------------- init_conversion_tables function -- internal initialise the tables conversion for BASE64 coding -----------------------------------------------------------------------*/ static void init_conversion_tables (void) { byte value, /* Value to store in table */ offset, index; /* Index in table */ /* Reset the tables */ memset (char_to_base64, 0, sizeof (char_to_base64)); memset (base64_to_char, 0, sizeof (base64_to_char)); value = 'A'; offset = 0; for (index = 0; index < 62; index++) { if (index == 26) { value = 'a'; offset = 26; } else if (index == 52) { value = '0'; offset = 52; } base64_to_char [index] = value + index - offset; char_to_base64 [value + index - offset] = index; } base64_to_char [62] = '+'; base64_to_char [63] = '/'; char_to_base64 ['+'] = 62; char_to_base64 ['/'] = 63; tables_initialised = TRUE; } /* ---------------------------------------------------------------------[<]- Function: decode_mime_time Synopsis: Takes a MIME date and time string in various formats and converts to a date and time (both long values). Returns TRUE if it could convert the date and time okay, else returns FALSE. Accepts these formats: