/*
* Implements the message store.
*
- * Copyright (c) 1987-2012 by the citadel.org team
+ * Copyright (c) 1987-2016 by the citadel.org team
*
* 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.
#include "ctdl_module.h"
#include "citserver.h"
#include "control.h"
+#include "config.h"
#include "clientsocket.h"
#include "genstamp.h"
#include "room_ops.h"
* These are the four-character field headers we use when outputting
* messages in Citadel format (as opposed to RFC822 format).
*/
-char *msgkeys[] = {
+char *msgkeys[91] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL,
- "from", /* A */
- NULL, /* B */
- NULL, /* C */
- NULL, /* D */
- "exti", /* E */
- "rfca", /* F */
+ "from", /* A -> eAuthor */
+ NULL, /* B -> eBig_message */
+ NULL, /* C -> eRemoteRoom */
+ NULL, /* D -> eDestination */
+ "exti", /* E -> eXclusivID */
+ "rfca", /* F -> erFc822Addr */
NULL, /* G */
- "hnod", /* H */
- "msgn", /* I */
- "jrnl", /* J */
- "rep2", /* K */
- "list", /* L */
- "text", /* M */
- "node", /* N */
- "room", /* O */
- "path", /* P */
+ "hnod", /* H -> eHumanNode */
+ "msgn", /* I -> emessageId */
+ "jrnl", /* J -> eJournal */
+ "rep2", /* K -> eReplyTo */
+ "list", /* L -> eListID */
+ "text", /* M -> eMesageText */
+ "node", /* N -> eNodeName */
+ "room", /* O -> eOriginalRoom */
+ "path", /* P -> eMessagePath */
NULL, /* Q */
- "rcpt", /* R */
- "spec", /* S */
- "time", /* T */
- "subj", /* U */
- "nvto", /* V */
- "wefw", /* W */
+ "rcpt", /* R -> eRecipient */
+ "spec", /* S -> eSpecialField */
+ "time", /* T -> eTimestamp */
+ "subj", /* U -> eMsgSubject */
+ "nvto", /* V -> eenVelopeTo */
+ "wefw", /* W -> eWeferences */
NULL, /* X */
- "cccc", /* Y */
- NULL /* Z */
+ "cccc", /* Y -> eCarbonCopY */
+ NULL /* Z */
+
};
+HashList *msgKeyLookup = NULL;
+
+int GetFieldFromMnemonic(eMsgField *f, const char* c)
+{
+ void *v = NULL;
+ if (GetHash(msgKeyLookup, c, 4, &v)) {
+ *f = (eMsgField) v;
+ return 1;
+ }
+ return 0;
+}
+
+void FillMsgKeyLookupTable(void)
+{
+ long i;
+
+ msgKeyLookup = NewHash (1, FourHash);
+
+ for (i=0; i < 91; i++) {
+ if (msgkeys[i] != NULL) {
+ Put(msgKeyLookup, msgkeys[i], 4, (void*)i, reference_free_handler);
+ }
+ }
+}
eMsgField FieldOrder[] = {
/* Important fields */
* This is used by CtdlOutputMsg() and other fetch functions.
*
* NOTE: Caller is responsible for freeing the returned CtdlMessage struct
- * using the CtdlMessageFree() function.
+ * using the CM_Free(); function.
*/
struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body, int run_msg_hooks)
{
void OutputRFC822MsgHeaders(
struct CtdlMessage *TheMessage,
int flags, /* should the bessage be exported clean */
- const char *nl,
+ const char *nl, int nlen,
char *mid, long sizeof_mid,
char *suser, long sizeof_suser,
char *luser, long sizeof_luser,
if (haschar(mptr, '@') == 0)
{
sanitize_truncated_recipient(mptr);
- cprintf("To: %s@%s", mptr, config.c_fqdn);
+ cprintf("To: %s@%s", mptr, CtdlGetConfigStr("c_fqdn"));
cprintf("%s", nl);
}
else
int headers_only, /* eschew the message body? */
int flags, /* should the bessage be exported clean? */
- const char *nl)
+ const char *nl, int nlen)
{
cit_uint8_t prev_ch;
int eoh = 0;
int outlen = 0;
int nllen = strlen(nl);
char *mptr;
+ int lfSent = 0;
mptr = TheMessage->cm_fields[eMesageText];
MSGM_syslog(LOG_ERR, "Dump_RFC822HeadersBody(): aborting due to write failure.\n");
return;
}
+ lfSent = (outbuf[outlen - 1] == '\n');
outlen = 0;
}
}
if (outlen > 0) {
client_write(outbuf, outlen);
+ lfSent = (outbuf[outlen - 1] == '\n');
}
+ if (!lfSent)
+ client_write(nl, nlen);
}
void DumpFormatFixed(
struct CtdlMessage *TheMessage,
int mode, /* how would you like that message? */
- const char *nl)
+ const char *nl, int nllen)
{
cit_uint8_t ch;
char buf[SIZ];
int buflen;
int xlline = 0;
- int nllen = strlen (nl);
char *mptr;
mptr = TheMessage->cm_fields[eMesageText];
struct CitContext *CCC = CC;
int i;
const char *nl; /* newline string */
+ int nlen;
struct ma_info ma;
/* Buffers needed for RFC822 translation. These are all filled
strcpy(mid, "unknown");
nl = (crlf ? "\r\n" : "\n");
+ nlen = crlf ? 2 : 1;
if (!CM_IsValidMsg(TheMessage)) {
MSGM_syslog(LOG_ERR,
strcpy(suser, "");
strcpy(luser, "");
strcpy(fuser, "");
- memcpy(snode, CFG_KEY(c_nodename) + 1);
+ memcpy(snode, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")) + 1);
if (mode == MT_RFC822)
OutputRFC822MsgHeaders(
TheMessage,
flags,
- nl,
+ nl, nlen,
mid, sizeof(mid),
suser, sizeof(suser),
luser, sizeof(luser),
TheMessage,
headers_only,
flags,
- nl);
+ nl, nlen);
goto DONE;
}
}
DumpFormatFixed(
TheMessage,
mode, /* how would you like that message? */
- nl);
+ nl, nlen);
/* If the message on disk is format 0 (Citadel vari-format), we
* output using the formatter at 80 columns. This is the final output
msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s",
(long unsigned int) time(NULL),
(long unsigned int) newmsgid,
- config.c_fqdn
+ CtdlGetConfigStr("c_fqdn")
);
CM_SetField(msg, emessageId, msgidbuf, msgidbuflen);
if (TWITDETECT) {
if (CCC->user.axlevel == AxProbU) {
strcpy(hold_rm, actual_rm);
- strcpy(actual_rm, config.c_twitroom);
+ strcpy(actual_rm, CtdlGetConfigStr("c_twitroom"));
MSGM_syslog(LOG_DEBUG, "Diverting to twit room\n");
}
}
strcpy(actual_rm, force_room);
}
- MSG_syslog(LOG_INFO, "Final selection: %s (%s)\n", actual_rm, room);
+ MSG_syslog(LOG_DEBUG, "Final selection: %s (%s)\n", actual_rm, room);
if (strcasecmp(actual_rm, CCC->room.QRname)) {
/* CtdlGetRoom(&CCC->room, actual_rm); */
CtdlUserGoto(actual_rm, 0, 1, NULL, NULL, NULL, NULL);
/*
* If this message has no O (room) field, generate one.
*/
- if (CM_IsEmpty(msg, eOriginalRoom)) {
+ if (CM_IsEmpty(msg, eOriginalRoom) && !IsEmptyStr(CCC->room.QRname)) {
CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
}
if ((!CCC->internal_pgm) || (recps == NULL)) {
if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) {
MSGM_syslog(LOG_ERR, "ERROR saving message pointer!\n");
- CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
+ CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg);
}
}
{
if (CCC->logged_in)
snprintf(bounce_to, sizeof bounce_to, "%s@%s",
- CCC->user.fullname, config.c_nodename);
+ CCC->user.fullname, CtdlGetConfigStr("c_nodename"));
else
snprintf(bounce_to, sizeof bounce_to, "%s@%s",
msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]);
}
else {
MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient);
- CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
+ CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg);
}
}
recps->recp_local = pch;
}
else {
if (recps == NULL) {
- qualified_for_journaling = config.c_journal_pubmsgs;
+ qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs");
}
else if (recps->num_local + recps->num_ignet + recps->num_internet > 0) {
- qualified_for_journaling = config.c_journal_email;
+ qualified_for_journaling = CtdlGetConfigInt("c_journal_email");
}
else {
- qualified_for_journaling = config.c_journal_pubmsgs;
+ qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs");
}
}
/*
* Convenience function for generating small administrative messages.
*/
-void quickie_message(const char *from,
+long quickie_message(const char *from,
const char *fromaddr,
const char *to,
char *room,
msg->cm_anon_type = MES_NORMAL;
msg->cm_format_type = format_type;
- if (from != NULL) {
+ if (!IsEmptyStr(from)) {
CM_SetField(msg, eAuthor, from, strlen(from));
}
- else if (fromaddr != NULL) {
+ else if (!IsEmptyStr(fromaddr)) {
char *pAt;
CM_SetField(msg, eAuthor, fromaddr, strlen(fromaddr));
pAt = strchr(msg->cm_fields[eAuthor], '@');
msg->cm_fields[eAuthor] = strdup("Citadel");
}
- if (fromaddr != NULL) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr));
- if (room != NULL) CM_SetField(msg, eOriginalRoom, room, strlen(room));
- CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
- if (to != NULL) {
+ if (!IsEmptyStr(fromaddr)) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr));
+ if (!IsEmptyStr(room)) CM_SetField(msg, eOriginalRoom, room, strlen(room));
+ CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+ if (!IsEmptyStr(to)) {
CM_SetField(msg, eRecipient, to, strlen(to));
recp = validate_recipients(to, NULL, 0);
}
- if (subject != NULL) {
+ if (!IsEmptyStr(subject)) {
CM_SetField(msg, eMsgSubject, subject, strlen(subject));
}
- CM_SetField(msg, eMesageText, text, strlen(text));
+ if (!IsEmptyStr(text)) {
+ CM_SetField(msg, eMesageText, text, strlen(text));
+ }
- CtdlSubmitMsg(msg, recp, room, 0);
+ long msgnum = CtdlSubmitMsg(msg, recp, room, 0);
CM_Free(msg);
if (recp != NULL) free_recipients(recp);
+ return msgnum;
}
+
void flood_protect_quickie_message(const char *from,
const char *fromaddr,
const char *to,
long ioid,
time_t NOW)
{
+ struct CitContext *CCC = CC;
int i;
u_char rawdigest[MD5_DIGEST_LEN];
struct MD5Context md5context;
{
FreeStrBuf(&guid);
/* yes, we did. flood protection kicks in. */
- syslog(LOG_DEBUG,
- "not sending message again - %ld < %ld \n", seenstamp, tsday);
+ MSG_syslog(LOG_DEBUG,
+ "not sending message again - %ld < %ld \n", seenstamp, tsday);
return;
}
else
{
- syslog(LOG_DEBUG,
- "sending message. %ld >= %ld", seenstamp, tsday);
+ MSG_syslog(LOG_DEBUG,
+ "sending message. %ld >= %ld", seenstamp, tsday);
FreeStrBuf(&guid);
/* no, this message isn't sent recently; go ahead. */
quickie_message(from,
if (myelen > 0) {
CM_SetField(msg, eMessagePath, my_email, myelen);
}
- else {
+ else if (!IsEmptyStr(author->fullname)) {
CM_SetField(msg, eMessagePath, author->fullname, strlen(author->fullname));
}
convert_spaces_to_underscores(msg->cm_fields[eMessagePath]);
CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor);
FreeStrBuf(&FakeAuthor);
- if (CCC->room.QRflags & QR_MAILBOX) { /* room */
- CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11]));
- }
- else {
- CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
+ if (!!IsEmptyStr(CCC->room.QRname)) {
+ if (CCC->room.QRflags & QR_MAILBOX) { /* room */
+ CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11]));
+ }
+ else {
+ CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
+ }
}
- CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
- CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+ CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+ CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
if (rcplen > 0) {
CM_SetField(msg, eRecipient, recipient, rcplen);
}
else {
StrBuf *MsgBody;
- MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+ MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0);
if (MsgBody != NULL) {
CM_SetAsFieldSB(msg, eMesageText, &MsgBody);
}
msg->cm_format_type = 4;
CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
CM_SetField(msg, eOriginalRoom, req_room, strlen(req_room));
- CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
- CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+ CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+ CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
msg->cm_flags = flags;
CM_SetAsFieldSB(msg, eMesageText, &encoded_message);
CTDL_MODULE_INIT(msgbase)
{
if (!threading) {
+ FillMsgKeyLookupTable();
CtdlRegisterDebugFlagHook(HKEY("messages"), SetMessageDebugEnabled, &MessageDebugEnabled);
}