* typedef wcsession, so we don't always need to say gcc again its a struct.
[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 HashList *ServHash = NULL;//// TODO;
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                 case 22:
96                         safestrncpy(serv_info.serv_svn_revision, buf, sizeof serv_info.serv_svn_revision);
97                         break;
98                 case 23:
99                         serv_info.serv_supports_openid = atoi(buf);
100                         break;
101                 }
102                 ++a;
103         }
104 }
105
106
107
108 /**
109  *  Read Citadel variformat text and spit it out as HTML.
110  *  align html align string
111  */
112 inline void fmout(char *align)
113 {
114         _fmout(WC->WBuf, align);
115 }
116
117 void _fmout(StrBuf *Target, char *align)
118 {
119         int intext = 0;
120         int bq = 0;
121         char buf[SIZ];
122
123         StrBufAppendPrintf(Target, "<div align=%s>\n", align);
124         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
125
126                 if ((intext == 1) && (isspace(buf[0]))) {
127                         wprintf("<br />");
128                 }
129                 intext = 1;
130
131                 /**
132                  * Quoted text should be displayed in italics and in a
133                  * different colour.  This code understands Citadel-style
134                  * " >" quotes and will convert to <BLOCKQUOTE> tags.
135                  */
136                 if ((bq == 0) && (!strncmp(buf, " >", 2))) {
137                         StrBufAppendBufPlain(Target, HKEY("<BLOCKQUOTE>"), 0);
138                         bq = 1;
139                 } else if ((bq == 1) && (strncmp(buf, " >", 2))) {
140                         StrBufAppendBufPlain(Target, HKEY("</BLOCKQUOTE>"), 0);
141                         bq = 0;
142                 }
143                 if ((bq == 1) && (!strncmp(buf, " >", 2))) {
144                         strcpy(buf, &buf[2]);
145                 }
146                 /** Activate embedded URL's */
147                 url(buf, sizeof(buf));
148
149                 escputs(buf);//// TODO: Target
150                 StrBufAppendBufPlain(Target, HKEY("\n"), 0);
151         }
152         if (bq == 1) {
153                 wprintf("</I>");
154         }
155         wprintf("</div><br />\n");
156 }
157
158 void FmOut(StrBuf *Target, char *align, StrBuf *Source)
159 {
160         const char *ptr, *pte;
161         const char *BufPtr = NULL;
162         StrBuf *Line = NewStrBuf();
163         StrBuf *Line1 = NewStrBuf();
164         StrBuf *Line2 = NewStrBuf();
165         int bn = 0;
166         int bq = 0;
167         int i, n, done = 0;
168         long len;
169         int intext = 0;
170
171         StrBufAppendPrintf(Target, "<div align=\"%s\">\n", align);
172         while ((n = StrBufSipLine(Line, Source, &BufPtr), n >= 0) && !done)
173         {
174                 done = n == 0;
175                 bq = 0;
176                 i = 0;
177                 ptr = ChrPtr(Line);
178                 len = StrLength(Line);
179                 pte = ptr + len;
180
181                 if ((intext == 1) && (isspace(*ptr))) {
182                         StrBufAppendBufPlain(Target, HKEY("<br />"), 0);
183                 }
184                 intext = 1;
185                 if (isspace(*ptr)) while ((ptr < pte) &&
186                        ((*ptr == '>') ||
187                         isspace(*ptr)))
188                 {
189                         if (*ptr == '>')
190                                 bq++;
191                         ptr ++;
192                         i++;
193                 }
194
195                 /**
196                  * Quoted text should be displayed in italics and in a
197                  * different colour.  This code understands Citadel-style
198                  * " >" quotes and will convert to <BLOCKQUOTE> tags.
199                  */
200                 if (i > 0) StrBufCutLeft(Line, i);
201                 
202
203                 for (i = bn; i < bq; i++)                               
204                         StrBufAppendBufPlain(Target, HKEY("<blockquote>"), 0);
205                 for (i = bq; i < bn; i++)                               
206                         StrBufAppendBufPlain(Target, HKEY("</blockquote>"), 0);
207                 bn = bq;
208
209                 if (StrLength(Line) == 0)
210                         continue;
211                 /** Activate embedded URL's */
212                 UrlizeText(Line1, Line, Line2);
213
214                 StrEscAppend(Target, Line1, NULL, 0, 0);
215
216                 StrBufAppendBufPlain(Target, HKEY("\n"), 0);
217         }
218         for (i = 0; i < bn; i++)                                
219                 StrBufAppendBufPlain(Target, HKEY("</blockquote>"), 0);
220         StrBufAppendBufPlain(Target, HKEY("</div><br />\n"), 0);
221         FreeStrBuf(&Line);
222         FreeStrBuf(&Line1);
223         FreeStrBuf(&Line2);
224 }
225
226
227
228
229 /**
230  *  Read Citadel variformat text and spit it out as HTML in a form
231  * suitable for embedding in another message (forward/quote).
232  * (NO LINEBREAKS ALLOWED HERE!)
233  */
234 void pullquote_fmout(void) {
235         int intext = 0;
236         int bq = 0;
237         char buf[SIZ];
238
239         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
240
241                 if ((intext == 1) && (isspace(buf[0]))) {
242                         wprintf("<br />");
243                 }
244                 intext = 1;
245
246                 /**
247                  * Quoted text should be displayed in italics and in a
248                  * different colour.  This code understands Citadel-style
249                  * " >" quotes and will convert to <BLOCKQUOTE> tags.
250                  */
251                 if ((bq == 0) && (!strncmp(buf, " >", 2))) {
252                         wprintf("<BLOCKQUOTE>");
253                         bq = 1;
254                 } else if ((bq == 1) && (strncmp(buf, " >", 2))) {
255                         wprintf("</BLOCKQUOTE>");
256                         bq = 0;
257                 }
258                 if ((bq == 1) && (!strncmp(buf, " >", 2))) {
259                         strcpy(buf, &buf[2]);
260                 }
261
262                 msgescputs(buf);
263         }
264         if (bq == 1) {
265                 wprintf("</I>");
266         }
267 }
268
269
270
271
272 /**
273  *  Transmit message text (in memory) to the server.
274  *
275  *  ptr Pointer to the message being transmitted
276  */
277 void text_to_server(char *ptr)
278 {
279         char buf[256];
280         int ch, a, pos, len;
281
282         pos = 0;
283         buf[0] = 0;
284
285         while (ptr[pos] != 0) {
286                 ch = ptr[pos++];
287                 if (ch == 10) {
288                         len = strlen(buf);
289                         while ( (isspace(buf[len - 1]))
290                                 && (buf[0] !=  '\0') 
291                                 && (buf[1] !=  '\0') )
292                                 buf[--len] = 0;
293                         serv_puts(buf);
294                         buf[0] = 0;
295                         if (ptr[pos] != 0) strcat(buf, " ");
296                 } else {
297                         a = strlen(buf);
298                         buf[a + 1] = 0;
299                         buf[a] = ch;
300                         if ((ch == 32) && (strlen(buf) > 200)) {
301                                 buf[a] = 0;
302                                 serv_puts(buf);
303                                 buf[0] = 0;
304                         }
305                         if (strlen(buf) > 250) {
306                                 serv_puts(buf);
307                                 buf[0] = 0;
308                         }
309                 }
310         }
311         serv_puts(buf);
312 }
313
314
315 /**
316  *  Transmit message text (in memory) to the server,
317  *        converting to Quoted-Printable encoding as we go.
318  *
319  *  ptr Pointer to the message being transmitted
320  */
321 void text_to_server_qp(char *ptr)
322 {
323         unsigned char ch, buf[256];
324         int pos;
325         int output_len = 0;
326
327         pos = 0;
328         buf[0] = 0;
329         output_len = 0;
330
331         while (ptr[pos] != 0) {
332                 ch = (unsigned char)(ptr[pos++]);
333
334                 if (ch == 13) {
335                         /* ignore carriage returns */
336                 }
337                 else if (ch == 10) {
338                         /* hard line break */
339                         if (output_len > 0) {
340                                 if (isspace(buf[output_len-1])) {
341                                         sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
342                                         output_len += 2;
343                                 }
344                         }
345                         buf[output_len++] = 0;
346                         serv_puts((char *)buf);
347                         output_len = 0;
348                 }
349                 else if (ch == 9) {
350                         buf[output_len++] = ch;
351                 }
352                 else if ( (ch >= 32) && (ch <= 60) ) {
353                         buf[output_len++] = ch;
354                 }
355                 else if ( (ch >= 62) && (ch <= 126) ) {
356                         buf[output_len++] = ch;
357                 }
358                 else {
359                         sprintf((char *)&buf[output_len], "=%02X", ch);
360                         output_len += 3;
361                 }
362                 
363                 if (output_len > 72) {
364                         /* soft line break */
365                         if (isspace(buf[output_len-1])) {
366                                 sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
367                                 output_len += 2;
368                         }
369                         buf[output_len++] = '=';
370                         buf[output_len++] = 0;
371                         serv_puts((char *)buf);
372                         output_len = 0;
373                 }
374         }
375
376         /* end of data - transmit anything that's left */
377         if (output_len > 0) {
378                 if (isspace(buf[output_len-1])) {
379                         sprintf((char *)&buf[output_len-1], "=%02X", buf[output_len-1]);
380                         output_len += 2;
381                 }
382                 buf[output_len++] = 0;
383                 serv_puts((char *)buf);
384                 output_len = 0;
385         }
386 }
387
388
389
390
391 /**
392  *  translate server message output to text
393  * (used for editing room info files and such)
394  */
395 void server_to_text()
396 {
397         char buf[SIZ];
398
399         int count = 0;
400
401         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
402                 if ((buf[0] == 32) && (count > 0)) {
403                         wprintf("\n");
404                 }
405                 wprintf("%s", buf);
406                 ++count;
407         }
408 }
409
410
411
412 /**
413  * Read binary data from server into memory using a series of
414  * server READ commands.
415  * \return the read content as StrBuf
416  */
417 int read_server_binary(StrBuf *Ret, size_t total_len) 
418 {
419         char buf[SIZ];
420         size_t bytes = 0;
421         size_t thisblock = 0;
422         StrBuf *Buf;
423         
424         Buf = NewStrBuf();
425         if (Ret == NULL)
426             return -1;
427
428         while (bytes < total_len) {
429                 thisblock = 4095;
430                 if ((total_len - bytes) < thisblock) {
431                         thisblock = total_len - bytes;
432                         if (thisblock == 0) {
433                                 FlushStrBuf(Ret); 
434                                 FreeStrBuf(&Buf);
435                                 return -1; 
436                         }
437                 }
438                 serv_printf("READ %d|%d", (int)bytes, (int)thisblock);
439                 if (StrBuf_ServGetln(Buf) > 0)
440                 {
441                     if (ChrPtr(Buf)[0] == '6')
442                     {
443                             StrBufCutLeft(Buf, 4); //thisblock = (size_t)atoi(&buf[4]);
444                             thisblock = StrTol(Buf);
445                             if (!WC->connected) {
446                                     FlushStrBuf(Ret); 
447                                     FreeStrBuf(&Buf); 
448                                     return -1; 
449                             }
450                             StrBuf_ServGetBLOB(Ret, thisblock);
451                             bytes += thisblock;
452                     }
453                     else {
454                             FreeStrBuf(&Buf);
455                             lprintf(3, "Error: %s\n", &buf[4]);
456                             return -1;
457                     }
458                 }
459         }
460         FreeStrBuf(&Buf);
461         return StrLength(Ret);
462 }
463
464
465 /**
466  *  Read text from server, appending to a string buffer until the
467  * usual 000 terminator is found.  Caller is responsible for freeing
468  * the returned pointer.
469  */
470 int read_server_text(StrBuf *Buf, long *nLines)
471 {
472         wcsession *WCC = WC;
473         long nRead;
474         long nTotal = 0;
475         long nlines;
476         
477         nlines = 0;
478         while ((WCC->serv_sock!=-1) &&
479                (nRead = StrBuf_ServGetln(Buf), (nRead >= 0) ))
480         {
481                 if (strcmp(ChrPtr(Buf) + nTotal, "000") != 0) {
482                         StrBufCutRight(Buf, nRead);
483                         break;
484                 }
485                 nTotal += nRead;
486                 nlines ++;
487         }
488
489         *nLines = nlines;
490         return nTotal;
491 }
492
493
494
495
496
497
498 int GetServerStatus(StrBuf *Line, long* FullState)
499 {
500         if (FullState != NULL)
501                 *FullState = StrTol(Line);
502         return ChrPtr(Line)[0] - 48;
503 }
504
505
506 void tmplput_serv_ip(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
507 {
508         StrBufAppendPrintf(Target, "%d", WC->ctdl_pid);
509 }
510
511 void tmplput_serv_nodename(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
512 {
513         StrEscAppend(Target, NULL, serv_info.serv_nodename, 0, 0);
514 }
515
516 void tmplput_serv_humannode(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
517 {
518         StrEscAppend(Target, NULL, serv_info.serv_humannode, 0, 0);
519 }
520
521 void tmplput_serv_fqdn(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
522 {
523         StrEscAppend(Target, NULL, serv_info.serv_fqdn, 0, 0);
524 }
525
526 void tmplput_serv_software(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
527 {
528         StrEscAppend(Target, NULL, serv_info.serv_software, 0, 0);
529 }
530
531 void tmplput_serv_rev_level(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
532 {
533         StrBufAppendPrintf(Target, "%d.%02d",
534                             serv_info.serv_rev_level / 100,
535                             serv_info.serv_rev_level % 100);
536 }
537 int conditional_serv_newuser_disabled(WCTemplateToken *Tokens, void *Context, int ContextType)
538 {
539         return serv_info.serv_newuser_disabled != 0;
540 }
541 int conditional_serv_supports_openid(WCTemplateToken *Tokens, void *Context, int ContextType)
542 {
543         return serv_info.serv_supports_openid != 0;
544 }
545
546 void tmplput_serv_bbs_city(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
547 {
548         StrEscAppend(Target, NULL, serv_info.serv_bbs_city, 0, 0);
549 }
550
551 void tmplput_current_user(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
552 {
553         StrEscAppend(Target, NULL, WC->wc_fullname, 0, 0);
554 }
555
556 void tmplput_current_room(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
557 {
558         StrEscAppend(Target, NULL, WC->wc_roomname, 0, 0);
559 }
560
561
562 void tmplput_mesg(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
563 {
564         int n = 0;
565         int Done = 0;
566         StrBuf *Line;
567         StrBuf *Buf;
568
569         Buf = NewStrBuf();
570         Line = NewStrBuf();
571         serv_printf("MESG %s", Tokens->Params[0]->Start);
572         StrBuf_ServGetln(Line);
573         while (!Done &&  (StrBuf_ServGetln(Line)>=0)) {
574                 if ( (StrLength(Line)==3) && 
575                     !strcmp(ChrPtr(Line), "000")) 
576                         Done = 1;
577                 else
578                 {
579                         if (n > 0)
580                                 StrBufAppendBufPlain(Buf, "\n", 1, 0);
581                         StrBufAppendBuf(Buf, Line, 0);
582                 }
583                 n++;
584         }
585         FlushStrBuf(Line);
586         FmOut(Line, "center", Buf);
587         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, Line, 1);
588         FreeStrBuf(&Buf);
589         FreeStrBuf(&Line);
590 }
591
592 void 
593 InitModule_SERVFUNC
594 (void)
595 {
596
597         RegisterConditional(HKEY("COND:SERV:OPENID"), 2, conditional_serv_supports_openid, CTX_NONE);
598         RegisterConditional(HKEY("COND:SERV:NEWU"), 2, conditional_serv_newuser_disabled, CTX_NONE);
599         RegisterNamespace("CURRENT_USER", 0, 0, tmplput_current_user, CTX_NONE);
600         RegisterNamespace("CURRENT_ROOM", 0, 0, tmplput_current_room, CTX_NONE);
601         RegisterNamespace("SERV:PID", 0, 0, tmplput_serv_ip, CTX_NONE);
602         RegisterNamespace("SERV:NODENAME", 0, 0, tmplput_serv_nodename, CTX_NONE);
603         RegisterNamespace("SERV:HUMANNODE", 0, 0, tmplput_serv_humannode, CTX_NONE);
604         RegisterNamespace("SERV:FQDN", 0, 0, tmplput_serv_fqdn, CTX_NONE);
605         RegisterNamespace("SERV:SOFTWARE", 0, 0, tmplput_serv_software, CTX_NONE);
606         RegisterNamespace("SERV:REV_LEVEL", 0, 0, tmplput_serv_rev_level, CTX_NONE);
607         RegisterNamespace("SERV:BBS_CITY", 0, 0, tmplput_serv_bbs_city, CTX_NONE);
608         RegisterNamespace("SERV:MESG", 1, 2, tmplput_mesg, CTX_NONE);
609 ///     RegisterNamespace("SERV:LDAP_SUPP", 0, 0, tmplput_serv_ldap_enabled, 0);
610 }
611
612 /*@}*/