* Added in a bunch of stupid JavaScript to allow the instant message
[citadel.git] / webcit / paging.c
1 /*
2  * $Id$
3  *
4  * Functions which implement the chat and paging facilities.
5  */
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <sys/socket.h>
16 #include <sys/poll.h>
17 #include <sys/time.h>
18 #include <limits.h>
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #include <string.h>
22 #include <pwd.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <pthread.h>
26 #include <signal.h>
27 #include "webcit.h"
28
29
30 /*
31  * display the form for paging (x-messaging) another user
32  */
33 void display_page(void)
34 {
35         char recp[SIZ];
36
37         strcpy(recp, bstr("recp"));
38
39         output_headers(1, 1, 0, 0, 0, 0, 0);
40
41         svprintf("BOXTITLE", WCS_STRING, "Page: %s", recp);
42         do_template("beginbox");
43
44         wprintf("<FORM METHOD=\"POST\" ACTION=\"/page_user\">\n");
45
46         wprintf("<TABLE border=0 width=100%%><TR><TD>\n");
47
48         wprintf("<INPUT TYPE=\"hidden\" NAME=\"recp\" VALUE=\"");
49         escputs(recp);
50         wprintf("\">\n");
51
52         wprintf("<INPUT TYPE=\"hidden\" NAME=\"closewin\" VALUE=\"");
53         escputs(bstr("closewin"));
54         wprintf("\">\n");
55
56         wprintf("Enter message text:<br />");
57
58         wprintf("<TEXTAREA NAME=\"msgtext\" wrap=soft ROWS=5 COLS=40 "
59                 "WIDTH=40></TEXTAREA>\n");
60
61         wprintf("</TD></TR></TABLE><br />\n");
62
63         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Send message\">");
64         wprintf("<br /><A HREF=\"javascript:window.close();\"Cancel</A>\n");
65
66         wprintf("</FORM></CENTER>\n");
67         do_template("endbox");
68         wDumpContent(1);
69 }
70
71 /*
72  * page another user
73  */
74 void page_user(void)
75 {
76         char recp[SIZ];
77         char sc[SIZ];
78         char buf[SIZ];
79         char closewin[SIZ];
80
81         output_headers(1, 1, 0, 0, 0, 0, 0);
82
83         strcpy(recp, bstr("recp"));
84         strcpy(sc, bstr("sc"));
85         strcpy(closewin, bstr("closewin"));
86
87         if (strcmp(sc, "Send message")) {
88                 wprintf("<EM>Message was not sent.</EM><br />\n");
89         } else {
90                 serv_printf("SEXP %s|-", recp);
91                 serv_gets(buf);
92
93                 if (buf[0] == '4') {
94                         text_to_server(bstr("msgtext"), 0);
95                         serv_puts("000");
96                         wprintf("<EM>Message has been sent to ");
97                         escputs(recp);
98                         wprintf(".</EM><br />\n");
99                 }
100                 else {
101                         wprintf("<EM>%s</EM><br />\n", &buf[4]);
102                 }
103         }
104         
105         if (!strcasecmp(closewin, "yes")) {
106                 wprintf("<CENTER><A HREF=\"javascript:window.close();\">"
107                         "[ close window ]</A></CENTER>\n");
108         }
109
110         wDumpContent(1);
111 }
112
113
114
115 /*
116  * multiuser chat
117  */
118 void do_chat(void)
119 {
120         char buf[SIZ];
121
122         /* First, check to make sure we're still allowed in this room. */
123         serv_printf("GOTO %s", WC->wc_roomname);
124         serv_gets(buf);
125         if (buf[0] != '2') {
126                 smart_goto("_BASEROOM_");
127                 return;
128         }
129
130         /* If the chat socket is still open from a previous chat,
131          * close it -- because it might be stale or in the wrong room.
132          */
133         if (WC->chat_sock < 0) {
134                 close(WC->chat_sock);
135                 WC->chat_sock = (-1);
136         }
137
138         /* WebCit Chat works by having transmit, receive, and refresh
139          * frames.  Load the frameset.
140          */
141         do_template("chatframeset");
142         return;
143 }
144
145
146 /*
147  *
148  */
149 void page_popup(void)
150 {
151         char buf[SIZ];
152         char pagefrom[SIZ];
153
154         while (serv_puts("GEXP"), serv_gets(buf), buf[0]=='1') {
155
156                 extract(pagefrom, &buf[4], 3);
157
158                 wprintf("<table border=1 bgcolor=\"#880000\"><tr><td>");
159                 wprintf("<span class=\"titlebar\">Instant message from ");
160                 escputs(pagefrom);
161                 wprintf("</span></td></tr><tr><td><font color=\"#FFFFFF\">");
162                 fmout(NULL, "LEFT");
163                 wprintf("</font></td></tr>"
164                         "<tr><td><div align=center><font color=\"#FFFFFF\">"
165                         "<a href=\"javascript:hide_page_popup()\">[ close window ]</a>"
166                         "</font></div>"
167                         "</td></tr>"
168                         "</table>\n");
169         }
170
171         WC->HaveInstantMessages = 0;
172 }
173
174
175
176 /*
177  * Support function for chat -- make sure the chat socket is connected
178  * and in chat mode.
179  */
180 int setup_chat_socket(void) {
181         char buf[SIZ];
182         int i;
183         int good_chatmode = 0;
184
185         if (WC->chat_sock < 0) {
186
187                 if (!strcasecmp(ctdlhost, "uds")) {
188                         /* unix domain socket */
189                         sprintf(buf, "%s/citadel.socket", ctdlport);
190                         WC->chat_sock = uds_connectsock(buf);
191                 }
192                 else {
193                         /* tcp socket */
194                         WC->chat_sock = tcp_connectsock(ctdlhost, ctdlport);
195                 }
196
197                 if (WC->chat_sock < 0) {
198                         return(errno);
199                 }
200
201                 /* Temporarily swap the serv and chat sockets during chat talk */
202                 i = WC->serv_sock;
203                 WC->serv_sock = WC->chat_sock;
204                 WC->chat_sock = i;
205
206                 serv_gets(buf);
207                 if (buf[0] == '2') {
208                         serv_printf("USER %s", WC->wc_username);
209                         serv_gets(buf);
210                         if (buf[0] == '3') {
211                                 serv_printf("PASS %s", WC->wc_password);
212                                 serv_gets(buf);
213                                 if (buf[0] == '2') {
214                                         serv_printf("GOTO %s", WC->wc_roomname);
215                                         serv_gets(buf);
216                                         if (buf[0] == '2') {
217                                                 serv_puts("CHAT");
218                                                 serv_gets(buf);
219                                                 if (buf[0] == '8') {
220                                                         good_chatmode = 1;
221                                                 }
222                                         }
223                                 }
224                         }
225                 }
226
227                 /* Unswap the sockets. */
228                 i = WC->serv_sock;
229                 WC->serv_sock = WC->chat_sock;
230                 WC->chat_sock = i;
231
232                 if (!good_chatmode) close(WC->serv_sock);
233
234         }
235         return(0);
236 }
237
238
239
240 /*
241  * Receiving side of the chat window.  This is implemented in a
242  * tiny hidden IFRAME that just does JavaScript writes to
243  * other frames whenever it refreshes and finds new data.
244  */
245 void chat_recv(void) {
246         int i;
247         struct pollfd pf;
248         int got_data = 0;
249         int end_chat_now = 0;
250         char buf[SIZ];
251         char cl_user[SIZ];
252         char cl_text[SIZ];
253         char *output_data = NULL;
254
255         output_headers(0, 0, 0, 0, 0, 0, 0);
256
257         wprintf("Content-type: text/html\n");
258         wprintf("\n");
259         wprintf("<html>\n"
260                 "<head>\n"
261                 "<meta http-equiv=\"refresh\" content=\"3\" />\n"
262                 "</head>\n"
263
264                 "<body bgcolor=\"#FFFFFF\">\n"
265         );
266
267         if (setup_chat_socket() != 0) {
268                 wprintf("Error setting up chat socket</BODY></HTML>\n");
269                 wDumpContent(0);
270                 return;
271         }
272
273         /*
274          * See if there is any chat data waiting.
275          */
276         output_data = strdup("");
277         do {
278                 got_data = 0;
279                 pf.fd = WC->chat_sock;
280                 pf.events = POLLIN;
281                 pf.revents = 0;
282                 if (poll(&pf, 1, 1) > 0) if (pf.revents & POLLIN) {
283                         ++got_data;
284
285                         /* Temporarily swap the serv and chat sockets during chat talk */
286                         i = WC->serv_sock;
287                         WC->serv_sock = WC->chat_sock;
288                         WC->chat_sock = i;
289         
290                         serv_gets(buf);
291
292                         if (!strcmp(buf, "000")) {
293                                 strcpy(buf, ":|exiting chat mode");
294                                 end_chat_now = 1;
295                         }
296                         
297                         /* Unswap the sockets. */
298                         i = WC->serv_sock;
299                         WC->serv_sock = WC->chat_sock;
300                         WC->chat_sock = i;
301
302                         /* Append our output data */
303                         output_data = realloc(output_data, strlen(output_data) + strlen(buf) + 4);
304                         strcat(output_data, buf);
305                         strcat(output_data, "\n");
306                 }
307
308         } while ( (got_data) && (!end_chat_now) );
309
310         if (end_chat_now) {
311                 close(WC->chat_sock);
312                 WC->chat_sock = (-1);
313                 wprintf("<IMG SRC=\"/static/blank.gif\" onLoad=\"parent.window.close();\">\n");
314         }
315
316         if (strlen(output_data) > 0) {
317
318                 if (output_data[strlen(output_data)-1] == '\n') {
319                         output_data[strlen(output_data)-1] = 0;
320                 }
321
322                 /* Output our fun to the other frame. */
323                 wprintf("<IMG SRC=\"/static/blank.gif\" WIDTH=1 HEIGHT=1\n"
324                         "onLoad=\" \n"
325                 );
326
327                 for (i=0; i<num_tokens(output_data, '\n'); ++i) {
328                         extract_token(buf, output_data, i, '\n');
329                         extract_token(cl_user, buf, 0, '|');
330                         extract_token(cl_text, buf, 1, '|');
331
332                         if (strcasecmp(cl_text, "NOOP")) {
333
334                                 wprintf("parent.chat_transcript.document.write('");
335         
336                                 if (strcasecmp(cl_user, WC->last_chat_user)) {
337                                         wprintf("<TABLE border=0 WIDTH=100%% "
338                                                 "CELLSPACING=1 CELLPADDING=0 "
339                                                 "BGCOLOR=&quot;#FFFFFF&quot;>"
340                                                 "<TR><TD></TR></TD></TABLE>"
341                                         );
342         
343                                 }
344
345                                 wprintf("<TABLE border=0 WIDTH=100%% "
346                                         "CELLSPACING=0 CELLPADDING=0 "
347                                         "BGCOLOR=&quot;#EEEEEE&quot;>");
348         
349                                 wprintf("<TR><TD>");
350         
351                                 if (!strcasecmp(cl_user, ":")) {
352                                         wprintf("<I>");
353                                 }
354
355                                 if (strcasecmp(cl_user, WC->last_chat_user)) {
356                                         wprintf("<B>");
357         
358                                         if (!strcasecmp(cl_user, WC->wc_username)) {
359                                                 wprintf("<FONT COLOR=&quot;#FF0000&quot;>");
360                                         }
361                                         else {
362                                                 wprintf("<FONT COLOR=&quot;#0000FF&quot;>");
363                                         }
364                                         jsescputs(cl_user);
365         
366                                         wprintf("</FONT>: </B>");
367                                 }
368                                 else {
369                                         wprintf("&nbsp;&nbsp;&nbsp;");
370                                 }
371                                 jsescputs(cl_text);
372                                 if (!strcasecmp(cl_user, ":")) {
373                                         wprintf("</I>");
374                                 }
375
376                                 wprintf("</TD></TR></TABLE>");
377                                 wprintf("'); \n");
378
379                                 strcpy(WC->last_chat_user, cl_user);
380                         }
381                 }
382
383                 wprintf("parent.chat_transcript.scrollTo(999999,999999);\">\n");
384         }
385
386         free(output_data);
387
388         wprintf("</BODY></HTML>\n");
389         wDumpContent(0);
390 }
391
392
393 /*
394  * sending side of the chat window
395  */
396 void chat_send(void) {
397         int i;
398         char send_this[SIZ];
399         char buf[SIZ];
400
401         output_headers(0, 0, 0, 0, 0, 0, 0);
402         wprintf("Content-type: text/html\n");
403         wprintf("\n");
404         wprintf("<HTML>"
405                 "<BODY onLoad=\"document.chatsendform.send_this.focus();\" >"
406         );
407
408         if (bstr("send_this") != NULL) {
409                 strcpy(send_this, bstr("send_this"));
410         }
411         else {
412                 strcpy(send_this, "");
413         }
414
415         if (bstr("sendbutton") != NULL) {
416
417                 if (!strcasecmp(bstr("sendbutton"), "Help")) {
418                         strcpy(send_this, "/help");
419                 }
420
421                 if (!strcasecmp(bstr("sendbutton"), "List Users")) {
422                         strcpy(send_this, "/who");
423                 }
424
425                 if (!strcasecmp(bstr("sendbutton"), "Exit")) {
426                         strcpy(send_this, "/quit");
427                 }
428
429                 if (setup_chat_socket() != 0) {
430                         wprintf("Error setting up chat socket</BODY></HTML>\n");
431                         wDumpContent(0);
432                         return;
433                 }
434
435                 /* Temporarily swap the serv and chat sockets during chat talk */
436                 i = WC->serv_sock;
437                 WC->serv_sock = WC->chat_sock;
438                 WC->chat_sock = i;
439
440                 while (strlen(send_this) > 0) {
441                         if (strlen(send_this) < 67) {
442                                 serv_puts(send_this);
443                                 strcpy(send_this, "");
444                         }
445                         else {
446                                 for (i=55; i<67; ++i) {
447                                         if (send_this[i] == ' ') break;
448                                 }
449                                 strncpy(buf, send_this, i);
450                                 buf[i] = 0;
451                                 strcpy(send_this, &send_this[i]);
452                                 serv_puts(buf);
453                         }
454                 }
455
456                 /* Unswap the sockets. */
457                 i = WC->serv_sock;
458                 WC->serv_sock = WC->chat_sock;
459                 WC->chat_sock = i;
460
461         }
462
463         wprintf("<FORM METHOD=\"POST\" ACTION=\"/chat_send\" NAME=\"chatsendform\">\n");
464         wprintf("<INPUT TYPE=\"text\" SIZE=\"80\" MAXLENGTH=\"%d\" "
465                 "NAME=\"send_this\">\n", SIZ-10);
466         wprintf("<br />");
467         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Send\">\n");
468         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Help\">\n");
469         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"List Users\">\n");
470         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Exit\">\n");
471         wprintf("</FORM>\n");
472
473         wprintf("</BODY></HTML>\n");
474         wDumpContent(0);
475 }
476
477