]> code.citadel.org Git - citadel.git/blob - citadel/serv_chat.c
remove duplicated declarations
[citadel.git] / citadel / serv_chat.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <fcntl.h>
5 #include <signal.h>
6 #include <pwd.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <sys/wait.h>
11 #include <string.h>
12 #include <pthread.h>
13 #include "citadel.h"
14 #include "server.h"
15 #include <syslog.h>
16 #ifdef NEED_SELECT_H
17 #include <sys/select.h>
18 #endif
19 #include "serv_chat.h"
20 #include "sysdep_decls.h"
21 #include "citserver.h"
22 #include "support.h"
23 #include "config.h"
24
25 struct ChatLine *ChatQueue = NULL;
26 int ChatLastMsg = 0;
27
28
29 void allwrite(char *cmdbuf, int flag, char *roomname, char *username)
30 {       
31         FILE *fp;
32         char bcast[256];
33         char *un;
34         struct ChatLine *clptr, *clnew;
35         time_t now;
36
37         if (CC->fake_username[0])
38            un = CC->fake_username;
39         else
40            un = CC->usersupp.fullname;
41         if (flag == 1) 
42         {
43                 sprintf(bcast,":|<%s %s>",un,cmdbuf);
44         }
45         else
46         if (flag == 0)
47         {
48                 sprintf(bcast,"%s|%s",un,cmdbuf);
49         }
50         else
51         if (flag == 2)
52         {
53                 sprintf(bcast,":|<%s whispers %s>", un, cmdbuf);
54         }
55         if ((strcasecmp(cmdbuf,"NOOP")) && (flag !=2)) {
56                 fp = fopen(CHATLOG,"a");
57                 fprintf(fp,"%s\n",bcast);
58                 fclose(fp);
59                 }
60
61         clnew = (struct ChatLine *) malloc(sizeof(struct ChatLine));
62         bzero(clnew, sizeof(struct ChatLine));
63         if (clnew == NULL) {
64                 fprintf(stderr, "citserver: cannot alloc chat line: %s\n",
65                         strerror(errno));
66                 return;
67                 }
68
69         time(&now);
70         clnew->next = NULL;
71         clnew->chat_time = now;
72         strncpy(clnew->chat_room, roomname, 19);
73         if (username)
74            strncpy(clnew->chat_username, username, 31); 
75         else
76            clnew->chat_username[0] = '\0';
77         strcpy(clnew->chat_text, bcast);
78
79         /* Here's the critical section.
80          * First, add the new message to the queue...
81          */
82         begin_critical_section(S_CHATQUEUE);
83         ++ChatLastMsg;
84         clnew->chat_seq = ChatLastMsg;
85         if (ChatQueue == NULL) {
86                 ChatQueue = clnew;
87                 }
88         else {
89                 for (clptr=ChatQueue; clptr->next != NULL; clptr=clptr->next) ;;
90                 clptr->next = clnew;
91                 }
92
93         /* Then, before releasing the lock, free the expired messages */
94         while(1) {
95                 if (ChatQueue == NULL) goto DONE_FREEING;
96                 if ( (now - ChatQueue->chat_time) < 120L ) goto DONE_FREEING;
97                 clptr = ChatQueue;
98                 ChatQueue = ChatQueue->next;
99                 free(clptr);
100                 }
101 DONE_FREEING:   end_critical_section(S_CHATQUEUE);
102         }
103
104
105 t_context *find_context(char **unstr)
106 {
107    t_context *t_cc, *found_cc = NULL;
108    char *name, *tptr;
109    
110    if ((!*unstr) || (!unstr))
111       return(NULL);
112       
113    begin_critical_section(S_SESSION_TABLE);
114    for (t_cc = ContextList; ((t_cc) && (!found_cc)); t_cc = t_cc->next)
115    {
116       if (t_cc->fake_username[0])
117          name = t_cc->fake_username;
118       else
119          name = t_cc->curr_user;
120       tptr = *unstr;
121       if ((!strncasecmp(name, tptr, strlen(name))) && (tptr[strlen(name)] == ' '))
122       {
123          found_cc = t_cc;
124          *unstr = &(tptr[strlen(name)+1]);
125       }
126    }
127    end_critical_section(S_SESSION_TABLE);
128
129    return(found_cc);
130 }
131
132 /*
133  * List users in chat.  Setting allflag to 1 also lists users elsewhere.
134  */
135  
136
137 void do_chat_listing(int allflag)
138 {
139         struct CitContext *ccptr;
140
141         cprintf(":|\n:| Users currently in chat:\n");
142         begin_critical_section(S_SESSION_TABLE);
143         for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
144                 if ( (!strcasecmp(ccptr->cs_room, "<chat>"))
145                    && ((ccptr->cs_flags & CS_STEALTH) == 0)) {
146                         cprintf(":| %-25s <%s>\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, ccptr->chat_room);
147                         }
148                 }
149
150         if (allflag == 1) 
151         {
152                 cprintf(":|\n:| Users not in chat:\n");
153                 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) 
154                 {
155                         if ( (strcasecmp(ccptr->cs_room, "<chat>"))
156                            && ((ccptr->cs_flags & CS_STEALTH) == 0)) 
157                         {
158                                 cprintf(":| %-25s <%s>:\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, (ccptr->fake_roomname[0]) ? ccptr->fake_roomname : ccptr->cs_room);
159                         }
160                 }
161         }
162         
163         end_critical_section(S_SESSION_TABLE);
164         cprintf(":|\n");
165         }
166
167
168 void cmd_chat(char *argbuf)
169 {
170         char cmdbuf[256];
171         char *un;
172         char *strptr1;
173         char hold_cs_room[20];
174         int MyLastMsg, ThisLastMsg;
175         struct ChatLine *clptr;
176         struct CitContext *t_context;
177         int retval;
178
179         if (!(CC->logged_in)) {
180                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
181                 return;
182                 }
183
184         strcpy(CC->chat_room, "Main room");
185
186         strcpy(hold_cs_room,CC->cs_room);
187         CC->cs_flags = CC->cs_flags | CS_CHAT;
188         set_wtmpsupp("<chat>");
189         cprintf("%d Entering chat mode (type '/help' for available commands)\n",
190                 START_CHAT_MODE);
191
192         MyLastMsg = ChatLastMsg;
193
194         if ((CC->cs_flags & CS_STEALTH) == 0) {
195                 allwrite("<entering chat>",0, CC->chat_room, NULL);
196                 }
197
198         strcpy(cmdbuf, "");
199
200         while(1) {
201                 int ok_cmd;
202                 
203                 ok_cmd = 0;
204                 cmdbuf[strlen(cmdbuf) + 1] = 0;
205                 retval = client_read_to(&cmdbuf[strlen(cmdbuf)], 1, 2);
206
207                 /* if we have a complete line, do send processing */
208                 if (strlen(cmdbuf) > 0) if (cmdbuf[strlen(cmdbuf)-1] == 10) {
209                         cmdbuf[strlen(cmdbuf) - 1] = 0;
210                         time(&CC->lastcmd);
211                         time(&CC->lastidle);
212
213                         if ( (!strcasecmp(cmdbuf,"exit"))
214                         ||(!strcasecmp(cmdbuf,"/exit"))
215                         ||(!strcasecmp(cmdbuf,"quit"))
216                         ||(!strcasecmp(cmdbuf,"logout"))
217                         ||(!strcasecmp(cmdbuf,"logoff"))
218                         ||(!strcasecmp(cmdbuf,"/q"))
219                         ||(!strcasecmp(cmdbuf,".q"))
220                         ||(!strcasecmp(cmdbuf,"/quit"))
221                                 ) strcpy(cmdbuf,"000");
222         
223                         if (!strcmp(cmdbuf,"000")) {
224                                 if ((CC->cs_flags & CS_STEALTH) == 0) {
225                                         allwrite("<exiting chat>",0, CC->chat_room, NULL);
226                                         }
227                                 sleep(1);
228                                 cprintf("000\n");
229                                 CC->cs_flags = CC->cs_flags - CS_CHAT;
230                                 set_wtmpsupp(hold_cs_room);
231                                 return;
232                                 }
233         
234                         if ((!strcasecmp(cmdbuf,"/help"))
235                         ||(!strcasecmp(cmdbuf,"help"))
236                         ||(!strcasecmp(cmdbuf,"/?"))
237                         ||(!strcasecmp(cmdbuf,"?"))) {
238                                 cprintf(":|\n");
239                                 cprintf(":|Available commands: \n");
240                                 cprintf(":|/help   (prints this message) \n");
241                                 cprintf(":|/who    (list users currently in chat) \n");
242                                 cprintf(":|/whobbs (list users in chat -and- elsewhere) \n");
243                                 cprintf(":|/me     ('action' line, ala irc) \n");
244                                 cprintf(":|/msg    (send private message, ala irc) \n");
245                                 cprintf(":|/join   (join new room) \n"); 
246                                 cprintf(":|/quit   (return to the BBS) \n");
247                                 cprintf(":|\n");
248                                 ok_cmd = 1;
249                                 }
250                         if (!strcasecmp(cmdbuf,"/who")) {
251                                 do_chat_listing(0);
252                                 ok_cmd = 1;
253                                 }
254                         if (!strcasecmp(cmdbuf,"/whobbs")) {
255                                 do_chat_listing(1);
256                                 ok_cmd = 1;
257                                 }
258                         if (!strncasecmp(cmdbuf,"/me ",4)) {
259                                 allwrite(&cmdbuf[4],1, CC->chat_room, NULL);
260                                 ok_cmd = 1;
261                                 }
262                                 
263                         if (!strncasecmp(cmdbuf,"/msg ", 5))
264                         {
265                            ok_cmd =1;
266                            strptr1 = &cmdbuf[5];
267                            if ((t_context = find_context(&strptr1)))
268                            {
269                               allwrite(strptr1, 2, "", CC->curr_user);
270                               if (strcasecmp(CC->curr_user, t_context->curr_user))
271                                  allwrite(strptr1, 2, "", t_context->curr_user);
272                            }
273                            else
274                               cprintf(":|User not found.\n", cmdbuf);
275                         cprintf("\n");
276                         }
277
278                         if (!strncasecmp(cmdbuf,"/join ", 6))
279                         {
280                            ok_cmd = 1;
281                            allwrite("<changing rooms>",0, CC->chat_room, NULL);
282                            if (!cmdbuf[6])
283                               strcpy(CC->chat_room, "Main room");
284                            else
285                            {
286                               strncpy(CC->chat_room, &cmdbuf[6], 20);
287                            }
288                            allwrite("<joining room>",0, CC->chat_room, NULL);
289                            cprintf("\n");
290                         }
291                         if ((cmdbuf[0]!='/')&&(strlen(cmdbuf)>0)) {
292                                 ok_cmd = 1;
293                                 allwrite(cmdbuf,0, CC->chat_room, NULL);
294                                 }
295
296                         if (!ok_cmd)
297                            cprintf(":|Command %s is not understood.\n", cmdbuf);
298                            
299                         strcpy(cmdbuf, "");
300
301                         }
302         
303                 /* now check the queue for new incoming stuff */
304                 
305                 if (CC->fake_username[0])
306                    un = CC->fake_username;
307                 else
308                    un = CC->curr_user;
309                 if (ChatLastMsg > MyLastMsg) {
310                         ThisLastMsg = ChatLastMsg;
311                         for (clptr=ChatQueue; clptr!=NULL; clptr=clptr->next) 
312                         {
313                            if ((clptr->chat_seq > MyLastMsg) && ((!clptr->chat_username[0]) || (!strncasecmp(un, clptr->chat_username, 32))))
314                            {
315                               if ((!clptr->chat_room[0]) || (!strncasecmp(CC->chat_room, clptr->chat_room, 20)))
316                               {
317                                  cprintf("%s\n", clptr->chat_text);
318                               }
319                            }
320                         }
321                         MyLastMsg = ThisLastMsg;
322                         }
323
324                 }
325         }
326
327
328 /*
329  * poll for express messages
330  */
331 void cmd_pexp(void) {
332         struct ExpressMessage *emptr;
333
334         if (CC->FirstExpressMessage == NULL) {
335                 cprintf("%d No express messages waiting.\n",ERROR);
336                 return;
337                 }
338
339         cprintf("%d Express msgs:\n",LISTING_FOLLOWS);
340
341         while (CC->FirstExpressMessage != NULL) {
342                 cprintf("%s", CC->FirstExpressMessage->em_text);
343                 begin_critical_section(S_SESSION_TABLE);
344                 emptr = CC->FirstExpressMessage;
345                 CC->FirstExpressMessage = CC->FirstExpressMessage->next;
346                 free(emptr);
347                 end_critical_section(S_SESSION_TABLE);
348                 }
349         cprintf("000\n");
350         }
351
352 /*
353  * returns an asterisk if there are any express messages waiting,
354  * space otherwise.
355  */
356 char check_express(void) {
357         if (CC->FirstExpressMessage == NULL) {
358                 return(' ');
359                 }
360         else {
361                 return('*');
362                 }
363         }
364
365
366 /*
367  * send express messages  <bc>
368  */
369 void cmd_sexp(char *argbuf)
370 {
371         char x_user[256];
372         char x_msg[256];
373         int message_sent = 0;
374         struct CitContext *ccptr;
375         struct ExpressMessage *emptr, *emnew;
376         char *lun;              /* <bc> */
377
378         if (!(CC->logged_in)) {
379                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
380                 return;
381                 }
382
383         if (num_parms(argbuf)!=2) {
384                 cprintf("%d usage error\n",ERROR);
385                 return; 
386                 }
387
388         if (CC->fake_username[0])
389            lun = CC->fake_username;
390         else
391            lun = CC->usersupp.fullname;
392
393         extract(x_user,argbuf,0);
394
395         if (!strcmp(x_user, "."))
396         {
397            strcpy(x_user, CC->last_pager);
398         }
399         extract(x_msg,argbuf,1);
400         
401         if (!x_user[0])
402         {
403            cprintf("%d You were not previously paged.\n", ERROR);
404            return;
405         }
406
407         if ( (!strcasecmp(x_user, "broadcast")) && (CC->usersupp.axlevel < 6) ) {
408                 cprintf("%d Higher access required to send a broadcast.\n",
409                         ERROR+HIGHER_ACCESS_REQUIRED);
410                 return;
411                 }
412
413         /* find the target user's context and append the message */
414         begin_critical_section(S_SESSION_TABLE);
415         for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
416                 char *un;
417                 
418                 if (ccptr->fake_username[0])            /* <bc> */
419                    un = ccptr->fake_username;
420                 else
421                    un = ccptr->usersupp.fullname;
422                    
423                 if ( (!strcasecmp(un, x_user))
424                    || (!strcasecmp(x_user, "broadcast")) ) {
425                         strcpy(ccptr->last_pager, CC->curr_user);
426                         emnew = (struct ExpressMessage *)
427                                 malloc(sizeof(struct ExpressMessage));
428                         emnew->next = NULL;
429                         sprintf(emnew->em_text, "%s from %s:\n %s\n",
430                                 ( (!strcasecmp(x_user, "broadcast")) ? "Broadcast message" : "Message" ),
431                                 lun, x_msg);
432
433                         if (ccptr->FirstExpressMessage == NULL) {
434                                 ccptr->FirstExpressMessage = emnew;
435                                 }
436                         else {
437                                 emptr = ccptr->FirstExpressMessage;
438                                 while (emptr->next != NULL) {
439                                         emptr = emptr->next;
440                                         }
441                                 emptr->next = emnew;
442                                 }
443
444                         ++message_sent;
445                         }
446                 }
447         end_critical_section(S_SESSION_TABLE);
448
449         if (message_sent > 0) {
450                 cprintf("%d Message sent.\n",OK);
451                 }
452         else {
453                 cprintf("%d No user '%s' logged in.\n",ERROR,x_user);
454                 }
455         }