* The size constant "256" which shows up everywhere as a buffer size has now
[citadel.git] / citadel / client_chat.c
1 /*
2  * $Id$
3  *
4  * front end for chat mode
5  * (the "single process" version - no more fork() anymore)
6  *
7  */
8
9 #include "sysdep.h"
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <errno.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23 #include <stdarg.h>
24 #include "citadel.h"
25 #include "client_chat.h"
26 #include "commands.h"
27 #include "routines.h"
28 #include "ipc.h"
29 #include "citadel_decls.h"
30 #include "tools.h"
31 #include "rooms.h"
32 #include "messages.h"
33 #ifndef HAVE_SNPRINTF
34 #include "snprintf.h"
35 #endif
36
37 #define MIN(a, b) ((a) < (b) ? (a) : (b))
38
39 extern struct CtdlServInfo serv_info;
40 extern char temp[];
41 void getline(char *, int);
42
43 void chatmode(void)
44 {
45         char wbuf[SIZ];
46         char buf[SIZ];
47         char c_user[SIZ];
48         char c_text[SIZ];
49         char c_room[SIZ];
50         char last_user[SIZ];
51         int send_complete_line;
52         int recv_complete_line;
53         char ch;
54         int a, pos;
55         time_t last_transmit;
56
57         fd_set rfds;
58         struct timeval tv;
59         int retval;
60
61         serv_puts("CHAT");
62         serv_gets(buf);
63         if (buf[0] != '8') {
64                 printf("%s\n", &buf[4]);
65                 return;
66         }
67         printf("Entering chat mode (type /quit to exit, /help for other cmds)\n");
68         set_keepalives(KA_NO);
69         last_transmit = time(NULL);
70
71         strcpy(buf, "");
72         strcpy(wbuf, "");
73         color(BRIGHT_YELLOW);
74         printf("> ");
75         send_complete_line = 0;
76         recv_complete_line = 0;
77
78         while (1) {
79                 fflush(stdout);
80                 FD_ZERO(&rfds);
81                 FD_SET(0, &rfds);
82                 FD_SET(getsockfd(), &rfds);
83                 tv.tv_sec = S_KEEPALIVE;
84                 tv.tv_usec = 0;
85                 retval = select(getsockfd() + 1, &rfds, NULL, NULL, &tv);
86
87                 if (FD_ISSET(getsockfd(), &rfds)) {
88                         ch = serv_getc();
89                         if (ch == 10) {
90                                 recv_complete_line = 1;
91                                 goto RCL;       /* ugly, but we've gotta get out! */
92                         } else {
93                                 buf[strlen(buf) + 1] = 0;
94                                 buf[strlen(buf)] = ch;
95                         }
96                         goto RCL;
97                 }
98                 if (FD_ISSET(0, &rfds)) {
99                         ch = inkey();
100                         if ((ch == 10) || (ch == 13)) {
101                                 send_complete_line = 1;
102                         } else if ((ch == 8) || (ch == 127)) {
103                                 if (strlen(wbuf) > 0) {
104                                         wbuf[strlen(wbuf) - 1] = 0;
105                                         printf("%c %c", 8, 8);
106                                 }
107                         } else {
108                                 putc(ch, stdout);
109                                 wbuf[strlen(wbuf) + 1] = 0;
110                                 wbuf[strlen(wbuf)] = ch;
111                         }
112                 }
113                 /* if the user hit return, send the line */
114               RCL:if (send_complete_line) {
115                         serv_puts(wbuf);
116                         last_transmit = time(NULL);
117                         strcpy(wbuf, "");
118                         send_complete_line = 0;
119                 }
120                 /* if it's time to word wrap, send a partial line */
121                 if (strlen(wbuf) >= (77 - strlen(fullname))) {
122                         pos = 0;
123                         for (a = 0; a < strlen(wbuf); ++a) {
124                                 if (wbuf[a] == 32)
125                                         pos = a;
126                         }
127                         if (pos == 0) {
128                                 serv_puts(wbuf);
129                                 last_transmit = time(NULL);
130                                 strcpy(wbuf, "");
131                                 send_complete_line = 0;
132                         } else {
133                                 wbuf[pos] = 0;
134                                 serv_puts(wbuf);
135                                 last_transmit = time(NULL);
136                                 strcpy(wbuf, &wbuf[pos + 1]);
137                         }
138                 }
139                 if (recv_complete_line) {
140                         printf("\r%79s\r", "");
141                         if (!strcmp(buf, "000")) {
142                                 color(BRIGHT_WHITE);
143                                 printf("Exiting chat mode\n");
144
145                                 fflush(stdout);
146                                 set_keepalives(KA_YES);
147
148
149                                 /* Some users complained about the client and server
150                                  * losing protocol synchronization when exiting chat.
151                                  * This little dialog forces everything to be
152                                  * hunky-dory.
153                                  */
154                                 serv_puts("ECHO __ExitingChat__");
155                                 do {
156                                         serv_gets(buf);
157                                 } while (strcmp(buf, "200 __ExitingChat__"));
158
159
160                                 return;
161                         }
162                         if (num_parms(buf) >= 2) {
163                                 extract(c_user, buf, 0);
164                                 extract(c_text, buf, 1);
165                                 if (num_parms(buf) > 2) {
166                                         extract(c_room, buf, 2);
167                                         printf("Got room %s\n", c_room);
168                                 }
169                                 if (strcasecmp(c_text, "NOOP")) {
170                                         if (!strcmp(c_user, fullname)) {
171                                                 color(BRIGHT_YELLOW);
172                                         } else if (!strcmp(c_user, ":")) {
173                                                 color(BRIGHT_RED);
174                                         } else {
175                                                 color(BRIGHT_GREEN);
176                                         }
177                                         if (strcmp(c_user, last_user)) {
178                                                 snprintf(buf, sizeof buf, "%s: %s", c_user, c_text);
179                                         } else {
180                                                 size_t i = MIN(sizeof buf - 1,
181                                                      strlen(c_user) + 2);
182
183                                                 memset(buf, ' ', i);
184                                                 safestrncpy(&buf[i], c_text,
185                                                          sizeof buf - i);
186                                         }
187                                         while (strlen(buf) < 79)
188                                                 strcat(buf, " ");
189                                         if (strcmp(c_user, last_user)) {
190                                                 printf("\r%79s\n", "");
191                                                 strcpy(last_user, c_user);
192                                         }
193                                         printf("\r%s\n", buf);
194                                         fflush(stdout);
195                                 }
196                         }
197                         color(BRIGHT_YELLOW);
198                         printf("> %s", wbuf);
199                         recv_complete_line = 0;
200                         strcpy(buf, "");
201                 }
202
203                 /* If the user is sitting idle, send a half-keepalive to the
204                  * server to prevent session timeout.
205                  */
206                 if ((time(NULL) - last_transmit) >= S_KEEPALIVE) {
207                         serv_puts("NOOP");
208                         last_transmit = time(NULL);
209                 }
210
211         }
212 }
213
214 /*
215  * send an express message
216  */
217 void page_user()
218 {
219         static char last_paged[32] = "";
220         char buf[SIZ], touser[SIZ], msg[SIZ];
221         FILE *pagefp;
222
223         strcpy(touser, last_paged);
224         strprompt("Page who", touser, 30);
225
226         /* old server -- use inline paging */
227         if (serv_info.serv_paging_level == 0) {
228                 newprompt("Message:  ", msg, 69);
229                 snprintf(buf, sizeof buf, "SEXP %s|%s", touser, msg);
230                 serv_puts(buf);
231                 serv_gets(buf);
232                 if (!strncmp(buf, "200", 3)) {
233                         strcpy(last_paged, touser);
234                 }
235                 printf("%s\n", &buf[4]);
236                 return;
237         }
238         /* new server -- use extended paging */
239         else if (serv_info.serv_paging_level >= 1) {
240                 snprintf(buf, sizeof buf, "SEXP %s||", touser);
241                 serv_puts(buf);
242                 serv_gets(buf);
243                 if (buf[0] != '2') {
244                         printf("%s\n", &buf[4]);
245                         return;
246                 }
247                 if (make_message(temp, touser, 0, 0, 0) != 0) {
248                         printf("No message sent.\n");
249                         return;
250                 }
251                 pagefp = fopen(temp, "r");
252                 unlink(temp);
253                 snprintf(buf, sizeof buf, "SEXP %s|-", touser);
254                 serv_puts(buf);
255                 serv_gets(buf);
256                 if (buf[0] == '4') {
257                         strcpy(last_paged, touser);
258                         while (fgets(buf, sizeof buf, pagefp) != NULL) {
259                                 buf[strlen(buf) - 1] = 0;
260                                 serv_puts(buf);
261                         }
262                         fclose(pagefp);
263                         serv_puts("000");
264                         printf("Message sent.\n");
265                 } else {
266                         printf("%s\n", &buf[4]);
267                 }
268         }
269 }
270
271
272
273
274 void quiet_mode(void)
275 {
276         int qstate;
277         char buf[SIZ];
278
279         serv_puts("DEXP 2");
280         serv_gets(buf);
281         if (buf[0] != '2') {
282                 printf("%s\n", &buf[4]);
283                 return;
284         }
285         qstate = atoi(&buf[4]);
286         if (qstate == 0)
287                 qstate = 1;
288         else
289                 qstate = 0;
290         sprintf(buf, "DEXP %d", qstate);
291         serv_puts(buf);
292         serv_gets(buf);
293         if (buf[0] != '2') {
294                 printf("%s\n", &buf[4]);
295                 return;
296         }
297         qstate = atoi(&buf[4]);
298         if (qstate) {
299                 printf("Quiet mode enabled (no other users may page you)\n");
300         } else {
301                 printf("Quiet mode disabled (other users may page you)\n");
302         }
303 }