]> code.citadel.org Git - citadel.git/blob - libcitadel/lib/vnote.c
vnote.c is now (for the most part) complete.
[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 = (int) bmstrcasestr(thisline, "encoding=base64");
100                                 is_quoted_printable = (int) bmstrcasestr(thisline,
101                                                                 "encoding=quoted-printable");
102
103                                 char *semicolon_pos = strchr(thisline, ';');
104                                 if (semicolon_pos) {
105                                         *semicolon_pos = 0;
106                                 }
107
108                                 decoded_value = malloc(thisline_len);
109                                 if (is_base64) {
110                                         CtdlDecodeBase64(decoded_value,
111                                                         encoded_value,
112                                                         strlen(encoded_value));
113                                 }
114                                 else if (is_quoted_printable) {
115                                         CtdlDecodeQuotedPrintable(decoded_value,
116                                                         encoded_value,
117                                                         strlen(encoded_value));
118                                 }
119                                 else {
120                                         strcpy(decoded_value, encoded_value);
121                                 }
122
123                                 if (!strcasecmp(thisline, "UID")) {
124                                         if (v->uid) free(v->uid);
125                                         v->uid = decoded_value;
126                                 }
127                                 else if (!strcasecmp(thisline, "SUMMARY")) {
128                                         if (v->summary) free(v->summary);
129                                         v->summary = decoded_value;
130                                 }
131                                 else if ( (!strcasecmp(thisline, "NOTE"))
132                                      || (!strcasecmp(thisline, "BODY")) ) {
133                                         if (v->body) free(v->body);
134                                         v->body = decoded_value;
135                                 }
136                                 else if (!strcasecmp(thisline, "X-OUTLOOK-WIDTH")) {
137                                         v->pos_width = atoi(decoded_value);
138                                         free(decoded_value);
139                                 }
140                                 else if (!strcasecmp(thisline, "X-OUTLOOK-HEIGHT")) {
141                                         v->pos_height = atoi(decoded_value);
142                                         free(decoded_value);
143                                 }
144                                 else if (!strcasecmp(thisline, "X-OUTLOOK-LEFT")) {
145                                         v->pos_left = atoi(decoded_value);
146                                         free(decoded_value);
147                                 }
148                                 else if (!strcasecmp(thisline, "X-OUTLOOK-TOP")) {
149                                         v->pos_top = atoi(decoded_value);
150                                         free(decoded_value);
151                                 }
152                                 else if ( (!strcasecmp(thisline, "X-OUTLOOK-COLOR"))
153                                      && (strlen(decoded_value) == 7)
154                                      && (decoded_value[0] == '#') ) {
155                                         sscanf(&decoded_value[1], "%2x%2x%2x",
156                                                 &v->color_red,
157                                                 &v->color_green,
158                                                 &v->color_blue);
159                                         free(decoded_value);
160                                 }
161                                 else {
162                                         free(decoded_value);    // throw it away
163                                 }
164
165                                 /* FIXME still need to handle these:
166                                  * X-OUTLOOK-CREATE-TIME:20070611T204615Z
167                                  * REV:20070611T204621Z
168                                  */
169                         }
170                         free(thisline);
171                 }
172         }
173
174         return(v);
175 }
176
177 void vnote_free(struct vnote *v) {
178         if (!v) return;
179         if (v->magic != CTDL_VNOTE_MAGIC) return;
180
181         if (v->uid) free(v->uid);
182         if (v->summary) free(v->summary);
183         if (v->body) free(v->body);
184         
185         memset(v, 0, sizeof(struct vnote));
186         free(v);
187 }
188
189
190 /* helper function for vnote_serialize() */
191 void vnote_serialize_output_field(char *append_to, char *field, char *label) {
192
193         char *mydup;
194         int output_len = 0;
195         int is_qp = 0;
196         char *ptr = field;
197         unsigned char ch;
198         int pos = 0;
199
200         if (!append_to) return;
201         if (!field) return;
202         if (!label) return;
203
204         mydup = malloc((strlen(field) * 3) + 1);
205         if (!mydup) return;
206         strcpy(mydup, "");
207
208         while (ptr[pos] != 0) {
209                 ch = (unsigned char)(ptr[pos++]);
210
211                 if (ch == 9) {
212                         mydup[output_len++] = ch;
213                 }
214                 else if ( (ch >= 32) && (ch <= 60) ) {
215                         mydup[output_len++] = ch;
216                 }
217                 else if ( (ch >= 62) && (ch <= 126) ) {
218                         mydup[output_len++] = ch;
219                 }
220                 else {
221                         sprintf((char *)&mydup[output_len], "=%02X", ch);
222                         output_len += 3;
223                         is_qp = 1;
224                 }
225         }
226         mydup[output_len] = 0;
227
228         sprintf(&append_to[strlen(append_to)], "%s%s:%s\r\n",
229                 label,
230                 (is_qp ? ";ENCODING=QUOTED-PRINTABLE" : ""),
231                 mydup);
232         free(mydup);
233 }
234
235
236 char *vnote_serialize(struct vnote *v) {
237         char *s;
238         int bytes_needed = 0;
239
240         if (!v) return NULL;
241         if (v->magic != CTDL_VNOTE_MAGIC) return NULL;
242
243         bytes_needed = 1024;
244         if (v->summary) bytes_needed += strlen(v->summary);
245         if (v->body) bytes_needed += strlen(v->body);
246         s = malloc(bytes_needed);
247         if (!s) return NULL;
248
249         strcpy(s, "");
250         vnote_serialize_output_field(s, "vnote", "BEGIN");
251         vnote_serialize_output_field(s, "//Citadel//vNote handler library//EN", "PRODID");
252         vnote_serialize_output_field(s, "1.1", "VERSION");
253         vnote_serialize_output_field(s, "PUBLIC", "CLASS");
254         vnote_serialize_output_field(s, v->uid, "UID");
255         vnote_serialize_output_field(s, v->summary, "SUMMARY");
256         vnote_serialize_output_field(s, v->body, "BODY");
257         vnote_serialize_output_field(s, v->body, "NOTE");
258         sprintf(&s[strlen(s)], "X-OUTLOOK-COLOR:#%02X%02X%02X\r\n",
259                 v->color_red, v->color_green, v->color_blue);
260         sprintf(&s[strlen(s)], "X-OUTLOOK-LEFT:%d\r\n", v->pos_left);
261         sprintf(&s[strlen(s)], "X-OUTLOOK-TOP:%d\r\n", v->pos_top);
262         sprintf(&s[strlen(s)], "X-OUTLOOK-WIDTH:%d\r\n", v->pos_width);
263         sprintf(&s[strlen(s)], "X-OUTLOOK-HEIGHT:%d\r\n", v->pos_height);
264         vnote_serialize_output_field(s, "vnote", "END");
265         return(s);
266 }