/*
- * $Id$
- *
* This module handles instant messaging between users.
*
- * Copyright (c) 1987-2010 by the citadel.org team
+ * Copyright (c) 1987-2019 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 open source software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3.
*
* 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>
#include <unistd.h>
#include "config.h"
#include "msgbase.h"
#include "user_ops.h"
-
-#ifndef HAVE_SNPRINTF
-#include "snprintf.h"
-#endif
-
#include "ctdl_module.h"
struct imlog {
this_im->conversation = NewStrBuf();
this_im->next = imlist;
imlist = this_im;
- StrBufAppendBufPlain(this_im->conversation, HKEY(
- "Content-type: text/html\r\n"
- "Content-transfer-encoding: 7bit\r\n"
- "\r\n"
- "<html><body>\r\n"
- ), 0);
+ StrBufAppendBufPlain(this_im->conversation, HKEY("<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.
}
-
/*
* Retrieve instant messages
*/
(long)ptr->timestamp, /* time sent */
ptr->flags, /* flags */
ptr->sender, /* sender of msg */
- config.c_nodename, /* static for now (and possibly deprecated) */
+ CtdlGetConfigStr("c_nodename"), /* static for now (and possibly deprecated) */
ptr->sender_email /* email or jid of sender */
);
free(ptr);
}
+
/*
* Asynchronously deliver instant messages
*/
cprintf("%d instant msg\n", ASYNC_MSG + ASYNC_GEXP);
}
+
/*
* Back end support function for send_instant_message() and company
*/
}
-
-
/*
* This is the back end to the instant message sending function.
* Returns the number of users to which the message was sent.
int message_sent = 0; /* number of successful sends */
struct CitContext *ccptr;
struct ExpressMessage *newmsg = NULL;
- char *un;
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) {
+ if (!IsEmptyStr(x_msg)) {
do_send = 1;
}
++serial_number;
for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
- if (ccptr->fake_username[0]) {
- un = ccptr->fake_username;
- }
- else {
- un = ccptr->user.fullname;
- }
-
- if ( ((!strcasecmp(un, x_user))
+ if ( ((!strcasecmp(ccptr->user.fullname, x_user))
|| (!strcasecmp(x_user, "broadcast")))
&& (ccptr->can_receive_im)
&& ((ccptr->disable_exp == 0)
return (message_sent);
}
+
/*
* send instant messages
*/
int message_sent = 0;
char x_user[USERNAME_SIZE];
char x_msg[1024];
- char *lun;
char *lem;
char *x_big_msgbuf = NULL;
cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
return;
}
- if (CC->fake_username[0])
- lun = CC->fake_username;
- else
- lun = CC->user.fullname;
- lem = CC->cs_inet_email;
+ lem = CC->cs_principal_id;
extract_token(x_user, argbuf, 0, '|', sizeof x_user);
extract_token(x_msg, argbuf, 1, '|', sizeof x_msg);
}
/* This loop handles text-transfer pages */
if (!strcmp(x_msg, "-")) {
- message_sent = PerformXmsgHooks(lun, lem, x_user, "");
+ message_sent = PerformXmsgHooks(CC->user.fullname, lem, x_user, "");
if (message_sent == 0) {
if (CtdlGetUser(NULL, x_user))
cprintf("%d '%s' does not exist.\n",
strcat(x_big_msgbuf, "\n");
strcat(x_big_msgbuf, x_msg);
}
- PerformXmsgHooks(lun, lem, x_user, x_big_msgbuf);
+ PerformXmsgHooks(CC->user.fullname, lem, x_user, x_big_msgbuf);
free(x_big_msgbuf);
/* This loop handles inline pages */
} else {
- message_sent = PerformXmsgHooks(lun, lem, x_user, x_msg);
+ message_sent = PerformXmsgHooks(CC->user.fullname, lem, x_user, x_msg);
if (message_sent > 0) {
- if (!IsEmptyStr(x_msg))
+ if (!IsEmptyStr(x_msg)) {
cprintf("%d Message sent", CIT_OK);
- else
+ }
+ else {
cprintf("%d Ok to send message", CIT_OK);
- if (message_sent > 1)
+ }
+ if (message_sent > 1) {
cprintf(" to %d users", message_sent);
+ }
cprintf(".\n");
} else {
- if (CtdlGetUser(NULL, x_user))
- cprintf("%d '%s' does not exist.\n",
- ERROR + NO_SUCH_USER, x_user);
- else
- cprintf("%d '%s' is not logged in "
- "or is not accepting pages.\n",
+ if (CtdlGetUser(NULL, x_user)) {
+ cprintf("%d '%s' does not exist.\n", ERROR + NO_SUCH_USER, x_user);
+ }
+ else {
+ cprintf("%d '%s' is not logged in or is not accepting instant messages.\n",
ERROR + RESOURCE_NOT_OPEN, x_user);
+ }
}
}
-
/*
* Enter or exit paging-disabled mode
*/
struct CtdlMessage *msg;
long msgnum = 0;
char roomname[ROOMNAMELEN];
+ StrBuf *MsgBuf, *FullMsgBuf;
StrBufAppendBufPlain(im->conversation, HKEY(
"</body>\r\n"
), 0
);
+ MsgBuf = StrBufRFC2047encodeMessage(im->conversation);
+ FlushStrBuf(im->conversation);
+ FullMsgBuf = NewStrBufPlain(NULL, StrLength(im->conversation) + 100);
+
+ StrBufAppendBufPlain(FullMsgBuf, HKEY(
+ "Content-type: text/html; charset=UTF-8\r\n"
+ "Content-Transfer-Encoding: quoted-printable\r\n"
+ "\r\n"
+ ), 0
+ );
+ StrBufAppendBuf (FullMsgBuf, MsgBuf, 0);
+ FreeStrBuf(&MsgBuf);
+
msg = malloc(sizeof(struct CtdlMessage));
memset(msg, 0, sizeof(struct CtdlMessage));
msg->cm_magic = CTDLMESSAGE_MAGIC;
msg->cm_anon_type = MES_NORMAL;
msg->cm_format_type = FMT_RFC822;
if (!IsEmptyStr(im->usernames[0])) {
- msg->cm_fields['A'] = strdup(im->usernames[0]);
+ CM_SetField(msg, eAuthor, im->usernames[0], strlen(im->usernames[0]));
} else {
- msg->cm_fields['A'] = strdup("Citadel");
+ CM_SetField(msg, eAuthor, HKEY("Citadel"));
}
if (!IsEmptyStr(im->usernames[1])) {
- msg->cm_fields['R'] = strdup(im->usernames[1]);
+ CM_SetField(msg, eRecipient, im->usernames[1], strlen(im->usernames[1]));
}
- msg->cm_fields['O'] = strdup(PAGELOGROOM);
- msg->cm_fields['N'] = strdup(NODENAME);
- msg->cm_fields['M'] = SmashStrBuf(&im->conversation); /* we own this memory now */
+
+ CM_SetField(msg, eOriginalRoom, HKEY(PAGELOGROOM));
+ CM_SetAsFieldSB(msg, eMesageText, &FullMsgBuf); /* 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.
snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[1], PAGELOGROOM);
CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS);
msgnum = CtdlSubmitMsg(msg, NULL, roomname, 0);
- CtdlFreeMessage(msg);
+ CM_Free(msg);
/* If there is a valid user number in usernums[0], save a copy for them too. */
if (im->usernums[0] > 0) {
}
/* Finally, if we're logging instant messages globally, do that now. */
- if (!IsEmptyStr(config.c_logpages)) {
- CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);
- CtdlSaveMsgPointerInRoom(config.c_logpages, msgnum, 0, NULL);
+ if (!IsEmptyStr(CtdlGetConfigStr("c_logpages"))) {
+ CtdlCreateRoom(CtdlGetConfigStr("c_logpages"), 3, "", 0, 1, 1, VIEW_BBS);
+ CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_logpages"), msgnum, 0, NULL);
}
}
struct imlog *flush_these = NULL;
struct imlog *dont_flush_these = NULL;
struct imlog *imptr = NULL;
+ struct CitContext *nptr;
+ int nContexts, i;
+
+ nptr = CtdlGetContextArray(&nContexts) ; /* Make a copy of the current wholist */
begin_critical_section(S_IM_LOGS);
while (imlist)
{
imptr = imlist;
imlist = imlist->next;
+
+ /* For a two party conversation, if one party has logged out, force flush. */
+ if (nptr) {
+ int user0_is_still_online = 0;
+ int user1_is_still_online = 0;
+ for (i=0; i<nContexts; i++) {
+ if (nptr[i].user.usernum == imptr->usernums[0]) ++user0_is_still_online;
+ if (nptr[i].user.usernum == imptr->usernums[1]) ++user1_is_still_online;
+ }
+ if (imptr->usernums[0] != imptr->usernums[1]) { /* two party conversation */
+ if ((!user0_is_still_online) || (!user1_is_still_online)) {
+ imptr->lastmsg = 0L; /* force flush */
+ }
+ }
+ else { /* one party conversation (yes, people do IM themselves) */
+ if (!user0_is_still_online) {
+ imptr->lastmsg = 0L; /* force flush */
+ }
+ }
+ }
+
+ /* Now test this conversation to see if it qualifies for flushing. */
if ((time(NULL) - imptr->lastmsg) > if_older_than)
{
/* This conversation qualifies. Move it to the list of ones to flush. */
}
imlist = dont_flush_these;
end_critical_section(S_IM_LOGS);
+ free(nptr);
/* We are now outside of the critical section, and we are the only thread holding a
* pointer to a linked list of conversations to be flushed to disk.
CtdlRegisterProtoHook(cmd_sexp, "SEXP", "Send an instant message");
CtdlRegisterProtoHook(cmd_dexp, "DEXP", "Disable instant messages");
CtdlRegisterProtoHook(cmd_reqt, "REQT", "Request client termination");
- CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC);
- CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP);
+ CtdlRegisterSessionHook(cmd_gexp_async, EVT_ASYNC, PRIO_ASYNC + 1);
+ CtdlRegisterSessionHook(delete_instant_messages, EVT_STOP, PRIO_STOP + 1);
CtdlRegisterXmsgHook(send_instant_message, XMSG_PRI_LOCAL);
- CtdlRegisterSessionHook(instmsg_timer, EVT_TIMER);
- CtdlRegisterSessionHook(instmsg_shutdown, EVT_SHUTDOWN);
+ CtdlRegisterSessionHook(instmsg_timer, EVT_TIMER, PRIO_CLEANUP + 400);
+ CtdlRegisterSessionHook(instmsg_shutdown, EVT_SHUTDOWN, PRIO_SHUTDOWN + 10);
}
- /* return our Subversion id for the Log */
- return "$Id$";
+ /* return our module name for the log */
+ return "instmsg";
}