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