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