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