* More license declarations
[citadel.git] / citadel / modules / chat / serv_chat.c
index 262232bbb56c8afa7f549f542ecce01413c7ffa0..d5c7be32c68e2ca9b74c073e36d3e09088a243b6 100644 (file)
@@ -4,6 +4,22 @@
  * This module handles all "real time" communication between users.  The
  * modes of communication currently supported are Chat and Paging.
  *
+ * Copyright (c) 1987-2009 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"
 #include <stdlib.h>
@@ -52,7 +68,9 @@ int ChatLastMsg = 0;
 struct imlog {
        struct imlog *next;
        long usernums[2];
+       char usernames[2][128];
        time_t lastmsg;
+       int last_serial;
        StrBuf *conversation;
 };
 
@@ -61,7 +79,7 @@ struct imlog *imlist = NULL;
 /*
  * 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;
@@ -100,23 +118,39 @@ void log_instant_message(struct CitContext *me, struct CitContext *them, char *m
                memset(this_im, 0, sizeof (struct imlog));
                this_im->usernums[0] = usernums[0];
                this_im->usernums[1] = usernums[1];
+               /* usernames[] and usernums[] might not be in the same order.  This is not an error. */
+               if (me) {
+                       safestrncpy(this_im->usernames[0], me->user.fullname, sizeof this_im->usernames[0]);
+               }
+               if (them) {
+                       safestrncpy(this_im->usernames[1], them->user.fullname, sizeof this_im->usernames[1]);
+               }
                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);
 }
 
@@ -251,13 +285,11 @@ void do_chat_listing(int allflag)
                }
 
                GenerateRoomDisplay(roomname, ccptr, CC);
-               if ((CC->user.axlevel < 6)
-                  && (!IsEmptyStr(ccptr->fake_roomname))) {
+               if ((CC->user.axlevel < 6) && (!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,
@@ -633,6 +665,7 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
        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;
@@ -641,6 +674,7 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
 
        /* 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]) {
@@ -656,10 +690,8 @@ int send_instant_message(char *lun, char *lem, char *x_user, char *x_msg)
                    && ((ccptr->disable_exp == 0)
                    || (CC->user.axlevel >= 6)) ) {
                        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);
@@ -672,7 +704,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;
@@ -838,10 +870,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));
@@ -849,10 +881,17 @@ void flush_individual_conversation(struct imlog *im) {
        msg->cm_magic = CTDLMESSAGE_MAGIC;
        msg->cm_anon_type = MES_NORMAL;
        msg->cm_format_type = FMT_RFC822;
-       msg->cm_fields['A'] = strdup("Citadel");
+       if (!IsEmptyStr(im->usernames[0])) {
+               msg->cm_fields['A'] = strdup(im->usernames[0]);
+       } else {
+               msg->cm_fields['A'] = strdup("Citadel");
+       }
+       if (!IsEmptyStr(im->usernames[1])) {
+               msg->cm_fields['R'] = strdup(im->usernames[1]);
+       }
        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.
@@ -919,10 +958,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);
        }
 }