* *** HUGE CHANGES *** *** WARNING: NOT FULLY FUNCTIONAL ***
[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         /* suppress express message check, do headers but no banner */
155         output_headers(1, 1, 0, 0, 0, 1, 0);
156
157         while (serv_puts("GEXP"), serv_gets(buf), buf[0]=='1') {
158
159                 extract(pagefrom, &buf[4], 3);
160
161                 wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#444455\"><TR><TD>");
162                 wprintf("<SPAN CLASS=\"titlebar\">Instant message from ");
163                 escputs(pagefrom);
164                 wprintf("</SPAN></TD></TR></TABLE>\n");
165                 
166                 fmout(NULL, "LEFT");
167         }
168
169         wprintf("<CENTER>");
170         wprintf("<A HREF=\"/display_page&closewin=yes&recp=");
171         urlescputs(pagefrom);
172         wprintf("\">[ reply ]</A>&nbsp;&nbsp;&nbsp;\n");
173
174         wprintf("<A HREF=\"javascript:window.close();\">"
175                 "[ close window ]</A></B>\n"
176                 "</CENTER>");
177
178         wDumpContent(1);
179         WC->HaveExpressMessages = 0;
180 }
181
182
183
184 /*
185  * Support function for chat -- make sure the chat socket is connected
186  * and in chat mode.
187  */
188 int setup_chat_socket(void) {
189         char buf[SIZ];
190         int i;
191         int good_chatmode = 0;
192
193         if (WC->chat_sock < 0) {
194
195                 if (!strcasecmp(ctdlhost, "uds")) {
196                         /* unix domain socket */
197                         sprintf(buf, "%s/citadel.socket", ctdlport);
198                         WC->chat_sock = uds_connectsock(buf);
199                 }
200                 else {
201                         /* tcp socket */
202                         WC->chat_sock = tcp_connectsock(ctdlhost, ctdlport);
203                 }
204
205                 if (WC->chat_sock < 0) {
206                         return(errno);
207                 }
208
209                 /* Temporarily swap the serv and chat sockets during chat talk */
210                 i = WC->serv_sock;
211                 WC->serv_sock = WC->chat_sock;
212                 WC->chat_sock = i;
213
214                 serv_gets(buf);
215                 if (buf[0] == '2') {
216                         serv_printf("USER %s", WC->wc_username);
217                         serv_gets(buf);
218                         if (buf[0] == '3') {
219                                 serv_printf("PASS %s", WC->wc_password);
220                                 serv_gets(buf);
221                                 if (buf[0] == '2') {
222                                         serv_printf("GOTO %s", WC->wc_roomname);
223                                         serv_gets(buf);
224                                         if (buf[0] == '2') {
225                                                 serv_puts("CHAT");
226                                                 serv_gets(buf);
227                                                 if (buf[0] == '8') {
228                                                         good_chatmode = 1;
229                                                 }
230                                         }
231                                 }
232                         }
233                 }
234
235                 /* Unswap the sockets. */
236                 i = WC->serv_sock;
237                 WC->serv_sock = WC->chat_sock;
238                 WC->chat_sock = i;
239
240                 if (!good_chatmode) close(WC->serv_sock);
241
242         }
243         return(0);
244 }
245
246
247
248 /*
249  * Receiving side of the chat window.  This is implemented in a
250  * tiny hidden IFRAME that just does JavaScript writes to
251  * other frames whenever it refreshes and finds new data.
252  */
253 void chat_recv(void) {
254         int i;
255         struct pollfd pf;
256         int got_data = 0;
257         int end_chat_now = 0;
258         char buf[SIZ];
259         char cl_user[SIZ];
260         char cl_text[SIZ];
261         char *output_data = NULL;
262
263         output_headers(0, 0, 0, 0, 0, 0, 0);
264
265         wprintf("Content-type: text/html\n");
266         wprintf("\n");
267         wprintf("<html>\n"
268                 "<head>\n"
269                 "<meta http-equiv=\"refresh\" content=\"3\" />\n"
270                 "</head>\n"
271
272                 "<body bgcolor=\"#FFFFFF\">\n"
273         );
274
275         if (setup_chat_socket() != 0) {
276                 wprintf("Error setting up chat socket</BODY></HTML>\n");
277                 wDumpContent(0);
278                 return;
279         }
280
281         /*
282          * See if there is any chat data waiting.
283          */
284         output_data = strdup("");
285         do {
286                 got_data = 0;
287                 pf.fd = WC->chat_sock;
288                 pf.events = POLLIN;
289                 pf.revents = 0;
290                 if (poll(&pf, 1, 1) > 0) if (pf.revents & POLLIN) {
291                         ++got_data;
292
293                         /* Temporarily swap the serv and chat sockets during chat talk */
294                         i = WC->serv_sock;
295                         WC->serv_sock = WC->chat_sock;
296                         WC->chat_sock = i;
297         
298                         serv_gets(buf);
299
300                         if (!strcmp(buf, "000")) {
301                                 strcpy(buf, ":|exiting chat mode");
302                                 end_chat_now = 1;
303                         }
304                         
305                         /* Unswap the sockets. */
306                         i = WC->serv_sock;
307                         WC->serv_sock = WC->chat_sock;
308                         WC->chat_sock = i;
309
310                         /* Append our output data */
311                         output_data = realloc(output_data, strlen(output_data) + strlen(buf) + 4);
312                         strcat(output_data, buf);
313                         strcat(output_data, "\n");
314                 }
315
316         } while ( (got_data) && (!end_chat_now) );
317
318         if (end_chat_now) {
319                 close(WC->chat_sock);
320                 WC->chat_sock = (-1);
321                 wprintf("<IMG SRC=\"/static/blank.gif\" onLoad=\"parent.window.close();\">\n");
322         }
323
324         if (strlen(output_data) > 0) {
325
326                 if (output_data[strlen(output_data)-1] == '\n') {
327                         output_data[strlen(output_data)-1] = 0;
328                 }
329
330                 /* Output our fun to the other frame. */
331                 wprintf("<IMG SRC=\"/static/blank.gif\" WIDTH=1 HEIGHT=1\n"
332                         "onLoad=\" \n"
333                 );
334
335                 for (i=0; i<num_tokens(output_data, '\n'); ++i) {
336                         extract_token(buf, output_data, i, '\n');
337                         extract_token(cl_user, buf, 0, '|');
338                         extract_token(cl_text, buf, 1, '|');
339
340                         if (strcasecmp(cl_text, "NOOP")) {
341
342                                 wprintf("parent.chat_transcript.document.write('");
343         
344                                 if (strcasecmp(cl_user, WC->last_chat_user)) {
345                                         wprintf("<TABLE border=0 WIDTH=100%% "
346                                                 "CELLSPACING=1 CELLPADDING=0 "
347                                                 "BGCOLOR=&quot;#FFFFFF&quot;>"
348                                                 "<TR><TD></TR></TD></TABLE>"
349                                         );
350         
351                                 }
352
353                                 wprintf("<TABLE border=0 WIDTH=100%% "
354                                         "CELLSPACING=0 CELLPADDING=0 "
355                                         "BGCOLOR=&quot;#EEEEEE&quot;>");
356         
357                                 wprintf("<TR><TD>");
358         
359                                 if (!strcasecmp(cl_user, ":")) {
360                                         wprintf("<I>");
361                                 }
362
363                                 if (strcasecmp(cl_user, WC->last_chat_user)) {
364                                         wprintf("<B>");
365         
366                                         if (!strcasecmp(cl_user, WC->wc_username)) {
367                                                 wprintf("<FONT COLOR=&quot;#FF0000&quot;>");
368                                         }
369                                         else {
370                                                 wprintf("<FONT COLOR=&quot;#0000FF&quot;>");
371                                         }
372                                         jsescputs(cl_user);
373         
374                                         wprintf("</FONT>: </B>");
375                                 }
376                                 else {
377                                         wprintf("&nbsp;&nbsp;&nbsp;");
378                                 }
379                                 jsescputs(cl_text);
380                                 if (!strcasecmp(cl_user, ":")) {
381                                         wprintf("</I>");
382                                 }
383
384                                 wprintf("</TD></TR></TABLE>");
385                                 wprintf("'); \n");
386
387                                 strcpy(WC->last_chat_user, cl_user);
388                         }
389                 }
390
391                 wprintf("parent.chat_transcript.scrollTo(999999,999999);\">\n");
392         }
393
394         free(output_data);
395
396         wprintf("</BODY></HTML>\n");
397         wDumpContent(0);
398 }
399
400
401 /*
402  * sending side of the chat window
403  */
404 void chat_send(void) {
405         int i;
406         char send_this[SIZ];
407         char buf[SIZ];
408
409         output_headers(0, 0, 0, 0, 0, 0, 0);
410         wprintf("Content-type: text/html\n");
411         wprintf("\n");
412         wprintf("<HTML>"
413                 "<BODY onLoad=\"document.chatsendform.send_this.focus();\" >"
414         );
415
416         if (bstr("send_this") != NULL) {
417                 strcpy(send_this, bstr("send_this"));
418         }
419         else {
420                 strcpy(send_this, "");
421         }
422
423         if (bstr("sendbutton") != NULL) {
424
425                 if (!strcasecmp(bstr("sendbutton"), "Help")) {
426                         strcpy(send_this, "/help");
427                 }
428
429                 if (!strcasecmp(bstr("sendbutton"), "List Users")) {
430                         strcpy(send_this, "/who");
431                 }
432
433                 if (!strcasecmp(bstr("sendbutton"), "Exit")) {
434                         strcpy(send_this, "/quit");
435                 }
436
437                 if (setup_chat_socket() != 0) {
438                         wprintf("Error setting up chat socket</BODY></HTML>\n");
439                         wDumpContent(0);
440                         return;
441                 }
442
443                 /* Temporarily swap the serv and chat sockets during chat talk */
444                 i = WC->serv_sock;
445                 WC->serv_sock = WC->chat_sock;
446                 WC->chat_sock = i;
447
448                 while (strlen(send_this) > 0) {
449                         if (strlen(send_this) < 67) {
450                                 serv_puts(send_this);
451                                 strcpy(send_this, "");
452                         }
453                         else {
454                                 for (i=55; i<67; ++i) {
455                                         if (send_this[i] == ' ') break;
456                                 }
457                                 strncpy(buf, send_this, i);
458                                 buf[i] = 0;
459                                 strcpy(send_this, &send_this[i]);
460                                 serv_puts(buf);
461                         }
462                 }
463
464                 /* Unswap the sockets. */
465                 i = WC->serv_sock;
466                 WC->serv_sock = WC->chat_sock;
467                 WC->chat_sock = i;
468
469         }
470
471         wprintf("<FORM METHOD=\"POST\" ACTION=\"/chat_send\" NAME=\"chatsendform\">\n");
472         wprintf("<INPUT TYPE=\"text\" SIZE=\"80\" MAXLENGTH=\"%d\" "
473                 "NAME=\"send_this\">\n", SIZ-10);
474         wprintf("<br />");
475         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Send\">\n");
476         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Help\">\n");
477         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"List Users\">\n");
478         wprintf("<INPUT TYPE=\"submit\" NAME=\"sendbutton\" VALUE=\"Exit\">\n");
479         wprintf("</FORM>\n");
480
481         wprintf("</BODY></HTML>\n");
482         wDumpContent(0);
483 }
484
485