5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2004 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silcstrutil.h"
24 static unsigned char pem_enc[64] =
25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
30 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
33 SilcUInt32 bits, c, char_count;
40 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
42 for (i = 0; i < len; i++) {
47 if (char_count == 3) {
48 pem[j++] = pem_enc[bits >> 18];
49 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
50 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
51 pem[j++] = pem_enc[bits & 0x3f];
59 if (char_count != 0) {
60 bits <<= 16 - (8 * char_count);
61 pem[j++] = pem_enc[bits >> 18];
62 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
64 if (char_count == 1) {
68 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
76 /* Same as above but puts newline ('\n') every 72 characters. */
78 char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
84 pem = silc_pem_encode(data, data_len);
87 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
89 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
104 /* Decodes PEM into data. Returns the decoded data. */
106 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
110 SilcUInt32 len, c, char_count, bits;
112 static char ialpha[256], decoder[256];
114 for (i = 64 - 1; i >= 0; i--) {
115 ialpha[pem_enc[i]] = 1;
116 decoder[pem_enc[i]] = i;
128 data = silc_calloc(((len * 6) / 8), sizeof(*data));
130 for (i = 0; i < len; i++) {
136 if (c > 127 || !ialpha[c])
142 if (char_count == 4) {
143 data[j++] = bits >> 16;
144 data[j++] = (bits >> 8) & 0xff;
145 data[j++] = bits & 0xff;
159 data[j++] = bits >> 10;
162 data[j++] = bits >> 16;
163 data[j++] = (bits >> 8) & 0xff;
173 /* Mime constants and macros */
174 #define MIME_VERSION "MIME-Version: "
175 #define MIME_VERSION_LEN 14
176 #define MIME_CONTENT_TYPE "Content-Type: "
177 #define MIME_CONTENT_TYPE_LEN 14
178 #define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: "
179 #define MIME_TRANSFER_ENCODING_LEN 27
181 #define MIME_GET_FIELD(mime, mime_len, field, field_len, \
185 char *f = strstr(mime, field); \
189 parse_len = (mime_len - (f - (char *)mime)); \
190 for (i = 0; i < parse_len; i++) { \
191 if ((i == dest_size) || \
193 ((i == parse_len - 1) || \
194 ((f[i+1] != ' ') && (f[i+1] != '\t')))) || \
196 ((i == parse_len - 1) || (f[i+1] == '\n')) && \
197 ((i >= parse_len - 2) || \
198 ((f[i+2] != ' ') && (f[i+2] != '\t'))))) \
206 /* Parses MIME object and MIME header in it. */
209 silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len,
210 char *version, SilcUInt32 version_size,
211 char *content_type, SilcUInt32 content_type_size,
212 char *transfer_encoding, SilcUInt32 transfer_encoding_size,
213 unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len)
218 /* Get the pointer to the data area in the object */
219 for (i = 0; i < mime_len; i++) {
220 if ((mime_len >= i + 4 &&
221 mime[i ] == '\r' && mime[i + 1] == '\n' &&
222 mime[i + 2] == '\r' && mime[i + 3] == '\n') ||
223 (mime_len >= i + 2 &&
224 mime[i ] == '\n' && mime[i + 1] == '\n'))
231 *mime_data_ptr = (unsigned char *)mime + i +
232 (mime[i] == '\n' ? 2 : 4);
234 *mime_data_len = mime_len - (i + (mime[i] == '\n' ? 2 : 4));
236 /* Check for mandatory Content-Type field */
237 tmp = strstr(mime, MIME_CONTENT_TYPE);
238 if (!tmp || (tmp - mime) >= i)
241 /* Get MIME version, Content-Type and Transfer Encoding fields */
242 MIME_GET_FIELD(mime, mime_len,
243 MIME_VERSION, MIME_VERSION_LEN,
244 version, version_size);
245 MIME_GET_FIELD(mime, mime_len,
246 MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN,
247 content_type, content_type_size);
248 MIME_GET_FIELD(mime, mime_len,
249 MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN,
250 transfer_encoding, transfer_encoding_size);
255 /* Concatenates the `src' into `dest'. If `src_len' is more than the
256 size of the `dest' (minus NULL at the end) the `src' will be
259 char *silc_strncat(char *dest, SilcUInt32 dest_size,
260 const char *src, SilcUInt32 src_len)
264 dest[dest_size - 1] = '\0';
266 len = dest_size - 1 - strlen(dest);
269 strncat(dest, src, len);
271 strncat(dest, src, src_len);