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