};
static const long NDiskFields = sizeof(FieldOrder) / sizeof(eMsgField);
-void CtdlMsgSetCM_Fields(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length)
+
+int CM_IsEmpty(struct CtdlMessage *Msg, eMsgField which)
+{
+ return !((Msg->cm_fields[which] != NULL) &&
+ (Msg->cm_fields[which][0] != '\0'));
+}
+
+void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length)
{
if (Msg->cm_fields[which] != NULL)
free (Msg->cm_fields[which]);
Msg->cm_fields[which][length] = '\0';
}
+void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue)
+{
+ char buf[128];
+ long len;
+ len = snprintf(buf, sizeof(buf), "%ld", lvalue);
+ CM_SetField(Msg, which, buf, len);
+}
+void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen)
+{
+ if (Msg->cm_fields[WhichToCut] == NULL)
+ return;
+
+ if (strlen(Msg->cm_fields[WhichToCut]) > maxlen)
+ Msg->cm_fields[WhichToCut][maxlen] = '\0';
+}
+
+void CM_FlushField(struct CtdlMessage *Msg, eMsgField which)
+{
+ if (Msg->cm_fields[which] != NULL)
+ free (Msg->cm_fields[which]);
+ Msg->cm_fields[which] = NULL;
+}
+
+void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy)
+{
+ long len;
+ if (Msg->cm_fields[WhichToPutTo] != NULL)
+ free (Msg->cm_fields[WhichToPutTo]);
+
+ if (Msg->cm_fields[WhichtToCopy] != NULL)
+ {
+ len = strlen(Msg->cm_fields[WhichtToCopy]);
+ Msg->cm_fields[WhichToPutTo] = malloc(len + 1);
+ memcpy(Msg->cm_fields[WhichToPutTo], Msg->cm_fields[WhichToPutTo], len);
+ Msg->cm_fields[WhichToPutTo][len] = '\0';
+ }
+ else
+ Msg->cm_fields[WhichToPutTo] = NULL;
+}
+
+
+void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length)
+{
+ if (Msg->cm_fields[which] != NULL) {
+ long oldmsgsize;
+ long newmsgsize;
+ char *new;
+
+ oldmsgsize = strlen(Msg->cm_fields[which]) + 1;
+ newmsgsize = length + oldmsgsize;
+
+ new = malloc(newmsgsize);
+ memcpy(new, buf, length);
+ memcpy(new + length, Msg->cm_fields[which], oldmsgsize);
+ free(Msg->cm_fields[which]);
+ Msg->cm_fields[which] = new;
+ }
+ else {
+ Msg->cm_fields[which] = malloc(length + 1);
+ memcpy(Msg->cm_fields[which], buf, length);
+ Msg->cm_fields[which][length] = '\0';
+ }
+}
+
+void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long length)
+{
+ if (Msg->cm_fields[which] != NULL)
+ free (Msg->cm_fields[which]);
+
+ Msg->cm_fields[which] = *buf;
+ *buf = NULL;
+}
+
+void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf)
+{
+ if (Msg->cm_fields[which] != NULL)
+ free (Msg->cm_fields[which]);
+
+ Msg->cm_fields[which] = SmashStrBuf(buf);
+}
+
+void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *retlen)
+{
+ if (Msg->cm_fields[which] != NULL)
+ {
+ *retlen = strlen(Msg->cm_fields[which]);
+ *ret = Msg->cm_fields[which];
+ Msg->cm_fields[which] = NULL;
+ }
+ else
+ {
+ *ret = NULL;
+ *retlen = 0;
+ }
+}
+
+/*
+ * Returns 1 if the supplied pointer points to a valid Citadel message.
+ * If the pointer is NULL or the magic number check fails, returns 0.
+ */
+int is_valid_message(struct CtdlMessage *msg) {
+ if (msg == NULL)
+ return 0;
+ if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) {
+ struct CitContext *CCC = CC;
+ MSGM_syslog(LOG_WARNING, "is_valid_message() -- self-check failed\n");
+ return 0;
+ }
+ return 1;
+}
+
+void CtdlFreeMessageContents(struct CtdlMessage *msg)
+{
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ if (msg->cm_fields[i] != NULL) {
+ free(msg->cm_fields[i]);
+ }
+
+ msg->cm_magic = 0; /* just in case */
+}
+/*
+ * 'Destructor' for struct CtdlMessage
+ */
+void CtdlFreeMessage(struct CtdlMessage *msg)
+{
+ if (is_valid_message(msg) == 0)
+ {
+ if (msg != NULL) free (msg);
+ return;
+ }
+ CtdlFreeMessageContents(msg);
+ free(msg);
+}
+
+int DupCMField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg)
+{
+ long len;
+ len = strlen(OrgMsg->cm_fields[i]);
+ NewMsg->cm_fields[i] = malloc(len + 1);
+ if (NewMsg->cm_fields[i] == NULL)
+ return 0;
+ memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len);
+ NewMsg->cm_fields[i][len] = '\0';
+ return 1;
+}
+
+struct CtdlMessage * CtdlDuplicateMessage(struct CtdlMessage *OrgMsg)
+{
+ int i;
+ struct CtdlMessage *NewMsg;
+
+ if (is_valid_message(OrgMsg) == 0)
+ return NULL;
+ NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage));
+ if (NewMsg == NULL)
+ return NULL;
+
+ memcpy(NewMsg, OrgMsg, sizeof(struct CtdlMessage));
+
+ memset(&NewMsg->cm_fields, 0, sizeof(char*) * 256);
+
+ for (i = 0; i < 256; ++i)
+ {
+ if (OrgMsg->cm_fields[i] != NULL)
+ {
+ if (!DupCMField(i, OrgMsg, NewMsg))
+ {
+ CtdlFreeMessage(NewMsg);
+ return NULL;
+ }
+ }
+ }
+
+ return NewMsg;
+}
+
+
+
/*
* This function is self explanatory.
* (What can I say, I'm in a weird mood today...)
cprintf("%ld|%s|%s|%s|%s|%s|\n",
msgnum,
- (msg->cm_fields[eTimestamp] ? msg->cm_fields[eTimestamp] : "0"),
- (msg->cm_fields[eAuthor] ? msg->cm_fields[eAuthor] : ""),
- (msg->cm_fields[eNodeName] ? msg->cm_fields[eNodeName] : ""),
- (msg->cm_fields[erFc822Addr] ? msg->cm_fields[erFc822Addr] : ""),
- (msg->cm_fields[eMsgSubject] ? msg->cm_fields[eMsgSubject] : "")
+ (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"),
+ (!CM_IsEmpty(msg, eAuthor) ? msg->cm_fields[eAuthor] : ""),
+ (!CM_IsEmpty(msg, eNodeName) ? msg->cm_fields[eNodeName] : ""),
+ (!CM_IsEmpty(msg, erFc822Addr) ? msg->cm_fields[erFc822Addr] : ""),
+ (!CM_IsEmpty(msg, eMsgSubject) ? msg->cm_fields[eMsgSubject] : "")
);
CtdlFreeMessage(msg);
}
cprintf("%ld|%s|%s\n",
msgnum,
- (msg->cm_fields[eExclusiveID] ? msg->cm_fields[eExclusiveID] : ""),
- (msg->cm_fields[eTimestamp] ? msg->cm_fields[eTimestamp] : "0"));
+ (!CM_IsEmpty(msg, eExclusiveID) ? msg->cm_fields[eExclusiveID] : ""),
+ (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"));
CtdlFreeMessage(msg);
}
template->cm_anon_type = MES_NORMAL;
while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) {
+ long tValueLen;
extract_token(tfield, buf, 0, '|', sizeof tfield);
- extract_token(tvalue, buf, 1, '|', sizeof tvalue);
+ tValueLen = extract_token(tvalue, buf, 1, '|', sizeof tvalue);
for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) {
if (!strcasecmp(tfield, msgkeys[i])) {
- template->cm_fields[i] =
- strdup(tvalue);
+ CM_SetField(template, i, tvalue, tValueLen);
}
}
}
* have just processed the 'M' (message text) field.
*/
do {
+ long len;
if (mptr >= upper_bound) {
break;
}
field_header = *mptr++;
- ret->cm_fields[field_header] = strdup(mptr);
+ len = strlen(mptr);
+ CM_SetField(ret, field_header, mptr, len);
- while (*mptr++ != 0); /* advance to next field */
+ mptr += len + 1; /* advance to next field */
} while ((mptr < upper_bound) && (field_header != 'M'));
* so go ahead and fetch that. Failing that, just set a dummy
* body so other code doesn't barf.
*/
- if ( (ret->cm_fields[eMesageText] == NULL) && (with_body) ) {
+ if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) {
dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long));
if (dmsgtext != NULL) {
- ret->cm_fields[eMesageText] = dmsgtext->ptr;
- dmsgtext->ptr = NULL;
+ CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len);
cdb_free(dmsgtext);
}
}
- if (ret->cm_fields[eMesageText] == NULL) {
- ret->cm_fields[eMesageText] = strdup("\r\n\r\n (no text)\r\n");
+ if (CM_IsEmpty(ret, eMesageText)) {
+ CM_SetField(ret, eMesageText, HKEY("\r\n\r\n (no text)\r\n"));
}
/* Perform "before read" hooks (aborting if any return nonzero) */
}
-/*
- * Returns 1 if the supplied pointer points to a valid Citadel message.
- * If the pointer is NULL or the magic number check fails, returns 0.
- */
-int is_valid_message(struct CtdlMessage *msg) {
- if (msg == NULL)
- return 0;
- if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) {
- struct CitContext *CCC = CC;
- MSGM_syslog(LOG_WARNING, "is_valid_message() -- self-check failed\n");
- return 0;
- }
- return 1;
-}
-
-void CtdlFreeMessageContents(struct CtdlMessage *msg)
-{
- int i;
-
- for (i = 0; i < 256; ++i)
- if (msg->cm_fields[i] != NULL) {
- free(msg->cm_fields[i]);
- }
-
- msg->cm_magic = 0; /* just in case */
-}
-/*
- * 'Destructor' for struct CtdlMessage
- */
-void CtdlFreeMessage(struct CtdlMessage *msg)
-{
- if (is_valid_message(msg) == 0)
- {
- if (msg != NULL) free (msg);
- return;
- }
- CtdlFreeMessageContents(msg);
- free(msg);
-}
-
-int DupCMField(int i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg)
-{
- long len;
- len = strlen(OrgMsg->cm_fields[i]);
- NewMsg->cm_fields[i] = malloc(len + 1);
- if (NewMsg->cm_fields[i] == NULL)
- return 0;
- memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len);
- NewMsg->cm_fields[i][len] = '\0';
- return 1;
-}
-
-struct CtdlMessage * CtdlDuplicateMessage(struct CtdlMessage *OrgMsg)
-{
- int i;
- struct CtdlMessage *NewMsg;
-
- if (is_valid_message(OrgMsg) == 0)
- return NULL;
- NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage));
- if (NewMsg == NULL)
- return NULL;
-
- memcpy(NewMsg, OrgMsg, sizeof(struct CtdlMessage));
-
- memset(&NewMsg->cm_fields, 0, sizeof(char*) * 256);
-
- for (i = 0; i < 256; ++i)
- {
- if (OrgMsg->cm_fields[i] != NULL)
- {
- if (!DupCMField(i, OrgMsg, NewMsg))
- {
- CtdlFreeMessage(NewMsg);
- return NULL;
- }
- }
- }
-
- return NewMsg;
-}
-
-
/*
* Pre callback function for multipart/alternative
* encapsulated message instead of the top-level
* message. Isn't that neat?
*/
-
}
else {
if (do_proto) {
/* begin header processing loop for Citadel message format */
safestrncpy(display_name, "<unknown>", sizeof display_name);
- if (TheMessage->cm_fields[eAuthor]) {
+ if (!CM_IsEmpty(TheMessage, eAuthor)) {
strcpy(buf, TheMessage->cm_fields[eAuthor]);
if (TheMessage->cm_anon_type == MES_ANONONLY) {
safestrncpy(display_name, "****", sizeof display_name);
* local Citadel network.
*/
suppress_f = 0;
- if (TheMessage->cm_fields[eNodeName] != NULL)
- if (!IsEmptyStr(TheMessage->cm_fields[eNodeName]))
- if (haschar(TheMessage->cm_fields[eNodeName], '.') == 0) {
- suppress_f = 1;
- }
+ if (!CM_IsEmpty(TheMessage, eNodeName) &&
+ (haschar(TheMessage->cm_fields[eNodeName], '.') == 0))
+ {
+ suppress_f = 1;
+ }
/* Now spew the header fields in the order we like them. */
for (i=0; i< NDiskFields; ++i) {
eMsgField Field;
Field = FieldOrder[i];
if (Field != eMesageText) {
- if ( (TheMessage->cm_fields[Field] != NULL)
+ if ( (!CM_IsEmpty(TheMessage, Field))
&& (msgkeys[Field] != NULL) ) {
if ((Field == eenVelopeTo) ||
(Field == eRecipient) ||
/* Suppress envelope recipients if required to avoid disclosing BCC addresses.
* Pad it with spaces in order to avoid changing the RFC822 length of the message.
*/
- if ( (flags & SUPPRESS_ENV_TO) && (TheMessage->cm_fields[eenVelopeTo] != NULL) ) {
+ if ( (flags & SUPPRESS_ENV_TO) && (!CM_IsEmpty(TheMessage, eenVelopeTo)) ) {
memset(TheMessage->cm_fields[eenVelopeTo], ' ', strlen(TheMessage->cm_fields[eenVelopeTo]));
}
ReplicationChecks(msg);
/* If the message has an Exclusive ID, index that... */
- if (msg->cm_fields[eExclusiveID] != NULL) {
+ if (!CM_IsEmpty(msg, eExclusiveID)) {
index_message_by_euid(msg->cm_fields[eExclusiveID], &CCC->room, msgid);
}
long newmsgid;
long retval;
char msgidbuf[256];
+ long msgidbuflen;
struct ser_ret smr;
int is_bigmsg = 0;
char *holdM = NULL;
/* Get a new message number */
newmsgid = get_new_message_number();
- snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s",
- (long unsigned int) time(NULL),
- (long unsigned int) newmsgid,
- config.c_fqdn
+ msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s",
+ (long unsigned int) time(NULL),
+ (long unsigned int) newmsgid,
+ config.c_fqdn
);
/* Generate an ID if we don't have one already */
- if (msg->cm_fields[emessageId]==NULL) {
- msg->cm_fields[emessageId] = strdup(msgidbuf);
+ if (CM_IsEmpty(msg, emessageId)) {
+ CM_SetField(msg, emessageId, msgidbuf, msgidbuflen);
}
/* If the message is big, set its body aside for storage elsewhere */
- if (msg->cm_fields[eMesageText] != NULL) {
+ if (!CM_IsEmpty(msg, eMesageText)) {
if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) {
is_bigmsg = 1;
holdM = msg->cm_fields[eMesageText];
/* No exclusive id? Don't do anything. */
if (msg == NULL) return;
- if (msg->cm_fields[eExclusiveID] == NULL) return;
- if (IsEmptyStr(msg->cm_fields[eExclusiveID])) return;
+ if (CM_IsEmpty(msg, eExclusiveID)) return;
+
/*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n",
msg->cm_fields[eExclusiveID], CCC->room.QRname);*/
)
{
char submit_filename[128];
- char generated_timestamp[32];
char hold_rm[ROOMNAMELEN];
char actual_rm[ROOMNAMELEN];
char force_room[ROOMNAMELEN];
/* If this message has no timestamp, we take the liberty of
* giving it one, right now.
*/
- if (msg->cm_fields[eTimestamp] == NULL) {
- snprintf(generated_timestamp, sizeof generated_timestamp, "%ld", (long)time(NULL));
- msg->cm_fields[eTimestamp] = strdup(generated_timestamp);
+ if (CM_IsEmpty(msg, eTimestamp)) {
+ CM_SetFieldLONG(msg, eTimestamp, time(NULL));
}
/* If this message has no path, we generate one.
*/
- if (msg->cm_fields[eMessagePath] == NULL) {
- if (msg->cm_fields[eAuthor] != NULL) {
- msg->cm_fields[eMessagePath] = strdup(msg->cm_fields[eAuthor]);
+ if (CM_IsEmpty(msg, eMessagePath)) {
+ if (!CM_IsEmpty(msg, eAuthor)) {
+ CM_CopyField(msg, eMessagePath, eAuthor);
for (a=0; !IsEmptyStr(&msg->cm_fields[eMessagePath][a]); ++a) {
if (isspace(msg->cm_fields[eMessagePath][a])) {
msg->cm_fields[eMessagePath][a] = ' ';
}
}
else {
- msg->cm_fields[eMessagePath] = strdup("unknown");
+ CM_SetField(msg, eMessagePath, HKEY("unknown"));
}
}
if (force == NULL) {
- strcpy(force_room, "");
+ force_room[0] = '\0';
}
else {
strcpy(force_room, force);
}
/* Learn about what's inside, because it's what's inside that counts */
- if (msg->cm_fields[eMesageText] == NULL) {
+ if (CM_IsEmpty(msg, eMesageText)) {
MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n");
return(-2);
}
/*
* If this message has no O (room) field, generate one.
*/
- if (msg->cm_fields[eOriginalRoom] == NULL) {
- msg->cm_fields[eOriginalRoom] = strdup(CCC->room.QRname);
+ if (CM_IsEmpty(msg, eOriginalRoom)) {
+ CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
}
/* Perform "before save" hooks (aborting if any return nonzero) */
*/
if ((recps != NULL) && (recps->num_local > 0))
for (i=0; i<num_tokens(recps->recp_local, '|'); ++i) {
- extract_token(recipient, recps->recp_local, i,
- '|', sizeof recipient);
+ long recipientlen;
+ recipientlen = extract_token(recipient,
+ recps->recp_local, i,
+ '|', sizeof recipient);
MSG_syslog(LOG_DEBUG, "Delivering private local mail to <%s>\n",
recipient);
if (CtdlGetUser(&userbuf, recipient) == 0) {
/* Generate a instruction message for the Funambol notification
* server, in the same style as the SMTP queue
*/
+ long instrlen;
instr_alloc = 1024;
instr = malloc(instr_alloc);
- snprintf(instr, instr_alloc,
- "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
- "bounceto|%s\n",
- SPOOLMIME, newmsgid, (long)time(NULL),
- bounce_to
+ instrlen = snprintf(
+ instr, instr_alloc,
+ "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
+ "bounceto|%s\n",
+ SPOOLMIME,
+ newmsgid,
+ (long)time(NULL), //todo: time() is expensive!
+ bounce_to
);
imsg = malloc(sizeof(struct CtdlMessage));
imsg->cm_magic = CTDLMESSAGE_MAGIC;
imsg->cm_anon_type = MES_NORMAL;
imsg->cm_format_type = FMT_RFC822;
- imsg->cm_fields[eMsgSubject] = strdup("QMSG");
- imsg->cm_fields[eAuthor] = strdup("Citadel");
- imsg->cm_fields[eJournal] = strdup("do not journal");
- imsg->cm_fields[eMesageText] = instr; /* imsg owns this memory now */
- imsg->cm_fields[eExtnotify] = strdup(recipient);
+ CM_SetField(imsg, eMsgSubject, HKEY("QMSG"));
+ CM_SetField(imsg, eAuthor, HKEY("Citadel"));
+ CM_SetField(imsg, eJournal, HKEY("do not journal"));
+ CM_SetAsField(imsg, eMesageText, &instr, instrlen);
+ CM_SetField(imsg, eExtnotify, recipient, recipientlen);
CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0);
CtdlFreeMessage(imsg);
}
/* Perform "after save" hooks */
MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n");
- if (msg->cm_fields[eVltMsgNum] != NULL) free(msg->cm_fields[eVltMsgNum]);
- msg->cm_fields[eVltMsgNum] = malloc(20);
- snprintf(msg->cm_fields[eVltMsgNum], 20, "%ld", newmsgid);
+
+ CM_SetFieldLONG(msg, eVltMsgNum, newmsgid);
PerformMessageHooks(msg, EVT_AFTERSAVE);
- free(msg->cm_fields[eVltMsgNum]);
- msg->cm_fields[eVltMsgNum] = NULL;
+ CM_FlushField(msg, eVltMsgNum);
/* For IGnet mail, we have to save a new copy into the spooler for
* each recipient, with the R and D fields set to the recipient and
/*
* Determine whether this message qualifies for journaling.
*/
- if (msg->cm_fields[eJournal] != NULL) {
+ if (!CM_IsEmpty(msg, eJournal)) {
qualified_for_journaling = 0;
}
else {
client_write(HKEY("Internal error.\n"));
}
- if (msg->cm_fields[eExclusiveID] != NULL) {
+ if (!CM_IsEmpty(msg, eExclusiveID)) {
cprintf("%s\n", msg->cm_fields[eExclusiveID]);
} else {
cprintf("\n");