libical, expat, and libsieve are now *required*.
[citadel.git] / webcit / serv_func.c
1 /*
2  * $Id$
3  */
4
5 #include "webcit.h"
6 #include "webserver.h"
7
8 struct serv_info serv_info; /**< our connection data to the server */
9
10 /*
11  * get info about the server we've connected to
12  *
13  * browser_host         the citadell we want to connect to
14  * user_agent           which browser uses our client?
15  */
16 void get_serv_info(char *browser_host, char *user_agent)
17 {
18         char buf[SIZ];
19         int a;
20
21         /** Tell the server what kind of client is connecting */
22         serv_printf("IDEN %d|%d|%d|%s|%s",
23                 DEVELOPER_ID,
24                 CLIENT_ID,
25                 CLIENT_VERSION,
26                 user_agent,
27                 browser_host
28         );
29         serv_getln(buf, sizeof buf);
30
31         /** Tell the server what kind of richtext we prefer */
32         serv_puts("MSGP text/html|text/plain");
33         serv_getln(buf, sizeof buf);
34
35         /*
36          * Tell the server that when we save a calendar event, we
37          * want invitations to be generated by the Citadel server
38          * instead of by the client.
39          */
40         serv_puts("ICAL sgi|1");
41         serv_getln(buf, sizeof buf);
42
43         /** Now ask the server to tell us a little bit about itself... */
44         serv_puts("INFO");
45         serv_getln(buf, sizeof buf);
46         if (buf[0] != '1')
47                 return;
48
49         a = 0;
50         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
51                 switch (a) {
52                 case 0:
53                         serv_info.serv_pid = atoi(buf);
54                         WC->ctdl_pid = serv_info.serv_pid;
55                         break;
56                 case 1:
57                         safestrncpy(serv_info.serv_nodename, buf, sizeof serv_info.serv_nodename);
58                         break;
59                 case 2:
60                         safestrncpy(serv_info.serv_humannode, buf, sizeof serv_info.serv_humannode);
61                         break;
62                 case 3:
63                         safestrncpy(serv_info.serv_fqdn, buf, sizeof serv_info.serv_fqdn);
64                         break;
65                 case 4:
66                         safestrncpy(serv_info.serv_software, buf, sizeof serv_info.serv_software);
67                         break;
68                 case 5:
69                         serv_info.serv_rev_level = atoi(buf);
70                         break;
71                 case 6:
72                         safestrncpy(serv_info.serv_bbs_city, buf, sizeof serv_info.serv_bbs_city);
73                         break;
74                 case 7:
75                         safestrncpy(serv_info.serv_sysadm, buf, sizeof serv_info.serv_sysadm);
76                         break;
77                 case 9:
78                         safestrncpy(serv_info.serv_moreprompt, buf, sizeof serv_info.serv_moreprompt);
79                         break;
80                 case 14:
81                         serv_info.serv_supports_ldap = atoi(buf);
82                         break;
83                 case 15:
84                         serv_info.serv_newuser_disabled = atoi(buf);
85                         break;
86                 case 16:
87                         safestrncpy(serv_info.serv_default_cal_zone, buf, sizeof serv_info.serv_default_cal_zone);
88                         break;
89                 case 20:
90                         serv_info.serv_supports_sieve = atoi(buf);
91                         break;
92                 case 21:
93                         serv_info.serv_fulltext_enabled = atoi(buf);
94                         break;
95                 }
96                 ++a;
97         }
98 }
99
100
101
102 /**
103  * \brief Read Citadel variformat text and spit it out as HTML.
104  * \param align html align string
105  */
106 void fmout(char *align)
107 {
108         int intext = 0;
109         int bq = 0;
110         char buf[SIZ];
111
112         wprintf("<div align=%s>\n", align);
113         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
114
115                 if ((intext == 1) && (isspace(buf[0]))) {
116                         wprintf("<br />");
117                 }
118                 intext = 1;
119
120                 /**
121                  * Quoted text should be displayed in italics and in a
122                  * different colour.  This code understands Citadel-style
123                  * " >" quotes and will convert to <BLOCKQUOTE> tags.
124                  */
125                 if ((bq == 0) && (!strncmp(buf, " >", 2))) {
126                         wprintf("<BLOCKQUOTE>");
127                         bq = 1;
128                 } else if ((bq == 1) && (strncmp(buf, " >", 2))) {
129                         wprintf("</BLOCKQUOTE>");
130                         bq = 0;
131                 }
132                 if ((bq == 1) && (!strncmp(buf, " >", 2))) {
133                         strcpy(buf, &buf[2]);
134                 }
135                 /** Activate embedded URL's */
136                 url(buf);
137
138                 escputs(buf);
139                 wprintf("\n");
140         }
141         if (bq == 1) {
142                 wprintf("</I>");
143         }
144         wprintf("</div><br />\n");
145 }
146
147
148
149
150 /**
151  * \brief Read Citadel variformat text and spit it out as HTML in a form
152  * suitable for embedding in another message (forward/quote).
153  * (NO LINEBREAKS ALLOWED HERE!)
154  */
155 void pullquote_fmout(void) {
156         int intext = 0;
157         int bq = 0;
158         char buf[SIZ];
159
160         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
161
162                 if ((intext == 1) && (isspace(buf[0]))) {
163                         wprintf("<br />");
164                 }
165                 intext = 1;
166
167                 /**
168                  * Quoted text should be displayed in italics and in a
169                  * different colour.  This code understands Citadel-style
170                  * " >" quotes and will convert to <BLOCKQUOTE> tags.
171                  */
172                 if ((bq == 0) && (!strncmp(buf, " >", 2))) {
173                         wprintf("<BLOCKQUOTE>");
174                         bq = 1;
175                 } else if ((bq == 1) && (strncmp(buf, " >", 2))) {
176                         wprintf("</BLOCKQUOTE>");
177                         bq = 0;
178                 }
179                 if ((bq == 1) && (!strncmp(buf, " >", 2))) {
180                         strcpy(buf, &buf[2]);
181                 }
182
183                 msgescputs(buf);
184         }
185         if (bq == 1) {
186                 wprintf("</I>");
187         }
188 }
189
190
191
192
193 /**
194  * \brief Transmit message text (in memory) to the server.
195  *
196  * \param ptr Pointer to the message being transmitted
197  */
198 void text_to_server(char *ptr)
199 {
200         char buf[256];
201         int ch, a, pos, len;
202
203         pos = 0;
204         buf[0] = 0;
205
206         while (ptr[pos] != 0) {
207                 ch = ptr[pos++];
208                 if (ch == 10) {
209                         len = strlen(buf);
210                         while ( (isspace(buf[len - 1]))
211                                 && (buf[0] !=  '\0') 
212                                 && (buf[1] !=  '\0') )
213                                 buf[--len] = 0;
214                         serv_puts(buf);
215                         buf[0] = 0;
216                         if (ptr[pos] != 0) strcat(buf, " ");
217                 } else {
218                         a = strlen(buf);
219                         buf[a + 1] = 0;
220                         buf[a] = ch;
221                         if ((ch == 32) && (strlen(buf) > 200)) {
222                                 buf[a] = 0;
223                                 serv_puts(buf);
224                                 buf[0] = 0;
225                         }
226                         if (strlen(buf) > 250) {
227                                 serv_puts(buf);
228                                 buf[0] = 0;
229                         }
230                 }
231         }
232         serv_puts(buf);
233 }
234
235
236 /**
237  * \brief Transmit message text (in memory) to the server,
238  *        converting to Quoted-Printable encoding as we go.
239  *
240  * \param ptr Pointer to the message being transmitted
241  */
242 void text_to_server_qp(char *ptr)
243 {
244         unsigned char ch, buf[256];
245         int pos;
246         int output_len = 0;
247
248         pos = 0;
249         buf[0] = 0;
250         output_len = 0;
251
252         while (ptr[pos] != 0) {
253                 ch = (unsigned char)(ptr[pos++]);
254
255                 if (ch == 13) {
256                         /* ignore carriage returns */
257                 }
258                 else if (ch == 10) {
259                         /* hard line break */
260                         if (output_len > 0) {
261                                 if (isspace(buf[output_len-1])) {
262                                         sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
263                                         output_len += 2;
264                                 }
265                         }
266                         buf[output_len++] = 0;
267                         serv_puts((char *)buf);
268                         output_len = 0;
269                 }
270                 else if (ch == 9) {
271                         buf[output_len++] = ch;
272                 }
273                 else if ( (ch >= 32) && (ch <= 60) ) {
274                         buf[output_len++] = ch;
275                 }
276                 else if ( (ch >= 62) && (ch <= 126) ) {
277                         buf[output_len++] = ch;
278                 }
279                 else {
280                         sprintf((char *)&buf[output_len], "=%02X", ch);
281                         output_len += 3;
282                 }
283                 
284                 if (output_len > 72) {
285                         /* soft line break */
286                         if (isspace(buf[output_len-1])) {
287                                 sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
288                                 output_len += 2;
289                         }
290                         buf[output_len++] = '=';
291                         buf[output_len++] = 0;
292                         serv_puts((char *)buf);
293                         output_len = 0;
294                 }
295         }
296
297         /* end of data - transmit anything that's left */
298         if (output_len > 0) {
299                 if (isspace(buf[output_len-1])) {
300                         sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
301                         output_len += 2;
302                 }
303                 buf[output_len++] = 0;
304                 serv_puts((char *)buf);
305                 output_len = 0;
306         }
307 }
308
309
310
311
312 /**
313  * \brief translate server message output to text
314  * (used for editing room info files and such)
315  */
316 void server_to_text()
317 {
318         char buf[SIZ];
319
320         int count = 0;
321
322         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
323                 if ((buf[0] == 32) && (count > 0)) {
324                         wprintf("\n");
325                 }
326                 wprintf("%s", buf);
327                 ++count;
328         }
329 }
330
331
332
333 /**
334  * Read binary data from server into memory using a series of
335  * server READ commands.
336  * \param buffer the output buffer
337  * \param total_len the maximal length of buffer
338  */
339 void read_server_binary(char *buffer, size_t total_len) {
340         char buf[SIZ];
341         size_t bytes = 0;
342         size_t thisblock = 0;
343
344         memset(buffer, 0, total_len);
345         while (bytes < total_len) {
346                 thisblock = 4095;
347                 if ((total_len - bytes) < thisblock) {
348                         thisblock = total_len - bytes;
349                         if (thisblock == 0) return;
350                 }
351                 serv_printf("READ %d|%d", (int)bytes, (int)thisblock);
352                 serv_getln(buf, sizeof buf);
353                 if (buf[0] == '6') {
354                         thisblock = (size_t)atoi(&buf[4]);
355                         if (!WC->connected) return;
356                         serv_read(&buffer[bytes], thisblock);
357                         bytes += thisblock;
358                 }
359                 else {
360                         lprintf(3, "Error: %s\n", &buf[4]);
361                         return;
362                 }
363         }
364 }
365
366
367 /**
368  * \brief Read text from server, appending to a string buffer until the
369  * usual 000 terminator is found.  Caller is responsible for freeing
370  * the returned pointer.
371  */
372 char *read_server_text(void) {
373         char *text = NULL;
374         size_t bytes_allocated = 0;
375         size_t bytes_read = 0;
376         int linelen;
377         char buf[SIZ];
378
379         text = malloc(SIZ);
380         if (text == NULL) {
381                 return(NULL);
382         }
383         text[0] = 0;
384         bytes_allocated = SIZ;
385
386         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
387                 linelen = strlen(buf);
388                 buf[linelen] = '\n';
389                 buf[linelen+1] = 0;
390                 ++linelen;
391
392                 if ((bytes_read + linelen) >= (bytes_allocated - 2)) {
393                         bytes_allocated = 2 * bytes_allocated;
394                         text = realloc(text, bytes_allocated);
395                 }
396
397                 strcpy(&text[bytes_read], buf);
398                 bytes_read += linelen;
399         }
400
401         return(text);
402 }
403
404
405
406 /*@}*/