]> code.citadel.org Git - citadel.git/blobdiff - citadel/modules/chat/serv_chat.c
* Disabled CHAT cmd until the underlying I/O layer is fixed
[citadel.git] / citadel / modules / chat / serv_chat.c
index 5643cf849c93ea914438b96ac0fae86bf87263dc..5fbd1db2d2135447755da37980a00b26137c1fe9 100644 (file)
@@ -2,7 +2,23 @@
  * $Id$
  * 
  * This module handles all "real time" communication between users.  The
- * modes of communication currently supported are Chat and Paging.
+ * modes of communication currently supported are Chat and Instant Messages.
+ *
+ * Copyright (c) 1987-2010 by the citadel.org team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
 #include "sysdep.h"
@@ -38,7 +54,6 @@
 #include "config.h"
 #include "msgbase.h"
 #include "user_ops.h"
-#include "room_ops.h"
 
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
@@ -54,15 +69,26 @@ struct imlog {
        long usernums[2];
        char usernames[2][128];
        time_t lastmsg;
+       int last_serial;
        StrBuf *conversation;
 };
 
 struct imlog *imlist = NULL;
 
+
+
+
+/*
+ * FIXME: OMG this module is realy horrible to the rest of the system when accessing contexts.
+ * It pays no regard at all to how long it may have the context list locked for. 
+ * It carries out IO whilst the context list is locked.
+ * I'd recomend disabling this module altogether for the moment.
+ */
+
 /*
  * This function handles the logging of instant messages to disk.
  */
-void log_instant_message(struct CitContext *me, struct CitContext *them, char *msgtext)
+void log_instant_message(struct CitContext *me, struct CitContext *them, char *msgtext, int serial_number)
 {
        long usernums[2];
        long t;
@@ -111,20 +137,29 @@ void log_instant_message(struct CitContext *me, struct CitContext *them, char *m
                this_im->conversation = NewStrBuf();
                this_im->next = imlist;
                imlist = this_im;
-               StrBufAppendBufPlain(this_im->conversation,
+               StrBufAppendBufPlain(this_im->conversation, HKEY(
                        "Content-type: text/html\r\n"
-                       "Content-transfer-encoding: 7bit\r\n\r\n"
-                       "<html><head><title>instant message transcript</title></head>\r\n"
-                       "<body>\r\n",
-                       -1, 0);
-       }
-
-       this_im->lastmsg = time(NULL);          /* Touch the timestamp so we know when to flush */
-       StrBufAppendBufPlain(this_im->conversation, "<p><b>", -1, 0);
-       StrBufAppendBufPlain(this_im->conversation, me->user.fullname, -1, 0);
-       StrBufAppendBufPlain(this_im->conversation, ":</b> ", -1, 0);
-       StrEscAppend(this_im->conversation, NULL, msgtext, 0, 0);
-       StrBufAppendBufPlain(this_im->conversation, "</p>\r\n", -1, 0);
+                       "Content-transfer-encoding: 7bit\r\n"
+                       "\r\n"
+                       "<html><body>\r\n"
+                       ), 0);
+       }
+
+
+       /* Since it's possible for this function to get called more than once if a user is logged
+        * in on multiple sessions, we use the message's serial number to keep track of whether
+        * we've already logged it.
+        */
+       if (this_im->last_serial != serial_number)
+       {
+               this_im->lastmsg = time(NULL);          /* Touch the timestamp so we know when to flush */
+               this_im->last_serial = serial_number;
+               StrBufAppendBufPlain(this_im->conversation, HKEY("<p><b>"), 0);
+               StrBufAppendBufPlain(this_im->conversation, me->user.fullname, -1, 0);
+               StrBufAppendBufPlain(this_im->conversation, HKEY(":</b> "), 0);
+               StrEscAppend(this_im->conversation, NULL, msgtext, 0, 0);
+               StrBufAppendBufPlain(this_im->conversation, HKEY("</p>\r\n"), 0);
+       }
        end_critical_section(S_IM_LOGS);
 }
 
@@ -205,9 +240,9 @@ void allwrite(char *cmdbuf, int flag, char *username)
 }
 
 
-t_context *find_context(char **unstr)
+CitContext *find_context(char **unstr)
 {
-       t_context *t_cc, *found_cc = NULL;
+       CitContext *t_cc, *found_cc = NULL;
        char *name, *tptr;
 
        if ((!*unstr) || (!unstr))
@@ -259,13 +294,11 @@ void do_chat_listing(int allflag)
                }
 
                GenerateRoomDisplay(roomname, ccptr, CC);
-               if ((CC->user.axlevel < 6)
-                  && (!IsEmptyStr(ccptr->fake_roomname))) {
+               if ((CC->user.axlevel < AxAideU) && (!IsEmptyStr(ccptr->fake_roomname))) {
                        strcpy(roomname, ccptr->fake_roomname);
                }
 
-               if ((ccptr->cs_flags & CS_CHAT)
-                   && ((ccptr->cs_flags & CS_STEALTH) == 0)) {
+               if ((ccptr->cs_flags & CS_CHAT) && ((ccptr->cs_flags & CS_STEALTH) == 0)) {
                        if ((allflag == 0) || (allflag == 1)) {
                                cprintf(":| %-25s <%s>:\n",
                                        (ccptr->fake_username[0]) ? ccptr->fake_username : ccptr->curr_user,
@@ -279,7 +312,7 @@ void do_chat_listing(int allflag)
                for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
 
                        GenerateRoomDisplay(roomname, ccptr, CC);
-                       if ((CC->user.axlevel < 6)
+                       if ((CC->user.axlevel < AxAideU)
                        && (!IsEmptyStr(ccptr->fake_roomname))) {
                                strcpy(roomname, ccptr->fake_roomname);
                        }
@@ -312,6 +345,11 @@ void do_chat_listing(int allflag)
 
 void cmd_chat(char *argbuf)
 {
+       /* FIXME chat has been broken by the underlying buffered I/O layer */
+       cprintf("%d Chat is currently disabled at this site.\n", ERROR);
+       return;
+
+#if 0
        char cmdbuf[SIZ];
        char *un;
        char *strptr1;
@@ -319,20 +357,21 @@ void cmd_chat(char *argbuf)
        struct ChatLine *clptr;
        struct CitContext *t_context;
        int retval;
+       CitContext *CCC = CC;
 
-       if (!(CC->logged_in)) {
+       if (!(CCC->logged_in)) {
                cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
                return;
        }
 
-       CC->cs_flags = CC->cs_flags | CS_CHAT;
+       CCC->cs_flags = CCC->cs_flags | CS_CHAT;
        cprintf("%d Entering chat mode (type '/help' for available commands)\n",
                START_CHAT_MODE);
        unbuffer_output();
 
        MyLastMsg = ChatLastMsg;
 
-       if ((CC->cs_flags & CS_STEALTH) == 0) {
+       if ((CCC->cs_flags & CS_STEALTH) == 0) {
                allwrite("<entering chat>", 0, NULL);
        }
        strcpy(cmdbuf, "");
@@ -350,8 +389,8 @@ void cmd_chat(char *argbuf)
 
                retval = client_read_to(&cmdbuf[linelen], 1, 2);
 
-               if (retval < 0 || CC->kill_me) {        /* socket broken? */
-                       if ((CC->cs_flags & CS_STEALTH) == 0) {
+               if (retval < 0 || CCC->kill_me) {       /* socket broken? */
+                       if ((CCC->cs_flags & CS_STEALTH) == 0) {
                                allwrite("<disconnected>", 0, NULL);
                        }
                        return;
@@ -361,8 +400,8 @@ void cmd_chat(char *argbuf)
                if (!IsEmptyStr(cmdbuf))
                        if (cmdbuf[strlen(cmdbuf) - 1] == 10) {
                                cmdbuf[strlen(cmdbuf) - 1] = 0;
-                               time(&CC->lastcmd);
-                               time(&CC->lastidle);
+                               time(&CCC->lastcmd);
+                               time(&CCC->lastidle);
 
                                if ((!strcasecmp(cmdbuf, "exit"))
                                    || (!strcasecmp(cmdbuf, "/exit"))
@@ -376,12 +415,12 @@ void cmd_chat(char *argbuf)
                                        strcpy(cmdbuf, "000");
 
                                if (!strcmp(cmdbuf, "000")) {
-                                       if ((CC->cs_flags & CS_STEALTH) == 0) {
+                                       if ((CCC->cs_flags & CS_STEALTH) == 0) {
                                                allwrite("<exiting chat>", 0, NULL);
                                        }
                                        sleep(1);
                                        cprintf("000\n");
-                                       CC->cs_flags = CC->cs_flags - CS_CHAT;
+                                       CCC->cs_flags = CCC->cs_flags - CS_CHAT;
                                        return;
                                }
                                if ((!strcasecmp(cmdbuf, "/help"))
@@ -418,8 +457,8 @@ void cmd_chat(char *argbuf)
                                        ok_cmd = 1;
                                        strptr1 = &cmdbuf[5];
                                        if ((t_context = find_context(&strptr1))) {
-                                               allwrite(strptr1, 2, CC->curr_user);
-                                               if (strcasecmp(CC->curr_user, t_context->curr_user))
+                                               allwrite(strptr1, 2, CCC->curr_user);
+                                               if (strcasecmp(CCC->curr_user, t_context->curr_user))
                                                        allwrite(strptr1, 2, t_context->curr_user);
                                        } else
                                                cprintf(":|User not found.\n");
@@ -434,7 +473,7 @@ void cmd_chat(char *argbuf)
                                        strptr1 = &cmdbuf[6];
                                        strcat(strptr1, " ");
                                        if ((t_context = find_context(&strptr1))) {
-                                               if (strcasecmp(CC->curr_user, t_context->curr_user))
+                                               if (strcasecmp(CCC->curr_user, t_context->curr_user))
                                                        allwrite(strptr1, 3, t_context->curr_user);
                                        } else
                                                cprintf(":|User not found.\n");
@@ -452,15 +491,15 @@ void cmd_chat(char *argbuf)
                        }
                /* now check the queue for new incoming stuff */
 
-               if (CC->fake_username[0])
-                       un = CC->fake_username;
+               if (CCC->fake_username[0])
+                       un = CCC->fake_username;
                else
-                       un = CC->curr_user;
+                       un = CCC->curr_user;
                if (ChatLastMsg > MyLastMsg) {
                        ThisLastMsg = ChatLastMsg;
                        for (clptr = ChatQueue; clptr != NULL; clptr = clptr->next) {
                                if ((clptr->chat_seq > MyLastMsg) && ((!clptr->chat_username[0]) || (!strncasecmp(un, clptr->chat_username, 32)))) {
-                                       if ((!clptr->chat_room[0]) || (!strncasecmp(CC->room.QRname, clptr->chat_room, ROOMNAMELEN))) {
+                                       if ((!clptr->chat_room[0]) || (!strncasecmp(CCC->room.QRname, clptr->chat_room, ROOMNAMELEN))) {
                                                /* Output new chat data */
                                                cprintf("%s\n", clptr->chat_text);
 
@@ -468,13 +507,13 @@ void cmd_chat(char *argbuf)
                                                if (!strcmp(&clptr->chat_text[2], KICKEDMSG)) {
                                                        allwrite("<kicked out of this room>", 0, NULL);
                                                        cprintf("000\n");
-                                                       CC->cs_flags = CC->cs_flags - CS_CHAT;
+                                                       CCC->cs_flags = CCC->cs_flags - CS_CHAT;
 
                                                        /* Kick user out of room */
-                                                       CtdlInvtKick(CC->user.fullname, 0);
+                                                       CtdlInvtKick(CCC->user.fullname, 0);
 
                                                        /* And return to the Lobby */
-                                                       usergoto(config.c_baseroom, 0, 0, NULL, NULL);
+                                                       CtdlUserGoto(config.c_baseroom, 0, 0, NULL, NULL);
                                                        return;
                                                }
                                        }
@@ -483,6 +522,7 @@ void cmd_chat(char *argbuf)
                        MyLastMsg = ThisLastMsg;
                }
        }
+#endif
 }
 
 
@@ -506,48 +546,8 @@ void delete_instant_messages(void) {
 
 
 
-
-/*
- * Poll for instant messages (OLD METHOD -- ***DEPRECATED ***)
- */
-void cmd_pexp(char *argbuf)
-{
-       struct ExpressMessage *ptr, *holdptr;
-
-       if (CC->FirstExpressMessage == NULL) {
-               cprintf("%d No instant messages waiting.\n", ERROR + MESSAGE_NOT_FOUND);
-               return;
-       }
-       begin_critical_section(S_SESSION_TABLE);
-       ptr = CC->FirstExpressMessage;
-       CC->FirstExpressMessage = NULL;
-       end_critical_section(S_SESSION_TABLE);
-
-       cprintf("%d Express msgs:\n", LISTING_FOLLOWS);
-       while (ptr != NULL) {
-               if (ptr->flags && EM_BROADCAST)
-                       cprintf("Broadcast message ");
-               else if (ptr->flags && EM_CHAT)
-                       cprintf("Chat request ");
-               else if (ptr->flags && EM_GO_AWAY)
-                       cprintf("Please logoff now, as requested ");
-               else
-                       cprintf("Message ");
-               cprintf("from %s:\n", ptr->sender);
-               if (ptr->text != NULL)
-                       memfmout(ptr->text, 0, "\n");
-
-               holdptr = ptr->next;
-               if (ptr->text != NULL) free(ptr->text);
-               free(ptr);
-               ptr = holdptr;
-       }
-       cprintf("000\n");
-}
-
-
 /*
- * Get instant messages (new method)
+ * Retrieve instant messages
  */
 void cmd_gexp(char *argbuf) {
        struct ExpressMessage *ptr;
@@ -573,8 +573,7 @@ void cmd_gexp(char *argbuf) {
        );
 
        if (ptr->text != NULL) {
-               memfmout(ptr->text, 0, "\n");
-               if (ptr->text[strlen(ptr->text)-1] != '\n') cprintf("\n");
+               memfmout(ptr->text, "\n");
                free(ptr->text);
        }
 
@@ -617,12 +616,7 @@ void add_xmsg_to_context(struct CitContext *ccptr, struct ExpressMessage *newmsg
        /* If the target context is a session which can handle asynchronous
         * messages, go ahead and set the flag for that.
         */
-       if (ccptr->is_async) {
-               ccptr->async_waiting = 1;
-               if (ccptr->state == CON_IDLE) {
-                       ccptr->state = CON_READY;
-               }
-       }
+       set_async_waiting(ccptr);
 }
 
 
@@ -639,16 +633,16 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
        struct CitContext *ccptr;
        struct ExpressMessage *newmsg = NULL;
        char *un;
-       size_t msglen = 0;
        int do_send = 0;                /* 1 = send message; 0 = only check for valid recipient */
+       static int serial_number = 0;   /* this keeps messages from getting logged twice */
 
        if (strlen(x_msg) > 0) {
-               msglen = strlen(x_msg) + 4;
                do_send = 1;
        }
 
        /* find the target user's context and append the message */
        begin_critical_section(S_SESSION_TABLE);
+       ++serial_number;
        for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
 
                if (ccptr->fake_username[0]) {
@@ -662,12 +656,10 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
                    || (!strcasecmp(x_user, "broadcast")))
                    && (ccptr->can_receive_im)
                    && ((ccptr->disable_exp == 0)
-                   || (CC->user.axlevel >= 6)) ) {
+                   || (CC->user.axlevel >= AxAideU)) ) {
                        if (do_send) {
-                               newmsg = (struct ExpressMessage *)
-                                       malloc(sizeof (struct ExpressMessage));
-                               memset(newmsg, 0,
-                                       sizeof (struct ExpressMessage));
+                               newmsg = (struct ExpressMessage *) malloc(sizeof (struct ExpressMessage));
+                               memset(newmsg, 0, sizeof (struct ExpressMessage));
                                time(&(newmsg->timestamp));
                                safestrncpy(newmsg->sender, lun, sizeof newmsg->sender);
                                safestrncpy(newmsg->sender_email, lem, sizeof newmsg->sender_email);
@@ -680,7 +672,7 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
 
                                /* and log it ... */
                                if (ccptr != CC) {
-                                       log_instant_message(CC, ccptr, newmsg->text);
+                                       log_instant_message(CC, ccptr, newmsg->text, serial_number);
                                }
                        }
                        ++message_sent;
@@ -720,7 +712,7 @@ void cmd_sexp(char *argbuf)
                cprintf("%d You were not previously paged.\n", ERROR + NO_SUCH_USER);
                return;
        }
-       if ((!strcasecmp(x_user, "broadcast")) && (CC->user.axlevel < 6)) {
+       if ((!strcasecmp(x_user, "broadcast")) && (CC->user.axlevel < AxAideU)) {
                cprintf("%d Higher access required to send a broadcast.\n",
                        ERROR + HIGHER_ACCESS_REQUIRED);
                return;
@@ -729,7 +721,7 @@ void cmd_sexp(char *argbuf)
        if (!strcmp(x_msg, "-")) {
                message_sent = PerformXmsgHooks(lun, lem, x_user, "");
                if (message_sent == 0) {
-                       if (getuser(NULL, x_user))
+                       if (CtdlGetUser(NULL, x_user))
                                cprintf("%d '%s' does not exist.\n",
                                                ERROR + NO_SUCH_USER, x_user);
                        else
@@ -767,7 +759,7 @@ void cmd_sexp(char *argbuf)
                                cprintf(" to %d users", message_sent);
                        cprintf(".\n");
                } else {
-                       if (getuser(NULL, x_user))
+                       if (CtdlGetUser(NULL, x_user))
                                cprintf("%d '%s' does not exist.\n",
                                                ERROR + NO_SUCH_USER, x_user);
                        else
@@ -846,10 +838,10 @@ void flush_individual_conversation(struct imlog *im) {
        long msgnum = 0;
        char roomname[ROOMNAMELEN];
 
-       StrBufAppendBufPlain(im->conversation,
+       StrBufAppendBufPlain(im->conversation, HKEY(
                "</body>\r\n"
-               "</html>\r\n",
-               -1, 0
+               "</html>\r\n"
+               ), 0
        );
 
        msg = malloc(sizeof(struct CtdlMessage));
@@ -867,7 +859,7 @@ void flush_individual_conversation(struct imlog *im) {
        }
        msg->cm_fields['O'] = strdup(PAGELOGROOM);
        msg->cm_fields['N'] = strdup(NODENAME);
-       msg->cm_fields['M'] = strdup(ChrPtr(im->conversation));
+       msg->cm_fields['M'] = SmashStrBuf(&im->conversation);   /* we own this memory now */
 
        /* Start with usernums[1] because it's guaranteed to be higher than usernums[0],
         * so if there's only one party, usernums[0] will be zero but usernums[1] won't.
@@ -879,20 +871,20 @@ void flush_individual_conversation(struct imlog *im) {
         * prefix will be created.  That's ok because the auto-purger will clean it up later.
         */
        snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[1], PAGELOGROOM);
-       create_room(roomname, 5, "", 0, 1, 1, VIEW_BBS);
+       CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS);
        msgnum = CtdlSubmitMsg(msg, NULL, roomname, 0);
        CtdlFreeMessage(msg);
 
        /* If there is a valid user number in usernums[0], save a copy for them too. */
        if (im->usernums[0] > 0) {
                snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[0], PAGELOGROOM);
-               create_room(roomname, 5, "", 0, 1, 1, VIEW_BBS);
+               CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS);
                CtdlSaveMsgPointerInRoom(roomname, msgnum, 0, NULL);
        }
 
        /* Finally, if we're logging instant messages globally, do that now. */
        if (!IsEmptyStr(config.c_logpages)) {
-               create_room(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);
+               CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);
                CtdlSaveMsgPointerInRoom(config.c_logpages, msgnum, 0, NULL);
        }
 
@@ -934,10 +926,9 @@ void flush_conversations_to_disk(time_t if_older_than) {
         */
        while (flush_these) {
 
-               flush_individual_conversation(flush_these);
+               flush_individual_conversation(flush_these);     /* This will free the string buffer */
                imptr = flush_these;
                flush_these = flush_these->next;
-               FreeStrBuf(&imptr->conversation);
                free(imptr);
        }
 }
@@ -957,7 +948,6 @@ CTDL_MODULE_INIT(chat)
        if (!threading)
        {
                CtdlRegisterProtoHook(cmd_chat, "CHAT", "Begin real-time chat");
-               CtdlRegisterProtoHook(cmd_pexp, "PEXP", "Poll for instant messages");
                CtdlRegisterProtoHook(cmd_gexp, "GEXP", "Get instant messages");
                CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message");
                CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages");