]> code.citadel.org Git - citadel.git/blob - webcit/messages.c
17eaeb9abbc6b3af8f2682b738c08ca5c964c41d
[citadel.git] / webcit / messages.c
1 /*
2  * $Id$
3  *
4  * Functions which deal with the fetching and displaying of messages.
5  *
6  */
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <sys/socket.h>
17 #include <limits.h>
18 #include <netinet/in.h>
19 #include <netdb.h>
20 #include <string.h>
21 #include <pwd.h>
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include "webcit.h"
27 #include "vcard.h"
28 #include "webserver.h"
29
30
31 /*
32  * Look for URL's embedded in a buffer and make them linkable.  We use a
33  * target window in order to keep the BBS session in its own window.
34  */
35 void url(buf)
36 char buf[];
37 {
38
39         int pos;
40         int start, end;
41         char ench;
42         char urlbuf[SIZ];
43         char outbuf[1024];
44
45         start = (-1);
46         end = strlen(buf);
47         ench = 0;
48
49         for (pos = 0; pos < strlen(buf); ++pos) {
50                 if (!strncasecmp(&buf[pos], "http://", 7))
51                         start = pos;
52                 if (!strncasecmp(&buf[pos], "ftp://", 6))
53                         start = pos;
54         }
55
56         if (start < 0)
57                 return;
58
59         if ((start > 0) && (buf[start - 1] == '<'))
60                 ench = '>';
61         if ((start > 0) && (buf[start - 1] == '['))
62                 ench = ']';
63         if ((start > 0) && (buf[start - 1] == '('))
64                 ench = ')';
65         if ((start > 0) && (buf[start - 1] == '{'))
66                 ench = '}';
67
68         for (pos = strlen(buf); pos > start; --pos) {
69                 if ((buf[pos] == ' ') || (buf[pos] == ench))
70                         end = pos;
71         }
72
73         strncpy(urlbuf, &buf[start], end - start);
74         urlbuf[end - start] = 0;
75
76         strncpy(outbuf, buf, start);
77         sprintf(&outbuf[start], "%cA HREF=%c%s%c TARGET=%c%s%c%c%s%c/A%c",
78                 LB, QU, urlbuf, QU, QU, TARGET, QU, RB, urlbuf, LB, RB);
79         strcat(outbuf, &buf[end]);
80         if ( strlen(outbuf) < 250 )
81                 strcpy(buf, outbuf);
82 }
83
84
85 /* display_vcard() calls this after parsing the textual vCard into
86  * our 'struct vCard' data object.
87  *
88  * Set 'full' to nonzero to display the full card, otherwise it will only
89  * show a summary line.
90  */
91 void display_parsed_vcard(struct vCard *v, int full) {
92         int i, j;
93         char buf[SIZ];
94         char *name;
95
96         if (!full) {
97                 wprintf("<TD>");
98                 name = vcard_get_prop(v, "n", 1, 0, 0);
99                 if (name != NULL) {
100                         strcpy(buf, name);
101                         escputs(buf);
102                 }
103                 else {
104                         wprintf("&nbsp;");
105                 }
106                 wprintf("</TD>");
107                 return;
108         }
109
110         wprintf("<TABLE bgcolor=#888888>");
111         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
112                 if (!strcasecmp(v->prop[i].name, "n")) {
113                         wprintf("<TR BGCOLOR=#AAAAAA>"
114                         "<TD BGCOLOR=#FFFFFF>"
115                         "<IMG ALIGN=CENTER SRC=\"/static/vcard.gif\"></TD>"
116                         "<TD><FONT SIZE=+1><B>");
117                         escputs(v->prop[i].value);
118                         wprintf("</B></FONT></TD></TR>\n");
119                 }
120                 else if (!strcasecmp(v->prop[i].name, "email;internet")) {
121                         wprintf("<TR><TD>Internet e-mail:</TD>"
122                                 "<TD><A HREF=\"mailto:");
123                         urlescputs(v->prop[i].value);
124                         wprintf("\">");
125                         escputs(v->prop[i].value);
126                         wprintf("</A></TD></TR>\n");
127                 }
128                 else if (!strcasecmp(v->prop[i].name, "adr")) {
129                         wprintf("<TR><TD>Address:</TD><TD>");
130                         for (j=0; j<num_tokens(v->prop[i].value, ';'); ++j) {
131                                 extract_token(buf, v->prop[i].value, j, ';');
132                                 if (strlen(buf) > 0) {
133                                         escputs(buf);
134                                         wprintf("<BR>");
135                                 }
136                         }
137                         wprintf("</TD></TR>\n");
138                 }
139                 else if (!strncasecmp(v->prop[i].name, "tel;", 4)) {
140                         wprintf("<TR><TD>%s telephone:</TD><TD>",
141                                 &v->prop[i].name[4]);
142                         for (j=0; j<num_tokens(v->prop[i].value, ';'); ++j) {
143                                 extract_token(buf, v->prop[i].value, j, ';');
144                                 if (strlen(buf) > 0) {
145                                         escputs(buf);
146                                         wprintf("<BR>");
147                                 }
148                         }
149                         wprintf("</TD></TR>\n");
150                 }
151                 else {
152                         wprintf("<TR><TD>");
153                         escputs(v->prop[i].name);
154                         wprintf("</TD><TD>");
155                         escputs(v->prop[i].value);
156                         wprintf("</TD></TR>\n");
157                 }
158         }
159         wprintf("</TABLE>\n");
160 }
161
162
163
164 /*
165  * Display a textual vCard
166  * (Converts to a vCard object and then calls the actual display function)
167  * Set 'full' to nonzero to display the whole card instead of a one-liner
168  */
169 void display_vcard(char *vcard_source, char alpha, int full) {
170         struct vCard *v;
171         char *name;
172         char buf[SIZ];
173         char this_alpha = 0;
174
175         v = vcard_load(vcard_source);
176         if (v == NULL) return;
177
178         name = vcard_get_prop(v, "n", 1, 0, 0);
179         if (name != NULL) {
180                 strcpy(buf, name);
181                 this_alpha = buf[0];
182         }
183
184         if ( (alpha == 0)
185            || ((isalpha(alpha)) && (tolower(alpha) == tolower(this_alpha)) )
186            || ((!isalpha(alpha)) && (!isalpha(this_alpha))) ) {
187
188                 display_parsed_vcard(v, full);
189
190         }
191
192         vcard_free(v);
193 }
194
195
196
197
198 /*
199  * I wanna SEE that message!
200  */
201 void read_message(long msgnum) {
202         char buf[SIZ];
203         char mime_partnum[SIZ];
204         char mime_filename[SIZ];
205         char mime_content_type[SIZ];
206         char mime_disposition[SIZ];
207         int mime_length;
208         char *mime_http = NULL;
209         char m_subject[SIZ];
210         char from[SIZ];
211         char node[SIZ];
212         char rfca[SIZ];
213         char reply_to[512];
214         char now[SIZ];
215         int format_type = 0;
216         int nhdr = 0;
217         int bq = 0;
218         char vcard_partnum[SIZ];
219         char cal_partnum[SIZ];
220         char *part_source = NULL;
221
222         strcpy(from, "");
223         strcpy(node, "");
224         strcpy(rfca, "");
225         strcpy(reply_to, "");
226         strcpy(vcard_partnum, "");
227         strcpy(cal_partnum, "");
228
229         serv_printf("MSG4 %ld", msgnum);
230         serv_gets(buf);
231         if (buf[0] != '1') {
232                 wprintf("<STRONG>ERROR:</STRONG> %s<BR>\n", &buf[4]);
233                 return;
234         }
235
236         wprintf("<TABLE WIDTH=100%% BORDER=0 CELLSPACING=0 "
237                 "CELLPADDING=1 BGCOLOR=CCCCCC><TR><TD>\n");
238
239         wprintf("<FONT ");
240         wprintf("SIZE=+1 ");
241         wprintf("COLOR=\"000000\"> ");
242         strcpy(m_subject, "");
243
244         while (serv_gets(buf), strcasecmp(buf, "text")) {
245                 if (!strncasecmp(buf, "nhdr=yes", 8))
246                         nhdr = 1;
247                 if (nhdr == 1)
248                         buf[0] = '_';
249                 if (!strncasecmp(buf, "type=", 5))
250                         format_type = atoi(&buf[5]);
251                 if (!strncasecmp(buf, "from=", 5)) {
252                         strcpy(from, &buf[5]);
253                         wprintf("from <A HREF=\"/showuser&who=");
254                         urlescputs(from);
255                         wprintf("\">");
256                         escputs(from);
257                         wprintf("</A> ");
258                 }
259                 if (!strncasecmp(buf, "subj=", 5))
260                         strcpy(m_subject, &buf[5]);
261                 if ((!strncasecmp(buf, "hnod=", 5))
262                     && (strcasecmp(&buf[5], serv_info.serv_humannode)))
263                         wprintf("(%s) ", &buf[5]);
264                 if ((!strncasecmp(buf, "room=", 5))
265                     && (strcasecmp(&buf[5], WC->wc_roomname))
266                     && (strlen(&buf[5])>0) )
267                         wprintf("in %s> ", &buf[5]);
268                 if (!strncasecmp(buf, "rfca=", 5)) {
269                         strcpy(rfca, &buf[5]);
270                         wprintf("&lt;");
271                         escputs(rfca);
272                         wprintf("&gt; ");
273                 }
274
275                 if (!strncasecmp(buf, "node=", 5)) {
276                         if ( ((WC->room_flags & QR_NETWORK)
277                         || ((strcasecmp(&buf[5], serv_info.serv_nodename)
278                         && (strcasecmp(&buf[5], serv_info.serv_fqdn)))))
279                         && (strlen(rfca)==0)
280                         ) {
281                                 wprintf("@%s ", &buf[5]);
282                         }
283                 }
284                 if (!strncasecmp(buf, "rcpt=", 5))
285                         wprintf("to %s ", &buf[5]);
286                 if (!strncasecmp(buf, "time=", 5)) {
287                         fmt_date(now, atol(&buf[5]));
288                         wprintf("%s ", now);
289                 }
290
291                 if (!strncasecmp(buf, "part=", 5)) {
292                         extract(mime_filename, &buf[5], 1);
293                         extract(mime_partnum, &buf[5], 2);
294                         extract(mime_disposition, &buf[5], 3);
295                         extract(mime_content_type, &buf[5], 4);
296                         mime_length = extract_int(&buf[5], 5);
297
298                         if (!strcasecmp(mime_disposition, "attachment")) {
299                                 if (mime_http == NULL) {
300                                         mime_http = malloc(512);
301                                         strcpy(mime_http, "");
302                                 }
303                                 else {
304                                         mime_http = realloc(mime_http,
305                                                 strlen(mime_http) + 512);
306                                 }
307                                 sprintf(&mime_http[strlen(mime_http)],
308                                         "<A HREF=\"/output_mimepart?"
309                                         "msgnum=%ld&partnum=%s\" "
310                                         "TARGET=\"wc.%ld.%s\">"
311                                         "<IMG SRC=\"/static/attachment.gif\" "
312                                         "BORDER=0 ALIGN=MIDDLE>\n"
313                                         "Part %s: %s (%s, %d bytes)</A><BR>\n",
314                                         msgnum, mime_partnum,
315                                         msgnum, mime_partnum,
316                                         mime_partnum, mime_filename,
317                                         mime_content_type, mime_length);
318                         }
319
320                         if ((!strcasecmp(mime_disposition, "inline"))
321                            && (!strncasecmp(mime_content_type, "image/", 6)) ){
322                                 if (mime_http == NULL) {
323                                         mime_http = malloc(512);
324                                         strcpy(mime_http, "");
325                                 }
326                                 else {
327                                         mime_http = realloc(mime_http,
328                                                 strlen(mime_http) + 512);
329                                 }
330                                 sprintf(&mime_http[strlen(mime_http)],
331                                         "<IMG SRC=\"/output_mimepart?"
332                                         "msgnum=%ld&partnum=%s\">",
333                                         msgnum, mime_partnum);
334                         }
335
336                         /*** begin handler prep ***/
337                         if (!strcasecmp(mime_content_type, "text/x-vcard")) {
338                                 strcpy(vcard_partnum, mime_partnum);
339                         }
340
341                         if (!strcasecmp(mime_content_type, "text/calendar")) {
342                                 strcpy(cal_partnum, mime_partnum);
343                         }
344
345                         /*** end handler prep ***/
346
347                 }
348
349         }
350
351
352         /* Generate a reply-to address */
353         if (strlen(rfca) > 0) {
354                 strcpy(reply_to, rfca);
355         }
356         else {
357                 if (strlen(node) > 0) {
358                         snprintf(reply_to, sizeof(reply_to), "%s @ %s",
359                                 from, node);
360                 }
361                 else {
362                         snprintf(reply_to, sizeof(reply_to), "%s", from);
363                 }
364         }
365
366         if (nhdr == 1) {
367                 wprintf("****");
368         }
369
370         wprintf("</FONT></TD>");
371
372         wprintf("<TD ALIGN=RIGHT>\n"
373                 "<TABLE BORDER=0><TR>\n");
374
375         wprintf("<TD BGCOLOR=\"AAAADD\">"
376                 "<A HREF=\"/readfwd?startmsg=%ld", msgnum);
377         wprintf("&maxmsgs=1&summary=0\">Read</A>"
378                 "</TD>\n", msgnum);
379
380         wprintf("<TD BGCOLOR=\"AAAADD\">"
381                 "<A HREF=\"/display_enter?recp=");
382         urlescputs(reply_to);
383         wprintf("\"><FONT SIZE=-1>Reply</FONT></A>"
384                 "</TD>\n", msgnum);
385
386         if (WC->is_room_aide) {
387                 wprintf("<TD BGCOLOR=\"AAAADD\">"
388                         "<A HREF=\"/confirm_move_msg"
389                         "&msgid=%ld"
390                         "\"><FONT SIZE=-1>Move</FONT></A>"
391                         "</TD>\n", msgnum);
392
393                 wprintf("<TD BGCOLOR=\"AAAADD\">"
394                         "<A HREF=\"/delete_msg"
395                         "&msgid=%ld\""
396                         "onClick=\"return confirm('Delete this message?');\""
397                         "><FONT SIZE=-1>Del</FONT></A>"
398                         "</TD>\n", msgnum);
399         }
400
401         wprintf("</TR></TABLE>\n"
402                 "</TD>\n");
403
404         if (strlen(m_subject) > 0) {
405                 wprintf("<TR><TD><FONT COLOR=\"0000FF\">"
406                         "Subject: %s</FONT>"
407                         "</TD><TD>&nbsp;</TD></TR>\n", m_subject);
408         }
409
410         wprintf("</TR></TABLE>\n");
411
412         /* 
413          * Learn the content type
414          */
415         strcpy(mime_content_type, "text/plain");
416         while (serv_gets(buf), (strlen(buf) > 0)) {
417                 if (!strncasecmp(buf, "Content-type: ", 14)) {
418                         safestrncpy(mime_content_type, &buf[14],
419                                 sizeof(mime_content_type));
420                 }
421         }
422
423         /* Messages in legacy Citadel variformat get handled thusly... */
424         if (!strcasecmp(mime_content_type, "text/x-citadel-variformat")) {
425                 fmout(NULL);
426         }
427
428         /* Boring old 80-column fixed format text gets handled this way... */
429         else if (!strcasecmp(mime_content_type, "text/plain")) {
430                 while (serv_gets(buf), strcmp(buf, "000")) {
431                         while ((strlen(buf) > 0) && (isspace(buf[strlen(buf) - 1])))
432                                 buf[strlen(buf) - 1] = 0;
433                         if ((bq == 0) &&
434                         ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) || (!strncmp(buf, " :-)", 4)))) {
435                                 wprintf("<FONT COLOR=\"000044\"><I>");
436                                 bq = 1;
437                         } else if ((bq == 1) &&
438                                 (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) && (strncmp(buf, " :-)", 4))) {
439                                 wprintf("</FONT></I>");
440                                 bq = 0;
441                         }
442                         wprintf("<TT>");
443                         url(buf);
444                         escputs(buf);
445                         wprintf("</TT><BR>\n");
446                 }
447                 wprintf("</I><BR>");
448         }
449
450         else /* HTML is fun, but we've got to strip it first */
451         if (!strcasecmp(mime_content_type, "text/html")) {
452                 output_html();
453         }
454
455         /* Unknown weirdness */
456         else {
457                 wprintf("I don't know how to display %s<BR>\n",
458                         mime_content_type);
459                 while (serv_gets(buf), strcmp(buf, "000")) { }
460         }
461
462
463         /* Afterwards, offer links to download attachments 'n' such */
464         if (mime_http != NULL) {
465                 wprintf("%s", mime_http);
466                 free(mime_http);
467         }
468
469         /* Handler for vCard parts */
470         if (strlen(vcard_partnum) > 0) {
471                 part_source = load_mimepart(msgnum, vcard_partnum);
472                 if (part_source != NULL) {
473
474                         /* If it's my vCard I can edit it */
475                         if ( (!strcasecmp(WC->wc_roomname, USERCONFIGROOM))
476                            || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))) {
477                                 wprintf("<A HREF=\"/edit_vcard?"
478                                         "msgnum=%ld&partnum=%s\">",
479                                         msgnum, vcard_partnum);
480                                 wprintf("(edit)</A>");
481                         }
482
483                         /* In all cases, display the full card */
484                         display_vcard(part_source, 0, 1);
485                 }
486         }
487
488         /* Handler for calendar parts */
489         if (strlen(cal_partnum) > 0) {
490                 part_source = load_mimepart(msgnum, cal_partnum);
491                 if (part_source != NULL) {
492                         cal_process_attachment(part_source,
493                                                 msgnum, cal_partnum);
494                 }
495         }
496
497         if (part_source) {
498                 free(part_source);
499                 part_source = NULL;
500         }
501
502 }
503
504
505 void summarize_message(long msgnum) {
506         char buf[SIZ];
507
508         struct {
509                 char date[SIZ];
510                 char from[SIZ];
511                 char to[SIZ];
512                 char subj[SIZ];
513                 int hasattachments;
514         } summ;
515
516         memset(&summ, 0, sizeof(summ));
517         strcpy(summ.subj, "(no subject)");
518
519         sprintf(buf, "MSG0 %ld|1", msgnum);     /* ask for headers only */
520         serv_puts(buf);
521         serv_gets(buf);
522         if (buf[0] != '1') return;
523
524         while (serv_gets(buf), strcmp(buf, "000")) {
525                 if (!strncasecmp(buf, "from=", 5)) {
526                         strcpy(summ.from, &buf[5]);
527                 }
528                 if (!strncasecmp(buf, "subj=", 5)) {
529                         strcpy(summ.subj, &buf[5]);
530                 }
531                 if (!strncasecmp(buf, "rfca=", 5)) {
532                         strcat(summ.from, " <");
533                         strcat(summ.from, &buf[5]);
534                         strcat(summ.from, ">");
535                 }
536
537                 if (!strncasecmp(buf, "node=", 5)) {
538                         if ( ((WC->room_flags & QR_NETWORK)
539                         || ((strcasecmp(&buf[5], serv_info.serv_nodename)
540                         && (strcasecmp(&buf[5], serv_info.serv_fqdn)))))
541                         ) {
542                                 strcat(summ.from, " @ ");
543                                 strcat(summ.from, &buf[5]);
544                         }
545                 }
546
547                 if (!strncasecmp(buf, "rcpt=", 5)) {
548                         strcpy(summ.to, &buf[5]);
549                 }
550
551                 if (!strncasecmp(buf, "time=", 5)) {
552                         fmt_date(summ.date, atol(&buf[5]));
553                 }
554         }
555
556         wprintf("<TD><A HREF=\"/readfwd?startmsg=%ld"
557                 "&maxmsgs=1&summary=0\">", 
558                 msgnum);
559         escputs(summ.subj);
560         wprintf("</A></TD><TD>");
561         escputs(summ.from);
562         wprintf(" </TD><TD>");
563         escputs(summ.date);
564         wprintf(" </TD>");
565         wprintf("<TD>"
566                 "<INPUT TYPE=\"checkbox\" NAME=\"msg_%ld\" VALUE=\"yes\">"
567                 "</TD>\n");
568
569         return;
570 }
571
572
573
574 void display_addressbook(long msgnum, char alpha) {
575         char buf[SIZ];
576         char mime_partnum[SIZ];
577         char mime_filename[SIZ];
578         char mime_content_type[SIZ];
579         char mime_disposition[SIZ];
580         int mime_length;
581         char vcard_partnum[SIZ];
582         char *vcard_source = NULL;
583
584         struct {
585                 char date[SIZ];
586                 char from[SIZ];
587                 char to[SIZ];
588                 char subj[SIZ];
589                 int hasattachments;
590         } summ;
591
592         memset(&summ, 0, sizeof(summ));
593         strcpy(summ.subj, "(no subject)");
594
595         sprintf(buf, "MSG0 %ld|1", msgnum);     /* ask for headers only */
596         serv_puts(buf);
597         serv_gets(buf);
598         if (buf[0] != '1') return;
599
600         while (serv_gets(buf), strcmp(buf, "000")) {
601                 if (!strncasecmp(buf, "part=", 5)) {
602                         extract(mime_filename, &buf[5], 1);
603                         extract(mime_partnum, &buf[5], 2);
604                         extract(mime_disposition, &buf[5], 3);
605                         extract(mime_content_type, &buf[5], 4);
606                         mime_length = extract_int(&buf[5], 5);
607
608                         if (!strcasecmp(mime_content_type, "text/x-vcard")) {
609                                 strcpy(vcard_partnum, mime_partnum);
610                         }
611
612                 }
613         }
614
615         if (strlen(vcard_partnum) > 0) {
616                 vcard_source = load_mimepart(msgnum, vcard_partnum);
617                 if (vcard_source != NULL) {
618
619                         /* Display the summary line */
620                         display_vcard(vcard_source, alpha, 0);
621
622                         /* If it's my vCard I can edit it */
623                         if ( (!strcasecmp(WC->wc_roomname, USERCONFIGROOM))
624                            || (!strcasecmp(&WC->wc_roomname[11], USERCONFIGROOM))) {
625                                 wprintf("<A HREF=\"/edit_vcard?"
626                                         "msgnum=%ld&partnum=%s\">",
627                                         msgnum, vcard_partnum);
628                                 wprintf("(edit)</A>");
629                         }
630
631                         free(vcard_source);
632                 }
633         }
634
635 }
636
637
638
639 /* 
640  * load message pointers from the server
641  */
642 int load_msg_ptrs(char *servcmd)
643 {
644         char buf[SIZ];
645         int nummsgs;
646
647         nummsgs = 0;
648         serv_puts(servcmd);
649         serv_gets(buf);
650         if (buf[0] != '1') {
651                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
652                 return (nummsgs);
653         }
654         while (serv_gets(buf), strcmp(buf, "000")) {
655                 WC->msgarr[nummsgs] = atol(buf);
656                 /* FIXME check for overflow */
657                 ++nummsgs;
658         }
659         return (nummsgs);
660 }
661
662
663 /*
664  * command loop for reading messages
665  */
666 void readloop(char *oper)
667 {
668         char cmd[SIZ];
669         char buf[SIZ];
670         int a, b, i;
671         int nummsgs;
672         long startmsg;
673         int maxmsgs;
674         int num_displayed = 0;
675         int is_summary = 0;
676         int is_addressbook = 0;
677         int is_calendar = 0;
678         int is_tasks = 0;
679         int remaining_messages;
680         int lo, hi;
681         int lowest_displayed = (-1);
682         int highest_displayed = 0;
683         long pn_previous = 0L;
684         long pn_current = 0L;
685         long pn_next = 0L;
686         int bg = 0;
687         char alpha = 0;
688
689         startmsg = atol(bstr("startmsg"));
690         maxmsgs = atoi(bstr("maxmsgs"));
691         is_summary = atoi(bstr("summary"));
692         if (maxmsgs == 0) maxmsgs = 20;
693
694         output_headers(1);
695
696         if (!strcmp(oper, "readnew")) {
697                 strcpy(cmd, "MSGS NEW");
698         } else if (!strcmp(oper, "readold")) {
699                 strcpy(cmd, "MSGS OLD");
700         } else {
701                 strcpy(cmd, "MSGS ALL");
702         }
703
704         /* FIXME put in the correct constant #defs */
705         if ((WC->wc_view == 1) && (maxmsgs > 1)) {
706                 is_summary = 1;
707                 strcpy(cmd, "MSGS ALL");
708                 maxmsgs = 32767;
709         }
710         if ((WC->wc_view == 2) && (maxmsgs > 1)) {
711                 is_addressbook = 1;
712                 strcpy(cmd, "MSGS ALL");
713                 maxmsgs = 32767;
714                 if (bstr("alpha") == NULL) {
715                         alpha = 'A';
716                 }
717                 else {
718                         strcpy(buf, bstr("alpha"));
719                         alpha = buf[0];
720                 }
721
722                 for (i='A'; i<='Z'; ++i) {
723                         if (i == alpha) wprintf("<FONT SIZE=+2>"
724                                                 "%c</FONT>\n", i);
725                         else {
726                                 wprintf("<A HREF=\"/readfwd?alpha=%c\">"
727                                         "%c</A>\n", i, i);
728                         }
729                         wprintf("&nbsp;");
730                 }
731                 if (!isalpha(alpha)) wprintf("<FONT SIZE=+2>(other)</FONT>\n");
732                 else wprintf("<A HREF=\"/readfwd?alpha=1\">(other)</A>\n");
733                 wprintf("<HR width=100%%>\n");
734         }
735         if (WC->wc_view == 3) {         /* calendar */
736                 is_calendar = 1;
737                 strcpy(cmd, "MSGS ALL");
738                 maxmsgs = 32767;
739         }
740         if (WC->wc_view == 4) {         /* tasks */
741                 is_tasks = 1;
742                 strcpy(cmd, "MSGS ALL");
743                 maxmsgs = 32767;
744                 wprintf("<UL>");
745         }
746
747         nummsgs = load_msg_ptrs(cmd);
748         if (nummsgs == 0) {
749
750                 if ((!is_tasks) && (!is_calendar)) {
751                         if (!strcmp(oper, "readnew")) {
752                                 wprintf("<EM>No new messages in this room.</EM>\n");
753                         } else if (!strcmp(oper, "readold")) {
754                                 wprintf("<EM>No old messages in this room.</EM>\n");
755                         } else {
756                                 wprintf("<EM>This room is empty.</EM>\n");
757                         }
758                 }
759
760                 goto DONE;
761         }
762
763         if (startmsg == 0L) startmsg = WC->msgarr[0];
764         remaining_messages = 0;
765
766         for (a = 0; a < nummsgs; ++a) {
767                 if (WC->msgarr[a] >= startmsg) {
768                         ++remaining_messages;
769                 }
770         }
771
772         if (is_summary) {
773                 wprintf("<FORM METHOD=\"POST\" ACTION=\"/do_stuff_to_msgs\">\n"
774                         "<TABLE border=0 cellspacing=0 "
775                         "cellpadding=0 width=100%%>\n"
776                         "<TR>"
777                         "<TD><I>Subject</I></TD>"
778                         "<TD><I>Sender</I></TD>"
779                         "<TD><I>Date</I></TD>"
780                         "<TD></TD>"
781                         "</TR>\n"
782                 );
783         }
784
785         if (is_addressbook) {
786                 wprintf("<TABLE border=0 cellspacing=0 "
787                         "cellpadding=0 width=100%%>\n"
788                 );
789         }
790
791         for (a = 0; a < nummsgs; ++a) {
792                 if ((WC->msgarr[a] >= startmsg) && (num_displayed < maxmsgs)) {
793
794                         /* Learn which msgs "Prev" & "Next" buttons go to */
795                         pn_current = WC->msgarr[a];
796                         if (a > 0) pn_previous = WC->msgarr[a-1];
797                         if (a < (nummsgs-1)) pn_next = WC->msgarr[a+1];
798
799                         /* If a tabular view, set up the line */
800                         if ( (is_summary) || (is_addressbook) ) {
801                                 bg = 1 - bg;
802                                 wprintf("<TR BGCOLOR=%s>",
803                                         (bg ? "DDDDDD" : "FFFFFF")
804                                 );
805                         }
806
807                         /* Display the message */
808                         if (is_summary) {
809                                 summarize_message(WC->msgarr[a]);
810                         }
811                         else if (is_addressbook) {
812                                 display_addressbook(WC->msgarr[a], alpha);
813                         }
814                         else if (is_calendar) {
815                                 display_calendar(WC->msgarr[a]);
816                         }
817                         else if (is_tasks) {
818                                 display_task(WC->msgarr[a]);
819                         }
820                         else {
821                                 read_message(WC->msgarr[a]);
822                         }
823
824                         /* If a tabular view, finish the line */
825                         if ( (is_summary) || (is_addressbook) ) {
826                                 wprintf("</TR>\n");
827                         }
828
829                         if (lowest_displayed < 0) lowest_displayed = a;
830                         highest_displayed = a;
831
832                         ++num_displayed;
833                         --remaining_messages;
834                 }
835         }
836
837         if (is_summary) {
838                 wprintf("</TABLE>\n");
839         }
840
841         if (is_addressbook) {
842                 wprintf("</TABLE>\n");
843         }
844
845         if (is_tasks) {
846                 wprintf("</UL>\n");
847         }
848
849         /* Bump these because although we're thinking in zero base, the user
850          * is a drooling idiot and is thinking in one base.
851          */
852         ++lowest_displayed;
853         ++highest_displayed;
854
855         /* If we're only looking at one message, do a prev/next thing */
856         if (num_displayed == 1) {
857            if ((!is_tasks) && (!is_calendar)) {
858
859                 wprintf("<CENTER>"
860                         "<TABLE BORDER=0 WIDTH=100%% BGCOLOR=DDDDDD><TR><TD>"
861                         "Reading #%d of %d messages.</TD>\n"
862                         "<TD ALIGN=RIGHT><FONT SIZE=+1>",
863                         lowest_displayed, nummsgs);
864
865                 if (is_summary) {
866                         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" "
867                                 "VALUE=\"Delete selected\">\n");
868                 }
869
870                 if (pn_previous > 0L) {
871                         wprintf("<A HREF=\"/%s"
872                                 "?startmsg=%ld"
873                                 "&maxmsgs=1"
874                                 "&summary=0\">"
875                                 "Previous</A> \n",
876                                         oper,
877                                         pn_previous );
878                 }
879
880                 if (pn_next > 0L) {
881                         wprintf("<A HREF=\"/%s"
882                                 "?startmsg=%ld"
883                                 "&maxmsgs=1"
884                                 "&summary=0\">"
885                                 "Next</A> \n",
886                                         oper,
887                                         pn_next );
888                 }
889
890                 wprintf("<A HREF=\"/%s?startmsg=%ld"
891                         "&maxmsgs=999999&summary=1\">"
892                         "Summary"
893                         "</A>",
894                         oper,
895                         WC->msgarr[0]);
896
897                 wprintf("</TD></TR></TABLE></CENTER>\n");
898             }
899         }
900
901
902         /*
903          * If we're not currently looking at ALL requested
904          * messages, then display the selector bar
905          */
906         if (num_displayed > 1) {
907            if ((!is_tasks) && (!is_calendar)) {
908                 wprintf("<CENTER>"
909                         "<TABLE BORDER=0 WIDTH=100%% BGCOLOR=DDDDDD><TR><TD>"
910                         "Reading #%d-%d of %d messages.</TD>\n"
911                         "<TD ALIGN=RIGHT><FONT SIZE=+1>",
912                         lowest_displayed, highest_displayed, nummsgs);
913
914                 if (is_summary) {
915                         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" "
916                                 "VALUE=\"Delete selected\">\n");
917                 }
918
919
920                 for (b=0; b<nummsgs; b = b + maxmsgs) {
921                 lo = b+1;
922                 hi = b+maxmsgs+1;
923                 if (hi > nummsgs) hi = nummsgs;
924                         if (WC->msgarr[b] != startmsg) {
925                                 wprintf("<A HREF=\"/%s"
926                                         "?startmsg=%ld"
927                                         "&maxmsgs=%d"
928                                         "&summary=%d\">"
929                                         "%d-%d</A> \n",
930                                                 oper,
931                                                 WC->msgarr[b],
932                                                 maxmsgs,
933                                                 is_summary,
934                                                 lo, hi);
935                         }
936                         else {
937                                 wprintf("%d-%d \n", lo, hi);
938                         }
939
940                 }
941                 wprintf("<A HREF=\"/%s?startmsg=%ld"
942                         "&maxmsgs=999999&summary=%d\">"
943                         "ALL"
944                         "</A> ",
945                         oper,
946                         WC->msgarr[0], is_summary);
947
948                 wprintf("<A HREF=\"/%s?startmsg=%ld"
949                         "&maxmsgs=999999&summary=1\">"
950                         "Summary"
951                         "</A>",
952                         oper,
953                         WC->msgarr[0]);
954
955                 wprintf("</TD></TR></TABLE></CENTER>\n");
956             }
957         }
958         if (is_summary) wprintf("</FORM>\n");
959
960 DONE:
961         if (is_tasks) {
962                 wprintf("<A HREF=\"/display_edit_task?msgnum=0\">"
963                         "Add new task</A>\n"
964                 );
965         }
966
967         if (is_calendar) {
968                 do_calendar_view();     /* Render the calendar */
969         }
970
971         wDumpContent(1);
972 }
973
974
975
976
977 /*
978  * Post message (or don't post message)
979  *
980  * Note regarding the "dont_post" variable:
981  * A random value (actually, it's just a timestamp) is inserted as a hidden
982  * field called "postseq" when the display_enter page is generated.  This
983  * value is checked when posting, using the static variable dont_post.  If a
984  * user attempts to post twice using the same dont_post value, the message is
985  * discarded.  This prevents the accidental double-saving of the same message
986  * if the user happens to click the browser "back" button.
987  */
988 void post_message(void)
989 {
990         char buf[SIZ];
991         static long dont_post = (-1L);
992
993         output_headers(1);
994
995         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\">");
996         strcpy(buf, bstr("sc"));
997         if (strcasecmp(buf, "Save message")) {
998                 wprintf("Cancelled.  Message was not posted.<BR>\n");
999         } else if (atol(bstr("postseq")) == dont_post) {
1000                 wprintf("Automatically cancelled because you have already "
1001                         "saved this message.<BR>\n");
1002         } else {
1003                 sprintf(buf, "ENT0 1|%s|0|4|%s",
1004                         bstr("recp"),
1005                         bstr("subject") );
1006                 serv_puts(buf);
1007                 serv_gets(buf);
1008                 if (buf[0] == '4') {
1009                         serv_puts("Content-type: text/html");
1010                         serv_puts("");
1011                         text_to_server(bstr("msgtext"), 1);
1012                         serv_puts("000");
1013                         wprintf("Message has been posted.<BR>\n");
1014                         dont_post = atol(bstr("postseq"));
1015                 } else {
1016                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
1017                 }
1018         }
1019
1020         wDumpContent(1);
1021 }
1022
1023
1024
1025
1026 /*
1027  * display the message entry screen
1028  */
1029 void display_enter(void)
1030 {
1031         char buf[SIZ];
1032         long now;
1033         struct tm *tm;
1034
1035         output_headers(1);
1036
1037         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\">");
1038
1039         sprintf(buf, "ENT0 0|%s|0|0", bstr("recp"));
1040         serv_puts(buf);
1041         serv_gets(buf);
1042
1043         if (!strncmp(buf, "570", 3)) {
1044                 if (strlen(bstr("recp")) > 0) {
1045                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
1046                 }
1047                 do_template("prompt_for_recipient");
1048                 goto DONE;
1049         }
1050         if (buf[0] != '2') {
1051                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
1052                 goto DONE;
1053         }
1054
1055         now = time(NULL);
1056         tm = (struct tm *) localtime(&now);
1057         strcpy(buf, (char *) asctime(tm));
1058         buf[strlen(buf) - 1] = 0;
1059         strcpy(&buf[16], &buf[19]);
1060         wprintf("</CENTER><FONT COLOR=\"440000\">\n"
1061                 "<IMG SRC=\"static/enter.gif\" ALIGN=MIDDLE ALT=\" \" "
1062                 "onLoad=\"document.enterform.msgtext.focus();\" >");
1063         wprintf("<B> %s ", &buf[4]);
1064         wprintf("from %s ", WC->wc_username);
1065         if (strlen(bstr("recp")) > 0)
1066                 wprintf("to %s ", bstr("recp"));
1067         wprintf("in %s&gt; ", WC->wc_roomname);
1068         wprintf("</B></FONT><BR><CENTER>\n");
1069
1070         wprintf("<FORM METHOD=\"POST\" ACTION=\"/post\" "
1071                 "NAME=\"enterform\">\n");
1072         wprintf("<INPUT TYPE=\"hidden\" NAME=\"recp\" VALUE=\"%s\">\n",
1073                 bstr("recp"));
1074         wprintf("<INPUT TYPE=\"hidden\" NAME=\"postseq\" VALUE=\"%ld\">\n",
1075                 now);
1076         wprintf("<FONT SIZE=-1>Subject (optional):</FONT>"
1077                 "<INPUT TYPE=\"text\" NAME=\"subject\" MAXLENGTH=70>"
1078                 "&nbsp;&nbsp;&nbsp;"
1079                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Save message\">"
1080                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\"><BR>\n");
1081
1082         wprintf("<TEXTAREA NAME=\"msgtext\" wrap=soft ROWS=30 COLS=80 "
1083                 "WIDTH=80></TEXTAREA><P>\n");
1084
1085         wprintf("</FORM></CENTER>\n");
1086 DONE:   wDumpContent(1);
1087         wprintf("</FONT>");
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097 void delete_msg(void)
1098 {
1099         long msgid;
1100         char buf[SIZ];
1101
1102         msgid = atol(bstr("msgid"));
1103
1104         output_headers(1);
1105
1106         sprintf(buf, "DELE %ld", msgid);
1107         serv_puts(buf);
1108         serv_gets(buf);
1109         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
1110
1111         wDumpContent(1);
1112 }
1113
1114
1115
1116
1117 /*
1118  * Confirm move of a message
1119  */
1120 void confirm_move_msg(void)
1121 {
1122         long msgid;
1123         char buf[SIZ];
1124         char targ[SIZ];
1125
1126         msgid = atol(bstr("msgid"));
1127
1128         output_headers(1);
1129
1130         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=770000><TR><TD>");
1131         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
1132         wprintf("<B>Confirm move of message</B>\n");
1133         wprintf("</FONT></TD></TR></TABLE>\n");
1134
1135         wprintf("<CENTER>");
1136
1137         wprintf("Please select the room to which you would like this message moved:<BR>\n");
1138
1139         wprintf("<FORM METHOD=\"POST\" ACTION=\"/move_msg\">\n");
1140         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n",
1141                 bstr("msgid"));
1142
1143
1144         wprintf("<SELECT NAME=\"target_room\" SIZE=5>\n");
1145         serv_puts("LKRA");
1146         serv_gets(buf);
1147         if (buf[0] == '1') {
1148                 while (serv_gets(buf), strcmp(buf, "000")) {
1149                         extract(targ, buf, 0);
1150                         wprintf("<OPTION>");
1151                         escputs(targ);
1152                         wprintf("\n");
1153                 }
1154         }
1155         wprintf("</SELECT>\n");
1156         wprintf("<BR>\n");
1157
1158         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Move\">");
1159         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Cancel\">");
1160         wprintf("</FORM></CENTER>\n");
1161
1162         wprintf("</CENTER>\n");
1163         wDumpContent(1);
1164 }
1165
1166
1167
1168 void move_msg(void)
1169 {
1170         long msgid;
1171         char buf[SIZ];
1172
1173         msgid = atol(bstr("msgid"));
1174
1175         output_headers(1);
1176
1177         if (!strcasecmp(bstr("yesno"), "Move")) {
1178                 sprintf(buf, "MOVE %ld|%s", msgid, bstr("target_room"));
1179                 serv_puts(buf);
1180                 serv_gets(buf);
1181                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
1182         } else {
1183                 wprintf("<EM>Message not moved.</EM><BR>\n");
1184         }
1185
1186         wDumpContent(1);
1187 }
1188
1189
1190
1191 void do_stuff_to_msgs(void) {
1192         char buf[SIZ];
1193         char sc[SIZ];
1194
1195         struct stuff_t {
1196                 struct stuff_t *next;
1197                 long msgnum;
1198         };
1199
1200         struct stuff_t *stuff = NULL;
1201         struct stuff_t *ptr;
1202
1203
1204         serv_puts("MSGS ALL");
1205         serv_gets(buf);
1206
1207         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
1208                 ptr = malloc(sizeof(struct stuff_t));
1209                 ptr->msgnum = atol(buf);
1210                 ptr->next = stuff;
1211                 stuff = ptr;
1212         }
1213
1214         strcpy(sc, bstr("sc"));
1215
1216         while (stuff != NULL) {
1217
1218                 sprintf(buf, "msg_%ld", stuff->msgnum);
1219                 if (!strcasecmp(bstr(buf), "yes")) {
1220
1221                         if (!strcasecmp(sc, "Delete selected")) {
1222                                 serv_printf("DELE %ld", stuff->msgnum);
1223                                 serv_gets(buf);
1224                         }
1225
1226                 }
1227
1228                 ptr = stuff->next;
1229                 free(stuff);
1230                 stuff = ptr;
1231         }
1232
1233         readloop("readfwd");
1234 }