* Moved all diagnostic output to stderr
[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         output_headers(1);
244
245         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\"><CENTER><B>%s - ", WC->wc_roomname);
246         if (!strcmp(oper, "readnew")) {
247                 strcpy(cmd, "MSGS NEW");
248                 wprintf("new messages");
249         } else if (!strcmp(oper, "readold")) {
250                 strcpy(cmd, "MSGS OLD");
251                 wprintf("old messages");
252         } else {
253                 strcpy(cmd, "MSGS ALL");
254                 wprintf("all messages");
255         }
256         wprintf("</B></CENTER><BR>\n");
257
258         nummsgs = load_msg_ptrs(cmd);
259         if (nummsgs == 0) {
260                 if (!strcmp(oper, "readnew")) {
261                         wprintf("<EM>No new messages in this room.</EM>\n");
262                 } else if (!strcmp(oper, "readold")) {
263                         wprintf("<EM>No old messages in this room.</EM>\n");
264                 } else {
265                         wprintf("<EM>This room is empty.</EM>\n");
266                 }
267                 goto DONE;
268         }
269         for (a = 0; a < nummsgs; ++a) {
270                 read_message(msgarr[a], oper);
271         }
272
273       DONE:wDumpContent(1);
274 }
275
276
277
278
279 /*
280  * Post message (or don't post message)
281  *
282  * Note regarding the "dont_post" variable:
283  * A random value (actually, it's just a timestamp) is inserted as a hidden
284  * field called "postseq" when the display_enter page is generated.  This
285  * value is checked when posting, using the static variable dont_post.  If a
286  * user attempts to post twice using the same dont_post value, the message is
287  * discarded.  This prevents the accidental double-saving of the same message
288  * if the user happens to click the browser "back" button.
289  */
290 void post_message(void)
291 {
292         char buf[256];
293         static long dont_post = (-1L);
294
295         output_headers(1);
296
297         wprintf("<FONT FACE=\"Arial,Helvetica,sans-serif\">");
298         strcpy(buf, bstr("sc"));
299         if (strcasecmp(buf, "Save message")) {
300                 wprintf("Cancelled.  Message was not posted.<BR>\n");
301         } else if (atol(bstr("postseq")) == dont_post) {
302                 wprintf("Automatically cancelled because you have already "
303                         "saved this message.<BR>\n");
304         } else {
305                 sprintf(buf, "ENT0 1|%s|0|0", bstr("recp"));
306                 serv_puts(buf);
307                 serv_gets(buf);
308                 if (buf[0] == '4') {
309                         text_to_server(bstr("msgtext"));
310                         serv_puts("000");
311                         wprintf("Message has been posted.<BR>\n");
312                         dont_post = atol(bstr("postseq"));
313                 } else {
314                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
315                 }
316         }
317
318         wDumpContent(1);
319 }
320
321
322
323
324
325
326
327
328 /*
329  * prompt for a recipient (to be called from display_enter() only)
330  */
331 void prompt_for_recipient()
332 {
333
334         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=007700><TR><TD>");
335         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
336         wprintf("<B>Send private e-mail</B>\n");
337         wprintf("</FONT></TD></TR></TABLE>\n");
338
339         wprintf("<CENTER>");
340         wprintf("<FORM METHOD=\"POST\" ACTION=\"/display_enter\">\n");
341         wprintf("Enter recipient: ");
342         wprintf("<INPUT TYPE=\"text\" NAME=\"recp\" MAXLENGTH=\"64\"><BR>\n");
343         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Enter message\">");
344         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\">");
345         wprintf("</FORM></CENTER>\n");
346 }
347
348
349
350 /*
351  * display the message entry screen
352  */
353 void display_enter(void)
354 {
355         char buf[256];
356         long now;
357         struct tm *tm;
358
359         output_headers(1);
360
361         wprintf("<FACE=\"Arial,Helvetica,sans-serif\">");
362
363         sprintf(buf, "ENT0 0|%s|0|0", bstr("recp"));
364         serv_puts(buf);
365         serv_gets(buf);
366
367         if (!strncmp(buf, "570", 3)) {
368                 if (strlen(bstr("recp")) > 0) {
369                         wprintf("<EM>%s</EM><BR>\n", &buf[4]);
370                 }
371                 prompt_for_recipient();
372                 goto DONE;
373         }
374         if (buf[0] != '2') {
375                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
376                 goto DONE;
377         }
378         wprintf("<CENTER>Enter message below.  Messages are formatted to\n");
379         wprintf("the <EM>reader's</EM> screen width.  To defeat the\n");
380         wprintf("formatting, indent a line at least one space.  \n");
381         wprintf("<BR>");
382
383         now = time(NULL);
384         tm = (struct tm *) localtime(&now);
385         strcpy(buf, (char *) asctime(tm));
386         buf[strlen(buf) - 1] = 0;
387         strcpy(&buf[16], &buf[19]);
388         wprintf("</CENTER><FONT COLOR=\"440000\"><B> %s ", &buf[4]);
389         wprintf("from %s ", WC->wc_username);
390         if (strlen(bstr("recp")) > 0)
391                 wprintf("to %s ", bstr("recp"));
392         wprintf("in %s&gt; ", WC->wc_roomname);
393         wprintf("</B></FONT><BR><CENTER>\n");
394
395         wprintf("<FORM METHOD=\"POST\" ACTION=\"/post\">\n");
396         wprintf("<INPUT TYPE=\"hidden\" NAME=\"recp\" VALUE=\"%s\">\n",
397                 bstr("recp"));
398         wprintf("<INPUT TYPE=\"hidden\" NAME=\"postseq\" VALUE=\"%ld\">\n",
399                 now);
400         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Save message\">"
401                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\"><BR>\n");
402
403         wprintf("<TEXTAREA NAME=\"msgtext\" wrap=soft ROWS=30 COLS=80 "
404                 "WIDTH=80></TEXTAREA><P>\n");
405
406         wprintf("</FORM></CENTER>\n");
407 DONE:   wDumpContent(1);
408         wprintf("</FONT>");
409 }
410
411
412
413
414
415
416
417
418 /*
419  * Confirm deletion of a message
420  */
421 void confirm_delete_msg(void)
422 {
423         long msgid;
424
425         msgid = atol(bstr("msgid"));
426
427         output_headers(1);
428
429         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=770000><TR><TD>");
430         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
431         wprintf("<B>Confirm deletion of message</B>\n");
432         wprintf("</FONT></TD></TR></TABLE>\n");
433
434         wprintf("<CENTER>");
435
436         wprintf("Are you sure you want to delete this message? <BR>\n");
437
438         wprintf("<FORM METHOD=\"POST\" ACTION=\"/delete_msg\">\n");
439         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n",
440                 bstr("msgid"));
441         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Yes\">");
442         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"No\">");
443         wprintf("</FORM></CENTER>\n");
444
445         wprintf("</CENTER>\n");
446         wDumpContent(1);
447 }
448
449
450
451 void delete_msg(void)
452 {
453         long msgid;
454         char buf[256];
455
456         msgid = atol(bstr("msgid"));
457
458         output_headers(1);
459
460         if (!strcasecmp(bstr("yesno"), "Yes")) {
461                 sprintf(buf, "DELE %ld", msgid);
462                 serv_puts(buf);
463                 serv_gets(buf);
464                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
465         } else {
466                 wprintf("<EM>Message not deleted.</EM><BR>\n");
467         }
468
469         wDumpContent(1);
470 }
471
472
473
474
475 /*
476  * Confirm move of a message
477  */
478 void confirm_move_msg(void)
479 {
480         long msgid;
481         char buf[256];
482         char targ[256];
483
484         msgid = atol(bstr("msgid"));
485
486         output_headers(1);
487
488         wprintf("<TABLE WIDTH=100% BORDER=0 BGCOLOR=770000><TR><TD>");
489         wprintf("<FONT SIZE=+1 COLOR=\"FFFFFF\"");
490         wprintf("<B>Confirm move of message</B>\n");
491         wprintf("</FONT></TD></TR></TABLE>\n");
492
493         wprintf("<CENTER>");
494
495         wprintf("Please select the room to which you would like this message moved:<BR>\n");
496
497         wprintf("<FORM METHOD=\"POST\" ACTION=\"/move_msg\">\n");
498         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgid\" VALUE=\"%s\">\n",
499                 bstr("msgid"));
500
501
502         wprintf("<SELECT NAME=\"target_room\" SIZE=5>\n");
503         serv_puts("LKRA");
504         serv_gets(buf);
505         if (buf[0] == '1') {
506                 while (serv_gets(buf), strcmp(buf, "000")) {
507                         extract(targ, buf, 0);
508                         wprintf("<OPTION>");
509                         escputs(targ);
510                         wprintf("\n");
511                 }
512         }
513         wprintf("</SELECT>\n");
514         wprintf("<BR>\n");
515
516         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Move\">");
517         wprintf("<INPUT TYPE=\"submit\" NAME=\"yesno\" VALUE=\"Cancel\">");
518         wprintf("</FORM></CENTER>\n");
519
520         wprintf("</CENTER>\n");
521         wDumpContent(1);
522 }
523
524
525
526 void move_msg(void)
527 {
528         long msgid;
529         char buf[256];
530
531         msgid = atol(bstr("msgid"));
532
533         output_headers(1);
534
535         if (!strcasecmp(bstr("yesno"), "Move")) {
536                 sprintf(buf, "MOVE %ld|%s", msgid, bstr("target_room"));
537                 serv_puts(buf);
538                 serv_gets(buf);
539                 wprintf("<EM>%s</EM><BR>\n", &buf[4]);
540         } else {
541                 wprintf("<EM>Message not deleted.</EM><BR>\n");
542         }
543
544         wDumpContent(1);
545 }