17 #include <sys/select.h>
19 #include "serv_chat.h"
20 #include "sysdep_decls.h"
21 #include "citserver.h"
24 #include "dynloader.h"
26 struct ChatLine *ChatQueue = NULL;
28 symtab *My_Symtab = NULL; /* dyn */
30 extern struct CitContext *ContextList;
32 #define MODULE_NAME "Chat module"
33 #define MODULE_AUTHOR "Art Cancro"
34 #define MODULE_EMAIL "ig@uncnsrd.mt-kisco.ny.us"
35 #define MAJOR_VERSION 0
36 #define MINOR_VERSION 1
38 void ChatUnloadingTest(void) {
39 lprintf(9, "--- test of adding an unload hook --- \n");
44 void Dynamic_Module_Init(struct DLModule_Info *info)
46 add_symbol("cmd_chat", "CHAT", "Initiates a real-time chat session", &My_Symtab);
47 add_symbol("cmd_pexp", "PEXP", "Poll for express messages", &My_Symtab);
48 add_symbol("cmd_sexp", "SEXP", "Send an express message", &My_Symtab);
49 strncpy(info->module_name, MODULE_NAME, 30);
50 strncpy(info->module_author, MODULE_AUTHOR, 30);
51 strncpy(info->module_author_email, MODULE_EMAIL, 30);
52 info->major_version = MAJOR_VERSION;
53 info->minor_version = MINOR_VERSION;
55 CtdlRegisterHook(ChatUnloadingTest, HOOK_CLEANUP);
59 void Get_Symtab(symtab **the_symtab)
61 (*the_symtab) = My_Symtab;
67 void allwrite(char *cmdbuf, int flag, char *roomname, char *username)
72 struct ChatLine *clptr, *clnew;
75 if (CC->fake_username[0])
76 un = CC->fake_username;
78 un = CC->usersupp.fullname;
81 sprintf(bcast,":|<%s %s>",un,cmdbuf);
86 sprintf(bcast,"%s|%s",un,cmdbuf);
91 sprintf(bcast,":|<%s whispers %s>", un, cmdbuf);
93 if ((strcasecmp(cmdbuf,"NOOP")) && (flag !=2)) {
94 fp = fopen(CHATLOG,"a");
95 fprintf(fp,"%s\n",bcast);
99 clnew = (struct ChatLine *) malloc(sizeof(struct ChatLine));
100 bzero(clnew, sizeof(struct ChatLine));
102 fprintf(stderr, "citserver: cannot alloc chat line: %s\n",
109 clnew->chat_time = now;
110 strncpy(clnew->chat_room, roomname, 19);
112 strncpy(clnew->chat_username, username, 31);
114 clnew->chat_username[0] = '\0';
115 strcpy(clnew->chat_text, bcast);
117 /* Here's the critical section.
118 * First, add the new message to the queue...
120 begin_critical_section(S_CHATQUEUE);
122 clnew->chat_seq = ChatLastMsg;
123 if (ChatQueue == NULL) {
127 for (clptr=ChatQueue; clptr->next != NULL; clptr=clptr->next) ;;
131 /* Then, before releasing the lock, free the expired messages */
133 if (ChatQueue == NULL) goto DONE_FREEING;
134 if ( (now - ChatQueue->chat_time) < 120L ) goto DONE_FREEING;
136 ChatQueue = ChatQueue->next;
139 DONE_FREEING: end_critical_section(S_CHATQUEUE);
143 t_context *find_context(char **unstr)
145 t_context *t_cc, *found_cc = NULL;
148 if ((!*unstr) || (!unstr))
151 begin_critical_section(S_SESSION_TABLE);
152 for (t_cc = ContextList; ((t_cc) && (!found_cc)); t_cc = t_cc->next)
154 if (t_cc->fake_username[0])
155 name = t_cc->fake_username;
157 name = t_cc->curr_user;
159 if ((!strncasecmp(name, tptr, strlen(name))) && (tptr[strlen(name)] == ' '))
162 *unstr = &(tptr[strlen(name)+1]);
165 end_critical_section(S_SESSION_TABLE);
171 * List users in chat. Setting allflag to 1 also lists users elsewhere.
174 void do_chat_listing(int allflag)
176 struct CitContext *ccptr;
178 cprintf(":|\n:| Users currently in chat:\n");
179 begin_critical_section(S_SESSION_TABLE);
180 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
181 if ( (!strcasecmp(ccptr->cs_room, "<chat>"))
182 && ((ccptr->cs_flags & CS_STEALTH) == 0)) {
183 cprintf(":| %-25s <%s>\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, ccptr->chat_room);
189 cprintf(":|\n:| Users not in chat:\n");
190 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next)
192 if ( (strcasecmp(ccptr->cs_room, "<chat>"))
193 && ((ccptr->cs_flags & CS_STEALTH) == 0))
195 cprintf(":| %-25s <%s>:\n", (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user, (ccptr->fake_roomname[0]) ? ccptr->fake_roomname : ccptr->cs_room);
200 end_critical_section(S_SESSION_TABLE);
205 void cmd_chat(char *argbuf)
210 char hold_cs_room[20];
211 int MyLastMsg, ThisLastMsg;
212 struct ChatLine *clptr;
213 struct CitContext *t_context;
216 if (!(CC->logged_in)) {
217 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
221 strcpy(CC->chat_room, "Main room");
223 strcpy(hold_cs_room,CC->cs_room);
224 CC->cs_flags = CC->cs_flags | CS_CHAT;
225 set_wtmpsupp("<chat>");
226 cprintf("%d Entering chat mode (type '/help' for available commands)\n",
229 MyLastMsg = ChatLastMsg;
231 if ((CC->cs_flags & CS_STEALTH) == 0) {
232 allwrite("<entering chat>",0, CC->chat_room, NULL);
241 cmdbuf[strlen(cmdbuf) + 1] = 0;
242 retval = client_read_to(&cmdbuf[strlen(cmdbuf)], 1, 2);
244 /* if we have a complete line, do send processing */
245 if (strlen(cmdbuf) > 0) if (cmdbuf[strlen(cmdbuf)-1] == 10) {
246 cmdbuf[strlen(cmdbuf) - 1] = 0;
250 if ( (!strcasecmp(cmdbuf,"exit"))
251 ||(!strcasecmp(cmdbuf,"/exit"))
252 ||(!strcasecmp(cmdbuf,"quit"))
253 ||(!strcasecmp(cmdbuf,"logout"))
254 ||(!strcasecmp(cmdbuf,"logoff"))
255 ||(!strcasecmp(cmdbuf,"/q"))
256 ||(!strcasecmp(cmdbuf,".q"))
257 ||(!strcasecmp(cmdbuf,"/quit"))
258 ) strcpy(cmdbuf,"000");
260 if (!strcmp(cmdbuf,"000")) {
261 if ((CC->cs_flags & CS_STEALTH) == 0) {
262 allwrite("<exiting chat>",0, CC->chat_room, NULL);
266 CC->cs_flags = CC->cs_flags - CS_CHAT;
267 set_wtmpsupp(hold_cs_room);
271 if ((!strcasecmp(cmdbuf,"/help"))
272 ||(!strcasecmp(cmdbuf,"help"))
273 ||(!strcasecmp(cmdbuf,"/?"))
274 ||(!strcasecmp(cmdbuf,"?"))) {
276 cprintf(":|Available commands: \n");
277 cprintf(":|/help (prints this message) \n");
278 cprintf(":|/who (list users currently in chat) \n");
279 cprintf(":|/whobbs (list users in chat -and- elsewhere) \n");
280 cprintf(":|/me ('action' line, ala irc) \n");
281 cprintf(":|/msg (send private message, ala irc) \n");
282 cprintf(":|/join (join new room) \n");
283 cprintf(":|/quit (return to the BBS) \n");
287 if (!strcasecmp(cmdbuf,"/who")) {
291 if (!strcasecmp(cmdbuf,"/whobbs")) {
295 if (!strncasecmp(cmdbuf,"/me ",4)) {
296 allwrite(&cmdbuf[4],1, CC->chat_room, NULL);
300 if (!strncasecmp(cmdbuf,"/msg ", 5))
303 strptr1 = &cmdbuf[5];
304 if ((t_context = find_context(&strptr1)))
306 allwrite(strptr1, 2, "", CC->curr_user);
307 if (strcasecmp(CC->curr_user, t_context->curr_user))
308 allwrite(strptr1, 2, "", t_context->curr_user);
311 cprintf(":|User not found.\n", cmdbuf);
315 if (!strncasecmp(cmdbuf,"/join ", 6))
318 allwrite("<changing rooms>",0, CC->chat_room, NULL);
320 strcpy(CC->chat_room, "Main room");
323 strncpy(CC->chat_room, &cmdbuf[6], 20);
325 allwrite("<joining room>",0, CC->chat_room, NULL);
328 if ((cmdbuf[0]!='/')&&(strlen(cmdbuf)>0)) {
330 allwrite(cmdbuf,0, CC->chat_room, NULL);
333 if ((!ok_cmd) && (cmdbuf[0]) && (cmdbuf[0] != '\n'))
334 cprintf(":|Command %s is not understood.\n", cmdbuf);
340 /* now check the queue for new incoming stuff */
342 if (CC->fake_username[0])
343 un = CC->fake_username;
346 if (ChatLastMsg > MyLastMsg) {
347 ThisLastMsg = ChatLastMsg;
348 for (clptr=ChatQueue; clptr!=NULL; clptr=clptr->next)
350 if ((clptr->chat_seq > MyLastMsg) && ((!clptr->chat_username[0]) || (!strncasecmp(un, clptr->chat_username, 32))))
352 if ((!clptr->chat_room[0]) || (!strncasecmp(CC->chat_room, clptr->chat_room, 20)))
354 cprintf("%s\n", clptr->chat_text);
358 MyLastMsg = ThisLastMsg;
366 * poll for express messages
368 void cmd_pexp(void) {
369 struct ExpressMessage *emptr;
371 if (CC->FirstExpressMessage == NULL) {
372 cprintf("%d No express messages waiting.\n",ERROR);
376 cprintf("%d Express msgs:\n",LISTING_FOLLOWS);
378 while (CC->FirstExpressMessage != NULL) {
379 cprintf("%s", CC->FirstExpressMessage->em_text);
380 begin_critical_section(S_SESSION_TABLE);
381 emptr = CC->FirstExpressMessage;
382 CC->FirstExpressMessage = CC->FirstExpressMessage->next;
384 end_critical_section(S_SESSION_TABLE);
391 * send express messages <bc>
393 void cmd_sexp(char *argbuf)
397 int message_sent = 0;
398 struct CitContext *ccptr;
399 struct ExpressMessage *emptr, *emnew;
400 char *lun; /* <bc> */
402 if (!(CC->logged_in)) {
403 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
407 if (num_parms(argbuf)!=2) {
408 cprintf("%d usage error\n",ERROR);
412 if (CC->fake_username[0])
413 lun = CC->fake_username;
415 lun = CC->usersupp.fullname;
417 extract(x_user,argbuf,0);
419 if (!strcmp(x_user, "."))
421 strcpy(x_user, CC->last_pager);
423 extract(x_msg,argbuf,1);
427 cprintf("%d You were not previously paged.\n", ERROR);
431 if ( (!strcasecmp(x_user, "broadcast")) && (CC->usersupp.axlevel < 6) ) {
432 cprintf("%d Higher access required to send a broadcast.\n",
433 ERROR+HIGHER_ACCESS_REQUIRED);
437 /* find the target user's context and append the message */
438 begin_critical_section(S_SESSION_TABLE);
439 for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
442 if (ccptr->fake_username[0]) /* <bc> */
443 un = ccptr->fake_username;
445 un = ccptr->usersupp.fullname;
447 if ( (!strcasecmp(un, x_user))
448 || (!strcasecmp(x_user, "broadcast")) ) {
449 strcpy(ccptr->last_pager, CC->curr_user);
450 emnew = (struct ExpressMessage *)
451 malloc(sizeof(struct ExpressMessage));
453 sprintf(emnew->em_text, "%s from %s:\n %s\n",
454 ( (!strcasecmp(x_user, "broadcast")) ? "Broadcast message" : "Message" ),
457 if (ccptr->FirstExpressMessage == NULL) {
458 ccptr->FirstExpressMessage = emnew;
461 emptr = ccptr->FirstExpressMessage;
462 while (emptr->next != NULL) {
471 end_critical_section(S_SESSION_TABLE);
473 if (message_sent > 0) {
474 cprintf("%d Message sent.\n",OK);
477 cprintf("%d No user '%s' logged in.\n",ERROR,x_user);