b476ccbfa6f60cc5213a5d32d847c650bfa5d285
[citadel.git] / libcitadel / lib / vnote.c
1 /*
2  * $Id$
3  *
4  * vNote implementation for Citadel
5  *
6  * Copyright (C) 1999-2007 by the citadel.org development team.
7  * This code is freely redistributable under the terms of the GNU General
8  * Public License.  All other rights reserved.
9  */
10
11
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <signal.h>
17
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #include <ctype.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <string.h>
34 #include <libcitadel.h>
35
36
37 struct vnote *vnote_new(void) {
38         struct vnote *v;
39
40         v = (struct vnote *) malloc(sizeof(struct vnote));
41         if (v) {
42                 memset(v, 0, sizeof(struct vnote));
43                 v->magic = CTDL_VNOTE_MAGIC;
44                 v->pos_left = rand() % 256;
45                 v->pos_top = rand() % 256;
46                 v->pos_width = 200;
47                 v->pos_height = 150;
48                 v->color_red = 0xFF;
49                 v->color_green = 0xFF;
50                 v->color_blue = 0x00;
51         }
52         return v;
53 }
54
55 struct vnote *vnote_new_from_str(char *s) {
56         struct vnote *v;
57         char *ptr = s;
58         char *nexteol;
59         char *thisline;
60         int thisline_len;
61         char *encoded_value;
62         char *decoded_value;
63         int is_quoted_printable;
64         int is_base64;
65
66         v = vnote_new();
67         if (!v) return NULL;
68
69         while (*ptr) {          // keep going until we hit a null terminator
70                 thisline = NULL;
71                 nexteol = strchr(ptr, '\n');
72                 if (nexteol) {
73                         thisline = malloc((nexteol - ptr) + 2);
74                         strncpy(thisline, ptr, (nexteol-ptr));
75                         thisline_len = (nexteol-ptr);
76                         thisline[thisline_len] = 0;
77                         ptr = nexteol + 1;
78                 }
79                 else {
80                         thisline = strdup(ptr);
81                         thisline_len = strlen(thisline);
82                         ptr += thisline_len;
83                 }
84
85                 if (thisline) {
86                         if (thisline_len > 1) {
87                                 if (thisline[thisline_len - 1] == '\r') {
88                                         thisline[thisline_len - 1] = 0;
89                                         --thisline_len;
90                                 }
91                         }
92
93                         /* locate the colon separator */
94                         encoded_value = strchr(thisline, ':');
95                         if (encoded_value) {
96                                 *encoded_value++ = 0;
97
98                                 /* any qualifiers?  (look for a semicolon) */
99                                 is_base64 = bmstrcasestr(thisline, "encoding=base64") ? 1 : 0;
100                                 is_quoted_printable = bmstrcasestr(thisline, "encoding=quoted-printable") ? 1 : 0;
101
102                                 char *semicolon_pos = strchr(thisline, ';');
103                                 if (semicolon_pos) {
104                                         *semicolon_pos = 0;
105                                 }
106
107                                 decoded_value = malloc(thisline_len);
108                                 if (is_base64) {
109                                         CtdlDecodeBase64(decoded_value,
110                                                         encoded_value,
111                                                         strlen(encoded_value));
112                                 }
113                                 else if (is_quoted_printable) {
114                                         CtdlDecodeQuotedPrintable(decoded_value,
115                                                         encoded_value,
116                                                         strlen(encoded_value));
117                                 }
118                                 else {
119                                         strcpy(decoded_value, encoded_value);
120                                 }
121
122                                 if (!strcasecmp(thisline, "UID")) {
123                                         if (v->uid) free(v->uid);
124                                         v->uid = decoded_value;
125                                 }
126                                 else if (!strcasecmp(thisline, "SUMMARY")) {
127                                         if (v->summary) free(v->summary);
128                                         v->summary = decoded_value;
129                                 }
130                                 else if ( (!strcasecmp(thisline, "NOTE"))
131                                      || (!strcasecmp(thisline, "BODY")) ) {
132                                         if (v->body) free(v->body);
133                                         v->body = decoded_value;
134                                 }
135                                 else if (!strcasecmp(thisline, "X-OUTLOOK-WIDTH")) {
136                                         v->pos_width = atoi(decoded_value);
137                                         free(decoded_value);
138                                 }
139                                 else if (!strcasecmp(thisline, "X-OUTLOOK-HEIGHT")) {
140                                         v->pos_height = atoi(decoded_value);
141                                         free(decoded_value);
142                                 }
143                                 else if (!strcasecmp(thisline, "X-OUTLOOK-LEFT")) {
144                                         v->pos_left = atoi(decoded_value);
145                                         free(decoded_value);
146                                 }
147                                 else if (!strcasecmp(thisline, "X-OUTLOOK-TOP")) {
148                                         v->pos_top = atoi(decoded_value);
149                                         free(decoded_value);
150                                 }
151                                 else if ( (!strcasecmp(thisline, "X-OUTLOOK-COLOR"))
152                                      && (strlen(decoded_value) == 7)
153                                      && (decoded_value[0] == '#') ) {
154                                         sscanf(&decoded_value[1], "%2x%2x%2x",
155                                                 &v->color_red,
156                                                 &v->color_green,
157                                                 &v->color_blue);
158                                         free(decoded_value);
159                                 }
160                                 else {
161                                         free(decoded_value);    // throw it away
162                                 }
163
164                                 /* FIXME still need to handle these:
165                                  * X-OUTLOOK-CREATE-TIME:20070611T204615Z
166                                  * REV:20070611T204621Z
167                                  */
168                         }
169                         free(thisline);
170                 }
171         }
172
173         return(v);
174 }
175
176 void vnote_free(struct vnote *v) {
177         if (!v) return;
178         if (v->magic != CTDL_VNOTE_MAGIC) return;
179
180         if (v->uid) free(v->uid);
181         if (v->summary) free(v->summary);
182         if (v->body) free(v->body);
183         
184         memset(v, 0, sizeof(struct vnote));
185         free(v);
186 }
187
188
189 /* helper function for vnote_serialize() */
190 void vnote_serialize_output_field(char *append_to, char *field, char *label) {
191
192         char *mydup;
193         int output_len = 0;
194         int is_qp = 0;
195         char *ptr = field;
196         unsigned char ch;
197         int pos = 0;
198
199         if (!append_to) return;
200         if (!field) return;
201         if (!label) return;
202
203         mydup = malloc((strlen(field) * 3) + 1);
204         if (!mydup) return;
205         strcpy(mydup, "");
206
207         while (ptr[pos] != 0) {
208                 ch = (unsigned char)(ptr[pos++]);
209
210                 if (ch == 9) {
211                         mydup[output_len++] = ch;
212                 }
213                 else if ( (ch >= 32) && (ch <= 60) ) {
214                         mydup[output_len++] = ch;
215                 }
216                 else if ( (ch >= 62) && (ch <= 126) ) {
217                         mydup[output_len++] = ch;
218                 }
219                 else {
220                         sprintf((char *)&mydup[output_len], "=%02X", ch);
221                         output_len += 3;
222                         is_qp = 1;
223                 }
224         }
225         mydup[output_len] = 0;
226
227         sprintf(&append_to[strlen(append_to)], "%s%s:%s\r\n",
228                 label,
229                 (is_qp ? ";ENCODING=QUOTED-PRINTABLE" : ""),
230                 mydup);
231         free(mydup);
232 }
233
234
235 char *vnote_serialize(struct vnote *v) {
236         char *s;
237         int bytes_needed = 0;
238
239         if (!v) return NULL;
240         if (v->magic != CTDL_VNOTE_MAGIC) return NULL;
241
242         bytes_needed = 1024;
243         if (v->summary) bytes_needed += strlen(v->summary);
244         if (v->body) bytes_needed += strlen(v->body);
245         s = malloc(bytes_needed);
246         if (!s) return NULL;
247
248         strcpy(s, "");
249         vnote_serialize_output_field(s, "vnote", "BEGIN");
250         vnote_serialize_output_field(s, "//Citadel//vNote handler library//EN", "PRODID");
251         vnote_serialize_output_field(s, "1.1", "VERSION");
252         vnote_serialize_output_field(s, "PUBLIC", "CLASS");
253         vnote_serialize_output_field(s, v->uid, "UID");
254         vnote_serialize_output_field(s, v->summary, "SUMMARY");
255         vnote_serialize_output_field(s, v->body, "BODY");
256         vnote_serialize_output_field(s, v->body, "NOTE");
257         sprintf(&s[strlen(s)], "X-OUTLOOK-COLOR:#%02X%02X%02X\r\n",
258                 v->color_red, v->color_green, v->color_blue);
259         sprintf(&s[strlen(s)], "X-OUTLOOK-LEFT:%d\r\n", v->pos_left);
260         sprintf(&s[strlen(s)], "X-OUTLOOK-TOP:%d\r\n", v->pos_top);
261         sprintf(&s[strlen(s)], "X-OUTLOOK-WIDTH:%d\r\n", v->pos_width);
262         sprintf(&s[strlen(s)], "X-OUTLOOK-HEIGHT:%d\r\n", v->pos_height);
263         vnote_serialize_output_field(s, "vnote", "END");
264         return(s);
265 }