/*
* Implements the message store.
*
- * Copyright (c) 1987-2015 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.
* 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,
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,
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
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));
}
/*
* 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));
+ 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 (to != NULL) {
+ 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, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
CTDL_MODULE_INIT(msgbase)
{
if (!threading) {
+ FillMsgKeyLookupTable();
CtdlRegisterDebugFlagHook(HKEY("messages"), SetMessageDebugEnabled, &MessageDebugEnabled);
}