18 #ifdef HAVE_SYS_SELECT_H
19 #include <sys/select.h>
21 #include "serv_chat.h"
22 #include "sysdep_decls.h"
23 #include "citserver.h"
26 #include "dynloader.h"
29 struct ChatLine *ChatQueue = NULL;
32 extern struct CitContext *ContextList;
34 #define MODULE_NAME "Chat module"
35 #define MODULE_AUTHOR "Art Cancro"
36 #define MODULE_EMAIL "ajc@uncnsrd.mt-kisco.ny.us"
37 #define MAJOR_VERSION 0
38 #define MINOR_VERSION 2
40 static struct DLModule_Info info =
49 struct DLModule_Info *Dynamic_Module_Init(void)
51 CtdlRegisterProtoHook(cmd_chat, "CHAT",
52 "Initiates a real-time chat session");
53 CtdlRegisterProtoHook(cmd_pexp, "PEXP", "Poll for express messages");
54 CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an express message");
58 void allwrite(char *cmdbuf, int flag, char *roomname, char *username)
63 struct ChatLine *clptr, *clnew;
66 if (CC->fake_username[0])
67 un = CC->fake_username;
69 un = CC->usersupp.fullname;
72 sprintf(bcast,":|<%s %s>",un,cmdbuf);
77 sprintf(bcast,"%s|%s",un,cmdbuf);
82 sprintf(bcast,":|<%s whispers %s>", un, cmdbuf);
84 if ((strcasecmp(cmdbuf,"NOOP")) && (flag !=2)) {
85 fp = fopen(CHATLOG,"a");
86 fprintf(fp,"%s\n",bcast);
90 clnew = (struct ChatLine *) mallok(sizeof(struct ChatLine));
91 memset(clnew, 0, sizeof(struct ChatLine));
93 fprintf(stderr, "citserver: cannot alloc chat line: %s\n",
100 clnew->chat_time = now;
101 strncpy(clnew->chat_room, roomname, sizeof clnew->chat_room);
102 clnew->chat_room[sizeof clnew->chat_room - 1] = 0;
105 strncpy(clnew->chat_username, username,
106 sizeof clnew->chat_username);
107 clnew->chat_username[sizeof clnew->chat_username - 1] = 0;
110 clnew->chat_username[0] = '\0';
111 strcpy(clnew->chat_text, bcast);
113 /* Here's the critical section.
114 * First, add the new message to the queue...
116 begin_critical_section(S_CHATQUEUE);
118 clnew->chat_seq = ChatLastMsg;
119 if (ChatQueue == NULL) {
123 for (clptr=ChatQueue; clptr->next != NULL; clptr=clptr->next) ;;
127 /* Then, before releasing the lock, free the expired messages */
129 if (ChatQueue == NULL) goto DONE_FREEING;
130 if ( (now - ChatQueue->chat_time) < 120L ) goto DONE_FREEING;
132 ChatQueue = ChatQueue->next;
135 DONE_FREEING: end_critical_section(S_CHATQUEUE);
139 t_context *find_context(char **unstr)
141 t_context *t_cc, *found_cc = NULL;
144 if ((!*unstr) || (!unstr))
147 begin_critical_section(S_SESSION_TABLE);
148 for (t_cc = ContextList; ((t_cc) && (!found_cc)); t_cc = t_cc->next)
150 if (t_cc->fake_username[0])
151 name = t_cc->fake_username;
153 name = t_cc->curr_user;
155 if ((!strncasecmp(name, tptr, strlen(name))) && (tptr[strlen(name)] == ' '))
158 *unstr = &(tptr[strlen(name)+1]);
161 end_critical_section(S_SESSION_TABLE);
167 * List users in chat. Setting allflag to 1 also lists users elsewhere.
170 void do_chat_listing(int allflag)
172 struct CitContext *ccptr;
174 cprintf(":|\n:| Users currently in chat:\n");
175 begin_critical_section(S_SESSION_TABLE);
176 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
177 if ( (!strcasecmp(ccptr->cs_room, "<chat>"))
178 && ((ccptr->cs_flags & CS_STEALTH) == 0)) {
179 cprintf(":| %-25s <%s>\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, ccptr->chat_room);
185 cprintf(":|\n:| Users not in chat:\n");
186 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next)
188 if ( (strcasecmp(ccptr->cs_room, "<chat>"))
189 && ((ccptr->cs_flags & CS_STEALTH) == 0))
191 cprintf(":| %-25s <%s>:\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, (ccptr->fake_roomname[0]) ? ccptr->fake_roomname : ccptr->cs_room);
196 end_critical_section(S_SESSION_TABLE);
201 void cmd_chat(char *argbuf)
206 char hold_cs_room[ROOMNAMELEN];
207 int MyLastMsg, ThisLastMsg;
208 struct ChatLine *clptr;
209 struct CitContext *t_context;
212 if (!(CC->logged_in)) {
213 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
217 strcpy(CC->chat_room, "Main room");
219 strcpy(hold_cs_room,CC->cs_room);
220 CC->cs_flags = CC->cs_flags | CS_CHAT;
221 set_wtmpsupp("<chat>");
222 cprintf("%d Entering chat mode (type '/help' for available commands)\n",
225 MyLastMsg = ChatLastMsg;
227 if ((CC->cs_flags & CS_STEALTH) == 0) {
228 allwrite("<entering chat>",0, CC->chat_room, NULL);
237 cmdbuf[strlen(cmdbuf) + 1] = 0;
238 retval = client_read_to(&cmdbuf[strlen(cmdbuf)], 1, 2);
240 /* if we have a complete line, do send processing */
241 if (strlen(cmdbuf) > 0) if (cmdbuf[strlen(cmdbuf)-1] == 10) {
242 cmdbuf[strlen(cmdbuf) - 1] = 0;
246 if ( (!strcasecmp(cmdbuf,"exit"))
247 ||(!strcasecmp(cmdbuf,"/exit"))
248 ||(!strcasecmp(cmdbuf,"quit"))
249 ||(!strcasecmp(cmdbuf,"logout"))
250 ||(!strcasecmp(cmdbuf,"logoff"))
251 ||(!strcasecmp(cmdbuf,"/q"))
252 ||(!strcasecmp(cmdbuf,".q"))
253 ||(!strcasecmp(cmdbuf,"/quit"))
254 ) strcpy(cmdbuf,"000");
256 if (!strcmp(cmdbuf,"000")) {
257 if ((CC->cs_flags & CS_STEALTH) == 0) {
258 allwrite("<exiting chat>",0, CC->chat_room, NULL);
262 CC->cs_flags = CC->cs_flags - CS_CHAT;
263 set_wtmpsupp(hold_cs_room);
267 if ((!strcasecmp(cmdbuf,"/help"))
268 ||(!strcasecmp(cmdbuf,"help"))
269 ||(!strcasecmp(cmdbuf,"/?"))
270 ||(!strcasecmp(cmdbuf,"?"))) {
272 cprintf(":|Available commands: \n");
273 cprintf(":|/help (prints this message) \n");
274 cprintf(":|/who (list users currently in chat) \n");
275 cprintf(":|/whobbs (list users in chat -and- elsewhere) \n");
276 cprintf(":|/me ('action' line, ala irc) \n");
277 cprintf(":|/msg (send private message, ala irc) \n");
278 cprintf(":|/join (join new room) \n");
279 cprintf(":|/quit (return to the BBS) \n");
283 if (!strcasecmp(cmdbuf,"/who")) {
287 if (!strcasecmp(cmdbuf,"/whobbs")) {
291 if (!strncasecmp(cmdbuf,"/me ",4)) {
292 allwrite(&cmdbuf[4],1, CC->chat_room, NULL);
296 if (!strncasecmp(cmdbuf,"/msg ", 5))
299 strptr1 = &cmdbuf[5];
300 if ((t_context = find_context(&strptr1)))
302 allwrite(strptr1, 2, "", CC->curr_user);
303 if (strcasecmp(CC->curr_user, t_context->curr_user))
304 allwrite(strptr1, 2, "", t_context->curr_user);
307 cprintf(":|User not found.\n", cmdbuf);
311 if (!strncasecmp(cmdbuf,"/join ", 6))
314 allwrite("<changing rooms>",0, CC->chat_room, NULL);
316 strcpy(CC->chat_room, "Main room");
319 strncpy(CC->chat_room, &cmdbuf[6],
320 sizeof CC->chat_room);
321 CC->chat_room[sizeof CC->chat_room - 1] = 0;
323 allwrite("<joining room>",0, CC->chat_room, NULL);
326 if ((cmdbuf[0]!='/')&&(strlen(cmdbuf)>0)) {
328 allwrite(cmdbuf,0, CC->chat_room, NULL);
331 if ((!ok_cmd) && (cmdbuf[0]) && (cmdbuf[0] != '\n'))
332 cprintf(":|Command %s is not understood.\n", cmdbuf);
338 /* now check the queue for new incoming stuff */
340 if (CC->fake_username[0])
341 un = CC->fake_username;
344 if (ChatLastMsg > MyLastMsg) {
345 ThisLastMsg = ChatLastMsg;
346 for (clptr=ChatQueue; clptr!=NULL; clptr=clptr->next)
348 if ((clptr->chat_seq > MyLastMsg) && ((!clptr->chat_username[0]) || (!strncasecmp(un, clptr->chat_username, 32))))
350 if ((!clptr->chat_room[0]) || (!strncasecmp(CC->chat_room, clptr->chat_room, ROOMNAMELEN)))
352 cprintf("%s\n", clptr->chat_text);
356 MyLastMsg = ThisLastMsg;
364 * poll for express messages
366 void cmd_pexp(char *argbuf) /* arg unused */ {
367 struct ExpressMessage *emptr;
369 if (CC->FirstExpressMessage == NULL) {
370 cprintf("%d No express messages waiting.\n",ERROR);
374 cprintf("%d Express msgs:\n",LISTING_FOLLOWS);
376 while (CC->FirstExpressMessage != NULL) {
377 cprintf("%s", CC->FirstExpressMessage->em_text);
378 begin_critical_section(S_SESSION_TABLE);
379 emptr = CC->FirstExpressMessage;
380 CC->FirstExpressMessage = CC->FirstExpressMessage->next;
382 end_critical_section(S_SESSION_TABLE);
389 * send express messages <bc>
391 void cmd_sexp(char *argbuf)
395 int message_sent = 0;
396 struct CitContext *ccptr;
397 struct ExpressMessage *emptr, *emnew;
398 char *lun; /* <bc> */
400 if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
401 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
405 if (num_parms(argbuf)!=2) {
406 cprintf("%d usage error\n",ERROR);
410 if (CC->fake_username[0])
411 lun = CC->fake_username;
413 lun = CC->usersupp.fullname;
415 extract(x_user,argbuf,0);
417 if (!strcmp(x_user, "."))
419 strcpy(x_user, CC->last_pager);
421 extract(x_msg,argbuf,1);
425 cprintf("%d You were not previously paged.\n", ERROR);
429 if ( (!strcasecmp(x_user, "broadcast")) && (CC->usersupp.axlevel < 6) ) {
430 cprintf("%d Higher access required to send a broadcast.\n",
431 ERROR+HIGHER_ACCESS_REQUIRED);
435 /* find the target user's context and append the message */
436 begin_critical_section(S_SESSION_TABLE);
437 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
440 if (ccptr->fake_username[0]) /* <bc> */
441 un = ccptr->fake_username;
443 un = ccptr->usersupp.fullname;
445 if ( (!strcasecmp(un, x_user))
446 || (!strcasecmp(x_user, "broadcast")) ) {
447 strcpy(ccptr->last_pager, CC->curr_user);
448 emnew = (struct ExpressMessage *)
449 mallok(sizeof(struct ExpressMessage));
451 sprintf(emnew->em_text, "%s from %s:\n %s\n",
452 ( (!strcasecmp(x_user, "broadcast")) ? "Broadcast message" : "Message" ),
455 if (ccptr->FirstExpressMessage == NULL) {
456 ccptr->FirstExpressMessage = emnew;
459 emptr = ccptr->FirstExpressMessage;
460 while (emptr->next != NULL) {
469 end_critical_section(S_SESSION_TABLE);
471 if (message_sent > 0) {
472 cprintf("%d Message sent.\n",OK);
475 cprintf("%d No user '%s' logged in.\n",ERROR,x_user);