* Rewrote the HTTP engine and application coupling to run in a worker thread
[citadel.git] / webcit / messages.c
1
2
3
4
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <sys/socket.h>
14 #include <sys/time.h>
15 #include <limits.h>
16 #include <netinet/in.h>
17 #include <netdb.h>
18 #include <string.h>
19 #include <pwd.h>
20 #include <errno.h>
21 #include <stdarg.h>
22 #include <pthread.h>
23 #include <signal.h>
24 #include "webcit.h"
25
26
27
28
29
30 char reply_to[512];
31 long msgarr[1024];
32
33 /*
34  * Look for URL's embedded in a buffer and make them linkable.  We use a
35  * target window in order to keep the BBS session in its own window.
36  */
37 void url(buf)
38 char buf[];
39 {
40
41         int pos;
42         int start, end;
43         char ench;
44         char urlbuf[256];
45         char outbuf[1024];
46
47         start = (-1);
48         end = strlen(buf);
49         ench = 0;
50
51         for (pos = 0; pos < strlen(buf); ++pos) {
52                 if (!strncasecmp(&buf[pos], "http://", 7))
53                         start = pos;
54                 if (!strncasecmp(&buf[pos], "ftp://", 6))
55                         start = pos;
56         }
57
58         if (start < 0)
59                 return;
60
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         if ((start > 0) && (buf[start - 1] == '{'))
68                 ench = '}';
69
70         for (pos = strlen(buf); pos > start; --pos) {
71                 if ((buf[pos] == ' ') || (buf[pos] == ench))
72                         end = pos;
73         }
74
75         strncpy(urlbuf, &buf[start], end - start);
76         urlbuf[end - start] = 0;
77
78
79         strncpy(outbuf, buf, start);
80         sprintf(&outbuf[start], "%cA HREF=%c%s%c TARGET=%c%s%c%c%s%c/A%c",
81                 LB, QU, urlbuf, QU, QU, TARGET, QU, RB, urlbuf, LB, RB);
82         strcat(outbuf, &buf[end]);
83         if ( strlen(outbuf) < 250 )
84                 strcpy(buf, outbuf);
85 }
86
87
88 void read_message(msgnum, oper)
89 long msgnum;
90 char *oper;
91 {
92         char buf[256];
93         char m_subject[256];
94         char from[256];
95         long now;
96         struct tm *tm;
97         int format_type = 0;
98         int nhdr = 0;
99         int bq = 0;
100
101         sprintf(buf, "MSG0 %ld", msgnum);
102         serv_puts(buf);
103         serv_gets(buf);
104         if (buf[0] != '1') {
105                 wprintf("<STRONG>ERROR:</STRONG> %s<BR>\n", &buf[4]);
106                 return;
107         }
108         wprintf("<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 CELLPADDING=0 BGCOLOR=000077><TR><TD>\n");
109         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\" SIZE=+1 COLOR=\"FFFF00\"> ");
110         strcpy(m_subject, "");
111
112         strcpy(reply_to, "nobody...xxxxx");
113         while (serv_gets(buf), strncasecmp(buf, "text", 4)) {
114                 if (!strncasecmp(buf, "nhdr=yes", 8))
115                         nhdr = 1;
116                 if (nhdr == 1)
117                         buf[0] = '_';
118                 if (!strncasecmp(buf, "type=", 5))
119                         format_type = atoi(&buf[5]);
120                 if (!strncasecmp(buf, "from=", 5)) {
121                         wprintf("from %s ", &buf[5]);
122                         strcpy(from, &buf[5]);
123                 }
124                 if (!strncasecmp(buf, "path=", 5))
125                         strcpy(reply_to, &buf[5]);
126                 if (!strncasecmp(buf, "subj=", 5))
127                         strcpy(m_subject, &buf[5]);
128                 if ((!strncasecmp(buf, "hnod=", 5))
129                     && (strcasecmp(&buf[5], serv_info.serv_humannode)))
130                         wprintf("(%s) ", &buf[5]);
131                 if ((!strncasecmp(buf, "room=", 5))
132                     && (strcasecmp(&buf[5], WC->wc_roomname)))
133                         wprintf("in %s> ", &buf[5]);
134
135                 if (!strncasecmp(buf, "node=", 5)) {
136                         if ((WC->room_flags & QR_NETWORK)
137                         || ((strcasecmp(&buf[5], serv_info.serv_nodename)
138                         && (strcasecmp(&buf[5], serv_info.serv_fqdn))))) {
139                                 wprintf("@%s ", &buf[5]);
140                         }
141                         if ((!strcasecmp(&buf[5], serv_info.serv_nodename))
142                         || (!strcasecmp(&buf[5], serv_info.serv_fqdn))) {
143                                 strcpy(reply_to, from);
144                         } else if (haschar(&buf[5], '.') == 0) {
145                                 sprintf(reply_to, "%s @ %s", from, &buf[5]);
146                         }
147                 }
148                 if (!strncasecmp(buf, "rcpt=", 5))
149                         wprintf("to %s ", &buf[5]);
150                 if (!strncasecmp(buf, "time=", 5)) {
151                         now = atol(&buf[5]);
152                         tm = (struct tm *) localtime(&now);
153                         strcpy(buf, (char *) asctime(tm));
154                         buf[strlen(buf) - 1] = 0;
155                         strcpy(&buf[16], &buf[19]);
156                         wprintf("%s ", &buf[4]);
157                 }
158         }
159
160         if (nhdr == 1)
161                 wprintf("****");
162         wprintf("</FONT></TD>");
163
164         if (WC->is_room_aide) {
165                 wprintf("<TD ALIGN=RIGHT NOWRAP><FONT FACE=\"Arial,Helvetica,sans-serif\" COLOR=\"FFFF00\"><B>");
166
167                 wprintf("<A HREF=\"/confirm_move_msg");
168                 wprintf("&msgid=%ld", msgnum);
169                 wprintf("\">Move</A>");
170
171                 wprintf("&nbsp;&nbsp;");
172
173                 wprintf("<A HREF=\"/confirm_delete_msg");
174                 wprintf("&msgid=%ld", msgnum);
175                 wprintf("\">Del</A>");
176
177                 wprintf("</B></FONT></TD>");
178         }
179         wprintf("</TR></TABLE>\n");
180
181         if (strlen(m_subject) > 0) {
182                 wprintf("Subject: %s<BR>\n", m_subject);
183         }
184         if (format_type == 0) {
185                 fmout(NULL);
186         } else {
187                 while (serv_gets(buf), strcmp(buf, "000")) {
188                         while ((strlen(buf) > 0) && (isspace(buf[strlen(buf) - 1])))
189                                 buf[strlen(buf) - 1] = 0;
190                         if ((bq == 0) &&
191                             ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) || (!strncmp(buf, " :-)", 4)))) {
192                                 wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\" COLOR=\"000044\"><I>");
193                                 bq = 1;
194                         } else if ((bq == 1) &&
195                                    (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) && (strncmp(buf, " :-)", 4))) {
196                                 wprintf("</FONT></I>");
197                                 bq = 0;
198                         }
199                         wprintf("<TT>");
200                         url(buf);
201                         escputs(buf);
202                         wprintf("</TT><BR>\n");
203                 }
204         }
205         wprintf("</I><BR>");
206 }
207
208
209
210 /* 
211  * load message pointers from the server
212  */
213 int load_msg_ptrs(servcmd)
214 char *servcmd;
215 {
216         char buf[256];
217         int nummsgs;
218
219         nummsgs = 0;
220         serv_puts(servcmd);
221         serv_gets(buf);
222         if (buf[0] != '1') {
223                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
224                 return (nummsgs);
225         }
226         while (serv_gets(buf), strcmp(buf, "000")) {
227                 msgarr[nummsgs] = atol(buf);
228                 ++nummsgs;
229         }
230         return (nummsgs);
231 }
232
233
234 /*
235  * command loop for reading messages
236  */
237 void readloop(char *oper)
238 {
239         char cmd[256];
240         int a;
241         int nummsgs;
242
243         wprintf("HTTP/1.0 200 OK\n");
244         output_headers(1);
245
246         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\"><CENTER><B>%s - ", WC->wc_roomname);
247         if (!strcmp(oper, "readnew")) {
248                 strcpy(cmd, "MSGS NEW");
249                 wprintf("new messages");
250         } else if (!strcmp(oper, "readold")) {
251                 strcpy(cmd, "MSGS OLD");
252                 wprintf("old messages");
253         } else {
254                 strcpy(cmd, "MSGS ALL");
255                 wprintf("all messages");
256         }
257         wprintf("</B></CENTER><BR>\n");
258
259         nummsgs = load_msg_ptrs(cmd);
260         if (nummsgs == 0) {
261                 if (!strcmp(oper, "readnew")) {
262                         wprintf("<EM>No new messages in this room.</EM>\n");
263                 } else if (!strcmp(oper, "readold")) {
264                         wprintf("<EM>No old messages in this room.</EM>\n");
265                 } else {
266                         wprintf("<EM>This room is empty.</EM>\n");
267                 }
268                 goto DONE;
269         }
270         for (a = 0; a < nummsgs; ++a) {
271                 read_message(msgarr[a], oper);
272         }
273
274       DONE:wDumpContent(1);
275 }
276
277
278
279
280 /*
281  * Post message (or don't post message)
282  *
283  * Note regarding the "dont_post" variable:
284  * A random value (actually, it's just a timestamp) is inserted as a hidden
285  * field called "postseq" when the display_enter page is generated.  This
286  * value is checked when posting, using the static variable dont_post.  If a
287  * user attempts to post twice using the same dont_post value, the message is
288  * discarded.  This prevents the accidental double-saving of the same message
289  * if the user happens to click the browser "back" button.
290  */
291 void post_message(void)
292 {
293         char buf[256];
294         static long dont_post = (-1L);
295
296         wprintf("HTTP/1.0 200 OK\n");
297         output_headers(1);
298
299         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\">");
300         strcpy(buf, bstr("sc"));
301         if (strcasecmp(buf, "Save message")) {
302                 wprintf("Cancelled.  Message was not posted.<BR>\n");
303         } else if (atol(bstr("postseq")) == dont_post) {
304                 wprintf("Automatically cancelled because you have already "
305                         "saved this message.<BR>\n");
306         } else {
307                 sprintf(buf, "ENT0 1|%s|0|0", bstr("recp"));
308                 serv_puts(buf);
309                 serv_gets(buf);
310                 if (buf[0] == '4') {
311                         text_to_server(bstr("msgtext"));
312                         serv_puts("000");
313                         wprintf("Message has been posted.<BR>\n");
314                         dont_post = atol(bstr("postseq"));
315                 } else {
316                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
317                 }
318         }
319
320         wDumpContent(1);
321 }
322
323
324
325
326
327
328
329
330 /*
331  * prompt for a recipient (to be called from display_enter() only)
332  */
333 void prompt_for_recipient()
334 {
335
336         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=007700><TR><TD>");
337         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
338         wprintf("<B>Send private e-mail</B>\n");
339         wprintf("</FONT></TD></TR></TABLE>\n");
340
341         wprintf("<CENTER>");
342         wprintf("<FORM METHOD=\"POST\" ACTION=\"/display_enter\">\n");
343         wprintf("Enter recipient: ");
344         wprintf("<INPUT TYPE=\"text\" NAME=\"recp\" MAXLENGTH=\"64\"><BR>\n");
345         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Enter message\">");
346         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\">");
347         wprintf("</FORM></CENTER>\n");
348 }
349
350
351
352 /*
353  * display the message entry screen
354  */
355 void display_enter(void)
356 {
357         char buf[256];
358         long now;
359         struct tm *tm;
360
361         wprintf("HTTP/1.0 200 OK\n");
362         output_headers(1);
363
364         wprintf("<FACE=\"Arial,Helvetica,sans-serif\">");
365
366         sprintf(buf, "ENT0 0|%s|0|0", bstr("recp"));
367         serv_puts(buf);
368         serv_gets(buf);
369
370         if (!strncmp(buf, "570", 3)) {
371                 if (strlen(bstr("recp")) > 0) {
372                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
373                 }
374                 prompt_for_recipient();
375                 goto DONE;
376         }
377         if (buf[0] != '2') {
378                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
379                 goto DONE;
380         }
381         wprintf("<CENTER>Enter message below.  Messages are formatted to\n");
382         wprintf("the <EM>reader's</EM> screen width.  To defeat the\n");
383         wprintf("formatting, indent a line at least one space.  \n");
384         wprintf("<BR>");
385
386         now = time(NULL);
387         tm = (struct tm *) localtime(&now);
388         strcpy(buf, (char *) asctime(tm));
389         buf[strlen(buf) - 1] = 0;
390         strcpy(&buf[16], &buf[19]);
391         wprintf("</CENTER><FONT COLOR=\"440000\"><B> %s ", &buf[4]);
392         wprintf("from %s ", WC->wc_username);
393         if (strlen(bstr("recp")) > 0)
394                 wprintf("to %s ", bstr("recp"));
395         wprintf("in %s&gt; ", WC->wc_roomname);
396         wprintf("</B></FONT><BR><CENTER>\n");
397
398         wprintf("<FORM METHOD=\"POST\" ACTION=\"/post\">\n");
399         wprintf("<INPUT TYPE=\"hidden\" NAME=\"recp\" VALUE=\"%s\">\n",
400                 bstr("recp"));
401         wprintf("<INPUT TYPE=\"hidden\" NAME=\"postseq\" VALUE=\"%ld\">\n",
402                 now);
403         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Save message\">"
404                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\"><BR>\n");
405
406         wprintf("<TEXTAREA NAME=\"msgtext\" wrap=soft ROWS=30 COLS=80 "
407                 "WIDTH=80></TEXTAREA><P>\n");
408
409         wprintf("</FORM></CENTER>\n");
410 DONE:   wDumpContent(1);
411         wprintf("</FONT>");
412 }
413
414
415
416
417
418
419
420
421 /*
422  * Confirm deletion of a message
423  */
424 void confirm_delete_msg(void)
425 {
426         long msgid;
427
428         msgid = atol(bstr("msgid"));
429
430         wprintf("HTTP/1.0 200 OK\n");
431         output_headers(1);
432
433         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=770000><TR><TD>");
434         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
435         wprintf("<B>Confirm deletion of message</B>\n");
436         wprintf("</FONT></TD></TR></TABLE>\n");
437
438         wprintf("<CENTER>");
439
440         wprintf("Are you sure you want to delete this message? <BR>\n");
441
442         wprintf("<FORM METHOD=\"POST\" ACTION=\"/delete_msg\">\n");
443         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n",
444                 bstr("msgid"));
445         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Yes\">");
446         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"No\">");
447         wprintf("</FORM></CENTER>\n");
448
449         wprintf("</CENTER>\n");
450         wDumpContent(1);
451 }
452
453
454
455 void delete_msg(void)
456 {
457         long msgid;
458         char buf[256];
459
460         msgid = atol(bstr("msgid"));
461
462         wprintf("HTTP/1.0 200 OK\n");
463         output_headers(1);
464
465         if (!strcasecmp(bstr("yesno"), "Yes")) {
466                 sprintf(buf, "DELE %ld", msgid);
467                 serv_puts(buf);
468                 serv_gets(buf);
469                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
470         } else {
471                 wprintf("<EM>Message not deleted.</EM><BR>\n");
472         }
473
474         wDumpContent(1);
475 }
476
477
478
479
480 /*
481  * Confirm move of a message
482  */
483 void confirm_move_msg(void)
484 {
485         long msgid;
486         char buf[256];
487         char targ[256];
488
489         msgid = atol(bstr("msgid"));
490
491         wprintf("HTTP/1.0 200 OK\n");
492         output_headers(1);
493
494         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=770000><TR><TD>");
495         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
496         wprintf("<B>Confirm move of message</B>\n");
497         wprintf("</FONT></TD></TR></TABLE>\n");
498
499         wprintf("<CENTER>");
500
501         wprintf("Please select the room to which you would like this message moved:<BR>\n");
502
503         wprintf("<FORM METHOD=\"POST\" ACTION=\"/move_msg\">\n");
504         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n",
505                 bstr("msgid"));
506
507
508         wprintf("<SELECT NAME=\"target_room\" SIZE=5>\n");
509         serv_puts("LKRA");
510         serv_gets(buf);
511         if (buf[0] == '1') {
512                 while (serv_gets(buf), strcmp(buf, "000")) {
513                         extract(targ, buf, 0);
514                         wprintf("<OPTION>");
515                         escputs(targ);
516                         wprintf("\n");
517                 }
518         }
519         wprintf("</SELECT>\n");
520         wprintf("<BR>\n");
521
522         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Move\">");
523         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Cancel\">");
524         wprintf("</FORM></CENTER>\n");
525
526         wprintf("</CENTER>\n");
527         wDumpContent(1);
528 }
529
530
531
532 void move_msg(void)
533 {
534         long msgid;
535         char buf[256];
536
537         msgid = atol(bstr("msgid"));
538
539         wprintf("HTTP/1.0 200 OK\n");
540         output_headers(1);
541
542         if (!strcasecmp(bstr("yesno"), "Move")) {
543                 sprintf(buf, "MOVE %ld|%s", msgid, bstr("target_room"));
544                 serv_puts(buf);
545                 serv_gets(buf);
546                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
547         } else {
548                 wprintf("<EM>Message not deleted.</EM><BR>\n");
549         }
550
551         wDumpContent(1);
552 }