* Close chat socket if already open
[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(3);
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(3);
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         /* Ok, we're good.  Here we go. */
139         output_headers(3);
140
141         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#000077\"><TR><TD>"
142                 "<SPAN CLASS=\"titlebar\">"
143                 "<IMG SRC=\"/static/chat-icon.gif\" WIDTH=16 HEIGHT=16 ALIGN=MIDDLE>"
144         );
145         escputs(WC->wc_roomname);
146         wprintf(": real-time chat</SPAN>\n"
147                 "</TD></TR></TABLE>\n"
148
149                 "<IFRAME WIDTH=100%% HEIGHT=200 SRC=\"about:blank\" "
150                 "NAME=\"chat_transcript\">\n"
151                 "<!-- Alternate content for non-supporting browsers -->\n"
152                 "If you are seeing this message, your browser does not contain\n"
153                 "the IFRAME support required for the chat window.  Please upgrade\n"
154                 "to a supported browser, such as\n"
155                 "<A HREF=\"http://www.mozilla.org\">Mozilla</A>.\n"
156                 "</IFRAME>\n"
157
158                 "<IFRAME WIDTH=100%% HEIGHT=1 SRC=\"/chat_recv\" "
159                 "NAME=\"chat_recv\">\n"
160                 "</IFRAME>"
161
162                 "<BR>\n"
163
164                 "<IFRAME WIDTH=100%% HEIGHT=60 SRC=\"/chat_send\" "
165                 "NAME=\"chat_send\">\n"
166                 "</IFRAME>\n"
167         );
168         wDumpContent(1);
169 }
170
171
172 /*
173  *
174  */
175 void page_popup(void)
176 {
177         char buf[SIZ];
178         char pagefrom[SIZ];
179
180         /* suppress express message check, do headers but no frames */
181         output_headers(0x08 | 0x03);
182
183         while (serv_puts("GEXP"), serv_gets(buf), buf[0]=='1') {
184
185                 extract(pagefrom, &buf[4], 3);
186
187                 wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#007700\"><TR><TD>");
188                 wprintf("<SPAN CLASS=\"titlebar\">Instant message from ");
189                 escputs(pagefrom);
190                 wprintf("</SPAN></TD></TR></TABLE>\n");
191                 
192                 fmout(NULL, "LEFT");
193         }
194
195         wprintf("<CENTER>");
196         wprintf("<A HREF=\"/display_page&closewin=yes&recp=");
197         urlescputs(pagefrom);
198         wprintf("\">[ reply ]</A>&nbsp;&nbsp;&nbsp;\n");
199
200         wprintf("<A HREF=\"javascript:window.close();\">"
201                 "[ close window ]</A></B>\n"
202                 "</CENTER>");
203
204         wDumpContent(1);
205         WC->HaveExpressMessages = 0;
206 }
207
208
209
210 /*
211  * Support function for chat -- make sure the chat socket is connected
212  * and in chat mode.
213  */
214 int setup_chat_socket(void) {
215         char buf[SIZ];
216         int i;
217         int good_chatmode = 0;
218
219         if (WC->chat_sock < 0) {
220
221                 if (!strcasecmp(ctdlhost, "uds")) {
222                         /* unix domain socket */
223                         sprintf(buf, "%s/citadel.socket", ctdlport);
224                         WC->chat_sock = uds_connectsock(buf);
225                 }
226                 else {
227                         /* tcp socket */
228                         WC->chat_sock = tcp_connectsock(ctdlhost, ctdlport);
229                 }
230
231                 if (WC->chat_sock < 0) {
232                         return(errno);
233                 }
234
235                 /* Temporarily swap the serv and chat sockets during chat talk */
236                 i = WC->serv_sock;
237                 WC->serv_sock = WC->chat_sock;
238                 WC->chat_sock = i;
239
240                 serv_gets(buf);
241                 if (buf[0] == '2') {
242                         serv_printf("USER %s", WC->wc_username);
243                         serv_gets(buf);
244                         if (buf[0] == '3') {
245                                 serv_printf("PASS %s", WC->wc_password);
246                                 serv_gets(buf);
247                                 if (buf[0] == '2') {
248                                         serv_printf("GOTO %s", WC->wc_roomname);
249                                         serv_gets(buf);
250                                         if (buf[0] == '2') {
251                                                 serv_puts("CHAT");
252                                                 serv_gets(buf);
253                                                 if (buf[0] == '8') {
254                                                         good_chatmode = 1;
255                                                 }
256                                         }
257                                 }
258                         }
259                 }
260
261                 /* Unswap the sockets. */
262                 i = WC->serv_sock;
263                 WC->serv_sock = WC->chat_sock;
264                 WC->chat_sock = i;
265
266                 if (!good_chatmode) close(WC->serv_sock);
267
268         }
269         return(0);
270 }
271
272
273
274 /*
275  * Receiving side of the chat window.  This is implemented in a
276  * tiny hidden IFRAME that just does JavaScript writes to
277  * other frames whenever it refreshes and finds new data.
278  */
279 void chat_recv(void) {
280         int i;
281         struct pollfd pf;
282         int got_data = 0;
283         int end_chat_now = 0;
284         char buf[SIZ];
285         char cl_user[SIZ];
286         char cl_text[SIZ];
287         char *output_data = NULL;
288
289         output_headers(0);
290
291         wprintf("Content-type: text/html\n");
292         wprintf("\n");
293         wprintf("<HTML>\n"
294                 "<HEAD>\n"
295                 "<META HTTP-EQUIV=\"refresh\" CONTENT=\"3\">\n"
296                 "</HEAD>\n"
297
298                 "<BODY BGCOLOR=\"#FFFFFF\">\n"
299         );
300
301         if (setup_chat_socket() != 0) {
302                 wprintf("Error setting up chat socket</BODY></HTML>\n");
303                 wDumpContent(0);
304                 return;
305         }
306
307         /*
308          * See if there is any chat data waiting.
309          */
310         output_data = strdup("");
311         do {
312                 got_data = 0;
313                 pf.fd = WC->chat_sock;
314                 pf.events = POLLIN;
315                 pf.revents = 0;
316                 if (poll(&pf, 1, 1) > 0) if (pf.revents & POLLIN) {
317                         ++got_data;
318
319                         /* Temporarily swap the serv and chat sockets during chat talk */
320                         i = WC->serv_sock;
321                         WC->serv_sock = WC->chat_sock;
322                         WC->chat_sock = i;
323         
324                         serv_gets(buf);
325
326                         if (!strcmp(buf, "000")) {
327                                 strcpy(buf, ":|exiting chat mode");
328                                 end_chat_now = 1;
329                         }
330                         
331                         /* Unswap the sockets. */
332                         i = WC->serv_sock;
333                         WC->serv_sock = WC->chat_sock;
334                         WC->chat_sock = i;
335
336                         /* Append our output data */
337                         output_data = realloc(output_data, strlen(output_data) + strlen(buf) + 4);
338                         strcat(output_data, buf);
339                         strcat(output_data, "\n");
340                 }
341
342         } while ( (got_data) && (!end_chat_now) );
343
344         if (end_chat_now) {
345                 close(WC->chat_sock);
346                 WC->chat_sock = (-1);
347                 wprintf("<IMG SRC=\"/static/blank.gif\" onLoad=\"parent.location.replace('/display_main_menu');\">\n");
348         }
349
350         if (strlen(output_data) > 0) {
351
352                 if (output_data[strlen(output_data)-1] == '\n') {
353                         output_data[strlen(output_data)-1] = 0;
354                 }
355
356                 /* Output our fun to the other frame. */
357                 wprintf("<IMG SRC=\"/static/blank.gif\" WIDTH=1 HEIGHT=1\n"
358                         "onLoad=\" \n"
359                 );
360
361                 for (i=0; i<num_tokens(output_data, '\n'); ++i) {
362                         extract_token(buf, output_data, i, '\n');
363                         extract_token(cl_user, buf, 0, '|');
364                         extract_token(cl_text, buf, 1, '|');
365
366                         wprintf("parent.chat_transcript.document.write('");
367                         wprintf("<FONT SIZE=-1><B>");
368                         jsescputs(cl_user);
369                         wprintf(":</B> ");
370                         jsescputs(cl_text);
371                         wprintf("</FONT><BR>");
372                         wprintf("'); \n");
373                 }
374
375                 wprintf("parent.chat_transcript.scrollTo(999999,999999);\">\n");
376         }
377
378         free(output_data);
379
380         wprintf("</BODY></HTML>\n");
381         wDumpContent(0);
382 }
383
384
385 /*
386  * sending side of the chat window
387  */
388 void chat_send(void) {
389         int i;
390         char send_this[SIZ];
391
392         output_headers(0);
393         wprintf("Content-type: text/html\n");
394         wprintf("\n");
395         wprintf("<HTML>"
396                 "<BODY onLoad=\"document.chatsendform.send_this.focus();\" >"
397         );
398
399         if (bstr("send_this") != NULL) {
400                 strcpy(send_this, bstr("send_this"));
401         }
402         else {
403                 strcpy(send_this, "");
404         }
405
406         if (bstr("sendbutton") != NULL) {
407
408                 if (!strcasecmp(bstr("sendbutton"), "Help")) {
409                         strcpy(send_this, "/help");
410                 }
411
412                 if (!strcasecmp(bstr("sendbutton"), "Exit")) {
413                         strcpy(send_this, "/quit");
414                 }
415
416                 if (setup_chat_socket() != 0) {
417                         wprintf("Error setting up chat socket</BODY></HTML>\n");
418                         wDumpContent(0);
419                         return;
420                 }
421
422                 /* Temporarily swap the serv and chat sockets during chat talk */
423                 i = WC->serv_sock;
424                 WC->serv_sock = WC->chat_sock;
425                 WC->chat_sock = i;
426
427                 serv_puts(send_this);
428
429                 /* Unswap the sockets. */
430                 i = WC->serv_sock;
431                 WC->serv_sock = WC->chat_sock;
432                 WC->chat_sock = i;
433
434         }
435
436         wprintf("<FORM METHOD=\"POST\" ACTION=\"/chat_send\" NAME=\"chatsendform\">\n");
437         wprintf("<INPUT TYPE=\"text\" SIZE=\"80\" MAXLENGTH=\"80\" NAME=\"send_this\">\n");
438         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Send\">\n");
439         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Help\">\n");
440         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Exit\">\n");
441         wprintf("</FORM>\n");
442
443         wprintf("</BODY></HTML>\n");
444         wDumpContent(0);
445 }
446
447